1 package backend
2
3 import (
4 "errors"
5 "fmt"
6 "strconv"
7 "strings"
8
9 dfutil "github.com/devfile/library/v2/pkg/util"
10 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
11 "k8s.io/apimachinery/pkg/runtime/schema"
12
13 "github.com/redhat-developer/odo/pkg/binding/asker"
14 "github.com/redhat-developer/odo/pkg/kclient"
15 )
16
17 const (
18 FLAG_WORKLOAD = "workload"
19 FLAG_SERVICE = "service"
20 FLAG_SERVICE_NAMESPACE = "service-namespace"
21 FLAG_NAME = "name"
22 FLAG_BIND_AS_FILES = "bind-as-files"
23 FLAG_NAMING_STRATEGY = "naming-strategy"
24 )
25
26
27 type FlagsBackend struct{}
28
29 var _ AddBindingBackend = (*FlagsBackend)(nil)
30
31 func NewFlagsBackend() *FlagsBackend {
32 return &FlagsBackend{}
33 }
34
35 func (o *FlagsBackend) Validate(flags map[string]string, withDevfile bool) error {
36 if flags[FLAG_SERVICE] == "" {
37 return errors.New("missing --service parameter: please add --service <name>[/<kind>.<apigroup>] to specify the service instance for binding")
38 }
39 if flags[FLAG_NAME] == "" {
40 return errors.New("missing --name parameter: please add --name <name> to specify a name for the service binding instance")
41 }
42
43 if withDevfile && flags[FLAG_WORKLOAD] != "" {
44 return errors.New("--workload cannot be used from a directory containing a Devfile")
45 }
46
47 if !withDevfile && flags[FLAG_WORKLOAD] == "" {
48 return errors.New("missing --workload parameter: please add --workload <workload> so specify a workload to bind information to")
49 }
50 return dfutil.ValidateK8sResourceName(FLAG_NAME, flags[FLAG_NAME])
51 }
52
53 func (o *FlagsBackend) SelectWorkloadInstance(workloadName string) (string, schema.GroupVersionKind, error) {
54 selectedName, selectedKind, selectedGroup := parseServiceName(workloadName)
55 for _, gvk := range append(kclient.NativeWorkloadKinds, kclient.CustomWorkloadKinds...) {
56 if gvk.Group == selectedGroup && gvk.Kind == selectedKind {
57 return selectedName, gvk, nil
58 }
59 }
60 return "", schema.GroupVersionKind{}, fmt.Errorf("group/kind %q not found on the cluster", selectedGroup+"/"+selectedKind)
61 }
62
63 func (o *FlagsBackend) SelectNamespace(flags map[string]string) (string, error) {
64 return flags[FLAG_SERVICE_NAMESPACE], nil
65 }
66
67
68
69
70
71 func (o *FlagsBackend) SelectServiceInstance(serviceName string, serviceMap map[string]unstructured.Unstructured) (string, error) {
72 selectedServiceName, selectedServiceKind, selectedServiceGroup := parseServiceName(serviceName)
73
74 var services []string
75 for option, unstructuredService := range serviceMap {
76
77 if unstructuredService.GetName() == selectedServiceName {
78 if selectedServiceKind != "" && unstructuredService.GetKind() == selectedServiceKind {
79 if selectedServiceGroup != "" && unstructuredService.GroupVersionKind().Group == selectedServiceGroup {
80 services = append(services, option)
81 continue
82 } else if selectedServiceGroup == "" {
83 services = append(services, option)
84 continue
85 }
86 } else if selectedServiceKind == "" {
87 services = append(services, option)
88 }
89 }
90 }
91 if len(services) == 0 {
92 return "", fmt.Errorf("%q service not found", serviceName)
93 }
94 if len(services) > 1 {
95 return "", fmt.Errorf("Found more than one services with name %q [%+v]. Please mention <name>/<kind>.<apigroup>", serviceName, strings.Join(services, ","))
96 }
97
98 return services[0], nil
99 }
100
101 func (o *FlagsBackend) AskBindingName(_ string, flags map[string]string) (string, error) {
102 return flags[FLAG_NAME], nil
103 }
104
105 func (o *FlagsBackend) AskBindAsFiles(flags map[string]string) (bool, error) {
106 if flags[FLAG_BIND_AS_FILES] == "" {
107
108 return true, nil
109 }
110 bindAsFiles, err := strconv.ParseBool(flags[FLAG_BIND_AS_FILES])
111 if err != nil {
112 return false, fmt.Errorf("unable to set %q to --%v, value must be a boolean", flags[FLAG_BIND_AS_FILES], FLAG_BIND_AS_FILES)
113 }
114 return bindAsFiles, nil
115 }
116
117 func (o *FlagsBackend) AskNamingStrategy(flags map[string]string) (string, error) {
118 return flags[FLAG_NAMING_STRATEGY], nil
119 }
120
121 func (o *FlagsBackend) SelectCreationOptions(flags map[string]string) ([]asker.CreationOption, error) {
122 return []asker.CreationOption{asker.OutputToStdout}, nil
123 }
124
125 func (o *FlagsBackend) AskOutputFilePath(flags map[string]string, defaultValue string) (string, error) {
126 return "", errors.New("this is not implemented")
127 }
128
129
130
131
132
133
134
135 func parseServiceName(service string) (name, kind, group string) {
136 if serviceNKG := strings.Split(service, "/"); len(serviceNKG) > 1 {
137
138 name = serviceNKG[0]
139 kindGroup := strings.SplitN(serviceNKG[1], ".", 2)
140 kind = kindGroup[0]
141 if len(kindGroup) > 1 {
142
143 group = kindGroup[1]
144 }
145 } else if serviceNKG = strings.SplitN(service, ".", 3); len(serviceNKG) > 1 {
146
147 name = serviceNKG[0]
148 kind = serviceNKG[1]
149 if len(serviceNKG) > 2 {
150
151 group = serviceNKG[2]
152 }
153 } else {
154
155 name = service
156 }
157 return
158 }
159
View as plain text