mirror of https://github.com/docker/compose.git
Break out aci backend.go into several files for each service
Signed-off-by: Guillaume Tardif <guillaume.tardif@docker.com>
This commit is contained in:
parent
dcbc1c3fb2
commit
15addf5c22
28
aci/aci.go
28
aci/aci.go
|
@ -129,6 +129,34 @@ func getACIContainerGroup(ctx context.Context, aciContext store.AciContext, cont
|
|||
return containerGroupsClient.Get(ctx, aciContext.ResourceGroup, containerGroupName)
|
||||
}
|
||||
|
||||
func getACIContainerGroups(ctx context.Context, subscriptionID string, resourceGroup string) ([]containerinstance.ContainerGroup, error) {
|
||||
groupsClient, err := login.NewContainerGroupsClient(subscriptionID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var containerGroups []containerinstance.ContainerGroup
|
||||
result, err := groupsClient.ListByResourceGroup(ctx, resourceGroup)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for result.NotDone() {
|
||||
containerGroups = append(containerGroups, result.Values()...)
|
||||
if err := result.NextWithContext(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
var groups []containerinstance.ContainerGroup
|
||||
for _, group := range containerGroups {
|
||||
group, err := groupsClient.Get(ctx, resourceGroup, *group.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
groups = append(groups, group)
|
||||
}
|
||||
return groups, nil
|
||||
}
|
||||
|
||||
func deleteACIContainerGroup(ctx context.Context, aciContext store.AciContext, containerGroupName string) (containerinstance.ContainerGroup, error) {
|
||||
containerGroupsClient, err := login.NewContainerGroupsClient(aciContext.SubscriptionID)
|
||||
if err != nil {
|
||||
|
|
394
aci/backend.go
394
aci/backend.go
|
@ -18,18 +18,11 @@ package aci
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/services/containerinstance/mgmt/2018-10-01/containerinstance"
|
||||
"github.com/Azure/go-autorest/autorest"
|
||||
"github.com/Azure/go-autorest/autorest/to"
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/docker/compose-cli/aci/convert"
|
||||
"github.com/docker/compose-cli/aci/login"
|
||||
|
@ -41,7 +34,6 @@ import (
|
|||
apicontext "github.com/docker/compose-cli/context"
|
||||
"github.com/docker/compose-cli/context/cloud"
|
||||
"github.com/docker/compose-cli/context/store"
|
||||
"github.com/docker/compose-cli/errdefs"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -111,7 +103,7 @@ func getAciAPIService(aciCtx store.AciContext) *aciAPIService {
|
|||
ctx: aciCtx,
|
||||
},
|
||||
aciVolumeService: &aciVolumeService{
|
||||
ctx: aciCtx,
|
||||
aciContext: aciCtx,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -138,60 +130,6 @@ func (a *aciAPIService) VolumeService() volumes.Service {
|
|||
return a.aciVolumeService
|
||||
}
|
||||
|
||||
type aciContainerService struct {
|
||||
ctx store.AciContext
|
||||
}
|
||||
|
||||
func (cs *aciContainerService) List(ctx context.Context, all bool) ([]containers.Container, error) {
|
||||
containerGroups, err := getContainerGroups(ctx, cs.ctx.SubscriptionID, cs.ctx.ResourceGroup)
|
||||
if err != nil {
|
||||
return []containers.Container{}, err
|
||||
}
|
||||
var res []containers.Container
|
||||
for _, group := range containerGroups {
|
||||
if group.Containers == nil || len(*group.Containers) < 1 {
|
||||
return []containers.Container{}, fmt.Errorf("no containers found in ACI container group %s", *group.Name)
|
||||
}
|
||||
|
||||
for _, container := range *group.Containers {
|
||||
if isContainerVisible(container, group, all) {
|
||||
continue
|
||||
}
|
||||
c := convert.ContainerGroupToContainer(getContainerID(group, container), group, container)
|
||||
res = append(res, c)
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func getContainerGroups(ctx context.Context, subscriptionID string, resourceGroup string) ([]containerinstance.ContainerGroup, error) {
|
||||
groupsClient, err := login.NewContainerGroupsClient(subscriptionID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var containerGroups []containerinstance.ContainerGroup
|
||||
result, err := groupsClient.ListByResourceGroup(ctx, resourceGroup)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for result.NotDone() {
|
||||
containerGroups = append(containerGroups, result.Values()...)
|
||||
if err := result.NextWithContext(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
var groups []containerinstance.ContainerGroup
|
||||
for _, group := range containerGroups {
|
||||
group, err := groupsClient.Get(ctx, resourceGroup, *group.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
groups = append(groups, group)
|
||||
}
|
||||
return groups, nil
|
||||
}
|
||||
|
||||
func getContainerID(group containerinstance.ContainerGroup, container containerinstance.Container) string {
|
||||
containerID := *group.Name + composeContainerSeparator + *container.Name
|
||||
if _, ok := group.Tags[singleContainerTag]; ok {
|
||||
|
@ -204,26 +142,6 @@ func isContainerVisible(container containerinstance.Container, group containerin
|
|||
return *container.Name == convert.ComposeDNSSidecarName || (!showAll && convert.GetStatus(container, group) != convert.StatusRunning)
|
||||
}
|
||||
|
||||
func (cs *aciContainerService) Run(ctx context.Context, r containers.ContainerConfig) error {
|
||||
if strings.Contains(r.ID, composeContainerSeparator) {
|
||||
return errors.New(fmt.Sprintf("invalid container name. ACI container name cannot include %q", composeContainerSeparator))
|
||||
}
|
||||
|
||||
project, err := convert.ContainerToComposeProject(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logrus.Debugf("Running container %q with name %q\n", r.Image, r.ID)
|
||||
groupDefinition, err := convert.ToContainerGroup(ctx, cs.ctx, project)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
addTag(&groupDefinition, singleContainerTag)
|
||||
|
||||
return createACIContainers(ctx, cs.ctx, groupDefinition)
|
||||
}
|
||||
|
||||
func addTag(groupDefinition *containerinstance.ContainerGroup, tagName string) {
|
||||
if groupDefinition.Tags == nil {
|
||||
groupDefinition.Tags = make(map[string]*string, 1)
|
||||
|
@ -231,52 +149,6 @@ func addTag(groupDefinition *containerinstance.ContainerGroup, tagName string) {
|
|||
groupDefinition.Tags[tagName] = to.StringPtr(tagName)
|
||||
}
|
||||
|
||||
func (cs *aciContainerService) Start(ctx context.Context, containerID string) error {
|
||||
groupName, containerName := getGroupAndContainerName(containerID)
|
||||
if groupName != containerID {
|
||||
msg := "cannot start specified service %q from compose application %q, you can update and restart the entire compose app with docker compose up --project-name %s"
|
||||
return errors.New(fmt.Sprintf(msg, containerName, groupName, groupName))
|
||||
}
|
||||
|
||||
containerGroupsClient, err := login.NewContainerGroupsClient(cs.ctx.SubscriptionID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
future, err := containerGroupsClient.Start(ctx, cs.ctx.ResourceGroup, containerName)
|
||||
if err != nil {
|
||||
var aerr autorest.DetailedError
|
||||
if ok := errors.As(err, &aerr); ok {
|
||||
if aerr.StatusCode == http.StatusNotFound {
|
||||
return errdefs.ErrNotFound
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
return future.WaitForCompletionRef(ctx, containerGroupsClient.Client)
|
||||
}
|
||||
|
||||
func (cs *aciContainerService) Stop(ctx context.Context, containerID string, timeout *uint32) error {
|
||||
if timeout != nil && *timeout != uint32(0) {
|
||||
return errors.Errorf("ACI integration does not support setting a timeout to stop a container before killing it.")
|
||||
}
|
||||
groupName, containerName := getGroupAndContainerName(containerID)
|
||||
if groupName != containerID {
|
||||
msg := "cannot stop service %q from compose application %q, you can stop the entire compose app with docker stop %s"
|
||||
return errors.New(fmt.Sprintf(msg, containerName, groupName, groupName))
|
||||
}
|
||||
return stopACIContainerGroup(ctx, cs.ctx, groupName)
|
||||
}
|
||||
|
||||
func (cs *aciContainerService) Kill(ctx context.Context, containerID string, _ string) error {
|
||||
groupName, containerName := getGroupAndContainerName(containerID)
|
||||
if groupName != containerID {
|
||||
msg := "cannot kill service %q from compose application %q, you can kill the entire compose app with docker kill %s"
|
||||
return errors.New(fmt.Sprintf(msg, containerName, groupName, groupName))
|
||||
}
|
||||
return stopACIContainerGroup(ctx, cs.ctx, groupName) // As ACI doesn't have a kill command, we are using the stop implementation instead
|
||||
}
|
||||
|
||||
func getGroupAndContainerName(containerID string) (string, string) {
|
||||
tokens := strings.Split(containerID, composeContainerSeparator)
|
||||
|
@ -289,267 +161,3 @@ func getGroupAndContainerName(containerID string) (string, string) {
|
|||
return groupName, containerName
|
||||
}
|
||||
|
||||
func (cs *aciContainerService) Exec(ctx context.Context, name string, request containers.ExecRequest) error {
|
||||
err := verifyExecCommand(request.Command)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
groupName, containerAciName := getGroupAndContainerName(name)
|
||||
containerExecResponse, err := execACIContainer(ctx, cs.ctx, request.Command, groupName, containerAciName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return exec(
|
||||
context.Background(),
|
||||
*containerExecResponse.WebSocketURI,
|
||||
*containerExecResponse.Password,
|
||||
request,
|
||||
)
|
||||
}
|
||||
|
||||
func verifyExecCommand(command string) error {
|
||||
tokens := strings.Split(command, " ")
|
||||
if len(tokens) > 1 {
|
||||
return errors.New("ACI exec command does not accept arguments to the command. " +
|
||||
"Only the binary should be specified")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cs *aciContainerService) Logs(ctx context.Context, containerName string, req containers.LogsRequest) error {
|
||||
groupName, containerAciName := getGroupAndContainerName(containerName)
|
||||
var tail *int32
|
||||
|
||||
if req.Follow {
|
||||
return streamLogs(ctx, cs.ctx, groupName, containerAciName, req)
|
||||
}
|
||||
|
||||
if req.Tail != "all" {
|
||||
reqTail, err := strconv.Atoi(req.Tail)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i32 := int32(reqTail)
|
||||
tail = &i32
|
||||
}
|
||||
|
||||
logs, err := getACIContainerLogs(ctx, cs.ctx, groupName, containerAciName, tail)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = fmt.Fprint(req.Writer, logs)
|
||||
return err
|
||||
}
|
||||
|
||||
func (cs *aciContainerService) Delete(ctx context.Context, containerID string, request containers.DeleteRequest) error {
|
||||
groupName, containerName := getGroupAndContainerName(containerID)
|
||||
if groupName != containerID {
|
||||
msg := "cannot delete service %q from compose application %q, you can delete the entire compose app with docker compose down --project-name %s"
|
||||
return errors.New(fmt.Sprintf(msg, containerName, groupName, groupName))
|
||||
}
|
||||
|
||||
if !request.Force {
|
||||
containerGroupsClient, err := login.NewContainerGroupsClient(cs.ctx.SubscriptionID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cg, err := containerGroupsClient.Get(ctx, cs.ctx.ResourceGroup, groupName)
|
||||
if err != nil {
|
||||
if cg.StatusCode == http.StatusNotFound {
|
||||
return errdefs.ErrNotFound
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
for _, container := range *cg.Containers {
|
||||
status := convert.GetStatus(container, cg)
|
||||
|
||||
if status == convert.StatusRunning {
|
||||
return errdefs.ErrForbidden
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cg, err := deleteACIContainerGroup(ctx, cs.ctx, groupName)
|
||||
// Delete returns `StatusNoContent` if the group is not found
|
||||
if cg.StatusCode == http.StatusNoContent {
|
||||
return errdefs.ErrNotFound
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (cs *aciContainerService) Inspect(ctx context.Context, containerID string) (containers.Container, error) {
|
||||
groupName, containerName := getGroupAndContainerName(containerID)
|
||||
|
||||
cg, err := getACIContainerGroup(ctx, cs.ctx, groupName)
|
||||
if err != nil {
|
||||
return containers.Container{}, err
|
||||
}
|
||||
if cg.StatusCode == http.StatusNoContent {
|
||||
return containers.Container{}, errdefs.ErrNotFound
|
||||
}
|
||||
|
||||
var cc containerinstance.Container
|
||||
var found = false
|
||||
for _, c := range *cg.Containers {
|
||||
if to.String(c.Name) == containerName {
|
||||
cc = c
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return containers.Container{}, errdefs.ErrNotFound
|
||||
}
|
||||
|
||||
return convert.ContainerGroupToContainer(containerID, cg, cc), nil
|
||||
}
|
||||
|
||||
type aciComposeService struct {
|
||||
ctx store.AciContext
|
||||
}
|
||||
|
||||
func (cs *aciComposeService) Up(ctx context.Context, project *types.Project) error {
|
||||
logrus.Debugf("Up on project with name %q\n", project.Name)
|
||||
groupDefinition, err := convert.ToContainerGroup(ctx, cs.ctx, *project)
|
||||
addTag(&groupDefinition, composeContainerTag)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return createOrUpdateACIContainers(ctx, cs.ctx, groupDefinition)
|
||||
}
|
||||
|
||||
func (cs *aciComposeService) Down(ctx context.Context, project string) error {
|
||||
logrus.Debugf("Down on project with name %q\n", project)
|
||||
|
||||
cg, err := deleteACIContainerGroup(ctx, cs.ctx, project)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if cg.StatusCode == http.StatusNoContent {
|
||||
return errdefs.ErrNotFound
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (cs *aciComposeService) Ps(ctx context.Context, project string) ([]compose.ServiceStatus, error) {
|
||||
groupsClient, err := login.NewContainerGroupsClient(cs.ctx.SubscriptionID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
group, err := groupsClient.Get(ctx, cs.ctx.ResourceGroup, project)
|
||||
if err != nil {
|
||||
return []compose.ServiceStatus{}, err
|
||||
}
|
||||
|
||||
if group.Containers == nil || len(*group.Containers) < 1 {
|
||||
return []compose.ServiceStatus{}, fmt.Errorf("no containers found in ACI container group %s", project)
|
||||
}
|
||||
|
||||
res := []compose.ServiceStatus{}
|
||||
for _, container := range *group.Containers {
|
||||
if isContainerVisible(container, group, false) {
|
||||
continue
|
||||
}
|
||||
res = append(res, convert.ContainerGroupToServiceStatus(getContainerID(group, container), group, container))
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (cs *aciComposeService) List(ctx context.Context, project string) ([]compose.Stack, error) {
|
||||
containerGroups, err := getContainerGroups(ctx, cs.ctx.SubscriptionID, cs.ctx.ResourceGroup)
|
||||
if err != nil {
|
||||
return []compose.Stack{}, err
|
||||
}
|
||||
|
||||
stacks := []compose.Stack{}
|
||||
for _, group := range containerGroups {
|
||||
if _, found := group.Tags[composeContainerTag]; !found {
|
||||
continue
|
||||
}
|
||||
if project != "" && *group.Name != project {
|
||||
continue
|
||||
}
|
||||
state := compose.RUNNING
|
||||
for _, container := range *group.ContainerGroupProperties.Containers {
|
||||
containerState := convert.GetStatus(container, group)
|
||||
if containerState != compose.RUNNING {
|
||||
state = containerState
|
||||
break
|
||||
}
|
||||
}
|
||||
stacks = append(stacks, compose.Stack{
|
||||
ID: *group.ID,
|
||||
Name: *group.Name,
|
||||
Status: state,
|
||||
})
|
||||
}
|
||||
return stacks, nil
|
||||
}
|
||||
|
||||
func (cs *aciComposeService) Logs(ctx context.Context, project string, w io.Writer) error {
|
||||
return errdefs.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (cs *aciComposeService) Convert(ctx context.Context, project *types.Project) ([]byte, error) {
|
||||
return nil, errdefs.ErrNotImplemented
|
||||
}
|
||||
|
||||
type aciVolumeService struct {
|
||||
ctx store.AciContext
|
||||
}
|
||||
|
||||
func (cs *aciVolumeService) List(ctx context.Context) ([]volumes.Volume, error) {
|
||||
storageHelper := login.StorageAccountHelper{AciContext: cs.ctx}
|
||||
return storageHelper.ListFileShare(ctx)
|
||||
}
|
||||
|
||||
//VolumeCreateOptions options to create a new ACI volume
|
||||
type VolumeCreateOptions struct {
|
||||
Account string
|
||||
Fileshare string
|
||||
}
|
||||
|
||||
func (cs *aciVolumeService) Create(ctx context.Context, options interface{}) (volumes.Volume, error) {
|
||||
opts, ok := options.(VolumeCreateOptions)
|
||||
if !ok {
|
||||
return volumes.Volume{}, errors.New("Could not read azure LoginParams struct from generic parameter")
|
||||
}
|
||||
storageHelper := login.StorageAccountHelper{AciContext: cs.ctx}
|
||||
return storageHelper.CreateFileShare(ctx, opts.Account, opts.Fileshare)
|
||||
}
|
||||
|
||||
type aciCloudService struct {
|
||||
loginService login.AzureLoginServiceAPI
|
||||
}
|
||||
|
||||
func (cs *aciCloudService) Login(ctx context.Context, params interface{}) error {
|
||||
opts, ok := params.(LoginParams)
|
||||
if !ok {
|
||||
return errors.New("Could not read azure LoginParams struct from generic parameter")
|
||||
}
|
||||
if opts.ClientID != "" {
|
||||
return cs.loginService.LoginServicePrincipal(opts.ClientID, opts.ClientSecret, opts.TenantID)
|
||||
}
|
||||
return cs.loginService.Login(ctx, opts.TenantID)
|
||||
}
|
||||
|
||||
func (cs *aciCloudService) Logout(ctx context.Context) error {
|
||||
return cs.loginService.Logout(ctx)
|
||||
}
|
||||
|
||||
func (cs *aciCloudService) CreateContextData(ctx context.Context, params interface{}) (interface{}, string, error) {
|
||||
contextHelper := newContextCreateHelper()
|
||||
createOpts := params.(ContextParams)
|
||||
return contextHelper.createContextData(ctx, createOpts)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
package aci
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/docker/compose-cli/aci/login"
|
||||
)
|
||||
|
||||
type aciCloudService struct {
|
||||
loginService login.AzureLoginServiceAPI
|
||||
}
|
||||
|
||||
func (cs *aciCloudService) Login(ctx context.Context, params interface{}) error {
|
||||
opts, ok := params.(LoginParams)
|
||||
if !ok {
|
||||
return errors.New("Could not read azure LoginParams struct from generic parameter")
|
||||
}
|
||||
if opts.ClientID != "" {
|
||||
return cs.loginService.LoginServicePrincipal(opts.ClientID, opts.ClientSecret, opts.TenantID)
|
||||
}
|
||||
return cs.loginService.Login(ctx, opts.TenantID)
|
||||
}
|
||||
|
||||
func (cs *aciCloudService) Logout(ctx context.Context) error {
|
||||
return cs.loginService.Logout(ctx)
|
||||
}
|
||||
|
||||
func (cs *aciCloudService) CreateContextData(ctx context.Context, params interface{}) (interface{}, string, error) {
|
||||
contextHelper := newContextCreateHelper()
|
||||
createOpts := params.(ContextParams)
|
||||
return contextHelper.createContextData(ctx, createOpts)
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
package aci
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/docker/compose-cli/aci/convert"
|
||||
"github.com/docker/compose-cli/aci/login"
|
||||
"github.com/docker/compose-cli/api/compose"
|
||||
"github.com/docker/compose-cli/context/store"
|
||||
"github.com/docker/compose-cli/errdefs"
|
||||
)
|
||||
|
||||
type aciComposeService struct {
|
||||
ctx store.AciContext
|
||||
}
|
||||
|
||||
func (cs *aciComposeService) Up(ctx context.Context, project *types.Project) error {
|
||||
logrus.Debugf("Up on project with name %q\n", project.Name)
|
||||
groupDefinition, err := convert.ToContainerGroup(ctx, cs.ctx, *project)
|
||||
addTag(&groupDefinition, composeContainerTag)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return createOrUpdateACIContainers(ctx, cs.ctx, groupDefinition)
|
||||
}
|
||||
|
||||
func (cs *aciComposeService) Down(ctx context.Context, project string) error {
|
||||
logrus.Debugf("Down on project with name %q\n", project)
|
||||
|
||||
cg, err := deleteACIContainerGroup(ctx, cs.ctx, project)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if cg.StatusCode == http.StatusNoContent {
|
||||
return errdefs.ErrNotFound
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (cs *aciComposeService) Ps(ctx context.Context, project string) ([]compose.ServiceStatus, error) {
|
||||
groupsClient, err := login.NewContainerGroupsClient(cs.ctx.SubscriptionID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
group, err := groupsClient.Get(ctx, cs.ctx.ResourceGroup, project)
|
||||
if err != nil {
|
||||
return []compose.ServiceStatus{}, err
|
||||
}
|
||||
|
||||
if group.Containers == nil || len(*group.Containers) < 1 {
|
||||
return []compose.ServiceStatus{}, fmt.Errorf("no containers found in ACI container group %s", project)
|
||||
}
|
||||
|
||||
res := []compose.ServiceStatus{}
|
||||
for _, container := range *group.Containers {
|
||||
if isContainerVisible(container, group, false) {
|
||||
continue
|
||||
}
|
||||
res = append(res, convert.ContainerGroupToServiceStatus(getContainerID(group, container), group, container))
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (cs *aciComposeService) List(ctx context.Context, project string) ([]compose.Stack, error) {
|
||||
containerGroups, err := getACIContainerGroups(ctx, cs.ctx.SubscriptionID, cs.ctx.ResourceGroup)
|
||||
if err != nil {
|
||||
return []compose.Stack{}, err
|
||||
}
|
||||
|
||||
stacks := []compose.Stack{}
|
||||
for _, group := range containerGroups {
|
||||
if _, found := group.Tags[composeContainerTag]; !found {
|
||||
continue
|
||||
}
|
||||
if project != "" && *group.Name != project {
|
||||
continue
|
||||
}
|
||||
state := compose.RUNNING
|
||||
for _, container := range *group.ContainerGroupProperties.Containers {
|
||||
containerState := convert.GetStatus(container, group)
|
||||
if containerState != compose.RUNNING {
|
||||
state = containerState
|
||||
break
|
||||
}
|
||||
}
|
||||
stacks = append(stacks, compose.Stack{
|
||||
ID: *group.ID,
|
||||
Name: *group.Name,
|
||||
Status: state,
|
||||
})
|
||||
}
|
||||
return stacks, nil
|
||||
}
|
||||
|
||||
func (cs *aciComposeService) Logs(ctx context.Context, project string, w io.Writer) error {
|
||||
return errdefs.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (cs *aciComposeService) Convert(ctx context.Context, project *types.Project) ([]byte, error) {
|
||||
return nil, errdefs.ErrNotImplemented
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,254 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
package aci
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/services/containerinstance/mgmt/2018-10-01/containerinstance"
|
||||
"github.com/Azure/go-autorest/autorest"
|
||||
"github.com/Azure/go-autorest/autorest/to"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/docker/compose-cli/aci/convert"
|
||||
"github.com/docker/compose-cli/aci/login"
|
||||
"github.com/docker/compose-cli/api/containers"
|
||||
"github.com/docker/compose-cli/context/store"
|
||||
"github.com/docker/compose-cli/errdefs"
|
||||
)
|
||||
|
||||
type aciContainerService struct {
|
||||
ctx store.AciContext
|
||||
}
|
||||
|
||||
func (cs *aciContainerService) List(ctx context.Context, all bool) ([]containers.Container, error) {
|
||||
containerGroups, err := getACIContainerGroups(ctx, cs.ctx.SubscriptionID, cs.ctx.ResourceGroup)
|
||||
if err != nil {
|
||||
return []containers.Container{}, err
|
||||
}
|
||||
var res []containers.Container
|
||||
for _, group := range containerGroups {
|
||||
if group.Containers == nil || len(*group.Containers) < 1 {
|
||||
return []containers.Container{}, fmt.Errorf("no containers found in ACI container group %s", *group.Name)
|
||||
}
|
||||
|
||||
for _, container := range *group.Containers {
|
||||
if isContainerVisible(container, group, all) {
|
||||
continue
|
||||
}
|
||||
c := convert.ContainerGroupToContainer(getContainerID(group, container), group, container)
|
||||
res = append(res, c)
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
|
||||
func (cs *aciContainerService) Run(ctx context.Context, r containers.ContainerConfig) error {
|
||||
if strings.Contains(r.ID, composeContainerSeparator) {
|
||||
return errors.New(fmt.Sprintf("invalid container name. ACI container name cannot include %q", composeContainerSeparator))
|
||||
}
|
||||
|
||||
project, err := convert.ContainerToComposeProject(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logrus.Debugf("Running container %q with name %q\n", r.Image, r.ID)
|
||||
groupDefinition, err := convert.ToContainerGroup(ctx, cs.ctx, project)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
addTag(&groupDefinition, singleContainerTag)
|
||||
|
||||
return createACIContainers(ctx, cs.ctx, groupDefinition)
|
||||
}
|
||||
|
||||
func (cs *aciContainerService) Start(ctx context.Context, containerID string) error {
|
||||
groupName, containerName := getGroupAndContainerName(containerID)
|
||||
if groupName != containerID {
|
||||
msg := "cannot start specified service %q from compose application %q, you can update and restart the entire compose app with docker compose up --project-name %s"
|
||||
return errors.New(fmt.Sprintf(msg, containerName, groupName, groupName))
|
||||
}
|
||||
|
||||
containerGroupsClient, err := login.NewContainerGroupsClient(cs.ctx.SubscriptionID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
future, err := containerGroupsClient.Start(ctx, cs.ctx.ResourceGroup, containerName)
|
||||
if err != nil {
|
||||
var aerr autorest.DetailedError
|
||||
if ok := errors.As(err, &aerr); ok {
|
||||
if aerr.StatusCode == http.StatusNotFound {
|
||||
return errdefs.ErrNotFound
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
return future.WaitForCompletionRef(ctx, containerGroupsClient.Client)
|
||||
}
|
||||
|
||||
func (cs *aciContainerService) Stop(ctx context.Context, containerID string, timeout *uint32) error {
|
||||
if timeout != nil && *timeout != uint32(0) {
|
||||
return errors.Errorf("ACI integration does not support setting a timeout to stop a container before killing it.")
|
||||
}
|
||||
groupName, containerName := getGroupAndContainerName(containerID)
|
||||
if groupName != containerID {
|
||||
msg := "cannot stop service %q from compose application %q, you can stop the entire compose app with docker stop %s"
|
||||
return errors.New(fmt.Sprintf(msg, containerName, groupName, groupName))
|
||||
}
|
||||
return stopACIContainerGroup(ctx, cs.ctx, groupName)
|
||||
}
|
||||
|
||||
func (cs *aciContainerService) Kill(ctx context.Context, containerID string, _ string) error {
|
||||
groupName, containerName := getGroupAndContainerName(containerID)
|
||||
if groupName != containerID {
|
||||
msg := "cannot kill service %q from compose application %q, you can kill the entire compose app with docker kill %s"
|
||||
return errors.New(fmt.Sprintf(msg, containerName, groupName, groupName))
|
||||
}
|
||||
return stopACIContainerGroup(ctx, cs.ctx, groupName) // As ACI doesn't have a kill command, we are using the stop implementation instead
|
||||
}
|
||||
|
||||
func (cs *aciContainerService) Exec(ctx context.Context, name string, request containers.ExecRequest) error {
|
||||
err := verifyExecCommand(request.Command)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
groupName, containerAciName := getGroupAndContainerName(name)
|
||||
containerExecResponse, err := execACIContainer(ctx, cs.ctx, request.Command, groupName, containerAciName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return exec(
|
||||
context.Background(),
|
||||
*containerExecResponse.WebSocketURI,
|
||||
*containerExecResponse.Password,
|
||||
request,
|
||||
)
|
||||
}
|
||||
|
||||
func verifyExecCommand(command string) error {
|
||||
tokens := strings.Split(command, " ")
|
||||
if len(tokens) > 1 {
|
||||
return errors.New("ACI exec command does not accept arguments to the command. " +
|
||||
"Only the binary should be specified")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cs *aciContainerService) Logs(ctx context.Context, containerName string, req containers.LogsRequest) error {
|
||||
groupName, containerAciName := getGroupAndContainerName(containerName)
|
||||
var tail *int32
|
||||
|
||||
if req.Follow {
|
||||
return streamLogs(ctx, cs.ctx, groupName, containerAciName, req)
|
||||
}
|
||||
|
||||
if req.Tail != "all" {
|
||||
reqTail, err := strconv.Atoi(req.Tail)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i32 := int32(reqTail)
|
||||
tail = &i32
|
||||
}
|
||||
|
||||
logs, err := getACIContainerLogs(ctx, cs.ctx, groupName, containerAciName, tail)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = fmt.Fprint(req.Writer, logs)
|
||||
return err
|
||||
}
|
||||
|
||||
func (cs *aciContainerService) Delete(ctx context.Context, containerID string, request containers.DeleteRequest) error {
|
||||
groupName, containerName := getGroupAndContainerName(containerID)
|
||||
if groupName != containerID {
|
||||
msg := "cannot delete service %q from compose application %q, you can delete the entire compose app with docker compose down --project-name %s"
|
||||
return errors.New(fmt.Sprintf(msg, containerName, groupName, groupName))
|
||||
}
|
||||
|
||||
if !request.Force {
|
||||
containerGroupsClient, err := login.NewContainerGroupsClient(cs.ctx.SubscriptionID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cg, err := containerGroupsClient.Get(ctx, cs.ctx.ResourceGroup, groupName)
|
||||
if err != nil {
|
||||
if cg.StatusCode == http.StatusNotFound {
|
||||
return errdefs.ErrNotFound
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
for _, container := range *cg.Containers {
|
||||
status := convert.GetStatus(container, cg)
|
||||
|
||||
if status == convert.StatusRunning {
|
||||
return errdefs.ErrForbidden
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cg, err := deleteACIContainerGroup(ctx, cs.ctx, groupName)
|
||||
// Delete returns `StatusNoContent` if the group is not found
|
||||
if cg.StatusCode == http.StatusNoContent {
|
||||
return errdefs.ErrNotFound
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (cs *aciContainerService) Inspect(ctx context.Context, containerID string) (containers.Container, error) {
|
||||
groupName, containerName := getGroupAndContainerName(containerID)
|
||||
|
||||
cg, err := getACIContainerGroup(ctx, cs.ctx, groupName)
|
||||
if err != nil {
|
||||
return containers.Container{}, err
|
||||
}
|
||||
if cg.StatusCode == http.StatusNoContent {
|
||||
return containers.Container{}, errdefs.ErrNotFound
|
||||
}
|
||||
|
||||
var cc containerinstance.Container
|
||||
var found = false
|
||||
for _, c := range *cg.Containers {
|
||||
if to.String(c.Name) == containerName {
|
||||
cc = c
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return containers.Container{}, errdefs.ErrNotFound
|
||||
}
|
||||
|
||||
return convert.ContainerGroupToContainer(containerID, cg, cc), nil
|
||||
}
|
|
@ -56,7 +56,7 @@ const (
|
|||
func ToContainerGroup(ctx context.Context, aciContext store.AciContext, p types.Project) (containerinstance.ContainerGroup, error) {
|
||||
project := projectAciHelper(p)
|
||||
containerGroupName := strings.ToLower(project.Name)
|
||||
storageHelper := login.StorageAccountHelper{
|
||||
storageHelper := login.StorageLogin{
|
||||
AciContext: aciContext,
|
||||
}
|
||||
volumesCache, volumesSlice, err := project.getAciFileVolumes(ctx, storageHelper)
|
||||
|
@ -200,7 +200,7 @@ func (p projectAciHelper) getAciSecretVolumes() ([]containerinstance.Volume, err
|
|||
return secretVolumes, nil
|
||||
}
|
||||
|
||||
func (p projectAciHelper) getAciFileVolumes(ctx context.Context, helper login.StorageAccountHelper) (map[string]bool, []containerinstance.Volume, error) {
|
||||
func (p projectAciHelper) getAciFileVolumes(ctx context.Context, helper login.StorageLogin) (map[string]bool, []containerinstance.Volume, error) {
|
||||
azureFileVolumesMap := make(map[string]bool, len(p.Volumes))
|
||||
var azureFileVolumesSlice []containerinstance.Volume
|
||||
for name, v := range p.Volumes {
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
package login
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/docker/compose-cli/context/store"
|
||||
)
|
||||
|
||||
// StorageLogin helper for Azure Storage Login
|
||||
type StorageLogin struct {
|
||||
AciContext store.AciContext
|
||||
}
|
||||
|
||||
// GetAzureStorageAccountKey retrieves the storage account ket from the current azure login
|
||||
func (helper StorageLogin) GetAzureStorageAccountKey(ctx context.Context, accountName string) (string, error) {
|
||||
client, err := NewStorageAccountsClient(helper.AciContext.SubscriptionID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
result, err := client.ListKeys(ctx, helper.AciContext.ResourceGroup, accountName, "")
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, fmt.Sprintf("could not access storage account acountKeys for %s, using the azure login", accountName))
|
||||
}
|
||||
if result.Keys != nil && len((*result.Keys)) < 1 {
|
||||
return "", fmt.Errorf("no key could be obtained for storage account %s from your azure login", accountName)
|
||||
}
|
||||
|
||||
key := (*result.Keys)[0]
|
||||
return *key.Value, nil
|
||||
}
|
|
@ -14,11 +14,12 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package login
|
||||
package aci
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/docker/compose-cli/aci/login"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-06-01/storage"
|
||||
|
||||
|
@ -30,48 +31,27 @@ import (
|
|||
"github.com/docker/compose-cli/context/store"
|
||||
)
|
||||
|
||||
// StorageAccountHelper helper for Azure Storage Account
|
||||
type StorageAccountHelper struct {
|
||||
AciContext store.AciContext
|
||||
type aciVolumeService struct {
|
||||
aciContext store.AciContext
|
||||
}
|
||||
|
||||
// GetAzureStorageAccountKey retrieves the storage account ket from the current azure login
|
||||
func (helper StorageAccountHelper) GetAzureStorageAccountKey(ctx context.Context, accountName string) (string, error) {
|
||||
client, err := NewStorageAccountsClient(helper.AciContext.SubscriptionID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
result, err := client.ListKeys(ctx, helper.AciContext.ResourceGroup, accountName, "")
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, fmt.Sprintf("could not access storage account acountKeys for %s, using the azure login", accountName))
|
||||
}
|
||||
if result.Keys != nil && len((*result.Keys)) < 1 {
|
||||
return "", fmt.Errorf("no key could be obtained for storage account %s from your azure login", accountName)
|
||||
}
|
||||
|
||||
key := (*result.Keys)[0]
|
||||
return *key.Value, nil
|
||||
}
|
||||
|
||||
// ListFileShare list file shares in all visible storage accounts
|
||||
func (helper StorageAccountHelper) ListFileShare(ctx context.Context) ([]volumes.Volume, error) {
|
||||
aciContext := helper.AciContext
|
||||
accountClient, err := NewStorageAccountsClient(aciContext.SubscriptionID)
|
||||
func (cs *aciVolumeService) List(ctx context.Context) ([]volumes.Volume, error) {
|
||||
accountClient, err := login.NewStorageAccountsClient(cs.aciContext.SubscriptionID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result, err := accountClient.ListByResourceGroup(ctx, aciContext.ResourceGroup)
|
||||
result, err := accountClient.ListByResourceGroup(ctx, cs.aciContext.ResourceGroup)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
accounts := result.Value
|
||||
fileShareClient, err := NewFileShareClient(aciContext.SubscriptionID)
|
||||
fileShareClient, err := login.NewFileShareClient(cs.aciContext.SubscriptionID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fileShares := []volumes.Volume{}
|
||||
for _, account := range *accounts {
|
||||
fileSharePage, err := fileShareClient.List(ctx, aciContext.ResourceGroup, *account.Name, "", "", "")
|
||||
fileSharePage, err := fileShareClient.List(ctx, cs.aciContext.ResourceGroup, *account.Name, "", "", "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -89,30 +69,30 @@ func (helper StorageAccountHelper) ListFileShare(ctx context.Context) ([]volumes
|
|||
return fileShares, nil
|
||||
}
|
||||
|
||||
func toVolume(account storage.Account, fileShareName string) volumes.Volume {
|
||||
return volumes.Volume{
|
||||
ID: fmt.Sprintf("%s@%s", *account.Name, fileShareName),
|
||||
Name: fileShareName,
|
||||
Description: fmt.Sprintf("Fileshare %s in %s storage account", fileShareName, *account.Name),
|
||||
}
|
||||
//VolumeCreateOptions options to create a new ACI volume
|
||||
type VolumeCreateOptions struct {
|
||||
Account string
|
||||
Fileshare string
|
||||
}
|
||||
|
||||
// CreateFileShare create a new fileshare
|
||||
func (helper StorageAccountHelper) CreateFileShare(ctx context.Context, accountName string, fileShareName string) (volumes.Volume, error) {
|
||||
aciContext := helper.AciContext
|
||||
accountClient, err := NewStorageAccountsClient(aciContext.SubscriptionID)
|
||||
func (cs *aciVolumeService) Create(ctx context.Context, options interface{}) (volumes.Volume, error) {
|
||||
opts, ok := options.(VolumeCreateOptions)
|
||||
if !ok {
|
||||
return volumes.Volume{}, errors.New("Could not read azure LoginParams struct from generic parameter")
|
||||
}
|
||||
accountClient, err := login.NewStorageAccountsClient(cs.aciContext.SubscriptionID)
|
||||
if err != nil {
|
||||
return volumes.Volume{}, err
|
||||
}
|
||||
account, err := accountClient.GetProperties(ctx, aciContext.ResourceGroup, accountName, "")
|
||||
account, err := accountClient.GetProperties(ctx, cs.aciContext.ResourceGroup, opts.Account, "")
|
||||
if err != nil {
|
||||
if account.StatusCode != 404 {
|
||||
return volumes.Volume{}, err
|
||||
}
|
||||
//TODO confirm storage account creation
|
||||
parameters := defaultStorageAccountParams(aciContext)
|
||||
parameters := defaultStorageAccountParams(cs.aciContext)
|
||||
// TODO progress account creation
|
||||
future, err := accountClient.Create(ctx, aciContext.ResourceGroup, accountName, parameters)
|
||||
future, err := accountClient.Create(ctx, cs.aciContext.ResourceGroup, opts.Account, parameters)
|
||||
if err != nil {
|
||||
return volumes.Volume{}, err
|
||||
}
|
||||
|
@ -121,25 +101,33 @@ func (helper StorageAccountHelper) CreateFileShare(ctx context.Context, accountN
|
|||
return volumes.Volume{}, err
|
||||
}
|
||||
}
|
||||
fileShareClient, err := NewFileShareClient(aciContext.SubscriptionID)
|
||||
fileShareClient, err := login.NewFileShareClient(cs.aciContext.SubscriptionID)
|
||||
if err != nil {
|
||||
return volumes.Volume{}, err
|
||||
}
|
||||
|
||||
fileShare, err := fileShareClient.Get(ctx, aciContext.ResourceGroup, *account.Name, fileShareName, "")
|
||||
fileShare, err := fileShareClient.Get(ctx, cs.aciContext.ResourceGroup, *account.Name, opts.Fileshare, "")
|
||||
if err == nil {
|
||||
return volumes.Volume{}, errors.Wrapf(errdefs.ErrAlreadyExists, "Azure fileshare %q already exists", fileShareName)
|
||||
return volumes.Volume{}, errors.Wrapf(errdefs.ErrAlreadyExists, "Azure fileshare %q already exists", opts.Fileshare)
|
||||
}
|
||||
if fileShare.StatusCode != 404 {
|
||||
return volumes.Volume{}, err
|
||||
}
|
||||
fileShare, err = fileShareClient.Create(ctx, aciContext.ResourceGroup, *account.Name, fileShareName, storage.FileShare{})
|
||||
fileShare, err = fileShareClient.Create(ctx, cs.aciContext.ResourceGroup, *account.Name, opts.Fileshare, storage.FileShare{})
|
||||
if err != nil {
|
||||
return volumes.Volume{}, err
|
||||
}
|
||||
return toVolume(account, *fileShare.Name), nil
|
||||
}
|
||||
|
||||
func toVolume(account storage.Account, fileShareName string) volumes.Volume {
|
||||
return volumes.Volume{
|
||||
ID: fmt.Sprintf("%s@%s", *account.Name, fileShareName),
|
||||
Name: fileShareName,
|
||||
Description: fmt.Sprintf("Fileshare %s in %s storage account", fileShareName, *account.Name),
|
||||
}
|
||||
}
|
||||
|
||||
func defaultStorageAccountParams(aciContext store.AciContext) storage.AccountCreateParameters {
|
||||
return storage.AccountCreateParameters{
|
||||
Location: &aciContext.Location,
|
Loading…
Reference in New Issue