github.xiaoq7.com/operator-framework/operator-sdk@v0.8.2/pkg/helm/release/manager_factory.go (about)

     1  // Copyright 2018 The Operator-SDK Authors
     2  //
     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  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package release
    16  
    17  import (
    18  	"fmt"
    19  	"strings"
    20  
    21  	"github.com/martinlindhe/base36"
    22  	"github.com/pborman/uuid"
    23  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    24  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    25  	apitypes "k8s.io/apimachinery/pkg/types"
    26  	clientset "k8s.io/client-go/kubernetes"
    27  	"k8s.io/client-go/kubernetes/typed/core/v1"
    28  	helmengine "k8s.io/helm/pkg/engine"
    29  	"k8s.io/helm/pkg/kube"
    30  	"k8s.io/helm/pkg/storage"
    31  	"k8s.io/helm/pkg/storage/driver"
    32  	"k8s.io/helm/pkg/tiller"
    33  	"k8s.io/helm/pkg/tiller/environment"
    34  	crmanager "sigs.k8s.io/controller-runtime/pkg/manager"
    35  
    36  	"github.com/operator-framework/operator-sdk/pkg/helm/client"
    37  	"github.com/operator-framework/operator-sdk/pkg/helm/engine"
    38  	"github.com/operator-framework/operator-sdk/pkg/helm/internal/types"
    39  )
    40  
    41  // ManagerFactory creates Managers that are specific to custom resources. It is
    42  // used by the HelmOperatorReconciler during resource reconciliation, and it
    43  // improves decoupling between reconciliation logic and the Helm backend
    44  // components used to manage releases.
    45  type ManagerFactory interface {
    46  	NewManager(r *unstructured.Unstructured) (Manager, error)
    47  }
    48  
    49  type managerFactory struct {
    50  	mgr      crmanager.Manager
    51  	chartDir string
    52  }
    53  
    54  // NewManagerFactory returns a new Helm manager factory capable of installing and uninstalling releases.
    55  func NewManagerFactory(mgr crmanager.Manager, chartDir string) ManagerFactory {
    56  	return &managerFactory{mgr, chartDir}
    57  }
    58  
    59  func (f managerFactory) NewManager(cr *unstructured.Unstructured) (Manager, error) {
    60  	clientv1, err := v1.NewForConfig(f.mgr.GetConfig())
    61  	if err != nil {
    62  		return nil, fmt.Errorf("failed to get core/v1 client: %s", err)
    63  	}
    64  	storageBackend := storage.Init(driver.NewSecrets(clientv1.Secrets(cr.GetNamespace())))
    65  	tillerKubeClient, err := client.NewFromManager(f.mgr)
    66  	if err != nil {
    67  		return nil, fmt.Errorf("failed to get client from manager: %s", err)
    68  	}
    69  	releaseServer, err := getReleaseServer(cr, storageBackend, tillerKubeClient)
    70  	if err != nil {
    71  		return nil, fmt.Errorf("failed to get helm release server: %s", err)
    72  	}
    73  	return &manager{
    74  		storageBackend:   storageBackend,
    75  		tillerKubeClient: tillerKubeClient,
    76  		chartDir:         f.chartDir,
    77  
    78  		tiller:      releaseServer,
    79  		releaseName: getReleaseName(cr),
    80  		namespace:   cr.GetNamespace(),
    81  
    82  		spec:   cr.Object["spec"],
    83  		status: types.StatusFor(cr),
    84  	}, nil
    85  }
    86  
    87  // getReleaseServer creates a ReleaseServer configured with a rendering engine that adds ownerrefs to rendered assets
    88  // based on the CR.
    89  func getReleaseServer(cr *unstructured.Unstructured, storageBackend *storage.Storage, tillerKubeClient *kube.Client) (*tiller.ReleaseServer, error) {
    90  	controllerRef := metav1.NewControllerRef(cr, cr.GroupVersionKind())
    91  	ownerRefs := []metav1.OwnerReference{
    92  		*controllerRef,
    93  	}
    94  	baseEngine := helmengine.New()
    95  	e := engine.NewOwnerRefEngine(baseEngine, ownerRefs)
    96  	var ey environment.EngineYard = map[string]environment.Engine{
    97  		environment.GoTplEngine: e,
    98  	}
    99  	env := &environment.Environment{
   100  		EngineYard: ey,
   101  		Releases:   storageBackend,
   102  		KubeClient: tillerKubeClient,
   103  	}
   104  	kubeconfig, err := tillerKubeClient.ToRESTConfig()
   105  	if err != nil {
   106  		return nil, err
   107  	}
   108  	cs, err := clientset.NewForConfig(kubeconfig)
   109  	if err != nil {
   110  		return nil, err
   111  	}
   112  
   113  	return tiller.NewReleaseServer(env, cs, false), nil
   114  }
   115  
   116  func getReleaseName(cr *unstructured.Unstructured) string {
   117  	return fmt.Sprintf("%s-%s", cr.GetName(), shortenUID(cr.GetUID()))
   118  }
   119  
   120  func shortenUID(uid apitypes.UID) string {
   121  	u := uuid.Parse(string(uid))
   122  	uidBytes, err := u.MarshalBinary()
   123  	if err != nil {
   124  		return strings.Replace(string(uid), "-", "", -1)
   125  	}
   126  	return strings.ToLower(base36.EncodeBytes(uidBytes))
   127  }