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 }