diff options
author | Mike Crute <mike@crute.us> | 2020-05-29 20:58:53 -0700 |
---|---|---|
committer | Mike Crute <mike@crute.us> | 2020-05-29 20:58:53 -0700 |
commit | b53492723dc99400d0caac6b6c007adf2f9af6fb (patch) | |
tree | 8634d6fbeac1d7a61b5e00980bd01b5895dc9c85 | |
parent | 5b2f32c9c854ab30178cb78bc2272f2c71d0a60e (diff) | |
download | alpine-ec2-ami-b53492723dc99400d0caac6b6c007adf2f9af6fb.tar.bz2 alpine-ec2-ami-b53492723dc99400d0caac6b6c007adf2f9af6fb.tar.xz alpine-ec2-ami-b53492723dc99400d0caac6b6c007adf2f9af6fb.zip |
Migrate full ami build to builder script
-rw-r--r-- | Makefile | 60 | ||||
-rw-r--r-- | README.md | 21 | ||||
-rwxr-xr-x | scripts/builder.py | 61 |
3 files changed, 54 insertions, 88 deletions
diff --git a/Makefile b/Makefile deleted file mode 100644 index e6f879c..0000000 --- a/Makefile +++ /dev/null | |||
@@ -1,60 +0,0 @@ | |||
1 | # vim: ts=8 noet: | ||
2 | |||
3 | NVME_SCRIPTS := $(subst scripts/,build/,$(wildcard scripts/nvme/*)) | ||
4 | CORE_PROFILES := $(wildcard profiles/*/*) | ||
5 | TARGET_PROFILES := $(wildcard profiles/*.conf) | ||
6 | |||
7 | PROFILE := | ||
8 | BUILD := | ||
9 | BUILDS := $(BUILD) | ||
10 | LEVEL := | ||
11 | |||
12 | # by default, use the 'packer' in the path | ||
13 | PACKER := packer | ||
14 | export PACKER | ||
15 | |||
16 | |||
17 | check_defined = \ | ||
18 | $(strip $(foreach 1,$1, \ | ||
19 | $(call __check_defined,$1,$(strip $(value 2))))) | ||
20 | __check_defined = \ | ||
21 | $(if $(value $1),, \ | ||
22 | $(error Undefined $1$(if $2, ($2))$(if $(value @), \ | ||
23 | required by target `$@'))) | ||
24 | |||
25 | |||
26 | .PHONY: amis prune release-readme clean | ||
27 | |||
28 | amis: build/packer.json build/profile/$(PROFILE) build | ||
29 | @:$(call check_defined, PROFILE, target profile name) | ||
30 | build/builder make-amis $(PROFILE) $(BUILDS) | ||
31 | |||
32 | prune: build | ||
33 | @:$(call check_defined, LEVEL, pruning level) | ||
34 | @:$(call check_defined, PROFILE, target profile name) | ||
35 | build/builder prune-amis $(LEVEL) $(PROFILE) $(BUILD) | ||
36 | |||
37 | release-readme: releases/README.md | ||
38 | releases/README.md: build | ||
39 | @:$(call check_defined, PROFILE, target profile name) | ||
40 | @:$(call require_var, PROFILE) | ||
41 | build/builder gen-release-readme $(PROFILE) | ||
42 | |||
43 | build: | ||
44 | python3 -m venv build | ||
45 | [ -d build/profile ] || mkdir -p build/profile | ||
46 | build/bin/pip install -U pip pyhocon pyyaml boto3 | ||
47 | |||
48 | echo -e "#!/bin/sh\n$$(pwd)/build/bin/python scripts/builder.py \$$@" > $@ | ||
49 | chmod +x $@ | ||
50 | |||
51 | build/packer.json: packer.conf build | ||
52 | build/builder convert-packer-config | ||
53 | |||
54 | .PHONY: build/profile/$(PROFILE) | ||
55 | build/profile/$(PROFILE): build $(CORE_PROFILES) $(TARGET_PROFILES) | ||
56 | @:$(call check_defined, PROFILE, target profile name) | ||
57 | build/builder resolve-profiles $(PROFILE) | ||
58 | |||
59 | clean: | ||
60 | rm -rf build | ||
@@ -36,7 +36,6 @@ include as much detailed information as possible. | |||
36 | 36 | ||
37 | * [Packer](https://packer.io) >= 1.4.1 | 37 | * [Packer](https://packer.io) >= 1.4.1 |
38 | * [Python 3.x](https://python.org) (3.7 is known to work) | 38 | * [Python 3.x](https://python.org) (3.7 is known to work) |
39 | * `make` (GNU Make is known to work) | ||
40 | * an AWS account with an existing subnet in an AWS Virtual Private Cloud | 39 | * an AWS account with an existing subnet in an AWS Virtual Private Cloud |
41 | 40 | ||
42 | ### Profile Configuration | 41 | ### Profile Configuration |
@@ -59,18 +58,12 @@ two methods on the list.* | |||
59 | 58 | ||
60 | To build all build targets in a target profile, simply... | 59 | To build all build targets in a target profile, simply... |
61 | ``` | 60 | ``` |
62 | make PROFILE=<profile> | 61 | ./scripts/builder.py amis <profile> |
63 | ``` | 62 | ``` |
64 | 63 | ||
65 | You can also build specfic build targets within a profile: | 64 | You can also build specfic build targets within a profile: |
66 | ``` | 65 | ``` |
67 | make PROFILE=<profile> BUILDS="<build1> <build2>" | 66 | ./scripts/builder.py amis <profile> <build1> <build2> |
68 | ``` | ||
69 | |||
70 | If the `packer` binary is not in your `PATH`, or you would like to specify a | ||
71 | different one, use... | ||
72 | ``` | ||
73 | make PACKER=<packer-path> PROFILE=<profile> | ||
74 | ``` | 67 | ``` |
75 | 68 | ||
76 | Before each build, new Alpine Linux *releases* are detected and the version's | 69 | Before each build, new Alpine Linux *releases* are detected and the version's |
@@ -98,7 +91,7 @@ pruning: | |||
98 | 91 | ||
99 | To prune a profile (or optionally one build target of a profile)... | 92 | To prune a profile (or optionally one build target of a profile)... |
100 | ``` | 93 | ``` |
101 | make prune LEVEL=<level> PROFILE=<profile> [BUILD=<build>] | 94 | ./scripts/builder.py prune-amis <profile> [<build>] |
102 | ``` | 95 | ``` |
103 | 96 | ||
104 | Any AMIs in the account which are "unknown" (to the profile/build target, at | 97 | Any AMIs in the account which are "unknown" (to the profile/build target, at |
@@ -110,14 +103,14 @@ This make target updates the [releases README](releases/README.md), primarily | |||
110 | for updating the list of our pre-built AMIs. This may-or-may-not be useful for | 103 | for updating the list of our pre-built AMIs. This may-or-may-not be useful for |
111 | other target profiles. | 104 | other target profiles. |
112 | ``` | 105 | ``` |
113 | make release-readme PROFILE=<profile> | 106 | ./scripts/builder.py gen-release-readme <profile> |
114 | ``` | 107 | ``` |
115 | 108 | ||
116 | ### Cleaning up the Build Environment | 109 | ### Cleaning up the Build Environment |
117 | 110 | ||
118 | `make clean` will remove the temporary `build` subdirectory, which contains the | 111 | `git clean -dxf` will remove the temporary `build` subdirectory, which contains |
119 | resolved profile and Packer configs, the Python virtual environment, and other | 112 | the resolved profile and Packer configs, the Python virtual environment, and |
120 | temporary build-related artifacts. | 113 | other temporary build-related artifacts. |
121 | 114 | ||
122 | ## Caveats | 115 | ## Caveats |
123 | 116 | ||
diff --git a/scripts/builder.py b/scripts/builder.py index 7491e25..021016b 100755 --- a/scripts/builder.py +++ b/scripts/builder.py | |||
@@ -287,8 +287,7 @@ class MakeAMIs: | |||
287 | print(text, end="") | 287 | print(text, end="") |
288 | 288 | ||
289 | if res.returncode == 0: | 289 | if res.returncode == 0: |
290 | subprocess.run([os.path.join(root, "build", "builder"), | 290 | UpdateReleases().update_readme(args.profile, build, root) |
291 | "update-releases", args.profile, build]) | ||
292 | else: | 291 | else: |
293 | if "is used by an existing AMI" in out.getvalue(): | 292 | if "is used by an existing AMI" in out.getvalue(): |
294 | continue | 293 | continue |
@@ -537,17 +536,20 @@ class ResolveProfiles: | |||
537 | parser.add_argument( | 536 | parser.add_argument( |
538 | "profile", help="name of profile to build", nargs="*") | 537 | "profile", help="name of profile to build", nargs="*") |
539 | 538 | ||
540 | def run(self, args, root): | 539 | def resolve_profiles(self, profiles, root): |
541 | builder = ConfigBuilder( | 540 | builder = ConfigBuilder( |
542 | os.path.join(root, "profiles"), | 541 | os.path.join(root, "profiles"), |
543 | os.path.join(root, "build", "profile")) | 542 | os.path.join(root, "build", "profile")) |
544 | 543 | ||
545 | if args.profile: | 544 | if profiles: |
546 | for profile in args.profile: | 545 | for profile in profiles: |
547 | builder.build_profile(profile) | 546 | builder.build_profile(profile) |
548 | else: | 547 | else: |
549 | builder.build_all() | 548 | builder.build_all() |
550 | 549 | ||
550 | def run(self, args, root): | ||
551 | self.resolve_profiles(args.profile, root) | ||
552 | |||
551 | 553 | ||
552 | class UpdateReleases: | 554 | class UpdateReleases: |
553 | """Update release YAML | 555 | """Update release YAML |
@@ -566,18 +568,21 @@ class UpdateReleases: | |||
566 | return dict(zip(parsed[0::2], parsed[1::2])) | 568 | return dict(zip(parsed[0::2], parsed[1::2])) |
567 | 569 | ||
568 | def run(self, args, root): | 570 | def run(self, args, root): |
571 | self.update_readme(args.profile, args.build, root) | ||
572 | |||
573 | def update_readme(self, profile, build, root): | ||
569 | release_dir = os.path.join(root, "releases") | 574 | release_dir = os.path.join(root, "releases") |
570 | if not os.path.exists(release_dir): | 575 | if not os.path.exists(release_dir): |
571 | os.makedirs(release_dir) | 576 | os.makedirs(release_dir) |
572 | 577 | ||
573 | release_yaml = os.path.join(release_dir, f"{args.profile}.yaml") | 578 | release_yaml = os.path.join(release_dir, f"{profile}.yaml") |
574 | releases = {} | 579 | releases = {} |
575 | if os.path.exists(release_yaml): | 580 | if os.path.exists(release_yaml): |
576 | with open(release_yaml, "r") as data: | 581 | with open(release_yaml, "r") as data: |
577 | releases = yaml.safe_load(data) | 582 | releases = yaml.safe_load(data) |
578 | 583 | ||
579 | manifest_json = os.path.join( | 584 | manifest_json = os.path.join( |
580 | root, "build", "profile", args.profile, args.build, | 585 | root, "build", "profile", profile, build, |
581 | "manifest.json") | 586 | "manifest.json") |
582 | with open(manifest_json, "r") as data: | 587 | with open(manifest_json, "r") as data: |
583 | manifest = json.load(data) | 588 | manifest = json.load(data) |
@@ -585,16 +590,16 @@ class UpdateReleases: | |||
585 | data = manifest["builds"][0]["custom_data"] | 590 | data = manifest["builds"][0]["custom_data"] |
586 | release = data["release"] | 591 | release = data["release"] |
587 | 592 | ||
588 | if args.build not in releases: | 593 | if build not in releases: |
589 | releases[args.build] = {} | 594 | releases[build] = {} |
590 | 595 | ||
591 | if release not in releases[args.build]: | 596 | if release not in releases[build]: |
592 | releases[args.build][release] = {} | 597 | releases[build][release] = {} |
593 | 598 | ||
594 | releases[args.build][release][data["ami_name"]] = { | 599 | releases[build][release][data["ami_name"]] = { |
595 | "description": data["ami_desc"], | 600 | "description": data["ami_desc"], |
596 | "profile": args.profile, | 601 | "profile": profile, |
597 | "profile_build": args.build, | 602 | "profile_build": build, |
598 | "version": data["version"], | 603 | "version": data["version"], |
599 | "release": release, | 604 | "release": release, |
600 | "arch": data["arch"], | 605 | "arch": data["arch"], |
@@ -628,6 +633,34 @@ class ConvertPackerJSON: | |||
628 | source, dest, "json", 2, False) | 633 | source, dest, "json", 2, False) |
629 | 634 | ||
630 | 635 | ||
636 | class FullBuild: | ||
637 | """Make all of the AMIs for a profile | ||
638 | """ | ||
639 | |||
640 | command_name = "amis" | ||
641 | |||
642 | @staticmethod | ||
643 | def add_args(parser): | ||
644 | parser.add_argument("--region", "-r", default="us-west-2", | ||
645 | help="region to use for build") | ||
646 | parser.add_argument("profile", help="name of profile to build") | ||
647 | parser.add_argument("builds", nargs="*", | ||
648 | help="name of builds within a profile to build") | ||
649 | |||
650 | def run(self, args, root): | ||
651 | print("Converting packer.conf to JSON...", file=sys.stderr) | ||
652 | ConvertPackerJSON().run(args, root) | ||
653 | |||
654 | print("Resolving profiles...", file=sys.stderr) | ||
655 | ResolveProfiles().resolve_profiles([args.profile], root) | ||
656 | |||
657 | print("Running packer...", file=sys.stderr) | ||
658 | MakeAMIs().run(args, root) | ||
659 | |||
660 | print("Updating release readme...", file=sys.stderr) | ||
661 | GenReleaseReadme().run(args, root) | ||
662 | |||
663 | |||
631 | def find_repo_root(): | 664 | def find_repo_root(): |
632 | path = os.getcwd() | 665 | path = os.getcwd() |
633 | 666 | ||