From f403307edf45b4bba819cdf1491bf585127566be Mon Sep 17 00:00:00 2001 From: Guillaume Tardif Date: Thu, 18 Jun 2020 10:03:28 +0200 Subject: [PATCH] =?UTF-8?q?Allow=20compose=20updates=20without=20having=20?= =?UTF-8?q?to=20delete=20the=20stack=20every=20time.=20Update=20will=20?= =?UTF-8?q?=E2=80=9Ctypically=E2=80=9D=20keep=20the=20same=20IP,=20but=20t?= =?UTF-8?q?his=20isn=E2=80=99t=20guaranteed=20by=20azure=20(ACI=20has=20li?= =?UTF-8?q?mitations=20on=20what=20can=20be=20updated,=20but=20this=20does?= =?UTF-8?q?=20not=20apply=20to=20us=20for=20the=20moment=20:=20https://doc?= =?UTF-8?q?s.microsoft.com/en-us/azure/container-instances/container-insta?= =?UTF-8?q?nces-update#properties-that-require-container-delete)=20For=20t?= =?UTF-8?q?he=20moment=20I=20check=20in=20the=20test=20that=20the=20IP=20i?= =?UTF-8?q?s=20keep=20the=20same?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- azure/aci.go | 8 ++++++ azure/backend.go | 2 +- tests/aci-e2e/e2e-aci_test.go | 54 ++++++++++++++++++++++++++++++----- 3 files changed, 56 insertions(+), 8 deletions(-) diff --git a/azure/aci.go b/azure/aci.go index d4547dd1b..bf7a51091 100644 --- a/azure/aci.go +++ b/azure/aci.go @@ -43,6 +43,14 @@ func createACIContainers(ctx context.Context, aciContext store.AciContext, group return fmt.Errorf("container group %q already exists", *groupDefinition.Name) } + return createOrUpdateACIContainers(ctx, aciContext, groupDefinition) +} + +func createOrUpdateACIContainers(ctx context.Context, aciContext store.AciContext, groupDefinition containerinstance.ContainerGroup) error { + containerGroupsClient, err := getContainerGroupsClient(aciContext.SubscriptionID) + if err != nil { + return errors.Wrapf(err, "cannot get container group client") + } future, err := containerGroupsClient.CreateOrUpdate( ctx, aciContext.ResourceGroup, diff --git a/azure/backend.go b/azure/backend.go index 35bbc5d48..ac15d41cd 100644 --- a/azure/backend.go +++ b/azure/backend.go @@ -283,7 +283,7 @@ func (cs *aciComposeService) Up(ctx context.Context, opts compose.ProjectOptions if err != nil { return err } - return createACIContainers(ctx, cs.ctx, groupDefinition) + return createOrUpdateACIContainers(ctx, cs.ctx, groupDefinition) } func (cs *aciComposeService) Down(ctx context.Context, opts compose.ProjectOptions) error { diff --git a/tests/aci-e2e/e2e-aci_test.go b/tests/aci-e2e/e2e-aci_test.go index 0326fbaaf..f4daa6280 100644 --- a/tests/aci-e2e/e2e-aci_test.go +++ b/tests/aci-e2e/e2e-aci_test.go @@ -3,7 +3,9 @@ package main import ( "context" "fmt" + "io/ioutil" "net/url" + "os" "strings" "testing" @@ -122,8 +124,11 @@ func (s *E2eACISuite) TestACIBackend() { Expect(Lines(output)[0]).To(Equal(testContainerName)) }) + var exposedURL string + const composeFile = "../composefiles/aci-demo/aci_demo_port.yaml" + const serverContainer = "acidemo_web" It("deploys a compose app", func() { - s.NewDockerCommand("compose", "up", "-f", "../composefiles/aci-demo/aci_demo_port.yaml", "--project-name", "acidemo").ExecOrDie() + s.NewDockerCommand("compose", "up", "-f", composeFile, "--project-name", "acidemo").ExecOrDie() // Expect(output).To(ContainSubstring("Successfully deployed")) output := s.NewDockerCommand("ps").ExecOrDie() Lines := Lines(output) @@ -132,16 +137,16 @@ func (s *E2eACISuite) TestACIBackend() { for _, line := range Lines[1:] { Expect(line).To(ContainSubstring("Running")) - if strings.Contains(line, "acidemo_web") { + if strings.Contains(line, serverContainer) { webChecked = true containerFields := Columns(line) exposedIP := containerFields[3] Expect(exposedIP).To(ContainSubstring(":80->80/tcp")) - url := strings.ReplaceAll(exposedIP, "->80/tcp", "") - output = s.NewCommand("curl", url).ExecOrDie() + exposedURL = strings.ReplaceAll(exposedIP, "->80/tcp", "") + output = s.NewCommand("curl", exposedURL).ExecOrDie() Expect(output).To(ContainSubstring("Docker Compose demo")) - output = s.NewCommand("curl", url+"/words/noun").ExecOrDie() + output = s.NewCommand("curl", exposedURL+"/words/noun").ExecOrDie() Expect(output).To(ContainSubstring("\"word\":")) } } @@ -150,12 +155,47 @@ func (s *E2eACISuite) TestACIBackend() { }) It("get logs from web service", func() { - output := s.NewDockerCommand("logs", "acidemo_web").ExecOrDie() + output := s.NewDockerCommand("logs", serverContainer).ExecOrDie() Expect(output).To(ContainSubstring("Listening on port 80")) }) + It("updates a compose app", func() { + input, err := ioutil.ReadFile(composeFile) + Expect(err).To(BeNil()) + modifiedInput := strings.Replace(string(input), "web:", "webserver:", 1) + modifiedComposeFile := strings.Replace(composeFile, ".yaml", "-modified.yaml", 1) + err = ioutil.WriteFile(modifiedComposeFile, []byte(modifiedInput), 0644) + Expect(err).To(BeNil()) + defer func() { + err := os.Remove(modifiedComposeFile) + Expect(err).To(BeNil()) + }() + + s.NewDockerCommand("compose", "up", "-f", modifiedComposeFile, "--project-name", "acidemo").ExecOrDie() + // Expect(output).To(ContainSubstring("Successfully deployed")) + output := s.NewDockerCommand("ps").ExecOrDie() + Lines := Lines(output) + Expect(len(Lines)).To(Equal(4)) + webChecked := false + + for _, line := range Lines[1:] { + Expect(line).To(ContainSubstring("Running")) + if strings.Contains(line, serverContainer+"server") { + webChecked = true + containerFields := Columns(line) + exposedIP := containerFields[3] + Expect(exposedIP).To(ContainSubstring(":80->80/tcp")) + + url := strings.ReplaceAll(exposedIP, "->80/tcp", "") + Expect(exposedURL).To(Equal(url)) + } + } + + Expect(webChecked).To(BeTrue()) + }) + It("shutdown compose app", func() { - s.NewDockerCommand("compose", "down", "-f", "../composefiles/aci-demo/aci_demo_port.yaml", "--project-name", "acidemo").ExecOrDie() + s.NewDockerCommand("compose", "down", "-f", composeFile, "--project-name", "acidemo").ExecOrDie() }) It("switches back to default context", func() { output := s.NewCommand("docker", "context", "use", "default").ExecOrDie()