2020-06-18 16:13:24 +02:00
|
|
|
/*
|
|
|
|
Copyright 2020 Docker, Inc.
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
*/
|
|
|
|
|
2020-05-05 17:55:53 +02:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2020-05-19 11:29:48 +02:00
|
|
|
"fmt"
|
2020-06-30 17:29:47 +02:00
|
|
|
"math/rand"
|
2020-05-19 11:29:48 +02:00
|
|
|
"net/url"
|
2020-06-29 17:57:06 +02:00
|
|
|
"os"
|
2020-07-08 16:01:54 +02:00
|
|
|
"os/exec"
|
2020-05-18 11:00:09 +02:00
|
|
|
"strings"
|
2020-05-20 15:57:10 +02:00
|
|
|
"testing"
|
2020-06-30 16:33:36 +02:00
|
|
|
"time"
|
2020-06-02 23:33:41 +02:00
|
|
|
|
2020-07-08 16:01:54 +02:00
|
|
|
"github.com/docker/api/errdefs"
|
|
|
|
|
2020-05-05 17:55:53 +02:00
|
|
|
"github.com/Azure/azure-sdk-for-go/profiles/2019-03-01/resources/mgmt/resources"
|
2020-05-19 11:29:48 +02:00
|
|
|
azure_storage "github.com/Azure/azure-sdk-for-go/profiles/2019-03-01/storage/mgmt/storage"
|
|
|
|
"github.com/Azure/azure-storage-file-go/azfile"
|
2020-05-20 18:05:32 +02:00
|
|
|
"github.com/Azure/go-autorest/autorest/to"
|
2020-05-13 07:52:43 +02:00
|
|
|
. "github.com/onsi/gomega"
|
2020-05-20 18:05:32 +02:00
|
|
|
log "github.com/sirupsen/logrus"
|
2020-05-20 15:57:10 +02:00
|
|
|
"github.com/stretchr/testify/suite"
|
2020-05-13 07:52:43 +02:00
|
|
|
|
2020-06-30 16:33:36 +02:00
|
|
|
"github.com/docker/api/azure"
|
|
|
|
"github.com/docker/api/azure/login"
|
2020-05-19 11:29:48 +02:00
|
|
|
"github.com/docker/api/context/store"
|
2020-05-19 15:26:59 +02:00
|
|
|
"github.com/docker/api/tests/aci-e2e/storage"
|
2020-05-05 17:55:53 +02:00
|
|
|
. "github.com/docker/api/tests/framework"
|
|
|
|
)
|
|
|
|
|
2020-05-13 08:54:48 +02:00
|
|
|
const (
|
|
|
|
location = "westeurope"
|
|
|
|
contextName = "acitest"
|
2020-05-13 17:09:18 +02:00
|
|
|
testContainerName = "testcontainername"
|
2020-06-30 17:29:47 +02:00
|
|
|
testShareName = "dockertestshare"
|
|
|
|
testFileContent = "Volume mounted with success!"
|
|
|
|
testFileName = "index.html"
|
2020-05-13 08:54:48 +02:00
|
|
|
)
|
2020-05-05 17:55:53 +02:00
|
|
|
|
2020-05-20 15:57:10 +02:00
|
|
|
var (
|
2020-07-07 18:29:24 +02:00
|
|
|
subscriptionID string
|
2020-05-20 15:57:10 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
type E2eACISuite struct {
|
|
|
|
Suite
|
|
|
|
}
|
2020-05-05 17:55:53 +02:00
|
|
|
|
2020-07-08 16:01:54 +02:00
|
|
|
func (s *E2eACISuite) TestLoginLogoutCreateContextError() {
|
|
|
|
s.Step("Logs in azure using service principal credentials", azureLogin)
|
|
|
|
|
|
|
|
s.Step("logout from azure", func() {
|
|
|
|
output := s.NewDockerCommand("logout", "azure").ExecOrDie()
|
|
|
|
Expect(output).To(ContainSubstring(""))
|
|
|
|
_, err := os.Stat(login.GetTokenStorePath())
|
|
|
|
Expect(os.IsNotExist(err)).To(BeTrue())
|
|
|
|
})
|
|
|
|
|
|
|
|
s.Step("check context create fails with an explicit error and returns a specific error code", func() {
|
|
|
|
cmd := exec.Command("docker", "context", "create", "aci", "someContext")
|
|
|
|
bytes, err := cmd.CombinedOutput()
|
|
|
|
Expect(err).NotTo(BeNil())
|
|
|
|
Expect(string(bytes)).To(ContainSubstring("not logged in to azure, you need to run \"docker login azure\" first"))
|
|
|
|
Expect(cmd.ProcessState.ExitCode()).To(Equal(errdefs.ExitCodeLoginRequired))
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-07-07 18:29:24 +02:00
|
|
|
func (s *E2eACISuite) TestACIRunSingleContainer() {
|
2020-07-16 10:39:41 +02:00
|
|
|
var containerName string
|
2020-07-07 18:29:24 +02:00
|
|
|
resourceGroupName := s.setupTestResourceGroup()
|
2020-05-05 17:55:53 +02:00
|
|
|
defer deleteResourceGroup(resourceGroupName)
|
|
|
|
|
2020-06-30 16:33:36 +02:00
|
|
|
var nginxExposedURL string
|
2020-07-07 16:25:30 +02:00
|
|
|
s.Step("runs nginx on port 80", func() {
|
2020-05-19 19:51:22 +02:00
|
|
|
aciContext := store.AciContext{
|
|
|
|
SubscriptionID: subscriptionID,
|
|
|
|
Location: location,
|
|
|
|
ResourceGroup: resourceGroupName,
|
|
|
|
}
|
2020-07-07 18:29:24 +02:00
|
|
|
|
|
|
|
testStorageAccountName := "storageteste2e" + RandStringBytes(6) // "between 3 and 24 characters in length and use numbers and lower-case letters only"
|
2020-05-19 19:51:22 +02:00
|
|
|
createStorageAccount(aciContext, testStorageAccountName)
|
2020-07-07 18:29:24 +02:00
|
|
|
defer deleteStorageAccount(aciContext, testStorageAccountName)
|
2020-05-19 19:51:22 +02:00
|
|
|
keys := getStorageKeys(aciContext, testStorageAccountName)
|
|
|
|
firstKey := *keys[0].Value
|
2020-07-07 18:29:24 +02:00
|
|
|
credential, u := createFileShare(firstKey, testShareName, testStorageAccountName)
|
2020-05-19 19:51:22 +02:00
|
|
|
uploadFile(credential, u.String(), testFileName, testFileContent)
|
|
|
|
|
|
|
|
mountTarget := "/usr/share/nginx/html"
|
2020-07-02 15:43:16 +02:00
|
|
|
output := s.NewDockerCommand("run", "-d", "nginx",
|
2020-05-19 19:51:22 +02:00
|
|
|
"-v", fmt.Sprintf("%s:%s@%s:%s",
|
|
|
|
testStorageAccountName, firstKey, testShareName, mountTarget),
|
|
|
|
"-p", "80:80",
|
2020-07-16 10:39:41 +02:00
|
|
|
).ExecOrDie()
|
|
|
|
runOutput := Lines(output)
|
|
|
|
containerName = runOutput[len(runOutput)-1]
|
|
|
|
|
2020-05-20 15:57:10 +02:00
|
|
|
output = s.NewDockerCommand("ps").ExecOrDie()
|
2020-05-19 19:51:22 +02:00
|
|
|
lines := Lines(output)
|
|
|
|
Expect(len(lines)).To(Equal(2))
|
|
|
|
|
|
|
|
containerFields := Columns(lines[1])
|
|
|
|
Expect(containerFields[1]).To(Equal("nginx"))
|
|
|
|
Expect(containerFields[2]).To(Equal("Running"))
|
|
|
|
exposedIP := containerFields[3]
|
2020-06-08 12:07:20 +02:00
|
|
|
containerID := containerFields[0]
|
2020-05-19 19:51:22 +02:00
|
|
|
Expect(exposedIP).To(ContainSubstring(":80->80/tcp"))
|
|
|
|
|
2020-06-30 16:33:36 +02:00
|
|
|
nginxExposedURL = strings.ReplaceAll(exposedIP, "->80/tcp", "")
|
|
|
|
output = s.NewCommand("curl", nginxExposedURL).ExecOrDie()
|
2020-05-19 19:51:22 +02:00
|
|
|
Expect(output).To(ContainSubstring(testFileContent))
|
2020-06-08 12:07:20 +02:00
|
|
|
|
|
|
|
output = s.NewDockerCommand("logs", containerID).ExecOrDie()
|
|
|
|
Expect(output).To(ContainSubstring("GET"))
|
2020-05-13 09:00:48 +02:00
|
|
|
})
|
|
|
|
|
2020-07-07 16:25:30 +02:00
|
|
|
s.Step("exec command", func() {
|
2020-07-16 10:39:41 +02:00
|
|
|
output := s.NewDockerCommand("exec", containerName, "pwd").ExecOrDie()
|
2020-07-08 14:31:27 +02:00
|
|
|
Expect(output).To(ContainSubstring("/"))
|
|
|
|
|
2020-07-16 10:39:41 +02:00
|
|
|
_, err := s.NewDockerCommand("exec", containerName, "echo", "fail_with_argument").Exec()
|
2020-07-07 14:05:25 +02:00
|
|
|
Expect(err.Error()).To(ContainSubstring("ACI exec command does not accept arguments to the command. " +
|
2020-07-06 03:29:48 +02:00
|
|
|
"Only the binary should be specified"))
|
|
|
|
})
|
|
|
|
|
2020-07-07 16:25:30 +02:00
|
|
|
s.Step("follow logs from nginx", func() {
|
2020-06-30 18:26:38 +02:00
|
|
|
timeChan := make(chan time.Time)
|
|
|
|
|
2020-07-16 10:39:41 +02:00
|
|
|
ctx := s.NewDockerCommand("logs", "--follow", containerName).WithTimeout(timeChan)
|
2020-06-30 16:33:36 +02:00
|
|
|
outChan := make(chan string)
|
|
|
|
|
|
|
|
go func() {
|
2020-07-10 13:00:41 +02:00
|
|
|
output, err := ctx.Exec()
|
|
|
|
// check the process is cancelled by the test, not another unexpected error
|
|
|
|
Expect(err.Error()).To(ContainSubstring("timed out"))
|
2020-06-30 16:33:36 +02:00
|
|
|
outChan <- output
|
|
|
|
}()
|
2020-07-10 13:00:41 +02:00
|
|
|
// Ensure logs -- follow is strated before we curl nginx
|
|
|
|
time.Sleep(5 * time.Second)
|
2020-06-30 16:33:36 +02:00
|
|
|
|
|
|
|
s.NewCommand("curl", nginxExposedURL+"/test").ExecOrDie()
|
2020-06-30 18:26:38 +02:00
|
|
|
// Give the `logs --follow` a little time to get logs of the curl call
|
2020-07-10 13:00:41 +02:00
|
|
|
time.Sleep(5 * time.Second)
|
|
|
|
|
2020-06-30 18:26:38 +02:00
|
|
|
// Trigger a timeout to make ctx.Exec exit
|
|
|
|
timeChan <- time.Now()
|
2020-06-30 16:33:36 +02:00
|
|
|
|
|
|
|
output := <-outChan
|
|
|
|
|
|
|
|
Expect(output).To(ContainSubstring("/test"))
|
|
|
|
})
|
|
|
|
|
2020-07-07 16:25:30 +02:00
|
|
|
s.Step("removes container nginx", func() {
|
2020-07-16 10:39:41 +02:00
|
|
|
output := s.NewDockerCommand("rm", containerName).ExecOrDie()
|
|
|
|
Expect(Lines(output)[0]).To(Equal(containerName))
|
2020-07-02 15:43:16 +02:00
|
|
|
})
|
|
|
|
|
2020-07-07 16:25:30 +02:00
|
|
|
s.Step("re-run nginx with modified cpu/mem, and without --detach and follow logs", func() {
|
2020-07-02 15:43:16 +02:00
|
|
|
shutdown := make(chan time.Time)
|
|
|
|
errs := make(chan error)
|
|
|
|
outChan := make(chan string)
|
|
|
|
cmd := s.NewDockerCommand("run", "nginx", "--memory", "0.1G", "--cpus", "0.1", "-p", "80:80", "--name", testContainerName).WithTimeout(shutdown)
|
|
|
|
go func() {
|
|
|
|
output, err := cmd.Exec()
|
|
|
|
outChan <- output
|
|
|
|
errs <- err
|
|
|
|
}()
|
|
|
|
var containerID string
|
|
|
|
err := WaitFor(time.Second, 100*time.Second, errs, func() bool {
|
|
|
|
output := s.NewDockerCommand("ps").ExecOrDie()
|
|
|
|
lines := Lines(output)
|
|
|
|
if len(lines) != 2 {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
containerFields := Columns(lines[1])
|
|
|
|
if containerFields[2] != "Running" {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
containerID = containerFields[0]
|
|
|
|
nginxExposedURL = strings.ReplaceAll(containerFields[3], "->80/tcp", "")
|
|
|
|
return true
|
|
|
|
})
|
|
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
|
|
|
|
s.NewCommand("curl", nginxExposedURL+"/test").ExecOrDie()
|
|
|
|
inspect := s.NewDockerCommand("inspect", containerID).ExecOrDie()
|
|
|
|
Expect(inspect).To(ContainSubstring("\"CPULimit\": 0.1"))
|
|
|
|
Expect(inspect).To(ContainSubstring("\"MemoryLimit\": 107374182"))
|
|
|
|
|
|
|
|
// Give a little time to get logs of the curl call
|
|
|
|
time.Sleep(5 * time.Second)
|
|
|
|
// Kill
|
|
|
|
close(shutdown)
|
|
|
|
|
|
|
|
output := <-outChan
|
|
|
|
Expect(output).To(ContainSubstring("/test"))
|
|
|
|
})
|
|
|
|
|
2020-07-07 16:25:30 +02:00
|
|
|
s.Step("removes container nginx", func() {
|
2020-05-20 15:57:10 +02:00
|
|
|
output := s.NewDockerCommand("rm", testContainerName).ExecOrDie()
|
2020-05-18 11:00:09 +02:00
|
|
|
Expect(Lines(output)[0]).To(Equal(testContainerName))
|
2020-05-13 09:00:48 +02:00
|
|
|
})
|
2020-07-07 18:29:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *E2eACISuite) TestACIComposeApplication() {
|
|
|
|
defer deleteResourceGroup(s.setupTestResourceGroup())
|
2020-05-05 17:55:53 +02:00
|
|
|
|
2020-06-18 10:03:28 +02:00
|
|
|
var exposedURL string
|
|
|
|
const composeFile = "../composefiles/aci-demo/aci_demo_port.yaml"
|
2020-06-24 18:20:27 +02:00
|
|
|
const composeFileMultiplePorts = "../composefiles/aci-demo/aci_demo_multi_port.yaml"
|
2020-07-06 16:56:30 +02:00
|
|
|
const composeProjectName = "acie2e"
|
|
|
|
const serverContainer = composeProjectName + "_web"
|
|
|
|
const wordsContainer = composeProjectName + "_words"
|
2020-06-30 16:33:36 +02:00
|
|
|
|
2020-07-07 16:25:30 +02:00
|
|
|
s.Step("deploys a compose app", func() {
|
2020-07-06 16:56:30 +02:00
|
|
|
// specifically do not specify project name here, it will be derived from current folder "acie2e"
|
|
|
|
s.NewDockerCommand("compose", "up", "-f", composeFile).ExecOrDie()
|
2020-05-20 15:57:10 +02:00
|
|
|
output := s.NewDockerCommand("ps").ExecOrDie()
|
2020-05-06 15:28:03 +02:00
|
|
|
Lines := Lines(output)
|
|
|
|
Expect(len(Lines)).To(Equal(4))
|
2020-05-18 11:00:09 +02:00
|
|
|
webChecked := false
|
|
|
|
|
2020-05-06 15:28:03 +02:00
|
|
|
for _, line := range Lines[1:] {
|
|
|
|
Expect(line).To(ContainSubstring("Running"))
|
2020-06-18 10:03:28 +02:00
|
|
|
if strings.Contains(line, serverContainer) {
|
2020-05-18 11:00:09 +02:00
|
|
|
webChecked = true
|
|
|
|
containerFields := Columns(line)
|
|
|
|
exposedIP := containerFields[3]
|
|
|
|
Expect(exposedIP).To(ContainSubstring(":80->80/tcp"))
|
|
|
|
|
2020-06-18 10:03:28 +02:00
|
|
|
exposedURL = strings.ReplaceAll(exposedIP, "->80/tcp", "")
|
|
|
|
output = s.NewCommand("curl", exposedURL).ExecOrDie()
|
2020-05-18 11:00:09 +02:00
|
|
|
Expect(output).To(ContainSubstring("Docker Compose demo"))
|
2020-06-18 10:03:28 +02:00
|
|
|
output = s.NewCommand("curl", exposedURL+"/words/noun").ExecOrDie()
|
2020-05-18 11:00:09 +02:00
|
|
|
Expect(output).To(ContainSubstring("\"word\":"))
|
2020-05-05 17:55:53 +02:00
|
|
|
}
|
2020-05-18 11:00:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Expect(webChecked).To(BeTrue())
|
2020-05-06 15:28:03 +02:00
|
|
|
})
|
2020-05-05 17:55:53 +02:00
|
|
|
|
2020-07-07 16:25:30 +02:00
|
|
|
s.Step("get logs from web service", func() {
|
2020-06-18 10:03:28 +02:00
|
|
|
output := s.NewDockerCommand("logs", serverContainer).ExecOrDie()
|
2020-05-06 17:14:53 +02:00
|
|
|
Expect(output).To(ContainSubstring("Listening on port 80"))
|
|
|
|
})
|
2020-05-06 15:28:03 +02:00
|
|
|
|
2020-07-07 16:25:30 +02:00
|
|
|
s.Step("updates a compose app", func() {
|
2020-07-06 16:56:30 +02:00
|
|
|
s.NewDockerCommand("compose", "up", "-f", composeFileMultiplePorts, "--project-name", composeProjectName).ExecOrDie()
|
2020-06-18 10:03:28 +02:00
|
|
|
// Expect(output).To(ContainSubstring("Successfully deployed"))
|
|
|
|
output := s.NewDockerCommand("ps").ExecOrDie()
|
|
|
|
Lines := Lines(output)
|
|
|
|
Expect(len(Lines)).To(Equal(4))
|
|
|
|
webChecked := false
|
2020-06-24 18:20:27 +02:00
|
|
|
wordsChecked := false
|
2020-06-18 10:03:28 +02:00
|
|
|
|
|
|
|
for _, line := range Lines[1:] {
|
|
|
|
Expect(line).To(ContainSubstring("Running"))
|
2020-06-24 18:20:27 +02:00
|
|
|
if strings.Contains(line, serverContainer) {
|
2020-06-18 10:03:28 +02:00
|
|
|
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))
|
|
|
|
}
|
2020-06-24 18:20:27 +02:00
|
|
|
if strings.Contains(line, wordsContainer) {
|
|
|
|
wordsChecked = true
|
|
|
|
containerFields := Columns(line)
|
|
|
|
exposedIP := containerFields[3]
|
|
|
|
Expect(exposedIP).To(ContainSubstring(":8080->8080/tcp"))
|
|
|
|
|
|
|
|
url := strings.ReplaceAll(exposedIP, "->8080/tcp", "")
|
|
|
|
output = s.NewCommand("curl", url+"/noun").ExecOrDie()
|
|
|
|
Expect(output).To(ContainSubstring("\"word\":"))
|
|
|
|
}
|
2020-06-18 10:03:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Expect(webChecked).To(BeTrue())
|
2020-06-24 18:20:27 +02:00
|
|
|
Expect(wordsChecked).To(BeTrue())
|
2020-06-18 10:03:28 +02:00
|
|
|
})
|
|
|
|
|
2020-07-07 16:25:30 +02:00
|
|
|
s.Step("shutdown compose app", func() {
|
2020-07-06 16:56:30 +02:00
|
|
|
s.NewDockerCommand("compose", "down", "--project-name", composeProjectName).ExecOrDie()
|
2020-05-06 15:28:03 +02:00
|
|
|
})
|
2020-07-07 18:29:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *E2eACISuite) TestACIDeployMySQlwithEnvVars() {
|
|
|
|
defer deleteResourceGroup(s.setupTestResourceGroup())
|
2020-06-30 16:33:36 +02:00
|
|
|
|
2020-07-07 16:25:30 +02:00
|
|
|
s.Step("runs mysql with env variables", func() {
|
2020-07-07 12:17:46 +02:00
|
|
|
err := os.Setenv("MYSQL_USER", "user1")
|
|
|
|
Expect(err).To(BeNil())
|
|
|
|
s.NewDockerCommand("run", "-d", "mysql:5.7", "-e", "MYSQL_ROOT_PASSWORD=rootpwd", "-e", "MYSQL_DATABASE=mytestdb", "-e", "MYSQL_USER", "-e", "MYSQL_PASSWORD=userpwd").ExecOrDie()
|
|
|
|
|
|
|
|
output := s.NewDockerCommand("ps").ExecOrDie()
|
|
|
|
lines := Lines(output)
|
|
|
|
Expect(len(lines)).To(Equal(2))
|
|
|
|
|
|
|
|
containerFields := Columns(lines[1])
|
|
|
|
containerID := containerFields[0]
|
|
|
|
Expect(containerFields[1]).To(Equal("mysql:5.7"))
|
|
|
|
Expect(containerFields[2]).To(Equal("Running"))
|
|
|
|
|
|
|
|
errs := make(chan error)
|
|
|
|
err = WaitFor(time.Second, 100*time.Second, errs, func() bool {
|
|
|
|
output = s.NewDockerCommand("logs", containerID).ExecOrDie()
|
|
|
|
return strings.Contains(output, "Giving user user1 access to schema mytestdb")
|
|
|
|
})
|
|
|
|
Expect(err).To(BeNil())
|
|
|
|
})
|
|
|
|
|
2020-07-07 16:25:30 +02:00
|
|
|
s.Step("switches back to default context", func() {
|
2020-05-20 15:57:10 +02:00
|
|
|
output := s.NewCommand("docker", "context", "use", "default").ExecOrDie()
|
2020-05-05 17:55:53 +02:00
|
|
|
Expect(output).To(ContainSubstring("default"))
|
|
|
|
})
|
|
|
|
|
2020-07-07 16:25:30 +02:00
|
|
|
s.Step("deletes test context", func() {
|
2020-05-20 15:57:10 +02:00
|
|
|
output := s.NewCommand("docker", "context", "rm", contextName).ExecOrDie()
|
2020-05-05 17:55:53 +02:00
|
|
|
Expect(output).To(ContainSubstring(contextName))
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-07-07 18:29:24 +02:00
|
|
|
func (s *E2eACISuite) setupTestResourceGroup() string {
|
|
|
|
var resourceGroupName = randomResourceGroup()
|
|
|
|
s.Step("should be initialized with default context", s.checkDefaultContext)
|
|
|
|
s.Step("Logs in azure using service principal credentials", azureLogin)
|
|
|
|
s.Step("creates a new aci context for tests and use it", s.createAciContextAndUseIt(resourceGroupName))
|
|
|
|
s.Step("ensures no container is running initially", s.checkNoContainnersRunning)
|
|
|
|
return resourceGroupName
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *E2eACISuite) checkDefaultContext() {
|
|
|
|
output := s.NewCommand("docker", "context", "ls").ExecOrDie()
|
|
|
|
Expect(output).To(Not(ContainSubstring(contextName)))
|
|
|
|
Expect(output).To(ContainSubstring("default *"))
|
|
|
|
}
|
|
|
|
|
|
|
|
func azureLogin() {
|
|
|
|
login, err := login.NewAzureLoginService()
|
|
|
|
Expect(err).To(BeNil())
|
|
|
|
// in order to create new service principal and get these 3 values : `az ad sp create-for-rbac --name 'TestServicePrincipal' --sdk-auth`
|
|
|
|
clientID := os.Getenv("AZURE_CLIENT_ID")
|
|
|
|
clientSecret := os.Getenv("AZURE_CLIENT_SECRET")
|
|
|
|
tenantID := os.Getenv("AZURE_TENANT_ID")
|
|
|
|
err = login.TestLoginFromServicePrincipal(clientID, clientSecret, tenantID)
|
|
|
|
Expect(err).To(BeNil())
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *E2eACISuite) createAciContextAndUseIt(resourceGroupName string) func() {
|
|
|
|
return func() {
|
|
|
|
setupTestResourceGroup(resourceGroupName)
|
|
|
|
helper := azure.NewACIResourceGroupHelper()
|
|
|
|
models, err := helper.GetSubscriptionIDs(context.TODO())
|
|
|
|
Expect(err).To(BeNil())
|
|
|
|
subscriptionID = *models[0].SubscriptionID
|
|
|
|
|
|
|
|
s.NewDockerCommand("context", "create", "aci", contextName, "--subscription-id", subscriptionID, "--resource-group", resourceGroupName, "--location", location).ExecOrDie()
|
|
|
|
|
|
|
|
currentContext := s.NewCommand("docker", "context", "use", contextName).ExecOrDie()
|
|
|
|
Expect(currentContext).To(ContainSubstring(contextName))
|
|
|
|
output := s.NewCommand("docker", "context", "ls").ExecOrDie()
|
|
|
|
Expect(output).To(ContainSubstring("acitest *"))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *E2eACISuite) checkNoContainnersRunning() {
|
|
|
|
output := s.NewDockerCommand("ps").ExecOrDie()
|
|
|
|
Expect(len(Lines(output))).To(Equal(1))
|
|
|
|
}
|
|
|
|
|
|
|
|
func randomResourceGroup() string {
|
|
|
|
return "resourceGroupTestE2E-" + RandStringBytes(10)
|
|
|
|
}
|
|
|
|
|
2020-05-19 11:29:48 +02:00
|
|
|
func createStorageAccount(aciContext store.AciContext, accountName string) azure_storage.Account {
|
2020-06-02 23:33:41 +02:00
|
|
|
log.Println("Creating storage account " + accountName)
|
2020-05-19 11:29:48 +02:00
|
|
|
storageAccount, err := storage.CreateStorageAccount(context.TODO(), aciContext, accountName)
|
|
|
|
Expect(err).To(BeNil())
|
|
|
|
Expect(*storageAccount.Name).To(Equal(accountName))
|
|
|
|
return storageAccount
|
|
|
|
}
|
|
|
|
|
|
|
|
func getStorageKeys(aciContext store.AciContext, storageAccountName string) []azure_storage.AccountKey {
|
|
|
|
list, err := storage.ListKeys(context.TODO(), aciContext, storageAccountName)
|
|
|
|
Expect(err).To(BeNil())
|
|
|
|
Expect(list.Keys).ToNot(BeNil())
|
|
|
|
Expect(len(*list.Keys)).To(BeNumerically(">", 0))
|
|
|
|
|
|
|
|
return *list.Keys
|
|
|
|
}
|
|
|
|
|
2020-07-07 18:29:24 +02:00
|
|
|
func deleteStorageAccount(aciContext store.AciContext, testStorageAccountName string) {
|
2020-06-02 23:33:41 +02:00
|
|
|
log.Println("Deleting storage account " + testStorageAccountName)
|
2020-05-19 11:29:48 +02:00
|
|
|
_, err := storage.DeleteStorageAccount(context.TODO(), aciContext, testStorageAccountName)
|
|
|
|
Expect(err).To(BeNil())
|
|
|
|
}
|
|
|
|
|
2020-07-07 18:29:24 +02:00
|
|
|
func createFileShare(key, shareName string, testStorageAccountName string) (azfile.SharedKeyCredential, url.URL) {
|
2020-05-19 11:29:48 +02:00
|
|
|
// Create a ShareURL object that wraps a soon-to-be-created share's URL and a default pipeline.
|
|
|
|
u, _ := url.Parse(fmt.Sprintf("https://%s.file.core.windows.net/%s", testStorageAccountName, shareName))
|
|
|
|
credential, err := azfile.NewSharedKeyCredential(testStorageAccountName, key)
|
|
|
|
Expect(err).To(BeNil())
|
|
|
|
|
|
|
|
shareURL := azfile.NewShareURL(*u, azfile.NewPipeline(credential, azfile.PipelineOptions{}))
|
|
|
|
_, err = shareURL.Create(context.TODO(), azfile.Metadata{}, 0)
|
|
|
|
Expect(err).To(BeNil())
|
|
|
|
|
|
|
|
return *credential, *u
|
|
|
|
}
|
|
|
|
|
|
|
|
func uploadFile(credential azfile.SharedKeyCredential, baseURL, fileName, fileContent string) {
|
|
|
|
fURL, err := url.Parse(baseURL + "/" + fileName)
|
|
|
|
Expect(err).To(BeNil())
|
|
|
|
fileURL := azfile.NewFileURL(*fURL, azfile.NewPipeline(&credential, azfile.PipelineOptions{}))
|
2020-05-19 20:03:53 +02:00
|
|
|
err = azfile.UploadBufferToAzureFile(context.TODO(), []byte(fileContent), fileURL, azfile.UploadToAzureFileOptions{})
|
2020-05-19 11:29:48 +02:00
|
|
|
Expect(err).To(BeNil())
|
|
|
|
}
|
|
|
|
|
2020-05-20 15:57:10 +02:00
|
|
|
func TestE2eACI(t *testing.T) {
|
|
|
|
suite.Run(t, new(E2eACISuite))
|
|
|
|
}
|
|
|
|
|
2020-07-07 18:29:24 +02:00
|
|
|
func setupTestResourceGroup(resourceGroupName string) {
|
2020-05-05 17:55:53 +02:00
|
|
|
log.Println("Creating resource group " + resourceGroupName)
|
|
|
|
ctx := context.TODO()
|
2020-06-02 23:33:41 +02:00
|
|
|
helper := azure.NewACIResourceGroupHelper()
|
|
|
|
models, err := helper.GetSubscriptionIDs(ctx)
|
2020-05-05 17:55:53 +02:00
|
|
|
Expect(err).To(BeNil())
|
2020-07-07 18:29:24 +02:00
|
|
|
_, err = helper.CreateOrUpdate(ctx, *models[0].SubscriptionID, resourceGroupName, resources.Group{
|
2020-05-13 08:54:48 +02:00
|
|
|
Location: to.StringPtr(location),
|
2020-05-05 17:55:53 +02:00
|
|
|
})
|
|
|
|
Expect(err).To(BeNil())
|
|
|
|
}
|
|
|
|
|
2020-07-07 18:29:24 +02:00
|
|
|
func deleteResourceGroup(resourceGroupName string) {
|
2020-05-05 17:55:53 +02:00
|
|
|
log.Println("Deleting resource group " + resourceGroupName)
|
|
|
|
ctx := context.TODO()
|
2020-06-02 23:33:41 +02:00
|
|
|
helper := azure.NewACIResourceGroupHelper()
|
|
|
|
models, err := helper.GetSubscriptionIDs(ctx)
|
2020-05-05 17:55:53 +02:00
|
|
|
Expect(err).To(BeNil())
|
2020-07-07 18:29:24 +02:00
|
|
|
err = helper.DeleteAsync(ctx, *models[0].SubscriptionID, resourceGroupName)
|
2020-05-05 17:55:53 +02:00
|
|
|
Expect(err).To(BeNil())
|
|
|
|
}
|
2020-06-30 17:29:47 +02:00
|
|
|
|
|
|
|
func RandStringBytes(n int) string {
|
|
|
|
rand.Seed(time.Now().UnixNano())
|
|
|
|
const digits = "0123456789"
|
|
|
|
b := make([]byte, n)
|
|
|
|
for i := range b {
|
|
|
|
b[i] = digits[rand.Intn(len(digits))]
|
|
|
|
}
|
|
|
|
return string(b)
|
|
|
|
}
|