|
28 | 28 | "source": [
|
29 | 29 | "#| export\n",
|
30 | 30 | "from fastcore.utils import *\n",
|
31 |
| - "import fastcore.xtras, yaml\n", |
32 |
| - "from textwrap import dedent" |
| 31 | + "from textwrap import dedent\n", |
| 32 | + "from jsonschema import validate\n", |
| 33 | + "from httpx import get as xget\n", |
| 34 | + "\n", |
| 35 | + "import fastcore.xtras, yaml, json" |
| 36 | + ] |
| 37 | + }, |
| 38 | + { |
| 39 | + "cell_type": "code", |
| 40 | + "execution_count": null, |
| 41 | + "id": "aa8f2efa", |
| 42 | + "metadata": {}, |
| 43 | + "outputs": [], |
| 44 | + "source": [ |
| 45 | + "from fastcore.test import test_eq,test_fail\n", |
| 46 | + "from jsonschema import ValidationError" |
33 | 47 | ]
|
34 | 48 | },
|
35 | 49 | {
|
|
315 | 329 | " return dict(runcmd=cmds)"
|
316 | 330 | ]
|
317 | 331 | },
|
| 332 | + { |
| 333 | + "cell_type": "code", |
| 334 | + "execution_count": null, |
| 335 | + "id": "0f608fa1", |
| 336 | + "metadata": {}, |
| 337 | + "outputs": [], |
| 338 | + "source": [ |
| 339 | + "def cc_validate(d):\n", |
| 340 | + " vsc = xget('https://raw.githubusercontent.com/canonical/cloud-init/main/cloudinit/config/schemas/versions.schema.cloud-config.json').text\n", |
| 341 | + " validate(d, schema=json.loads(vsc))" |
| 342 | + ] |
| 343 | + }, |
| 344 | + { |
| 345 | + "cell_type": "code", |
| 346 | + "execution_count": null, |
| 347 | + "id": "0646d7af", |
| 348 | + "metadata": {}, |
| 349 | + "outputs": [], |
| 350 | + "source": [ |
| 351 | + "samp = '''#cloud-config\n", |
| 352 | + "hostname: example-host\n", |
| 353 | + "fqdn: example-host.example.com\n", |
| 354 | + "# User setup configuration\n", |
| 355 | + "users:\n", |
| 356 | + " - name: exampleuser\n", |
| 357 | + " gecos: Example User\n", |
| 358 | + " sudo: ['ALL=(ALL) NOPASSWD:ALL']'''\n", |
| 359 | + "cc_validate(yaml.safe_load(samp))" |
| 360 | + ] |
| 361 | + }, |
| 362 | + { |
| 363 | + "cell_type": "markdown", |
| 364 | + "id": "ea5aa012", |
| 365 | + "metadata": {}, |
| 366 | + "source": [ |
| 367 | + "This example has an intentional key error (\"hostna\" instead of \"hostname\"):" |
| 368 | + ] |
| 369 | + }, |
| 370 | + { |
| 371 | + "cell_type": "code", |
| 372 | + "execution_count": null, |
| 373 | + "id": "a8d9e3fd", |
| 374 | + "metadata": {}, |
| 375 | + "outputs": [], |
| 376 | + "source": [ |
| 377 | + "samp = '''#cloud-config\n", |
| 378 | + "hostna: example-host\n", |
| 379 | + "fqdn: example-host.example.com'''\n", |
| 380 | + "try: cc_validate(yaml.safe_load(samp))\n", |
| 381 | + "except ValidationError: pass\n", |
| 382 | + "else: raise Exception('Expected validation error')" |
| 383 | + ] |
| 384 | + }, |
318 | 385 | {
|
319 | 386 | "cell_type": "code",
|
320 | 387 | "execution_count": null,
|
|
323 | 390 | "outputs": [],
|
324 | 391 | "source": [
|
325 | 392 | "#| export\n",
|
326 |
| - "def cloud_init_base(hostname, packages=None, **kw):\n", |
| 393 | + "def cloud_init_base(hostname, packages=None, check=True, **kw):\n", |
327 | 394 | " cfg = dict(\n",
|
328 | 395 | " hostname=hostname, preserve_hostname=False,\n",
|
329 | 396 | " packages=listify(packages), package_update=True, package_upgrade=True,\n",
|
330 | 397 | " disable_root=True, ssh_pwauth=False, **kw\n",
|
331 | 398 | " )\n",
|
| 399 | + " if check: cc_validate(cfg)\n", |
332 | 400 | " return \"#cloud-config\\n\" + yaml.safe_dump(cfg, sort_keys=False, width=1_000_000)"
|
333 | 401 | ]
|
334 | 402 | },
|
|
368 | 436 | "text": [
|
369 | 437 | "#cloud-config\n",
|
370 | 438 | "hostname: myhost\n",
|
371 |
| - "preserve_hostname: false\n", |
372 |
| - "packages:\n", |
373 |
| - "- unattended-upgrades\n", |
374 |
| - "- vim-nox\n", |
375 |
| - "- python3\n", |
376 |
| - "- rsync\n", |
377 |
| - "- ubuntu-drivers-common\n", |
378 |
| - "- python3-pip\n", |
379 |
| - "- ack\n", |
380 |
| - "- lsyncd\n", |
381 |
| - "- wget\n", |
382 |
| - "- bzip2\n", |
383 |
| - "- ca-certificates\n", |
384 |
| - "- git\n", |
385 |
| - "- build-essential\n", |
386 |
| - "- software-properties-common\n", |
387 |
| - "- curl\n", |
388 |
| - "- grep\n", |
389 |
| - "- sed\n", |
390 |
| - "- dpkg\n", |
391 |
| - "- tmux\n", |
392 |
| - "- less\n", |
393 |
| - "- htop\n", |
394 |
| - "- openssh-client\n", |
395 |
| - "- python-is-python3\n", |
396 |
| - "- python3-dev\n", |
397 |
| - "- cron\n", |
398 |
| - "- gnupg\n", |
399 |
| - "- docker-ce\n", |
400 |
| - "- docker-ce-cli\n", |
401 |
| - "- containerd.io\n", |
402 |
| - "- docker-buildx-plugin\n", |
403 |
| - "- docker-compose-plugin\n", |
404 |
| - "package_update: true\n", |
405 |
| - "package_upgrade: true\n", |
406 |
| - "disable_root: true\n", |
407 |
| - "ssh_pwauth: false\n", |
408 |
| - "users:\n", |
409 |
| - "- name: jph\n", |
410 |
| - " groups:\n", |
411 |
| - " - docker\n", |
412 |
| - " - sudo\n", |
413 |
| - " shell: /bin/bash\n", |
414 |
| - " sudo:\n", |
415 |
| - " - ALL=(ALL) NOPASSWD:ALL\n", |
416 |
| - " ssh_authorized_keys:\n", |
417 |
| - " - mykey\n", |
418 |
| - "runcmd:\n", |
419 |
| - "- ufw default deny incoming\n", |
420 |
| - "- ufw default allow outgoing\n", |
421 |
| - "- ufw logging off\n", |
422 |
| - "- ufw allow 22/tcp\n", |
423 |
| - "- ufw allow in on enp7s0\n", |
424 |
| - "- ufw --force enable\n", |
425 |
| - "apt:\n", |
426 |
| - " conf: 'APT::Periodic::Update-Package-Lists \"1\";\n", |
427 |
| - "\n", |
428 |
| - " APT::Periodic::Download-Upgradeable-Packages \"1\";\n", |
429 |
| - "\n", |
430 |
| - " APT::Periodic::AutocleanInterval \"7\";\n", |
431 |
| - "\n", |
432 |
| - " APT::Periodic::Unattended-Upgrade \"0\";\n", |
433 |
| - "\n", |
434 |
| - " Unattended-Upgrade::Automatic-Reboot \"false\";\n", |
435 |
| - "\n", |
436 |
| - " '\n", |
437 |
| - " sources:\n", |
438 |
| - " docker:\n", |
439 |
| - " source: deb [signed-by=$KEY_FILE] https://download.docker.com/linux/ubuntu $RELEASE stable\n", |
440 |
| - " keyid: 9DC858229FC7DD38854AE2D88D81803C0EBFCD88\n", |
441 |
| - " keyserver: https://download.docker.com/linux/ubuntu/gpg\n", |
442 |
| - "write_files:\n", |
443 |
| - "- path: /etc/logrotate.d/00-cloud-init-global\n", |
444 |
| - " owner: root:root\n", |
445 |
| - " permissions: '0644'\n", |
446 |
| - " content: \"/var/log/*.log {\\n weekly\\n rotate 7\\n compress\\n su root adm\\n create\\n missingok\\n}\\n\"\n", |
447 |
| - "- path: /etc/systemd/system/systemd-journald.service.d/override.conf\n", |
448 |
| - " owner: root:root\n", |
449 |
| - " permissions: '0644'\n", |
450 |
| - " content: '[Journal]\n", |
451 |
| - "\n", |
452 |
| - " SystemMaxUse=250M\n", |
453 |
| - "\n", |
454 |
| - " '\n", |
455 |
| - "mounts:\n", |
456 |
| - "- - mydevice\n", |
457 |
| - " - /data\n", |
458 |
| - " - ext4\n", |
459 |
| - " - defaults,nofail\n", |
460 |
| - " - '0'\n", |
461 |
| - " - '0'\n", |
462 |
| - "phone_home:\n", |
463 |
| - " url: https://ping.me\n", |
464 |
| - " post:\n", |
465 |
| - " - instance_id\n", |
466 |
| - " - hostname\n", |
467 |
| - " tries: 5\n", |
468 |
| - "power_state:\n", |
469 |
| - " mode: reboot\n", |
470 |
| - " message: Rebooting\n", |
471 |
| - " timeout: 1\n", |
472 |
| - " condition: true\n", |
473 |
| - "\n" |
| 439 | + "preserve_hostname: \n" |
474 | 440 | ]
|
475 | 441 | }
|
476 | 442 | ],
|
|
486 | 452 | "\n",
|
487 | 453 | "res = cloud_init_config('myhost', 'jph', 'mykey', 'j@answer.ai', dropins=dropins, groups=\"docker\", internal=\"enp7s0\",\n",
|
488 | 454 | " devices=devices, ping_host='https://ping.me', packages=packages, docker=dsource)\n",
|
489 |
| - "print(res)" |
| 455 | + "print(res[:50])" |
490 | 456 | ]
|
491 | 457 | },
|
492 | 458 | {
|
|
0 commit comments