github.com/amtisyAts/helm@v2.17.0+incompatible/pkg/storage/driver/secrets.go (about)

     1  /*
     2  Copyright The Helm Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package driver // import "k8s.io/helm/pkg/storage/driver"
    18  
    19  import (
    20  	"fmt"
    21  	"strconv"
    22  	"strings"
    23  	"time"
    24  
    25  	"k8s.io/api/core/v1"
    26  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    27  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    28  	kblabels "k8s.io/apimachinery/pkg/labels"
    29  	"k8s.io/apimachinery/pkg/util/validation"
    30  	corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
    31  
    32  	rspb "k8s.io/helm/pkg/proto/hapi/release"
    33  	storageerrors "k8s.io/helm/pkg/storage/errors"
    34  )
    35  
    36  var _ Driver = (*Secrets)(nil)
    37  
    38  // SecretsDriverName is the string name of the driver.
    39  const SecretsDriverName = "Secret"
    40  
    41  // Secrets is a wrapper around an implementation of a kubernetes
    42  // SecretsInterface.
    43  type Secrets struct {
    44  	impl corev1.SecretInterface
    45  	Log  func(string, ...interface{})
    46  }
    47  
    48  // NewSecrets initializes a new Secrets wrapping an implementation of
    49  // the kubernetes SecretsInterface.
    50  func NewSecrets(impl corev1.SecretInterface) *Secrets {
    51  	return &Secrets{
    52  		impl: impl,
    53  		Log:  func(_ string, _ ...interface{}) {},
    54  	}
    55  }
    56  
    57  // Name returns the name of the driver.
    58  func (secrets *Secrets) Name() string {
    59  	return SecretsDriverName
    60  }
    61  
    62  // Get fetches the release named by key. The corresponding release is returned
    63  // or error if not found.
    64  func (secrets *Secrets) Get(key string) (*rspb.Release, error) {
    65  	// fetch the secret holding the release named by key
    66  	obj, err := secrets.impl.Get(key, metav1.GetOptions{})
    67  	if err != nil {
    68  		if apierrors.IsNotFound(err) {
    69  			return nil, storageerrors.ErrReleaseNotFound(key)
    70  		}
    71  
    72  		secrets.Log("get: failed to get %q: %s", key, err)
    73  		return nil, err
    74  	}
    75  	// found the secret, decode the base64 data string
    76  	r, err := decodeRelease(string(obj.Data["release"]))
    77  	if err != nil {
    78  		secrets.Log("get: failed to decode data %q: %s", key, err)
    79  		return nil, err
    80  	}
    81  	// return the release object
    82  	return r, nil
    83  }
    84  
    85  // List fetches all releases and returns the list releases such
    86  // that filter(release) == true. An error is returned if the
    87  // secret fails to retrieve the releases.
    88  func (secrets *Secrets) List(filter func(*rspb.Release) bool) ([]*rspb.Release, error) {
    89  	lsel := kblabels.Set{"OWNER": "TILLER"}.AsSelector()
    90  	opts := metav1.ListOptions{LabelSelector: lsel.String()}
    91  
    92  	list, err := secrets.impl.List(opts)
    93  	if err != nil {
    94  		secrets.Log("list: failed to list: %s", err)
    95  		return nil, err
    96  	}
    97  
    98  	var results []*rspb.Release
    99  
   100  	// iterate over the secrets object list
   101  	// and decode each release
   102  	for _, item := range list.Items {
   103  		rls, err := decodeRelease(string(item.Data["release"]))
   104  		if err != nil {
   105  			secrets.Log("list: failed to decode release: %v: %s", item, err)
   106  			continue
   107  		}
   108  		if filter(rls) {
   109  			results = append(results, rls)
   110  		}
   111  	}
   112  	return results, nil
   113  }
   114  
   115  // Query fetches all releases that match the provided map of labels.
   116  // An error is returned if the secret fails to retrieve the releases.
   117  func (secrets *Secrets) Query(labels map[string]string) ([]*rspb.Release, error) {
   118  	ls := kblabels.Set{}
   119  	for k, v := range labels {
   120  		if errs := validation.IsValidLabelValue(v); len(errs) != 0 {
   121  			return nil, fmt.Errorf("invalid label value: %q: %s", v, strings.Join(errs, "; "))
   122  		}
   123  		ls[k] = v
   124  	}
   125  
   126  	opts := metav1.ListOptions{LabelSelector: ls.AsSelector().String()}
   127  
   128  	list, err := secrets.impl.List(opts)
   129  	if err != nil {
   130  		secrets.Log("query: failed to query with labels: %s", err)
   131  		return nil, err
   132  	}
   133  
   134  	if len(list.Items) == 0 {
   135  		return nil, storageerrors.ErrReleaseNotFound(labels["NAME"])
   136  	}
   137  
   138  	var results []*rspb.Release
   139  	for _, item := range list.Items {
   140  		rls, err := decodeRelease(string(item.Data["release"]))
   141  		if err != nil {
   142  			secrets.Log("query: failed to decode release: %s", err)
   143  			continue
   144  		}
   145  		results = append(results, rls)
   146  	}
   147  	return results, nil
   148  }
   149  
   150  // Create creates a new Secret holding the release. If the
   151  // Secret already exists, ErrReleaseExists is returned.
   152  func (secrets *Secrets) Create(key string, rls *rspb.Release) error {
   153  	// set labels for secrets object meta data
   154  	var lbs labels
   155  
   156  	lbs.init()
   157  	lbs.set("CREATED_AT", strconv.Itoa(int(time.Now().Unix())))
   158  
   159  	// create a new secret to hold the release
   160  	obj, err := newSecretsObject(key, rls, lbs)
   161  	if err != nil {
   162  		secrets.Log("create: failed to encode release %q: %s", rls.Name, err)
   163  		return err
   164  	}
   165  	// push the secret object out into the kubiverse
   166  	if _, err := secrets.impl.Create(obj); err != nil {
   167  		if apierrors.IsAlreadyExists(err) {
   168  			return storageerrors.ErrReleaseExists(rls.Name)
   169  		}
   170  
   171  		secrets.Log("create: failed to create: %s", err)
   172  		return err
   173  	}
   174  	return nil
   175  }
   176  
   177  // Update updates the Secret holding the release. If not found
   178  // the Secret is created to hold the release.
   179  func (secrets *Secrets) Update(key string, rls *rspb.Release) error {
   180  	// set labels for secrets object meta data
   181  	var lbs labels
   182  
   183  	lbs.init()
   184  	lbs.set("MODIFIED_AT", strconv.Itoa(int(time.Now().Unix())))
   185  
   186  	// create a new secret object to hold the release
   187  	obj, err := newSecretsObject(key, rls, lbs)
   188  	if err != nil {
   189  		secrets.Log("update: failed to encode release %q: %s", rls.Name, err)
   190  		return err
   191  	}
   192  	// push the secret object out into the kubiverse
   193  	_, err = secrets.impl.Update(obj)
   194  	if err != nil {
   195  		secrets.Log("update: failed to update: %s", err)
   196  		return err
   197  	}
   198  	return nil
   199  }
   200  
   201  // Delete deletes the Secret holding the release named by key.
   202  func (secrets *Secrets) Delete(key string) (rls *rspb.Release, err error) {
   203  	// fetch the release to check existence
   204  	if rls, err = secrets.Get(key); err != nil {
   205  		if apierrors.IsNotFound(err) {
   206  			return nil, storageerrors.ErrReleaseExists(rls.Name)
   207  		}
   208  
   209  		secrets.Log("delete: failed to get release %q: %s", key, err)
   210  		return nil, err
   211  	}
   212  	// delete the release
   213  	if err = secrets.impl.Delete(key, &metav1.DeleteOptions{}); err != nil {
   214  		return rls, err
   215  	}
   216  	return rls, nil
   217  }
   218  
   219  // newSecretsObject constructs a kubernetes Secret object
   220  // to store a release. Each secret data entry is the base64
   221  // encoded string of a release's binary protobuf encoding.
   222  //
   223  // The following labels are used within each secret:
   224  //
   225  //    "MODIFIED_AT"    - timestamp indicating when this secret was last modified. (set in Update)
   226  //    "CREATED_AT"     - timestamp indicating when this secret was created. (set in Create)
   227  //    "VERSION"        - version of the release.
   228  //    "STATUS"         - status of the release (see proto/hapi/release.status.pb.go for variants)
   229  //    "OWNER"          - owner of the secret, currently "TILLER".
   230  //    "NAME"           - name of the release.
   231  //
   232  func newSecretsObject(key string, rls *rspb.Release, lbs labels) (*v1.Secret, error) {
   233  	const owner = "TILLER"
   234  
   235  	// encode the release
   236  	s, err := encodeRelease(rls)
   237  	if err != nil {
   238  		return nil, err
   239  	}
   240  
   241  	if lbs == nil {
   242  		lbs.init()
   243  	}
   244  
   245  	// apply labels
   246  	lbs.set("NAME", rls.Name)
   247  	lbs.set("OWNER", owner)
   248  	lbs.set("STATUS", rspb.Status_Code_name[int32(rls.Info.Status.Code)])
   249  	lbs.set("VERSION", strconv.Itoa(int(rls.Version)))
   250  
   251  	// create and return secret object
   252  	return &v1.Secret{
   253  		ObjectMeta: metav1.ObjectMeta{
   254  			Name:   key,
   255  			Labels: lbs.toMap(),
   256  		},
   257  		Data: map[string][]byte{"release": []byte(s)},
   258  	}, nil
   259  }