-
Notifications
You must be signed in to change notification settings - Fork 25
/
binding.go
142 lines (133 loc) · 5.75 KB
/
binding.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/*
Copyright 2020 VMware, Inc.
SPDX-License-Identifier: Apache-2.0
*/
package command
import (
"fmt"
"net/url"
"github.com/spf13/cobra"
"github.com/vmware-tanzu/sources-for-knative/pkg/apis/sources/v1alpha1"
"github.com/vmware-tanzu/sources-for-knative/plugins/vsphere/pkg"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"knative.dev/pkg/apis"
duckv1alpha1 "knative.dev/pkg/apis/duck/v1alpha1"
"knative.dev/pkg/tracker"
)
type BindingOptions struct {
Namespace string
Name string
Address string
SkipTLSVerify bool
SecretRef string
SubjectAPIVersion string
SubjectKind string
SubjectName string
SubjectSelector string
}
func NewBindingCommand(clients *pkg.Clients) *cobra.Command {
options := BindingOptions{}
result := cobra.Command{
Use: "binding",
Short: "Create a vSphere binding to call into the vSphere API",
Long: "Create a vSphere binding to call into the vSphere API",
Example: `# Create the binding in the default namespace, targeting a Deployment subject
kn vsphere binding --name binding --address https://my-vsphere-endpoint.local --skip-tls-verify --secret-ref vsphere-credentials --subject-api-version app/v1 --subject-kind Deployment --subject-name my-simple-app
# Create the binding in the specified namespace, targeting a selection of Job subjects
kn vsphere binding --namespace ns --name source --address https://my-vsphere-endpoint.local --skip-tls-verify --secret-ref vsphere-credentials --subject-api-version batch/v1 --subject-kind Job --subject-selector foo=bar
`,
PreRunE: func(cmd *cobra.Command, args []string) error {
if options.Name == "" {
return fmt.Errorf("'name' requires a nonempty name provided with the --name option")
}
if options.Address == "" {
return fmt.Errorf("'address' requires a nonempty address provided with the --address option")
}
if options.SecretRef == "" {
return fmt.Errorf("'secret-ref' requires a nonempty secret reference provided with the --secret-ref option")
}
if options.SubjectAPIVersion == "" {
return fmt.Errorf("'subject-api-version' requires a nonempty subject API version provided with the --subject-api-version option")
}
if options.SubjectKind == "" {
return fmt.Errorf("'subject-kind' requires a nonempty subject kind provided with the --subject-kind option")
}
subjectName := options.SubjectName
subjectSelector := options.SubjectSelector
if subjectName == "" && subjectSelector == "" {
return fmt.Errorf("subject requires a nonempty subject name provided with the --subject-name option," +
"\nor a nonempty subject selector with the --subject-selector option")
}
if !MutuallyExclusiveStringFlags(subjectName, subjectSelector) {
return fmt.Errorf("subject can optionally be configured with one of the following flags (but several were set):\n\t" +
"--subject-name, --subject-selector")
}
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
namespace, err := clients.GetExplicitOrDefaultNamespace(options.Namespace)
if err != nil {
return fmt.Errorf("failed to get namespace: %+v", err)
}
address, err := url.Parse(options.Address)
if err != nil {
return fmt.Errorf("failed to parse binding address: %+v", err)
}
selector, err := metav1.ParseToLabelSelector(options.SubjectSelector)
if err != nil {
return fmt.Errorf("failed to parse subject selector: %+v", err)
}
if _, err := clients.VSphereClientSet.
SourcesV1alpha1().
VSphereBindings(namespace).
Create(cmd.Context(), newBinding(namespace, address, selector, options), metav1.CreateOptions{}); err != nil {
return fmt.Errorf("failed to create Binding: %+v", err)
}
fmt.Fprintln(cmd.OutOrStdout(), "Created binding")
return nil
},
}
flags := result.Flags()
flags.StringVarP(&options.Namespace, "namespace", "n", "", "namespace of the binding to create (default namespace if omitted)")
flags.StringVar(&options.Name, "name", "", "name of the binding to create")
_ = result.MarkFlagRequired("name")
flags.StringVarP(&options.Address, "address", "a", "", "URL of the events to fetch")
_ = result.MarkFlagRequired("address")
flags.BoolVarP(&options.SkipTLSVerify, "skip-tls-verify", "k", false, "disables certificate verification for the source address (same as GOVC_INSECURE)")
flags.StringVarP(&options.SecretRef, "secret-ref", "s", "", "reference to the Kubernetes secret for the vSphere credentials needed for the source address")
_ = result.MarkFlagRequired("secret-ref")
flags.StringVar(&options.SubjectAPIVersion, "subject-api-version", "", "subject API version")
_ = result.MarkFlagRequired("subject-api-version")
flags.StringVar(&options.SubjectKind, "subject-kind", "", "subject kind")
_ = result.MarkFlagRequired("subject-kind")
flags.StringVar(&options.SubjectName, "subject-name", "", "subject name (cannot be used with --subject-selector)")
flags.StringVar(&options.SubjectSelector, "subject-selector", "", "subject selector (cannot be used with --subject-name)")
return &result
}
func newBinding(namespace string, address *url.URL, selector *metav1.LabelSelector, options BindingOptions) *v1alpha1.VSphereBinding {
return &v1alpha1.VSphereBinding{
ObjectMeta: metav1.ObjectMeta{
Namespace: namespace,
Name: options.Name,
},
Spec: v1alpha1.VSphereBindingSpec{
BindingSpec: duckv1alpha1.BindingSpec{
Subject: tracker.Reference{
APIVersion: options.SubjectAPIVersion,
Kind: options.SubjectKind,
Namespace: namespace,
Name: options.SubjectName,
Selector: selector,
},
},
VAuthSpec: v1alpha1.VAuthSpec{
Address: apis.URL(*address),
SkipTLSVerify: options.SkipTLSVerify,
SecretRef: corev1.LocalObjectReference{
Name: options.SecretRef,
},
},
},
}
}