add packer ubuntu board generator

This commit is contained in:
Kyle Isom 2023-04-12 04:21:40 +00:00
parent a3403b0fc3
commit 6943facc81
16 changed files with 666 additions and 7 deletions

5
.gitignore vendored
View File

@ -1 +1,6 @@
packer/build packer/build
bazel-bin
bazel-bladerunner
bazel-out
.gitignore
bazel-testlogs

4
BUILD.bazel Normal file
View File

@ -0,0 +1,4 @@
load("@bazel_gazelle//:def.bzl", "gazelle")
# gazelle:prefix git.wntrmute.dev/kyle/bladerunner
gazelle(name = "gazelle")

View File

@ -1,9 +1,43 @@
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
## C++ dependencies ## C++ dependencies
# http_archive(
# name = "gtest",
# url = "https://github.com/google/googletest/archive/release-1.10.0.zip",
# sha256 = "94c634d499558a76fa649edb13721dce6e98fb1e7018dfaeba3cd7a083945e91",
# build_file = "@//:gtest.BUILD",
# )
http_archive( http_archive(
name = "gtest", name = "io_bazel_rules_go",
url = "https://github.com/google/googletest/archive/release-1.10.0.zip", sha256 = "6b65cb7917b4d1709f9410ffe00ecf3e160edf674b78c54a894471320862184f",
sha256 = "94c634d499558a76fa649edb13721dce6e98fb1e7018dfaeba3cd7a083945e91", urls = [
build_file = "@//:gtest.BUILD", "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.39.0/rules_go-v0.39.0.zip",
"https://github.com/bazelbuild/rules_go/releases/download/v0.39.0/rules_go-v0.39.0.zip",
],
) )
http_archive(
name = "bazel_gazelle",
sha256 = "ecba0f04f96b4960a5b250c8e8eeec42281035970aa8852dda73098274d14a1d",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.29.0/bazel-gazelle-v0.29.0.tar.gz",
"https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.29.0/bazel-gazelle-v0.29.0.tar.gz",
],
)
load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")
load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies", "go_repository")
############################################################
# Define your own dependencies here using go_repository.
# Else, dependencies declared by rules_go/gazelle will be used.
# The first declaration of an external repository "wins".
############################################################
go_rules_dependencies()
go_register_toolchains(version = "1.20.3")
gazelle_dependencies()

8
go.mod Normal file
View File

@ -0,0 +1,8 @@
module git.wntrmute.dev/kyle/bladerunner
go 1.20
require (
git.sr.ht/~kisom/goutils v1.5.3
gopkg.in/yaml.v2 v2.4.0
)

94
go.sum Normal file
View File

@ -0,0 +1,94 @@
bitbucket.org/liamstask/goose v0.0.0-20150115234039-8488cc47d90c/go.mod h1:hSVuE3qU7grINVSwrmzHfpg9k87ALBk+XaualNyUzI4=
git.sr.ht/~kisom/goutils v1.5.3 h1:Q0BI2Q8/gs5uYdi2e2op4uRt9hTLt5zgH9HdGDcx4pM=
git.sr.ht/~kisom/goutils v1.5.3/go.mod h1:azq1B7nq8lmva1FWeuw+tZ6xdJZCtJIlFskB3N2v9E4=
github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0=
github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0=
github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4=
github.com/cloudflare/backoff v0.0.0-20161212185259-647f3cdfc87a/go.mod h1:rzgs2ZOiguV6/NpiDgADjRLPNyZlApIWxKpkT+X8SdY=
github.com/cloudflare/cfssl v1.5.0/go.mod h1:sPPkBS5L8l8sRc/IOO1jG51Xb34u+TYhL6P//JdODMQ=
github.com/cloudflare/go-metrics v0.0.0-20151117154305-6a9aea36fb41/go.mod h1:eaZPlJWD+G9wseg1BuRXlHnjntPMrywMsyxf+LTOdP4=
github.com/cloudflare/redoctober v0.0.0-20171127175943-746a508df14c/go.mod h1:6Se34jNoqrd8bTxrmJB2Bg2aoZ2CdSXonils9NsiNgo=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/getsentry/raven-go v0.0.0-20180121060056-563b81fc02b7/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jmhodges/clock v0.0.0-20160418191101-880ee4c33548/go.mod h1:hGT6jSUVzF6no3QaDSMLGLEHtHSBSefs+MgcDWnmhmo=
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
github.com/kisielk/sqlstruct v0.0.0-20150923205031-648daed35d49/go.mod h1:yyMNCyc/Ib3bDTKd379tNMpB/7/H5TjM2Y9QJ5THLbE=
github.com/kisom/goutils v1.1.0/go.mod h1:+UBTfd78habUYWFbNWTJNG+jNG/i/lGURakr4A/yNRw=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/go-gypsy v0.0.0-20160905020020-08cad365cd28/go.mod h1:T/T7jsxVqf9k/zYOqbgNAsANsjxTd1Yq3htjDhQ1H0c=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8=
github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.12.0/go.mod h1:fUqqXB5vEgVCZ131L+9say31RAri6aF6KDViawhxKK8=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/weppos/publicsuffix-go v0.4.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k=
github.com/weppos/publicsuffix-go v0.13.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k=
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE=
github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is=
github.com/zmap/zcrypto v0.0.0-20200513165325-16679db567ff/go.mod h1:TxpejqcVKQjQaVVmMGfzx5HnmFMdIU+vLtaCyPBfGI4=
github.com/zmap/zcrypto v0.0.0-20200911161511-43ff0ea04f21/go.mod h1:TxpejqcVKQjQaVVmMGfzx5HnmFMdIU+vLtaCyPBfGI4=
github.com/zmap/zlint/v2 v2.2.1/go.mod h1:ixPWsdq8qLxYRpNUTbcKig3R7WgmspsHGLhCCs6rFAM=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200124225646-8b5121be2f68/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -11,7 +11,7 @@ errmsg () {
preflight () { preflight () {
case "${IMAGE_TYPE}" in case "${IMAGE_TYPE}" in
ubuntu) PACKER_BUILD_FILE="boards/raspberry-pi-4/ubuntu_server_20.04_arm64.json" ;; ubuntu) PACKER_BUILD_FILE="boards/pi-cm4-ubuntu-22.04.2.json" ;;
raspbian) PACKER_BUILD_FILE="boards/raspberry-pi/raspios-lite-arm.json" ;; raspbian) PACKER_BUILD_FILE="boards/raspberry-pi/raspios-lite-arm.json" ;;
custom) custom)
PACKER_BUILD_FILE="${2:-}" PACKER_BUILD_FILE="${2:-}"
@ -33,7 +33,6 @@ preflight () {
} }
build_image () { build_image () {
cd build/packer-builder-arm
sudo packer build ${PACKER_BUILD_FILE} sudo packer build ${PACKER_BUILD_FILE}
} }

11
packer/scripts/install-base.sh Executable file
View File

@ -0,0 +1,11 @@
#!/usr/bin/env bash
set -euxo pipefail
echo "==> Setting nameserver"
echo 'nameserver 8.8.8.8' > /etc/resolv.conf
echo "==> installing base updates"
apt-get -y update
apt-get -y install ansible apt-transport-https ca-certificates
apt-get -y clean

34
packer/setup-env.sh Normal file
View File

@ -0,0 +1,34 @@
#!/usr/bin/env bash
set -euxo pipefail
IMAGE_TYPE="${1:-ubuntu}"
select_image () {
case "${IMAGE_TYPE}" in
ubuntu)
PACKER_BUILD_FILE="boards/pi-cm4-ubuntu-22.04.2.json" ;;
REMOTE_IMAGE_URL="$(jq '.builders[0].file_urls' boards/pi-cm4-ubuntu-22.04.2.json | grep https | tr -d ' \"')"
raspbian) PACKER_BUILD_FILE="boards/raspberry-pi/raspios-lite-arm.json" ;;
PACKER_BUILD_FILE="boards/pi-cm4-ubuntu-22.04.2.json" ;;
REMOTE_IMAGE_URL="$(jq '.builders[0].file_urls' boards/pi-cm4-ubuntu-22.04.2.json | grep https | tr -d ' \"')"
custom)
PACKER_BUILD_FILE="${2:-}"
if [ -z "${PACKER_BUILD_FILE}" ]
then
errmsg "[!] custom board requires a board file path"
exit 1
fi
;;
*)
errmsg "[!] invalid image type ${IMAGE_TYPE}."
errmsg "[!] valid image types are"
errmsg " - raspbian"
errmsg " - ubuntu"
errmsg " - custom path/to/board/file"
exit 1
;;
esac
}

View File

@ -0,0 +1,18 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "ubuntu-board-gen_lib",
srcs = ["main.go"],
importpath = "git.wntrmute.dev/kyle/bladerunner/src/cmd/ubuntu-board-gen",
visibility = ["//visibility:private"],
deps = [
"//src/packer",
"@ht_sr_git_kisom_goutils//die:go_default_library",
],
)
go_binary(
name = "ubuntu-board-gen",
embed = [":ubuntu-board-gen_lib"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,22 @@
package main
import (
"flag"
"git.sr.ht/~kisom/goutils/die"
"git.wntrmute.dev/kyle/bladerunner/src/packer"
)
func main() {
var specFile, outputDir string
flag.StringVar(&specFile, "f", "ubuntu-boards.yml", "`path` to Ubuntu board spec file")
flag.StringVar(&outputDir, "o", "", "`directory` to store Ubuntu boards")
flag.Parse()
boardSpecs, err := packer.LoadUbuntuSpecs(specFile)
die.If(err)
err = boardSpecs.WriteBoards(outputDir)
die.If(err)
}

15
src/packer/BUILD.bazel Normal file
View File

@ -0,0 +1,15 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "packer",
srcs = [
"board.go",
"builder.go",
"packer.go",
"provisioner.go",
"ubuntu.go",
],
importpath = "git.wntrmute.dev/kyle/bladerunner/src/packer",
visibility = ["//visibility:public"],
deps = ["@in_gopkg_yaml_v2//:go_default_library"],
)

8
src/packer/board.go Normal file
View File

@ -0,0 +1,8 @@
package packer
type Board struct {
Variables interface{} `json:"variables"`
Builders []Builder `json:"builders"`
Provisioners []Provisioner `json:"provisioners"`
PostProcessors []string `json:"post-processors"`
}

192
src/packer/builder.go Normal file
View File

@ -0,0 +1,192 @@
package packer
// RootPartitionSizes describes how big a single root partition should
// be given a standard 256M boot partition. This should cover standard
// install media sizes.
var RootPartitionSizes = map[string]string{
"4G": "3.7G",
"8G": "7.7G",
"16G": "15.7G",
"32G": "31.7G",
}
// Safe defaults that can be used when a custom option isn't needed.
const (
QemuDefaultPath = "/usr/bin/qemu-aarch64-static"
RootPartitionSafeDefault = "2.8G"
StandardPath = "PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin"
)
// Partition describes a partition in the generated image.
type Partition struct {
Name string `json:"name"`
Type string `json:"type"`
StartSector int `json:"start_sector"` // should be a uint64, except JSON
Size string `json:"size"`
Mountpoint string `json:"mountpoint"`
}
// Builder specifically refers to an Arm builder as used for the images
// generated for a computeblade.
type Builder struct {
Type string `json:"type"`
FileURLs []string `json:"file_urls"`
FileChecksumURL string `json:"file_checksum_url"`
FileChecksumType string `json:"file_checksum_type"`
FileTargetExtension string `json:"file_target_extension"`
FileUnarchiveCommand []string `json:"file_unarchive_cmd"`
ImageBuildMethod string `json:"image_build_method"`
ImagePath string `json:"image_path"`
ImageSize string `json:"image_size"`
ImageType string `json:"image_type"`
ImagePartitions []Partition `json:"image_partitions"`
ImageChrootEnviron []string `json:"image_chroot_env"`
QemuBinarySourcePath string `json:"qemu_binary_source_path"`
QemuBinaryDestinationPath string `json:"qemu_binary_destination_path"`
}
func NewBuilder(fileURLs []string) Builder {
return Builder{
Type: "arm",
FileURLs: fileURLs,
}
}
// With256MBootPartition returns a standard 256M boot partition.
func (b Builder) With256MBootPartition() Builder {
p := Partition{
Name: "boot",
Type: "c",
StartSector: 2048,
Size: "256M",
Mountpoint: "/boot/firmware",
}
b.ImagePartitions = append(b.ImagePartitions, p)
return b
}
// WithSingleRootPartition should be called after With256MBootPartition,
// as it assumes a root partition immediately following the boot.
func (b Builder) WithSingleRootPartition(size string) Builder {
p := Partition{
Name: "root",
Type: "83",
StartSector: 526336,
Size: size,
Mountpoint: "/",
}
b.ImagePartitions = append(b.ImagePartitions, p)
return b
}
// WithStandardImage generates a standard image with a boot and root partition.
func (b Builder) WithStandardImage(size string, outputPath string) Builder {
b.ImageBuildMethod = "reuse"
b.ImagePath = outputPath
b.ImageSize = size
b.ImageType = "dos"
rootPartitionSize := RootPartitionSizes[size]
if rootPartitionSize == "" {
rootPartitionSize = RootPartitionSafeDefault
}
b = b.With256MBootPartition()
b = b.WithSingleRootPartition(rootPartitionSize)
// Append a standard PATH environment.
b.ImageChrootEnviron = append(b.ImageChrootEnviron, StandardPath)
return b
}
// WithStandard32GImage adds a standard 32G image spec to the Builder.
func (b Builder) WithStandard32GImage(outputPath string) Builder {
return b.WithStandardImage("32G", outputPath)
}
// WithQemuDefaults sets the standard qemu path in the builder.
func (b Builder) WithQemuDefaults() Builder {
b.QemuBinarySourcePath = QemuDefaultPath
b.QemuBinaryDestinationPath = QemuDefaultPath
return b
}
// WithSHA256Checksum sets a SHA256 checksum URL.
func (b Builder) WithSHA256Checksum(url string) Builder {
b.FileChecksumURL = url
b.FileChecksumType = "sha256"
return b
}
func (b Builder) withXZ() Builder {
b.FileTargetExtension = "xz"
b.FileUnarchiveCommand = []string{
"xz",
"--decompress",
}
return b
}
func (b Builder) withUnzip() Builder {
b.FileTargetExtension = "zip"
b.FileUnarchiveCommand = []string{
"unzip",
}
return b
}
func (b Builder) withTGZ() Builder {
b.FileTargetExtension = "tgz"
b.FileUnarchiveCommand = []string{
"tar",
"xzf",
}
return b
}
func (b Builder) withTarGZ() Builder {
b.FileTargetExtension = "tar.gz"
b.FileUnarchiveCommand = []string{
"tar",
"xzf",
}
return b
}
func (b Builder) withGZ() Builder {
b.FileTargetExtension = "gz"
b.FileUnarchiveCommand = []string{
"gunzip",
}
return b
}
// WithUnarchiver fills in the appropriate unarchiver command given the
// archive extension.
func (b Builder) WithUnarchiver(extension string) Builder {
switch extension {
case "xz":
b = b.withXZ()
case "zip":
b = b.withUnzip()
case "tgz":
b = b.withTGZ()
case "tar.gz":
b = b.withTarGZ()
case "gz":
b = b.withGZ()
}
b.FileUnarchiveCommand = append(b.FileUnarchiveCommand, "$ARCHIVE_PATH")
return b
}

3
src/packer/packer.go Normal file
View File

@ -0,0 +1,3 @@
// Package packer contains utilities for interacting with Packer
// in the context of building images for the computeblade cluster.
package packer

78
src/packer/provisioner.go Normal file
View File

@ -0,0 +1,78 @@
package packer
type Provisioner map[string]interface{}
// ShellProvisioner provisions machines built by Packer using shell scripts.
func ShellProvisioner(scripts ...string) Provisioner {
return map[string]interface{}{
"type": "shell",
"scripts": scripts,
}
}
// ShellLocalProvisioner will run a shell script of your choosing on the
// machine where Packer is being run - in other words, shell-local will run
// the shell script on your build server, or your desktop, etc., rather than
// the remote/guest machine being provisioned by Packer.
func ShellLocalProvisioner(scripts ...string) Provisioner {
return map[string]interface{}{
"type": "shell-local",
"scripts": scripts,
}
}
// uploads files to machines built by Packer. The recommended usage of the file
// provisioner is to use it to upload files, and then use shell provisioner to
// move them to the proper place, set permissions, etc.
func FileProvisioner(src, dest string) Provisioner {
return map[string]interface{}{
"type": "file",
"source": src,
"destination": dest,
}
}
// BreakpointProvisioner pauses until the user presses "enter" to resume the build.
func BreakpointProvisioner(note string) Provisioner {
return map[string]interface{}{
"type": "breakpoint",
"disable": false,
"note": note,
}
}
func (b Board) WithShellProvisioner(scripts ...string) Board {
b.Provisioners = append(b.Provisioners, ShellProvisioner(scripts...))
return b
}
func (b Board) WithShellLocalProvisioner(scripts ...string) Board {
b.Provisioners = append(b.Provisioners, ShellLocalProvisioner(scripts...))
return b
}
func (b Board) WithFileProvisioner(src, dest string) Board {
b.Provisioners = append(b.Provisioners, FileProvisioner(src, dest))
return b
}
func (b Board) WithBreakpointProvisioner(note string) Board {
b.Provisioners = append(b.Provisioners, BreakpointProvisioner(note))
return b
}
type FileSet struct {
Source string `yaml:"source"`
Destination string `yaml:"destination"`
}
func (fs FileSet) Provisioner() Provisioner {
return FileProvisioner(fs.Source, fs.Destination)
}
func (b Board) WithFileSetsProvisioner(fileSets []FileSet) Board {
for _, fs := range fileSets {
b.Provisioners = append(b.Provisioners, fs.Provisioner())
}
return b
}

134
src/packer/ubuntu.go Normal file
View File

@ -0,0 +1,134 @@
package packer
import (
"encoding/json"
"fmt"
"io/ioutil"
"path/filepath"
"strings"
"gopkg.in/yaml.v2"
)
type urlSet struct {
FileURLs []string
ChecksumURL string
}
// ubuntuImage returns a local cache path and a remote fetch path for an
// Ubuntu image for a given version.
func ubuntuImage(version string) urlSet {
imageBase := fmt.Sprintf("ubuntu-%s-preinstalled-server-arm64+raspi.img.xz", version)
imageDir := fmt.Sprintf("https://cdimage.ubuntu.com/releases/%s/release/", version)
checksumURL := fmt.Sprintf("http://cdimage.ubuntu.com/releases/%s/release/SHA256SUMS", version)
localImage := "build/" + imageBase
remoteImage := imageDir + imageBase
return urlSet{
FileURLs: []string{
localImage,
remoteImage,
},
ChecksumURL: checksumURL,
}
}
func UbuntuBuilder(version, size, outputPath string) Builder {
urlSet := ubuntuImage(version)
outputPath = "build/" + outputPath
b := NewBuilder(urlSet.FileURLs)
return b.
WithSHA256Checksum(urlSet.ChecksumURL).
WithUnarchiver("xz").
WithStandardImage(size, outputPath).
WithQemuDefaults()
}
type UbuntuBoardSpec struct {
Version string `yaml:"version"`
Size string `yaml:"size"`
ImageName string `yaml:"name"`
LocalScripts []string `yaml:"local-scripts"`
Files []FileSet `yaml:"files"`
Scripts []string `yaml:"scripts"`
}
func (spec UbuntuBoardSpec) JSONPath(base string) string {
dest := spec.ImageName
ext := filepath.Ext(dest)
if ext != "" {
ext = "." + ext
dest = strings.TrimSuffix(dest, ext)
}
dest += ".json"
if base != "" {
dest = filepath.Join(base, dest)
}
return dest
}
func (spec UbuntuBoardSpec) Board() Board {
board := Board{
Variables: []string{},
Builders: []Builder{
UbuntuBuilder(spec.Version, spec.Size, spec.ImageName),
},
}
if len(spec.LocalScripts) != 0 {
board = board.WithShellLocalProvisioner(spec.LocalScripts...)
}
if len(spec.Files) != 0 {
board = board.WithFileSetsProvisioner(spec.Files)
}
if len(spec.Scripts) != 0 {
board = board.WithShellProvisioner(spec.Scripts...)
}
return board
}
func LoadUbuntuSpecs(path string) (specFile UbuntuBoardSpecFile, err error) {
data, err := ioutil.ReadFile(path)
if err != nil {
return
}
err = yaml.Unmarshal(data, &specFile)
if err != nil {
return
}
return specFile, nil
}
// UbuntuBoardSpecFile describes a set of specifications for Ubuntu boards.
//
// In the future, this may include additional data.
type UbuntuBoardSpecFile struct {
Boards []UbuntuBoardSpec `yaml:"boards"`
}
func (specFile UbuntuBoardSpecFile) WriteBoards(outputDir string) error {
for _, spec := range specFile.Boards {
board := spec.Board()
dest := spec.JSONPath(outputDir)
contents, err := json.Marshal(board)
if err != nil {
return err
}
err = ioutil.WriteFile(dest, contents, 0644)
if err != nil {
return err
}
}
return nil
}