backend.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  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/2019-12-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/backend"
  23. "github.com/docker/compose-cli/api/compose"
  24. "github.com/docker/compose-cli/api/containers"
  25. "github.com/docker/compose-cli/api/resources"
  26. "github.com/docker/compose-cli/api/secrets"
  27. "github.com/docker/compose-cli/api/volumes"
  28. "github.com/docker/compose-cli/api/cloud"
  29. apicontext "github.com/docker/compose-cli/api/context"
  30. "github.com/docker/compose-cli/api/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. CloudName string
  45. }
  46. // Validate returns an error if options are not used properly
  47. func (opts LoginParams) Validate() error {
  48. if opts.ClientID != "" || opts.ClientSecret != "" {
  49. if opts.ClientID == "" || opts.ClientSecret == "" || opts.TenantID == "" {
  50. return errors.New("for Service Principal login, 3 options must be specified: --client-id, --client-secret and --tenant-id")
  51. }
  52. }
  53. return nil
  54. }
  55. func init() {
  56. backend.Register(backendType, backendType, service, getCloudService)
  57. }
  58. func service(ctx context.Context) (backend.Service, error) {
  59. contextStore := store.ContextStore(ctx)
  60. currentContext := apicontext.CurrentContext(ctx)
  61. var aciContext store.AciContext
  62. if err := contextStore.GetEndpoint(currentContext, &aciContext); err != nil {
  63. return nil, err
  64. }
  65. return getAciAPIService(aciContext), nil
  66. }
  67. func getCloudService() (cloud.Service, error) {
  68. service, err := login.NewAzureLoginService()
  69. if err != nil {
  70. return nil, err
  71. }
  72. return &aciCloudService{
  73. loginService: service,
  74. }, nil
  75. }
  76. func getAciAPIService(aciCtx store.AciContext) *aciAPIService {
  77. containerService := newContainerService(aciCtx)
  78. composeService := newComposeService(aciCtx)
  79. return &aciAPIService{
  80. aciContainerService: &containerService,
  81. aciComposeService: &composeService,
  82. aciVolumeService: &aciVolumeService{
  83. aciContext: aciCtx,
  84. },
  85. aciResourceService: &aciResourceService{
  86. aciContext: aciCtx,
  87. },
  88. }
  89. }
  90. type aciAPIService struct {
  91. *aciContainerService
  92. *aciComposeService
  93. *aciVolumeService
  94. *aciResourceService
  95. }
  96. func (a *aciAPIService) ContainerService() containers.Service {
  97. return a.aciContainerService
  98. }
  99. func (a *aciAPIService) ComposeService() compose.Service {
  100. return a.aciComposeService
  101. }
  102. func (a *aciAPIService) SecretsService() secrets.Service {
  103. // Not implemented on ACI
  104. // Secrets are created and mounted in the container at it's creation and not stored on ACI
  105. return nil
  106. }
  107. func (a *aciAPIService) VolumeService() volumes.Service {
  108. return a.aciVolumeService
  109. }
  110. func (a *aciAPIService) ResourceService() resources.Service {
  111. return a.aciResourceService
  112. }
  113. func getContainerID(group containerinstance.ContainerGroup, container containerinstance.Container) string {
  114. containerID := *group.Name + composeContainerSeparator + *container.Name
  115. if _, ok := group.Tags[singleContainerTag]; ok {
  116. containerID = *group.Name
  117. }
  118. return containerID
  119. }
  120. func isContainerVisible(container containerinstance.Container, group containerinstance.ContainerGroup, showAll bool) bool {
  121. return *container.Name == convert.ComposeDNSSidecarName || (!showAll && convert.GetStatus(container, group) != convert.StatusRunning)
  122. }
  123. func addTag(groupDefinition *containerinstance.ContainerGroup, tagName string) {
  124. if groupDefinition.Tags == nil {
  125. groupDefinition.Tags = make(map[string]*string, 1)
  126. }
  127. groupDefinition.Tags[tagName] = to.StringPtr(tagName)
  128. }
  129. func getGroupAndContainerName(containerID string) (string, string) {
  130. tokens := strings.Split(containerID, composeContainerSeparator)
  131. groupName := tokens[0]
  132. containerName := groupName
  133. if len(tokens) > 1 {
  134. containerName = tokens[len(tokens)-1]
  135. groupName = containerID[:len(containerID)-(len(containerName)+1)]
  136. }
  137. return groupName, containerName
  138. }