@@ -2,27 +2,26 @@ package cluster
22
33import (
44 "context"
5+ "crypto/rand"
56 "errors"
67 "fmt"
78 "github.com/AlecAivazis/survey/v2"
9+ "github.com/redhat-developer/app-services-cli/internal/localizer"
810 "github.com/redhat-developer/app-services-cli/pkg/color"
911 "github.com/redhat-developer/app-services-cli/pkg/logging"
12+ "github.com/redhat-developer/service-binding-operator/api/v1alpha1"
13+ "github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/builder"
1014 sboContext "github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/context"
15+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1116 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
1217 "k8s.io/apimachinery/pkg/runtime"
18+ "k8s.io/apimachinery/pkg/runtime/schema"
19+ "k8s.io/client-go/dynamic"
1320 "k8s.io/client-go/rest"
21+ "k8s.io/client-go/tools/clientcmd"
1422 clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
1523 "os"
1624 "path/filepath"
17- "time"
18-
19- "github.com/redhat-developer/app-services-cli/internal/localizer"
20- "github.com/redhat-developer/service-binding-operator/api/v1alpha1"
21- "github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/builder"
22- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
23- "k8s.io/apimachinery/pkg/runtime/schema"
24- "k8s.io/client-go/dynamic"
25- "k8s.io/client-go/tools/clientcmd"
2625 "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
2726)
2827
@@ -34,20 +33,28 @@ type KubernetesClients struct {
3433
3534var deploymentResource = schema.GroupVersionResource {Group : "apps" , Version : "v1" , Resource : "deployments" }
3635
37- // TODO extract arguments
38- func ExecuteServiceBinding (logger logging.Logger , serviceName string , ns string , appName string ,
39- forceCreationWithoutAsk bool , forceUseOperator bool ) error {
36+ type ServiceBindingOptions struct {
37+ ServiceName string
38+ Namespace string
39+ AppName string
40+ ForceCreationWithoutAsk bool
41+ ForceUseOperator bool
42+ ForceUseSDK bool
43+ BindingName string
44+ }
45+
46+ func ExecuteServiceBinding (logger logging.Logger , options * ServiceBindingOptions ) error {
4047 clients , err := client ()
4148 if err != nil {
4249 return err
4350 }
44-
51+ ns := options . Namespace
4552 if ns == "" {
4653 ns , _ , err = (* clients .clientConfig ).Namespace ()
4754 if err != nil {
4855 return err
4956 }
50- logger .Info (& localizer.Config {
57+ logger .Info (localizer.Config {
5158 MessageID : "cluster.serviceBinding.namespaceInfo" ,
5259 TemplateData : map [string ]interface {}{
5360 "Namespace" : color .Info (ns ),
@@ -56,22 +63,22 @@ func ExecuteServiceBinding(logger logging.Logger, serviceName string, ns string,
5663 }
5764
5865 // Get proper deployment
59- if appName == "" {
60- appName , err = fetchAppNameFromCluster (clients , ns )
66+ if options . AppName == "" {
67+ options . AppName , err = fetchAppNameFromCluster (clients , ns )
6168 if err != nil {
6269 return err
6370 }
6471 } else {
65- _ , err = clients .dynamicClient .Resource (deploymentResource ).Namespace (ns ).Get (context .TODO (), appName , metav1.GetOptions {})
72+ _ , err = clients .dynamicClient .Resource (deploymentResource ).Namespace (ns ).Get (context .TODO (), options . AppName , metav1.GetOptions {})
6673 if err != nil {
6774 return err
6875 }
6976 }
7077
7178 // Print desired action
72- logger .Info (fmt .Sprintf (localizer .MustLocalizeFromID ("cluster.serviceBinding.status.message" ), serviceName , appName ))
79+ logger .Info (fmt .Sprintf (localizer .MustLocalizeFromID ("cluster.serviceBinding.status.message" ), options . ServiceName , options . AppName ))
7380
74- if ! forceCreationWithoutAsk {
81+ if ! options . ForceCreationWithoutAsk {
7582 var shouldContinue bool
7683 confirm := & survey.Confirm {
7784 Message : localizer .MustLocalizeFromID ("cluster.serviceBinding.confirm.message" ),
@@ -87,30 +94,29 @@ func ExecuteServiceBinding(logger logging.Logger, serviceName string, ns string,
8794 }
8895
8996 // Check KafkaConnection
90- _ , err = clients .dynamicClient .Resource (AKCResource ).Namespace (ns ).Get (context .TODO (), serviceName , metav1.GetOptions {})
97+ _ , err = clients .dynamicClient .Resource (AKCResource ).Namespace (ns ).Get (context .TODO (), options . ServiceName , metav1.GetOptions {})
9198 if err != nil {
9299 return errors .New (localizer .MustLocalizeFromID ("cluster.serviceBinding.serviceMissing.message" ))
93100 }
94101
95102 // Execute binding
96- err = performBinding (serviceName , appName , ns , clients , forceUseOperator , logger )
103+ err = performBinding (options , ns , clients , logger )
97104 if err != nil {
98105 return err
99106 }
100107
101- logger .Info (fmt .Sprintf (localizer .MustLocalizeFromID ("cluster.serviceBinding.bindingSuccess" ), serviceName , appName ))
108+ logger .Info (fmt .Sprintf (localizer .MustLocalizeFromID ("cluster.serviceBinding.bindingSuccess" ), options . ServiceName , options . AppName ))
102109 return nil
103110}
104111
105- func performBinding (serviceName string , appName string , ns string , clients * KubernetesClients ,
106- forceUseOperator bool , logger logging.Logger ) error {
112+ func performBinding (options * ServiceBindingOptions , ns string , clients * KubernetesClients , logger logging.Logger ) error {
107113 serviceRef := v1alpha1.Service {
108114 NamespacedRef : v1alpha1.NamespacedRef {
109115 Ref : v1alpha1.Ref {
110116 Group : AKCResource .Group ,
111117 Version : AKCResource .Version ,
112118 Resource : AKCResource .Resource ,
113- Name : serviceName ,
119+ Name : options . ServiceName ,
114120 },
115121 },
116122 }
@@ -120,15 +126,23 @@ func performBinding(serviceName string, appName string, ns string, clients *Kube
120126 Group : deploymentResource .Group ,
121127 Version : deploymentResource .Version ,
122128 Resource : deploymentResource .Resource ,
123- Name : appName ,
129+ Name : options . AppName ,
124130 },
125131 }
126132
127- now := time .Now ()
133+ if options .BindingName == "" {
134+ randomValue := make ([]byte , 4 )
135+ _ , err := rand .Read (randomValue )
136+ if err != nil {
137+ return err
138+ }
139+ options .BindingName = fmt .Sprintf ("%v-%x" , options .ServiceName , randomValue )
140+ }
141+
128142 sb := & v1alpha1.ServiceBinding {
129143 ObjectMeta : metav1.ObjectMeta {
130- Name : fmt .Sprintf ("%v-%v" , serviceName , now . Unix () ),
131- Namespace : ns ,
144+ Name : fmt .Sprintf ("%v-%v" , options . ServiceName , options . BindingName ),
145+ Namespace : options . Namespace ,
132146 },
133147 Spec : v1alpha1.ServiceBindingSpec {
134148 BindAsFiles : true ,
@@ -138,26 +152,42 @@ func performBinding(serviceName string, appName string, ns string, clients *Kube
138152 }
139153 sb .SetGroupVersionKind (v1alpha1 .GroupVersionKind )
140154
155+ if options .ForceUseSDK {
156+ return useSDKForBinding (clients , sb )
157+ }
158+
141159 // Check of operator is installed
142160 _ , err := clients .dynamicClient .Resource (v1alpha1 .GroupVersionResource ).Namespace (ns ).
143161 List (context .TODO (), metav1.ListOptions {Limit : 1 })
144162
145163 if err != nil {
146- if forceUseOperator {
164+ if options . ForceUseOperator {
147165 return errors .New (localizer .MustLocalizeFromID ("cluster.serviceBinding.operatorMissing" ) + err .Error ())
148166 }
149- logger .Debug ("Service binding Operator not available. Will use SDK" )
150- } else {
151- logger .Info (localizer .MustLocalizeFromID ("cluster.serviceBinding.usingOperator" ))
152- sbData , err := runtime .DefaultUnstructuredConverter .ToUnstructured (sb )
153- unstructuredSB := unstructured.Unstructured {Object : sbData }
154- _ , err = clients .dynamicClient .Resource (v1alpha1 .GroupVersionResource ).Namespace (ns ).
155- Create (context .TODO (), & unstructuredSB , metav1.CreateOptions {})
167+ logger .Debug ("Service binding Operator not available. Will use SDK option for binding" )
168+ return useSDKForBinding (clients , sb )
169+ }
156170
171+ logger .Debug ("Using Operator to perform binding" )
172+ return useOperatorForBinding (logger , sb , clients , ns )
173+
174+ }
175+
176+ func useOperatorForBinding (logger logging.Logger , sb * v1alpha1.ServiceBinding , clients * KubernetesClients , ns string ) error {
177+ logger .Info (localizer .MustLocalizeFromID ("cluster.serviceBinding.usingOperator" ))
178+ sbData , err := runtime .DefaultUnstructuredConverter .ToUnstructured (sb )
179+ if err != nil {
157180 return err
158181 }
159182
160- // Use SDK instead of operatort
183+ unstructuredSB := unstructured.Unstructured {Object : sbData }
184+ _ , err = clients .dynamicClient .Resource (v1alpha1 .GroupVersionResource ).Namespace (ns ).
185+ Create (context .TODO (), & unstructuredSB , metav1.CreateOptions {})
186+
187+ return err
188+ }
189+
190+ func useSDKForBinding (clients * KubernetesClients , sb * v1alpha1.ServiceBinding ) error {
161191 restMapper , err := apiutil .NewDynamicRESTMapper (clients .restConfig )
162192 if err != nil {
163193 return err
0 commit comments