@@ -2,26 +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"
10- sboContext "github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/context"
11- "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
12- "k8s.io/client-go/rest"
13- clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
14- "os"
15- "path/filepath"
16- "time"
17-
18- "github.com/redhat-developer/app-services-cli/internal/localizer"
1912 "github.com/redhat-developer/service-binding-operator/api/v1alpha1"
2013 "github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/builder"
14+ sboContext "github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/context"
2115 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
16+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
17+ "k8s.io/apimachinery/pkg/runtime"
2218 "k8s.io/apimachinery/pkg/runtime/schema"
2319 "k8s.io/client-go/dynamic"
20+ "k8s.io/client-go/rest"
2421 "k8s.io/client-go/tools/clientcmd"
22+ clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
23+ "os"
24+ "path/filepath"
2525 "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
2626)
2727
@@ -33,42 +33,53 @@ type KubernetesClients struct {
3333
3434var deploymentResource = schema.GroupVersionResource {Group : "apps" , Version : "v1" , Resource : "deployments" }
3535
36- func ExecuteServiceBinding (logger logging.Logger , serviceName string , ns string , appName string , forceCreationWithoutAsk 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+ BindAsFiles bool
45+ }
46+
47+ func ExecuteServiceBinding (logger logging.Logger , options * ServiceBindingOptions ) error {
3748 clients , err := client ()
3849 if err != nil {
3950 return err
4051 }
41-
52+ ns := options . Namespace
4253 if ns == "" {
4354 ns , _ , err = (* clients .clientConfig ).Namespace ()
4455 if err != nil {
4556 return err
4657 }
47- logger .Info (& localizer.Config {
58+ logger .Info (localizer . MustLocalize ( & localizer.Config {
4859 MessageID : "cluster.serviceBinding.namespaceInfo" ,
4960 TemplateData : map [string ]interface {}{
5061 "Namespace" : color .Info (ns ),
5162 },
52- })
63+ }))
5364 }
5465
5566 // Get proper deployment
56- if appName == "" {
57- appName , err = fetchAppNameFromCluster (clients , ns )
67+ if options . AppName == "" {
68+ options . AppName , err = fetchAppNameFromCluster (clients , ns )
5869 if err != nil {
5970 return err
6071 }
6172 } else {
62- _ , err = clients .dynamicClient .Resource (deploymentResource ).Namespace (ns ).Get (context .TODO (), appName , metav1.GetOptions {})
73+ _ , err = clients .dynamicClient .Resource (deploymentResource ).Namespace (ns ).Get (context .TODO (), options . AppName , metav1.GetOptions {})
6374 if err != nil {
6475 return err
6576 }
6677 }
6778
6879 // Print desired action
69- logger .Info (fmt .Sprintf (localizer .MustLocalizeFromID ("cluster.serviceBinding.status.message" ), serviceName , appName ))
80+ logger .Info (fmt .Sprintf (localizer .MustLocalizeFromID ("cluster.serviceBinding.status.message" ), options . ServiceName , options . AppName ))
7081
71- if ! forceCreationWithoutAsk {
82+ if ! options . ForceCreationWithoutAsk {
7283 var shouldContinue bool
7384 confirm := & survey.Confirm {
7485 Message : localizer .MustLocalizeFromID ("cluster.serviceBinding.confirm.message" ),
@@ -84,29 +95,29 @@ func ExecuteServiceBinding(logger logging.Logger, serviceName string, ns string,
8495 }
8596
8697 // Check KafkaConnection
87- _ , err = clients .dynamicClient .Resource (AKCResource ).Namespace (ns ).Get (context .TODO (), serviceName , metav1.GetOptions {})
98+ _ , err = clients .dynamicClient .Resource (AKCResource ).Namespace (ns ).Get (context .TODO (), options . ServiceName , metav1.GetOptions {})
8899 if err != nil {
89100 return errors .New (localizer .MustLocalizeFromID ("cluster.serviceBinding.serviceMissing.message" ))
90101 }
91102
92103 // Execute binding
93- err = performBinding (serviceName , appName , ns , clients )
104+ err = performBinding (options , ns , clients , logger )
94105 if err != nil {
95106 return err
96107 }
97108
98- logger .Info (fmt .Sprintf (localizer .MustLocalizeFromID ("cluster.serviceBinding.bindingSuccess" ), serviceName , appName ))
109+ logger .Info (fmt .Sprintf (localizer .MustLocalizeFromID ("cluster.serviceBinding.bindingSuccess" ), options . ServiceName , options . AppName ))
99110 return nil
100111}
101112
102- func performBinding (serviceName string , appName string , ns string , clients * KubernetesClients ) error {
113+ func performBinding (options * ServiceBindingOptions , ns string , clients * KubernetesClients , logger logging. Logger ) error {
103114 serviceRef := v1alpha1.Service {
104115 NamespacedRef : v1alpha1.NamespacedRef {
105116 Ref : v1alpha1.Ref {
106117 Group : AKCResource .Group ,
107118 Version : AKCResource .Version ,
108119 Resource : AKCResource .Resource ,
109- Name : serviceName ,
120+ Name : options . ServiceName ,
110121 },
111122 },
112123 }
@@ -116,14 +127,22 @@ func performBinding(serviceName string, appName string, ns string, clients *Kube
116127 Group : deploymentResource .Group ,
117128 Version : deploymentResource .Version ,
118129 Resource : deploymentResource .Resource ,
119- Name : appName ,
130+ Name : options . AppName ,
120131 },
121132 }
122133
123- now := time .Now ()
134+ if options .BindingName == "" {
135+ randomValue := make ([]byte , 2 )
136+ _ , err := rand .Read (randomValue )
137+ if err != nil {
138+ return err
139+ }
140+ options .BindingName = fmt .Sprintf ("%v-%x" , options .ServiceName , randomValue )
141+ }
142+
124143 sb := & v1alpha1.ServiceBinding {
125144 ObjectMeta : metav1.ObjectMeta {
126- Name : fmt . Sprintf ( "%v-%v" , serviceName , now . Unix ()) ,
145+ Name : options . BindingName ,
127146 Namespace : ns ,
128147 },
129148 Spec : v1alpha1.ServiceBindingSpec {
@@ -134,6 +153,41 @@ func performBinding(serviceName string, appName string, ns string, clients *Kube
134153 }
135154 sb .SetGroupVersionKind (v1alpha1 .GroupVersionKind )
136155
156+ if options .ForceUseSDK {
157+ return useSDKForBinding (clients , sb )
158+ }
159+
160+ // Check of operator is installed
161+ _ , err := clients .dynamicClient .Resource (v1alpha1 .GroupVersionResource ).Namespace (ns ).
162+ List (context .TODO (), metav1.ListOptions {Limit : 1 })
163+
164+ if err != nil {
165+ if options .ForceUseOperator {
166+ return errors .New (localizer .MustLocalizeFromID ("cluster.serviceBinding.operatorMissing" ) + err .Error ())
167+ }
168+ logger .Debug ("Service binding Operator not available. Will use SDK option for binding" )
169+ return useSDKForBinding (clients , sb )
170+ }
171+
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 {
180+ return err
181+ }
182+
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 {
137191 restMapper , err := apiutil .NewDynamicRESTMapper (clients .restConfig )
138192 if err != nil {
139193 return err
0 commit comments