1
0

backend.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  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. }
  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. aciResourceService: &aciResourceService{
  85. aciContext: aciCtx,
  86. },
  87. }
  88. }
  89. type aciAPIService struct {
  90. *aciContainerService
  91. *aciComposeService
  92. *aciVolumeService
  93. *aciResourceService
  94. }
  95. func (a *aciAPIService) ContainerService() containers.Service {
  96. return a.aciContainerService
  97. }
  98. func (a *aciAPIService) ComposeService() compose.Service {
  99. return a.aciComposeService
  100. }
  101. func (a *aciAPIService) SecretsService() secrets.Service {
  102. // Not implemented on ACI
  103. // Secrets are created and mounted in the container at it's creation and not stored on ACI
  104. return nil
  105. }
  106. func (a *aciAPIService) VolumeService() volumes.Service {
  107. return a.aciVolumeService
  108. }
  109. func (a *aciAPIService) ResourceService() resources.Service {
  110. return a.aciResourceService
  111. }
  112. func getContainerID(group containerinstance.ContainerGroup, container containerinstance.Container) string {
  113. containerID := *group.Name + composeContainerSeparator + *container.Name
  114. if _, ok := group.Tags[singleContainerTag]; ok {
  115. containerID = *group.Name
  116. }
  117. return containerID
  118. }
  119. func isContainerVisible(container containerinstance.Container, group containerinstance.ContainerGroup, showAll bool) bool {
  120. return *container.Name == convert.ComposeDNSSidecarName || (!showAll && convert.GetStatus(container, group) != convert.StatusRunning)
  121. }
  122. func addTag(groupDefinition *containerinstance.ContainerGroup, tagName string) {
  123. if groupDefinition.Tags == nil {
  124. groupDefinition.Tags = make(map[string]*string, 1)
  125. }
  126. groupDefinition.Tags[tagName] = to.StringPtr(tagName)
  127. }
  128. func getGroupAndContainerName(containerID string) (string, string) {
  129. tokens := strings.Split(containerID, composeContainerSeparator)
  130. groupName := tokens[0]
  131. containerName := groupName
  132. if len(tokens) > 1 {
  133. containerName = tokens[len(tokens)-1]
  134. groupName = containerID[:len(containerID)-(len(containerName)+1)]
  135. }
  136. return groupName, containerName
  137. }