package secrets import ( "errors" "fmt" "io" kapi "k8s.io/kubernetes/pkg/api" kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" "github.com/openshift/origin/pkg/cmd/templates" "github.com/spf13/cobra" ) const UnlinkSecretRecommendedName = "unlink" var ( unlinkSecretLong = templates.LongDesc(` Unlink (detach) secrets from a service account If a secret is no longer valid for a pod, build or image pull, you may unlink it from a service account.`) unlinkSecretExample = templates.Examples(` # Unlink a secret currently associated with a service account: %[1]s serviceaccount-name secret-name another-secret-name ...`) ) type UnlinkSecretOptions struct { SecretOptions } // NewCmdUnlinkSecret creates a command object for detaching one or more secret references from a service account func NewCmdUnlinkSecret(name, fullName string, f *kcmdutil.Factory, out io.Writer) *cobra.Command { o := &UnlinkSecretOptions{SecretOptions{Out: out}} cmd := &cobra.Command{ Use: fmt.Sprintf("%s serviceaccount-name secret-name [another-secret-name] ...", name), Short: "Detach secrets from a ServiceAccount", Long: unlinkSecretLong, Example: fmt.Sprintf(unlinkSecretExample, fullName), Run: func(c *cobra.Command, args []string) { if err := o.Complete(f, args); err != nil { kcmdutil.CheckErr(kcmdutil.UsageError(c, err.Error())) } if err := o.Validate(); err != nil { kcmdutil.CheckErr(kcmdutil.UsageError(c, err.Error())) } if err := o.UnlinkSecrets(); err != nil { kcmdutil.CheckErr(err) } }, } return cmd } func (o UnlinkSecretOptions) UnlinkSecrets() error { serviceaccount, err := o.GetServiceAccount() if err != nil { return err } if err = o.unlinkSecretsFromServiceAccount(serviceaccount); err != nil { return err } return nil } // unlinkSecretsFromServiceAccount detaches pull and mount secrets from the service account. func (o UnlinkSecretOptions) unlinkSecretsFromServiceAccount(serviceaccount *kapi.ServiceAccount) error { // All of the requested secrets must be present in either the Mount or Pull secrets // If any of them are not present, we'll return an error and push no changes. rmSecrets, failLater, err := o.GetSecrets() if err != nil { return err } rmSecretNames := o.GetSecretNames(rmSecrets) newMountSecrets := []kapi.ObjectReference{} newPullSecrets := []kapi.LocalObjectReference{} // Check the mount secrets for _, secret := range serviceaccount.Secrets { if !rmSecretNames.Has(secret.Name) { // Copy this back in, since it doesn't match the ones we're removing newMountSecrets = append(newMountSecrets, secret) } } // Check the image pull secrets for _, imagePullSecret := range serviceaccount.ImagePullSecrets { if !rmSecretNames.Has(imagePullSecret.Name) { // Copy this back in, since it doesn't match the one we're removing newPullSecrets = append(newPullSecrets, imagePullSecret) } } // Save the updated Secret lists back to the server serviceaccount.Secrets = newMountSecrets serviceaccount.ImagePullSecrets = newPullSecrets _, err = o.ClientInterface.ServiceAccounts(o.Namespace).Update(serviceaccount) if err != nil { return err } if failLater { return errors.New("Some secrets could not be unlinked") } return nil }