secrets.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. package cluster
  2. import (
  3. "fmt"
  4. "strings"
  5. apitypes "github.com/docker/docker/api/types"
  6. types "github.com/docker/docker/api/types/swarm"
  7. "github.com/docker/docker/daemon/cluster/convert"
  8. swarmapi "github.com/docker/swarmkit/api"
  9. "golang.org/x/net/context"
  10. )
  11. func getSecretByNameOrIDPrefix(ctx context.Context, state *nodeState, nameOrIDPrefix string) (*swarmapi.Secret, error) {
  12. // attempt to lookup secret by full ID
  13. if r, err := state.controlClient.GetSecret(ctx, &swarmapi.GetSecretRequest{
  14. SecretID: nameOrIDPrefix,
  15. }); err == nil {
  16. return r.Secret, nil
  17. }
  18. // attempt to lookup secret by full name and partial ID
  19. // Note here ListSecretRequest_Filters operate with `or`
  20. r, err := state.controlClient.ListSecrets(ctx, &swarmapi.ListSecretsRequest{
  21. Filters: &swarmapi.ListSecretsRequest_Filters{
  22. Names: []string{nameOrIDPrefix},
  23. IDPrefixes: []string{nameOrIDPrefix},
  24. },
  25. })
  26. if err != nil {
  27. return nil, err
  28. }
  29. // attempt to lookup secret by full name
  30. for _, s := range r.Secrets {
  31. if s.Spec.Annotations.Name == nameOrIDPrefix {
  32. return s, nil
  33. }
  34. }
  35. // attempt to lookup secret by partial ID (prefix)
  36. // return error if more than one matches found (ambiguous)
  37. n := 0
  38. var found *swarmapi.Secret
  39. for _, s := range r.Secrets {
  40. if strings.HasPrefix(s.ID, nameOrIDPrefix) {
  41. found = s
  42. n++
  43. }
  44. }
  45. if n > 1 {
  46. return nil, fmt.Errorf("secret %s is ambiguous (%d matches found)", nameOrIDPrefix, n)
  47. }
  48. if found == nil {
  49. return nil, fmt.Errorf("no such secret: %s", nameOrIDPrefix)
  50. }
  51. return found, nil
  52. }
  53. // GetSecret returns a secret from a managed swarm cluster
  54. func (c *Cluster) GetSecret(nameOrIDPrefix string) (types.Secret, error) {
  55. c.mu.RLock()
  56. defer c.mu.RUnlock()
  57. state := c.currentNodeState()
  58. if !state.IsActiveManager() {
  59. return types.Secret{}, c.errNoManager(state)
  60. }
  61. ctx, cancel := c.getRequestContext()
  62. defer cancel()
  63. secret, err := getSecretByNameOrIDPrefix(ctx, &state, nameOrIDPrefix)
  64. if err != nil {
  65. return types.Secret{}, err
  66. }
  67. return convert.SecretFromGRPC(secret), nil
  68. }
  69. // GetSecrets returns all secrets of a managed swarm cluster.
  70. func (c *Cluster) GetSecrets(options apitypes.SecretListOptions) ([]types.Secret, error) {
  71. c.mu.RLock()
  72. defer c.mu.RUnlock()
  73. state := c.currentNodeState()
  74. if !state.IsActiveManager() {
  75. return nil, c.errNoManager(state)
  76. }
  77. filters, err := newListSecretsFilters(options.Filters)
  78. if err != nil {
  79. return nil, err
  80. }
  81. ctx, cancel := c.getRequestContext()
  82. defer cancel()
  83. r, err := state.controlClient.ListSecrets(ctx,
  84. &swarmapi.ListSecretsRequest{Filters: filters})
  85. if err != nil {
  86. return nil, err
  87. }
  88. secrets := []types.Secret{}
  89. for _, secret := range r.Secrets {
  90. secrets = append(secrets, convert.SecretFromGRPC(secret))
  91. }
  92. return secrets, nil
  93. }
  94. // CreateSecret creates a new secret in a managed swarm cluster.
  95. func (c *Cluster) CreateSecret(s types.SecretSpec) (string, error) {
  96. c.mu.RLock()
  97. defer c.mu.RUnlock()
  98. state := c.currentNodeState()
  99. if !state.IsActiveManager() {
  100. return "", c.errNoManager(state)
  101. }
  102. ctx, cancel := c.getRequestContext()
  103. defer cancel()
  104. secretSpec := convert.SecretSpecToGRPC(s)
  105. r, err := state.controlClient.CreateSecret(ctx,
  106. &swarmapi.CreateSecretRequest{Spec: &secretSpec})
  107. if err != nil {
  108. return "", err
  109. }
  110. return r.Secret.ID, nil
  111. }
  112. // RemoveSecret removes a secret from a managed swarm cluster.
  113. func (c *Cluster) RemoveSecret(nameOrIDPrefix string) error {
  114. c.mu.RLock()
  115. defer c.mu.RUnlock()
  116. state := c.currentNodeState()
  117. if !state.IsActiveManager() {
  118. return c.errNoManager(state)
  119. }
  120. ctx, cancel := c.getRequestContext()
  121. defer cancel()
  122. secret, err := getSecretByNameOrIDPrefix(ctx, &state, nameOrIDPrefix)
  123. if err != nil {
  124. return err
  125. }
  126. req := &swarmapi.RemoveSecretRequest{
  127. SecretID: secret.ID,
  128. }
  129. _, err = state.controlClient.RemoveSecret(ctx, req)
  130. return err
  131. }
  132. // UpdateSecret updates a secret in a managed swarm cluster.
  133. // Note: this is not exposed to the CLI but is available from the API only
  134. func (c *Cluster) UpdateSecret(id string, version uint64, spec types.SecretSpec) error {
  135. c.mu.RLock()
  136. defer c.mu.RUnlock()
  137. state := c.currentNodeState()
  138. if !state.IsActiveManager() {
  139. return c.errNoManager(state)
  140. }
  141. ctx, cancel := c.getRequestContext()
  142. defer cancel()
  143. secretSpec := convert.SecretSpecToGRPC(spec)
  144. _, err := state.controlClient.UpdateSecret(ctx,
  145. &swarmapi.UpdateSecretRequest{
  146. SecretID: id,
  147. SecretVersion: &swarmapi.Version{
  148. Index: version,
  149. },
  150. Spec: &secretSpec,
  151. })
  152. return err
  153. }