backend.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. /*
  2. Copyright 2020 Docker Compose CLI authors
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package aci
  14. import (
  15. "context"
  16. "strings"
  17. "github.com/Azure/azure-sdk-for-go/services/containerinstance/mgmt/2018-10-01/containerinstance"
  18. "github.com/Azure/go-autorest/autorest/to"
  19. "github.com/pkg/errors"
  20. "github.com/docker/compose-cli/aci/convert"
  21. "github.com/docker/compose-cli/aci/login"
  22. "github.com/docker/compose-cli/api/compose"
  23. "github.com/docker/compose-cli/api/containers"
  24. "github.com/docker/compose-cli/api/resources"
  25. "github.com/docker/compose-cli/api/secrets"
  26. "github.com/docker/compose-cli/api/volumes"
  27. "github.com/docker/compose-cli/backend"
  28. apicontext "github.com/docker/compose-cli/context"
  29. "github.com/docker/compose-cli/context/cloud"
  30. "github.com/docker/compose-cli/context/store"
  31. )
  32. const (
  33. backendType = store.AciContextType
  34. singleContainerTag = "docker-single-container"
  35. composeContainerTag = "docker-compose-application"
  36. dockerVolumeTag = "docker-volume"
  37. composeContainerSeparator = "_"
  38. )
  39. // LoginParams azure login options
  40. type LoginParams struct {
  41. TenantID string
  42. ClientID string
  43. ClientSecret string
  44. }
  45. // Validate returns an error if options are not used properly
  46. func (opts LoginParams) Validate() error {
  47. if opts.ClientID != "" || opts.ClientSecret != "" {
  48. if opts.ClientID == "" || opts.ClientSecret == "" || opts.TenantID == "" {
  49. return errors.New("for Service Principal login, 3 options must be specified: --client-id, --client-secret and --tenant-id")
  50. }
  51. }
  52. return nil
  53. }
  54. func init() {
  55. backend.Register(backendType, backendType, service, getCloudService)
  56. }
  57. func service(ctx context.Context) (backend.Service, error) {
  58. contextStore := store.ContextStore(ctx)
  59. currentContext := apicontext.CurrentContext(ctx)
  60. var aciContext store.AciContext
  61. if err := contextStore.GetEndpoint(currentContext, &aciContext); err != nil {
  62. return nil, err
  63. }
  64. return getAciAPIService(aciContext), nil
  65. }
  66. func getCloudService() (cloud.Service, error) {
  67. service, err := login.NewAzureLoginService()
  68. if err != nil {
  69. return nil, err
  70. }
  71. return &aciCloudService{
  72. loginService: service,
  73. }, nil
  74. }
  75. func getAciAPIService(aciCtx store.AciContext) *aciAPIService {
  76. containerService := newContainerService(aciCtx)
  77. composeService := newComposeService(aciCtx)
  78. return &aciAPIService{
  79. aciContainerService: &containerService,
  80. aciComposeService: &composeService,
  81. aciVolumeService: &aciVolumeService{
  82. aciContext: aciCtx,
  83. },
  84. }
  85. }
  86. type aciAPIService struct {
  87. *aciContainerService
  88. *aciComposeService
  89. *aciVolumeService
  90. *aciResourceService
  91. }
  92. func (a *aciAPIService) ContainerService() containers.Service {
  93. return a.aciContainerService
  94. }
  95. func (a *aciAPIService) ComposeService() compose.Service {
  96. return a.aciComposeService
  97. }
  98. func (a *aciAPIService) SecretsService() secrets.Service {
  99. // Not implemented on ACI
  100. // Secrets are created and mounted in the container at it's creation and not stored on ACI
  101. return nil
  102. }
  103. func (a *aciAPIService) VolumeService() volumes.Service {
  104. return a.aciVolumeService
  105. }
  106. func (a *aciAPIService) ResourceService() resources.Service {
  107. return a.aciResourceService
  108. }
  109. func getContainerID(group containerinstance.ContainerGroup, container containerinstance.Container) string {
  110. containerID := *group.Name + composeContainerSeparator + *container.Name
  111. if _, ok := group.Tags[singleContainerTag]; ok {
  112. containerID = *group.Name
  113. }
  114. return containerID
  115. }
  116. func isContainerVisible(container containerinstance.Container, group containerinstance.ContainerGroup, showAll bool) bool {
  117. return *container.Name == convert.ComposeDNSSidecarName || (!showAll && convert.GetStatus(container, group) != convert.StatusRunning)
  118. }
  119. func addTag(groupDefinition *containerinstance.ContainerGroup, tagName string) {
  120. if groupDefinition.Tags == nil {
  121. groupDefinition.Tags = make(map[string]*string, 1)
  122. }
  123. groupDefinition.Tags[tagName] = to.StringPtr(tagName)
  124. }
  125. func getGroupAndContainerName(containerID string) (string, string) {
  126. tokens := strings.Split(containerID, composeContainerSeparator)
  127. groupName := tokens[0]
  128. containerName := groupName
  129. if len(tokens) > 1 {
  130. containerName = tokens[len(tokens)-1]
  131. groupName = containerID[:len(containerID)-(len(containerName)+1)]
  132. }
  133. return groupName, containerName
  134. }