From 0101eb1bb1ef0c0c275049b0cbc15dd05933a596 Mon Sep 17 00:00:00 2001 From: Roman Mingazeev Date: Mon, 23 Nov 2020 13:19:50 +0300 Subject: [PATCH] support merge cloud user-data --- builder/yandex/cloud_init.go | 45 ++++++++++++++++++++++++++ builder/yandex/cloud_init_test.go | 38 ++++++++++++++++++++++ builder/yandex/step_create_instance.go | 17 ++++++---- 3 files changed, 93 insertions(+), 7 deletions(-) create mode 100644 builder/yandex/cloud_init.go create mode 100644 builder/yandex/cloud_init_test.go diff --git a/builder/yandex/cloud_init.go b/builder/yandex/cloud_init.go new file mode 100644 index 000000000..46ee4815c --- /dev/null +++ b/builder/yandex/cloud_init.go @@ -0,0 +1,45 @@ +package yandex + +import ( + "bytes" + "fmt" + "mime/multipart" + "net/textproto" +) + +const ( + defaultContentType = "text/cloud-config" + cloudInitIPv6Config = `#cloud-config +bootcmd: +- [ sh, -c, '/usr/bin/env dhclient -6 -D LL -nw -pf /run/dhclient_ipv6.eth0.pid -lf /var/lib/dhcp/dhclient_ipv6.eth0.leases eth0' ] +` +) + +// MergeCloudUserMetaData allow merge some user-data sections +func MergeCloudUserMetaData(usersData ...string) (string, error) { + buff := new(bytes.Buffer) + data := multipart.NewWriter(buff) + _, err := buff.WriteString(fmt.Sprintf("Content-Type: multipart/mixed; boundary=\"%s\"\r\n", data.Boundary())) + if err != nil { + return "", err + } + _, err = buff.WriteString("MIME-Version: 1.0\r\n\r\n") + if err != nil { + return "", err + } + + for i, userData := range usersData { + w, err := data.CreatePart(textproto.MIMEHeader{ + "Content-Disposition": {fmt.Sprintf("attachment; filename=\"user-data-%d.yaml\"", i)}, + "Content-Type": {defaultContentType}, + }) + if err != nil { + return "", err + } + _, err = w.Write([]byte(userData)) + if err != nil { + return "", err + } + } + return buff.String(), nil +} diff --git a/builder/yandex/cloud_init_test.go b/builder/yandex/cloud_init_test.go new file mode 100644 index 000000000..7b00b10e0 --- /dev/null +++ b/builder/yandex/cloud_init_test.go @@ -0,0 +1,38 @@ +package yandex + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +const ( + data1 = ` +#cloud-config +bootcmd: + - cmd1 + - cmd2 +` + data2 = ` +#cloud-config +runcmd: + - touch "cmd3" + - cmd4 +` +) + +func TestCloudInitMerge(t *testing.T) { + merged, err := MergeCloudUserMetaData( + data1, + data2, + ) + + require.NoError(t, err) + require.NotEmpty(t, merged) + + require.Contains(t, merged, "cmd1") + require.Contains(t, merged, "cmd2") + require.Contains(t, merged, "\"cmd3\"") + require.Contains(t, merged, "cmd4") + +} diff --git a/builder/yandex/step_create_instance.go b/builder/yandex/step_create_instance.go index 757b24c2a..0e6a99e89 100644 --- a/builder/yandex/step_create_instance.go +++ b/builder/yandex/step_create_instance.go @@ -205,14 +205,17 @@ func (s *StepCreateInstance) Run(ctx context.Context, state multistep.StateBag) return stepHaltWithError(state, fmt.Errorf("Error preparing instance metadata: %s", err)) } - // TODO make part metadata prepare process if config.UseIPv6 { - // this ugly hack will replace user provided 'user-data' - userData := `#cloud-config -runcmd: -- [ sh, -c, '/sbin/dhclient -6 -D LL -nw -pf /run/dhclient_ipv6.eth0.pid -lf /var/lib/dhcp/dhclient_ipv6.eth0.leases eth0' ] -` - instanceMetadata["user-data"] = userData + ui.Say("Prepare user-data...") + + oldUserData, ok := instanceMetadata["user-data"] + if !ok { + oldUserData = "" + } + instanceMetadata["user-data"], err = MergeCloudUserMetaData(oldUserData, cloudInitIPv6Config) + if err != nil { + return stepHaltWithError(state, fmt.Errorf("Error merge user data configs: %s", err)) + } } req := &compute.CreateInstanceRequest{