Skip to content

Commit

Permalink
Merge pull request #100 from m-lab/sandbox-kinkade
Browse files Browse the repository at this point in the history
Implements booting nodes from versioned GCS image paths
  • Loading branch information
nkinkade authored May 10, 2021
2 parents 3bb93ed + edb5128 commit bc19e97
Show file tree
Hide file tree
Showing 9 changed files with 67 additions and 43 deletions.
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#
# * test and build the Go code
language: go
go:
- 1.15.x
go_import_path: github.com/m-lab/epoxy

before_install:
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM golang:1.12 as build
FROM golang:1.15 as build

# Add the local files to be sure we are building the local source code instead
# of downloading from GitHub. All other package dependencies will be downloaded
Expand Down
19 changes: 11 additions & 8 deletions cmd/epoxy_admin/command/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ func runCreate(cmd *cobra.Command, args []string) {
storage.Stage2: fmtURL(cfUpdateStage2),
storage.Stage3: fmtURL(cfUpdateStage3),
},
ImagesVersion: cfImagesVersion,
CollectedInformation: datastorex.Map{},
}

Expand Down Expand Up @@ -124,27 +125,29 @@ func init() {
createCmd.Flags().BoolVar(&cfUpdate, "update", false,
"Set Host.UpdateEnabled to true for an existing Host.")
createCmd.Flags().StringVar(&cfBootStage1, "boot-stage1",
"https://epoxy-boot-api.%s.measurementlab.net:4430/v1/storage/stage3_ubuntu/stage1to2.ipxe",
"https://epoxy-boot-api.%s.measurementlab.net:4430/v1/storage/{{VERSION}}/stage3_ubuntu/stage1to2.ipxe",
"Absolute URL to an action definition to run during stage1 to stage2 boot.")
createCmd.Flags().StringVar(&cfBootStage1JSON, "boot-stage1-json",
"https://storage.googleapis.com/epoxy-%s/stage3_ubuntu/stage1to2.json",
"https://storage.googleapis.com/epoxy-%s/{{VERSION}}/stage3_ubuntu/stage1to2.json",
"Absolute URL to an action definition to run during stage1 to stage2 boot.")
createCmd.Flags().StringVar(&cfBootStage2, "boot-stage2",
"https://storage.googleapis.com/epoxy-%s/stage3_ubuntu/stage2to3.json",
"https://storage.googleapis.com/epoxy-%s/{{VERSION}}/stage3_ubuntu/stage2to3.json",
"Absolute URL to an action definition to run during stage2 to stage3 boot.")
createCmd.Flags().StringVar(&cfBootStage3, "boot-stage3",
"https://storage.googleapis.com/epoxy-%s/stage3_ubuntu/stage3post.json",
"https://storage.googleapis.com/epoxy-%s/{{VERSION}}/stage3_ubuntu/stage3post.json",
"Absolute URL to an action definition to run after running stage3 boot.")
createCmd.Flags().StringVar(&cfUpdateStage1, "update-stage1",
"https://epoxy-boot-api.%s.measurementlab.net:4430/v1/storage/stage3_update/stage1to2.ipxe",
"https://epoxy-boot-api.%s.measurementlab.net:4430/v1/storage/{{VERSION}}/stage3_update/stage1to2.ipxe",
"Absolute URL to an action definition to run during stage1 to stage2 update.")
createCmd.Flags().StringVar(&cfUpdateStage1JSON, "update-stage1-json",
"https://storage.googleapis.com/epoxy-%s/stage3_update/stage1to2.json",
"https://storage.googleapis.com/epoxy-%s/{{VERSION}}/stage3_update/stage1to2.json",
"Absolute URL to an action definition to run during stage1 to stage2 update.")
createCmd.Flags().StringVar(&cfUpdateStage2, "update-stage2",
"https://storage.googleapis.com/epoxy-%s/stage3_update/stage2to3.json",
"https://storage.googleapis.com/epoxy-%s/{{VERSION}}/stage3_update/stage2to3.json",
"Absolute URL to an action definition to run during stage2 to stage3 update.")
createCmd.Flags().StringVar(&cfUpdateStage3, "update-stage3",
"https://storage.googleapis.com/epoxy-%s/stage3_update/stage3post_mlx.json",
"https://storage.googleapis.com/epoxy-%s/{{VERSION}}/stage3_update/stage3post_mlx.json",
"Absolute URL to an action definition to run after running stage3 update.")
createCmd.Flags().StringVar(&cfImagesVersion, "images-version", "latest",
"Version of epoxy-images to use in each boot stage.")
}
2 changes: 2 additions & 0 deletions cmd/epoxy_admin/command/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ var (
cfUpdateStage1JSON string
cfUpdateStage2 string
cfUpdateStage3 string
cfImagesVersion string

// Update flags.
ufHostname string
Expand All @@ -57,6 +58,7 @@ var (
ufUpdateStage1JSON string
ufUpdateStage2 string
ufUpdateStage3 string
ufImagesVersion string

// List flags.
lfHostname string
Expand Down
4 changes: 4 additions & 0 deletions cmd/epoxy_admin/command/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ func handleUpdate(h *storage.Host) {
h.Update[storage.Stage1JSON] = updateURL(fmtURL(ufUpdateStage1JSON), h.Update[storage.Stage1JSON])
h.Update[storage.Stage2] = updateURL(fmtURL(ufUpdateStage2), h.Update[storage.Stage2])
h.Update[storage.Stage3] = updateURL(fmtURL(ufUpdateStage3), h.Update[storage.Stage3])

h.ImagesVersion = ufImagesVersion
}

func init() {
Expand Down Expand Up @@ -150,4 +152,6 @@ func init() {
"Absolute URL to an action definition to run during stage2 to stage3 update.")
updateCmd.Flags().StringVar(&ufUpdateStage3, "update-stage3", "",
"Absolute URL to an action definition to run after running stage3 update.")
updateCmd.Flags().StringVar(&ufImagesVersion, "images-version", "",
"Version of epoxy-images to use in each boot stage.")
}
3 changes: 3 additions & 0 deletions storage/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ type Host struct {
Boot datastorex.Map
// Update is an alternate boot sequence, typically used to update the system, e.g. reinstall, reflash.
Update datastorex.Map
// ImagesVersion is the version of epoxy-images to use when booting the
// machines in all stages (1-3).
ImagesVersion string

// UpdateEnabled controls whether ePoxy returns the Update sequence (true)
// or Boot sequence (false) Chain URLs.
Expand Down
26 changes: 14 additions & 12 deletions storage/host_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,19 @@ import (

func TestHostString(t *testing.T) {
hostExpected := `{
"Name": "mlab1.iad1t.measurement-lab.org",
"Name": "mlab1-lga0t.mlab-sandbox.measurement-lab.org",
"IPv4Addr": "165.117.240.9",
"Boot": {
"stage1.ipxe": "https://storage.googleapis.com/epoxy-boot-server/coreos/stage1to2.ipxe",
"stage2": "https://storage.googleapis.com/epoxy-boot-server/coreos/stage2to3.json",
"stage3": "https://storage.googleapis.com/epoxy-boot-server/coreos/stage3setup.json"
"stage1.ipxe": "https://storage.googleapis.com/epoxy-mlab-sandbox/latest/stage3_ubuntu/stage1to2.ipxe",
"stage2": "https://storage.googleapis.com/epoxy-mlab-sandbox/latest/stage3_ubuntu/stage2to3.json",
"stage3": "https://storage.googleapis.com/epoxy-mlab-sandbox/latest/stage3_ubuntu/stage3post.json"
},
"Update": {
"stage1.ipxe": "https://storage.googleapis.com/epoxy-boot-server/centos6/install.json",
"stage2": "https://storage.googleapis.com/epoxy-boot-server/centos6/boot.json",
"stage1.ipxe": "https://storage.googleapis.com/epoxy-mlab-sandbox/latest/stage3_update/stage1to2.ipxe",
"stage2": "https://storage.googleapis.com/epoxy-mlab-sandbox/latest/stage3_update/stage2to3.json",
"stage3": ""
},
"ImagesVersion": "latest",
"UpdateEnabled": false,
"Extensions": null,
"CurrentSessionIDs": {
Expand Down Expand Up @@ -65,18 +66,19 @@ func TestHostString(t *testing.T) {
t.Fatal(err)
}
h := Host{
Name: "mlab1.iad1t.measurement-lab.org",
Name: "mlab1-lga0t.mlab-sandbox.measurement-lab.org",
IPv4Addr: "165.117.240.9",
Boot: datastorex.Map{
Stage1IPXE: "https://storage.googleapis.com/epoxy-boot-server/coreos/stage1to2.ipxe",
Stage2: "https://storage.googleapis.com/epoxy-boot-server/coreos/stage2to3.json",
Stage3: "https://storage.googleapis.com/epoxy-boot-server/coreos/stage3setup.json",
Stage1IPXE: "https://storage.googleapis.com/epoxy-mlab-sandbox/latest/stage3_ubuntu/stage1to2.ipxe",
Stage2: "https://storage.googleapis.com/epoxy-mlab-sandbox/latest/stage3_ubuntu/stage2to3.json",
Stage3: "https://storage.googleapis.com/epoxy-mlab-sandbox/latest/stage3_ubuntu/stage3post.json",
},
Update: datastorex.Map{
Stage1IPXE: "https://storage.googleapis.com/epoxy-boot-server/centos6/install.json",
Stage2: "https://storage.googleapis.com/epoxy-boot-server/centos6/boot.json",
Stage1IPXE: "https://storage.googleapis.com/epoxy-mlab-sandbox/latest/stage3_update/stage1to2.ipxe",
Stage2: "https://storage.googleapis.com/epoxy-mlab-sandbox/latest/stage3_update/stage2to3.json",
Stage3: "",
},
ImagesVersion: "latest",
CurrentSessionIDs: SessionIDs{
Stage2ID: "01234",
Stage3ID: "56789",
Expand Down
16 changes: 10 additions & 6 deletions template/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"bytes"
"fmt"
"html/template"
"strings"

"github.com/m-lab/epoxy/nextboot"
"github.com/m-lab/epoxy/storage"
Expand All @@ -33,6 +34,7 @@ set stage1chain_url {{ .Stage1ChainURL }}
set stage2_url {{ .Stage2URL }}
set stage3_url {{ .Stage3URL }}
set report_url {{ .ReportURL }}
set images_version {{ .ImagesVersion }}
{{- range $key, $value := .Extensions }}
set {{ $key }}_url {{ $value }}
{{- end }}
Expand All @@ -53,13 +55,14 @@ func FormatStage1IPXEScript(h *storage.Host, serverAddr string) string {

// Prepare a map for evaluating template.
vals := make(map[string]interface{}, 5)
vals["Stage1ChainURL"] = s[storage.Stage1IPXE]
vals["Stage1ChainURL"] = strings.Replace(s[storage.Stage1IPXE], "{{VERSION}}", h.ImagesVersion, 1)
vals["Stage2URL"] = fmt.Sprintf("https://%s/v1/boot/%s/%s/stage2",
serverAddr, h.Name, h.CurrentSessionIDs.Stage2ID)
vals["Stage3URL"] = fmt.Sprintf("https://%s/v1/boot/%s/%s/stage3",
serverAddr, h.Name, h.CurrentSessionIDs.Stage3ID)
vals["ReportURL"] = fmt.Sprintf("https://%s/v1/boot/%s/%s/report",
serverAddr, h.Name, h.CurrentSessionIDs.ReportID)
vals["ImagesVersion"] = h.ImagesVersion

// Construct an extension URL for all extensions this host supports.
extensionURLs := make(map[string]string, len(h.Extensions))
Expand Down Expand Up @@ -89,12 +92,13 @@ func CreateStage1Action(h *storage.Host, serverAddr string) string {
c := nextboot.Config{
// clients receiving this configuration must support merging local and given Kargs.
Kargs: map[string]string{
"epoxy.stage2": fmt.Sprintf("https://%s/v1/boot/%s/%s/stage2", serverAddr, h.Name, h.CurrentSessionIDs.Stage2ID),
"epoxy.stage3": fmt.Sprintf("https://%s/v1/boot/%s/%s/stage3", serverAddr, h.Name, h.CurrentSessionIDs.Stage3ID),
"epoxy.report": fmt.Sprintf("https://%s/v1/boot/%s/%s/report", serverAddr, h.Name, h.CurrentSessionIDs.ReportID),
"epoxy.stage2": fmt.Sprintf("https://%s/v1/boot/%s/%s/stage2", serverAddr, h.Name, h.CurrentSessionIDs.Stage2ID),
"epoxy.stage3": fmt.Sprintf("https://%s/v1/boot/%s/%s/stage3", serverAddr, h.Name, h.CurrentSessionIDs.Stage3ID),
"epoxy.report": fmt.Sprintf("https://%s/v1/boot/%s/%s/report", serverAddr, h.Name, h.CurrentSessionIDs.ReportID),
"epoxy.images_version": h.ImagesVersion,
},
V1: &nextboot.V1{
Chain: s["stage1.json"],
Chain: strings.Replace(s["stage1.json"], "{{VERSION}}", h.ImagesVersion, 1),
},
}

Expand All @@ -114,7 +118,7 @@ func FormatJSONConfig(h *storage.Host, stage string) string {
s := h.CurrentSequence()
c := nextboot.Config{
V1: &nextboot.V1{
Chain: s[stage],
Chain: strings.Replace(s[stage], "{{VERSION}}", h.ImagesVersion, 1),
},
}
return c.String()
Expand Down
36 changes: 20 additions & 16 deletions template/template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,12 @@ import (
const expectedStage1Script = `#!ipxe
set stage1chain_url https://example.com/path/stage1to2/stage1to2.ipxe
set stage2_url https://boot-api-mlab-sandbox.appspot.com/v1/boot/mlab1.iad1t.measurement-lab.org/01234/stage2
set stage3_url https://boot-api-mlab-sandbox.appspot.com/v1/boot/mlab1.iad1t.measurement-lab.org/56789/stage3
set report_url https://boot-api-mlab-sandbox.appspot.com/v1/boot/mlab1.iad1t.measurement-lab.org/86420/report
set ext1_url https://boot-api-mlab-sandbox.appspot.com/v1/boot/mlab1.iad1t.measurement-lab.org/75319/extension/ext1
set ext2_url https://boot-api-mlab-sandbox.appspot.com/v1/boot/mlab1.iad1t.measurement-lab.org/75319/extension/ext2
set stage2_url https://epoxy-boot-api.mlab-sandbox.measurementlab.net/v1/boot/mlab1-lga0t.mlab-sandbox.measurement-lab.org/01234/stage2
set stage3_url https://epoxy-boot-api.mlab-sandbox.measurementlab.net/v1/boot/mlab1-lga0t.mlab-sandbox.measurement-lab.org/56789/stage3
set report_url https://epoxy-boot-api.mlab-sandbox.measurementlab.net/v1/boot/mlab1-lga0t.mlab-sandbox.measurement-lab.org/86420/report
set images_version latest
set ext1_url https://epoxy-boot-api.mlab-sandbox.measurementlab.net/v1/boot/mlab1-lga0t.mlab-sandbox.measurement-lab.org/75319/extension/ext1
set ext2_url https://epoxy-boot-api.mlab-sandbox.measurementlab.net/v1/boot/mlab1-lga0t.mlab-sandbox.measurement-lab.org/75319/extension/ext2
chain ${stage1chain_url}
`
Expand All @@ -41,12 +42,13 @@ chain ${stage1chain_url}
// The result is checked for a valid header and verbatim against the expected content.
func TestFormatStage1IPXEScript(t *testing.T) {
h := &storage.Host{
Name: "mlab1.iad1t.measurement-lab.org",
Name: "mlab1-lga0t.mlab-sandbox.measurement-lab.org",
IPv4Addr: "165.117.240.9",
Boot: datastorex.Map{
storage.Stage1IPXE: "https://example.com/path/stage1to2/stage1to2.ipxe",
},
Extensions: []string{"ext1", "ext2"},
ImagesVersion: "latest",
Extensions: []string{"ext1", "ext2"},
CurrentSessionIDs: storage.SessionIDs{
Stage2ID: "01234",
Stage3ID: "56789",
Expand All @@ -55,7 +57,7 @@ func TestFormatStage1IPXEScript(t *testing.T) {
},
}

script := FormatStage1IPXEScript(h, "boot-api-mlab-sandbox.appspot.com")
script := FormatStage1IPXEScript(h, "epoxy-boot-api.mlab-sandbox.measurementlab.net")
// Verify the correct script header.
if !strings.HasPrefix(script, "#!ipxe") {
lines := strings.SplitN(script, "\n", 2)
Expand All @@ -77,8 +79,9 @@ func TestCreateStage1Action(t *testing.T) {
{
name: "success",
h: &storage.Host{
Name: "mlab1.foo01.measurement-lab.org",
Extensions: []string{"allocate_k8s_token"},
Name: "mlab1-foo01.mlab-sandbox.measurement-lab.org",
Extensions: []string{"allocate_k8s_token"},
ImagesVersion: "v1.8.7",
CurrentSessionIDs: storage.SessionIDs{
Stage2ID: "01234",
Stage3ID: "56789",
Expand All @@ -89,18 +92,19 @@ func TestCreateStage1Action(t *testing.T) {
want: dedent.Dedent(`
{
"kargs": {
"epoxy.allocate_k8s_token": "https://boot-api-mlab-sandbox.appspot.com/v1/boot/mlab1.foo01.measurement-lab.org/75319/extension/allocate_k8s_token",
"epoxy.report": "https://boot-api-mlab-sandbox.appspot.com/v1/boot/mlab1.foo01.measurement-lab.org/86420/report",
"epoxy.stage2": "https://boot-api-mlab-sandbox.appspot.com/v1/boot/mlab1.foo01.measurement-lab.org/01234/stage2",
"epoxy.stage3": "https://boot-api-mlab-sandbox.appspot.com/v1/boot/mlab1.foo01.measurement-lab.org/56789/stage3"
"epoxy.allocate_k8s_token": "https://epoxy-boot-api.mlab-sandbox.measurementlab.net/v1/boot/mlab1-foo01.mlab-sandbox.measurement-lab.org/75319/extension/allocate_k8s_token",
"epoxy.images_version": "v1.8.7",
"epoxy.report": "https://epoxy-boot-api.mlab-sandbox.measurementlab.net/v1/boot/mlab1-foo01.mlab-sandbox.measurement-lab.org/86420/report",
"epoxy.stage2": "https://epoxy-boot-api.mlab-sandbox.measurementlab.net/v1/boot/mlab1-foo01.mlab-sandbox.measurement-lab.org/01234/stage2",
"epoxy.stage3": "https://epoxy-boot-api.mlab-sandbox.measurementlab.net/v1/boot/mlab1-foo01.mlab-sandbox.measurement-lab.org/56789/stage3"
},
"v1": {}
}`),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := CreateStage1Action(tt.h, "boot-api-mlab-sandbox.appspot.com"); got != tt.want[1:] {
if got := CreateStage1Action(tt.h, "epoxy-boot-api.mlab-sandbox.measurementlab.net"); got != tt.want[1:] {
t.Errorf("CreateStage1Action() = %v, want %v", got, tt.want)
}
})
Expand All @@ -117,7 +121,7 @@ func TestFormatJSONConfig(t *testing.T) {
{
name: "success",
h: &storage.Host{
Name: "mlab1.foo01.measurement-lab.org",
Name: "mlab1-foo01.mlab-sandbox.measurement-lab.org",
Boot: datastorex.Map{
"stage2": "https://example.com/path/stage2/stage2",
},
Expand Down

0 comments on commit bc19e97

Please sign in to comment.