mirror of
https://github.com/redhat-developer/odo.git
synced 2025-10-19 03:06:19 +03:00
Adds support for linking using service binding without the service binding operator (#4905)
* Adds support for linking using service binding without the service binding operator * Uses isLinkResource() to detect the service binding resources * Updates the success message for operator based links * Updates the flow to creating the deployment first * Adds annotations to the Redis CR in devfile-with-link.yaml file * Updates the flow to create only the services before the deployment. It also separates the push related code for link and service creation. * Moves the for loop in setLinksServiceNames() inside the if condition * Adds and returns a error message when the pipeline throws a forbidden type of error * Moves the updation of services and pvcs with owner references before attempting creation of links
This commit is contained in:
3
go.mod
3
go.mod
@@ -38,7 +38,7 @@ require (
|
||||
github.com/pborman/uuid v1.2.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/posener/complete v1.1.1
|
||||
github.com/redhat-developer/service-binding-operator v0.7.1
|
||||
github.com/redhat-developer/service-binding-operator v0.9.0
|
||||
github.com/securego/gosec/v2 v2.8.0
|
||||
github.com/segmentio/backo-go v0.0.0-20200129164019-23eae7c10bd3 // indirect
|
||||
github.com/sirupsen/logrus v1.8.1 // indirect
|
||||
@@ -63,6 +63,7 @@ require (
|
||||
k8s.io/klog v1.0.0
|
||||
k8s.io/klog/v2 v2.4.0
|
||||
k8s.io/kubectl v0.20.1
|
||||
sigs.k8s.io/controller-runtime v0.7.0
|
||||
sigs.k8s.io/yaml v1.2.0
|
||||
|
||||
)
|
||||
|
||||
5
go.sum
5
go.sum
@@ -721,6 +721,7 @@ github.com/mikefarah/yaml/v2 v2.4.0/go.mod h1:ahVqZF4n1W4NqwvVnZzC4es67xsW9uR/RR
|
||||
github.com/mikefarah/yq/v2 v2.4.1/go.mod h1:i8SYf1XdgUvY2OFwSqGAtWOOgimD2McJ6iutoxRm4k0=
|
||||
github.com/mistifyio/go-zfs v2.1.1+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ=
|
||||
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
|
||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
@@ -936,6 +937,10 @@ github.com/pseudomuto/protokit v0.2.0/go.mod h1:2PdH30hxVHsup8KpBTOXTBeMVhJZVio3
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/redhat-developer/service-binding-operator v0.7.1 h1:oFB0m3iHaFf8bRotao+shKx8BmbWPE4krGvgmJF1wjI=
|
||||
github.com/redhat-developer/service-binding-operator v0.7.1/go.mod h1:Z3fFouJGqy08JVWBFgb9ZyDcddcqx+AUIuMOeMFU8pQ=
|
||||
github.com/redhat-developer/service-binding-operator v0.8.0 h1:33nrUwKm+Osr8I/g9qZZ6Hf41dfePfZndS02/xyAYiI=
|
||||
github.com/redhat-developer/service-binding-operator v0.8.0/go.mod h1:Z3fFouJGqy08JVWBFgb9ZyDcddcqx+AUIuMOeMFU8pQ=
|
||||
github.com/redhat-developer/service-binding-operator v0.9.0 h1:CS+eEtzu/PtWuyvYQFQpZXd6ukSuFtN+U0EKKtTsvlA=
|
||||
github.com/redhat-developer/service-binding-operator v0.9.0/go.mod h1:D415gZQiz5Q8zyRbmrNrlieb6Xp73oFtCb+nCuTL6GA=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M=
|
||||
github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
|
||||
@@ -18,10 +18,10 @@ import (
|
||||
"github.com/devfile/library/pkg/devfile/parser"
|
||||
parsercommon "github.com/devfile/library/pkg/devfile/parser/data/v2/common"
|
||||
"github.com/openshift/odo/pkg/devfile/adapters/common"
|
||||
"github.com/openshift/odo/pkg/envinfo"
|
||||
"github.com/openshift/odo/pkg/kclient"
|
||||
"github.com/openshift/odo/pkg/localConfigProvider"
|
||||
|
||||
"github.com/openshift/odo/pkg/envinfo"
|
||||
"github.com/openshift/odo/pkg/service"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/klog"
|
||||
@@ -38,7 +38,7 @@ import (
|
||||
"github.com/openshift/odo/pkg/sync"
|
||||
urlpkg "github.com/openshift/odo/pkg/url"
|
||||
"github.com/openshift/odo/pkg/util"
|
||||
servicebinding "github.com/redhat-developer/service-binding-operator/api/v1alpha1"
|
||||
servicebinding "github.com/redhat-developer/service-binding-operator/apis/binding/v1alpha1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
@@ -1490,11 +1490,11 @@ func GetComponentState(client *occlient.Client, componentName, applicationName s
|
||||
|
||||
// GetComponent provides component definition
|
||||
func GetComponent(client *occlient.Client, componentName string, applicationName string, projectName string) (component Component, err error) {
|
||||
return getRemoteComponentMetadata(client, componentName, applicationName, projectName, true, true)
|
||||
return getRemoteComponentMetadata(client, componentName, applicationName, true, true)
|
||||
}
|
||||
|
||||
// getRemoteComponentMetadata provides component metadata from the cluster
|
||||
func getRemoteComponentMetadata(client *occlient.Client, componentName string, applicationName string, projectName string, getUrls, getStorage bool) (component Component, err error) {
|
||||
func getRemoteComponentMetadata(client *occlient.Client, componentName string, applicationName string, getUrls, getStorage bool) (component Component, err error) {
|
||||
fromCluster, err := GetPushedComponent(client, componentName, applicationName)
|
||||
if err != nil || fromCluster == nil {
|
||||
return Component{}, errors.Wrapf(err, "unable to get remote metadata for %s component", componentName)
|
||||
@@ -1562,18 +1562,12 @@ func getRemoteComponentMetadata(client *occlient.Client, componentName string, a
|
||||
}
|
||||
}
|
||||
|
||||
ok, err := client.GetKubeClient().IsServiceBindingSupported()
|
||||
linkedSecrets := fromCluster.GetLinkedSecrets()
|
||||
err = setLinksServiceNames(client, linkedSecrets, componentlabels.GetSelector(componentName, applicationName))
|
||||
if err != nil {
|
||||
return Component{}, fmt.Errorf("unable to check if service binding is supported: %w", err)
|
||||
}
|
||||
if ok {
|
||||
linkedSecrets := fromCluster.GetLinkedSecrets()
|
||||
err = setLinksServiceNames(client, linkedSecrets)
|
||||
if err != nil {
|
||||
return Component{}, fmt.Errorf("unable to get name of services: %w", err)
|
||||
}
|
||||
component.Status.LinkedServices = linkedSecrets
|
||||
return Component{}, fmt.Errorf("unable to get name of services: %w", err)
|
||||
}
|
||||
component.Status.LinkedServices = linkedSecrets
|
||||
|
||||
component.Namespace = client.Namespace
|
||||
component.Spec.App = applicationName
|
||||
@@ -1584,31 +1578,82 @@ func getRemoteComponentMetadata(client *occlient.Client, componentName string, a
|
||||
}
|
||||
|
||||
// setLinksServiceNames sets the service name of the links from the info in ServiceBindingRequests present in the cluster
|
||||
func setLinksServiceNames(client *occlient.Client, linkedSecrets []SecretMount) error {
|
||||
serviceBindings := map[string]string{}
|
||||
list, err := client.GetKubeClient().ListDynamicResource(kclient.ServiceBindingGroup, kclient.ServiceBindingVersion, kclient.ServiceBindingResource)
|
||||
if err != nil || list == nil {
|
||||
return err
|
||||
func setLinksServiceNames(client *occlient.Client, linkedSecrets []SecretMount, selector string) error {
|
||||
ok, err := client.GetKubeClient().IsServiceBindingSupported()
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to check if service binding is supported: %w", err)
|
||||
}
|
||||
for _, u := range list.Items {
|
||||
var sbr servicebinding.ServiceBinding
|
||||
js, err := u.MarshalJSON()
|
||||
|
||||
serviceBindings := map[string]string{}
|
||||
if ok {
|
||||
// service binding operator is installed on the cluster
|
||||
list, err := client.GetKubeClient().ListDynamicResource(kclient.ServiceBindingGroup, kclient.ServiceBindingVersion, kclient.ServiceBindingResource)
|
||||
if err != nil || list == nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, u := range list.Items {
|
||||
var sbr servicebinding.ServiceBinding
|
||||
js, err := u.MarshalJSON()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = json.Unmarshal(js, &sbr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
services := sbr.Spec.Services
|
||||
if len(services) != 1 {
|
||||
return errors.New("the ServiceBinding resource should define only one service")
|
||||
}
|
||||
service := services[0]
|
||||
if service.Kind == "Service" {
|
||||
serviceBindings[sbr.Status.Secret] = service.Name
|
||||
} else {
|
||||
serviceBindings[sbr.Status.Secret] = service.Kind + "/" + service.Name
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// service binding operator is not installed
|
||||
// get the secrets instead of the service binding objects to retrieve the link data
|
||||
secrets, err := client.GetKubeClient().ListSecrets(selector)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = json.Unmarshal(js, &sbr)
|
||||
|
||||
// get the services to get their names against the component names
|
||||
services, err := client.GetKubeClient().ListServices("")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
services := sbr.Spec.Services
|
||||
if len(services) != 1 {
|
||||
return errors.New("the ServiceBinding resource should define only one service")
|
||||
|
||||
serviceCompMap := make(map[string]string)
|
||||
for _, gotService := range services {
|
||||
serviceCompMap[gotService.Labels[componentlabels.ComponentLabel]] = gotService.Name
|
||||
}
|
||||
service := services[0]
|
||||
if service.Kind == "Service" {
|
||||
serviceBindings[sbr.Status.Secret] = service.Name
|
||||
} else {
|
||||
serviceBindings[sbr.Status.Secret] = service.Kind + "/" + service.Name
|
||||
|
||||
for _, secret := range secrets {
|
||||
serviceName, serviceOK := secret.Labels[service.ServiceLabel]
|
||||
_, linkOK := secret.Labels[service.LinkLabel]
|
||||
serviceKind, serviceKindOK := secret.Labels[service.ServiceKind]
|
||||
if serviceKindOK && serviceOK && linkOK {
|
||||
if serviceKind == "Service" {
|
||||
if _, ok := serviceBindings[secret.Name]; !ok {
|
||||
serviceBindings[secret.Name] = serviceCompMap[serviceName]
|
||||
}
|
||||
} else {
|
||||
// service name is stored as kind-name in the labels
|
||||
parts := strings.SplitN(serviceName, "-", 2)
|
||||
if len(parts) < 2 {
|
||||
continue
|
||||
}
|
||||
|
||||
serviceName = fmt.Sprintf("%v/%v", parts[0], parts[1])
|
||||
if _, ok := serviceBindings[secret.Name]; !ok {
|
||||
serviceBindings[secret.Name] = serviceName
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -139,7 +139,7 @@ func NewComponentFullDescriptionFromClientAndLocalConfig(client *occlient.Client
|
||||
}
|
||||
cfd.Status.State = state
|
||||
if state == StateTypePushed {
|
||||
componentDescFromCluster, err := getRemoteComponentMetadata(client, componentName, applicationName, projectName, false, false)
|
||||
componentDescFromCluster, err := getRemoteComponentMetadata(client, componentName, applicationName, false, false)
|
||||
if err != nil {
|
||||
return cfd, err
|
||||
}
|
||||
|
||||
@@ -159,30 +159,7 @@ func (a Adapter) Push(parameters common.PushParameters) (err error) {
|
||||
}
|
||||
s.End(true)
|
||||
|
||||
log.Info("\nUpdating services")
|
||||
// fetch the "kubernetes inlined components" to create them on cluster
|
||||
// from odo standpoint, these components contain yaml manifest of an odo service or an odo link
|
||||
k8sComponents, err := a.Devfile.Data.GetComponents(parsercommon.DevfileOptions{
|
||||
ComponentOptions: parsercommon.ComponentOptions{ComponentType: devfilev1.KubernetesComponentType},
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error while trying to fetch service(s) from devfile")
|
||||
}
|
||||
labels := componentlabels.GetLabels(a.ComponentName, a.AppName, true)
|
||||
// create the Kubernetes objects from the manifest and delete the ones not in the devfile
|
||||
needRestart, err := service.PushServiceFromKubernetesInlineComponents(a.Client.GetKubeClient(), k8sComponents, labels)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create service(s) associated with the component")
|
||||
}
|
||||
|
||||
if componentExists && needRestart {
|
||||
err = a.Client.GetKubeClient().WaitForPodNotReady(podName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
log.Infof("\nCreating Kubernetes resources for component %s", a.ComponentName)
|
||||
|
||||
previousMode := parameters.EnvSpecificInfo.GetRunMode()
|
||||
currentMode := envinfo.Run
|
||||
@@ -200,6 +177,25 @@ func (a Adapter) Push(parameters common.PushParameters) (err error) {
|
||||
parameters.RunModeChanged = true
|
||||
}
|
||||
|
||||
// fetch the "kubernetes inlined components" to create them on cluster
|
||||
// from odo standpoint, these components contain yaml manifest of an odo service or an odo link
|
||||
k8sComponents, err := a.Devfile.Data.GetComponents(parsercommon.DevfileOptions{
|
||||
ComponentOptions: parsercommon.ComponentOptions{ComponentType: devfilev1.KubernetesComponentType},
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error while trying to fetch service(s) from devfile")
|
||||
}
|
||||
|
||||
log.Infof("\nCreating Services for component %s", a.ComponentName)
|
||||
|
||||
// create the Kubernetes objects from the manifest and delete the ones not in the devfile
|
||||
err = service.PushServices(a.Client.GetKubeClient(), k8sComponents, labels)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create service(s) associated with the component")
|
||||
}
|
||||
|
||||
log.Infof("\nCreating Kubernetes resources for component %s", a.ComponentName)
|
||||
|
||||
err = a.createOrUpdateComponent(componentExists, parameters.EnvSpecificInfo)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to create or update component")
|
||||
@@ -234,11 +230,38 @@ func (a Adapter) Push(parameters common.PushParameters) (err error) {
|
||||
}
|
||||
}
|
||||
|
||||
err = service.UpdateKubernetesInlineComponentsOwnerReferences(a.Client.GetKubeClient(), k8sComponents, ownerReference)
|
||||
err = service.UpdateServicesWithOwnerReferences(a.Client.GetKubeClient(), k8sComponents, ownerReference)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// create the Kubernetes objects from the manifest and delete the ones not in the devfile
|
||||
needRestart, err := service.PushLinks(a.Client.GetKubeClient(), k8sComponents, labels, a.deployment)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create service(s) associated with the component")
|
||||
}
|
||||
|
||||
if needRestart {
|
||||
s := log.Spinner("Restarting the component")
|
||||
defer s.End(false)
|
||||
err = a.Client.GetKubeClient().WaitForPodDeletion(pod.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.End(true)
|
||||
}
|
||||
|
||||
a.deployment, err = a.Client.GetKubeClient().WaitForDeploymentRollout(a.deployment.Name)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error while waiting for deployment rollout")
|
||||
}
|
||||
|
||||
// Wait for Pod to be in running state otherwise we can't sync data or exec commands to it.
|
||||
pod, err = a.getPod(true)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "unable to get pod for component %s", a.ComponentName)
|
||||
}
|
||||
|
||||
parameters.EnvSpecificInfo.SetDevfileObj(a.Devfile)
|
||||
err = component.ApplyConfig(&a.Client, config.LocalConfigInfo{}, parameters.EnvSpecificInfo, color.Output, componentExists, false)
|
||||
if err != nil {
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"k8s.io/klog"
|
||||
|
||||
componentlabels "github.com/openshift/odo/pkg/component/labels"
|
||||
apiMachineryWatch "k8s.io/apimachinery/pkg/watch"
|
||||
)
|
||||
|
||||
func boolPtr(b bool) *bool {
|
||||
@@ -116,8 +117,8 @@ func (c *Client) ListDeployments(selector string) (*appsv1.DeploymentList, error
|
||||
})
|
||||
}
|
||||
|
||||
// WaitForPodNotReady waits for the status of the given pod to be not ready, or the pod to be deleted
|
||||
func (c *Client) WaitForPodNotReady(name string) error {
|
||||
// WaitForPodDeletion waits for the given pod to be deleted
|
||||
func (c *Client) WaitForPodDeletion(name string) error {
|
||||
watch, err := c.KubeClient.CoreV1().Pods(c.Namespace).Watch(context.TODO(), metav1.ListOptions{FieldSelector: "metadata.name=" + name})
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -131,20 +132,14 @@ func (c *Client) WaitForPodNotReady(name string) error {
|
||||
for {
|
||||
select {
|
||||
case <-time.After(time.Minute):
|
||||
return fmt.Errorf("timeout while waiting for %q pod to stop", name)
|
||||
return fmt.Errorf("timeout while waiting for %q pod to be deleted", name)
|
||||
|
||||
case val, ok := <-watch.ResultChan():
|
||||
if !ok {
|
||||
return errors.New("error getting value from resultchan")
|
||||
}
|
||||
if pod, ok := val.Object.(*corev1.Pod); ok {
|
||||
for _, cond := range pod.Status.Conditions {
|
||||
if cond.Type == "Ready" {
|
||||
if cond.Status == corev1.ConditionFalse {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
if val.Type == apiMachineryWatch.Deleted {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -329,13 +324,15 @@ func (c *Client) DeleteDeployment(labels map[string]string) error {
|
||||
}
|
||||
|
||||
// CreateDynamicResource creates a dynamic custom resource
|
||||
func (c *Client) CreateDynamicResource(exampleCustomResource map[string]interface{}, group, version, resource string) error {
|
||||
func (c *Client) CreateDynamicResource(exampleCustomResource map[string]interface{}, ownerReferences []metav1.OwnerReference, group, version, resource string) error {
|
||||
deploymentRes := schema.GroupVersionResource{Group: group, Version: version, Resource: resource}
|
||||
|
||||
deployment := &unstructured.Unstructured{
|
||||
Object: exampleCustomResource,
|
||||
}
|
||||
|
||||
deployment.SetOwnerReferences(ownerReferences)
|
||||
|
||||
debugOut, _ := json.MarshalIndent(deployment, " ", " ")
|
||||
klog.V(5).Infoln("Creating resource:")
|
||||
klog.V(5).Infoln(string(debugOut))
|
||||
|
||||
@@ -107,6 +107,24 @@ func (c *Client) GetSecret(name, namespace string) (*corev1.Secret, error) {
|
||||
return secret, nil
|
||||
}
|
||||
|
||||
// UpdateSecret updates the given Secret object in the given namespace
|
||||
func (c *Client) UpdateSecret(secret *corev1.Secret, namespace string) (*corev1.Secret, error) {
|
||||
secret, err := c.KubeClient.CoreV1().Secrets(namespace).Update(context.TODO(), secret, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "unable to update the secret %s", secret)
|
||||
}
|
||||
return secret, nil
|
||||
}
|
||||
|
||||
// DeleteSecret updates the given Secret object in the given namespace
|
||||
func (c *Client) DeleteSecret(secretName, namespace string) error {
|
||||
err := c.KubeClient.CoreV1().Secrets(namespace).Delete(context.TODO(), secretName, metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "unable to delete the secret %s", secretName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateSecret generates and creates the secret
|
||||
// commonObjectMeta is the ObjectMeta for the service
|
||||
func (c *Client) CreateSecret(objectMeta metav1.ObjectMeta, data map[string]string, ownerReference metav1.OwnerReference) error {
|
||||
@@ -124,7 +142,7 @@ func (c *Client) CreateSecret(objectMeta metav1.ObjectMeta, data map[string]stri
|
||||
return nil
|
||||
}
|
||||
|
||||
// Create a secret for each port, containing the host and port of the component
|
||||
// CreateSecrets creates a secret for each port, containing the host and port of the component
|
||||
// This is done so other components can later inject the secret into the environment
|
||||
// and have the "coordinates" to communicate with this component
|
||||
func (c *Client) CreateSecrets(componentName string, commonObjectMeta metav1.ObjectMeta, svc *corev1.Service, ownerReference metav1.OwnerReference) error {
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
"github.com/openshift/odo/pkg/secret"
|
||||
svc "github.com/openshift/odo/pkg/service"
|
||||
"github.com/openshift/odo/pkg/util"
|
||||
servicebinding "github.com/redhat-developer/service-binding-operator/api/v1alpha1"
|
||||
servicebinding "github.com/redhat-developer/service-binding-operator/apis/binding/v1alpha1"
|
||||
"github.com/spf13/cobra"
|
||||
"gopkg.in/yaml.v2"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
@@ -94,7 +94,7 @@ func (o *commonLinkOptions) complete(name string, cmd *cobra.Command, args []str
|
||||
return err
|
||||
}
|
||||
|
||||
if o.csvSupport && o.Context.EnvSpecificInfo != nil {
|
||||
if o.Context.EnvSpecificInfo != nil {
|
||||
return o.completeForOperator()
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ func (o *commonLinkOptions) complete(name string, cmd *cobra.Command, args []str
|
||||
}
|
||||
|
||||
func (o *commonLinkOptions) validate(wait bool) (err error) {
|
||||
if o.csvSupport && o.Context.EnvSpecificInfo != nil {
|
||||
if o.Context.EnvSpecificInfo != nil {
|
||||
return o.validateForOperator()
|
||||
}
|
||||
|
||||
@@ -167,7 +167,7 @@ func (o *commonLinkOptions) validate(wait bool) (err error) {
|
||||
}
|
||||
|
||||
func (o *commonLinkOptions) run() (err error) {
|
||||
if o.csvSupport && o.Context.EnvSpecificInfo != nil {
|
||||
if o.Context.EnvSpecificInfo != nil {
|
||||
if o.operationName == unlink {
|
||||
return o.unlinkOperator()
|
||||
}
|
||||
@@ -281,15 +281,6 @@ func (o *commonLinkOptions) getServiceBindingName(componentName string) string {
|
||||
|
||||
// completeForOperator completes the options when svc is supported
|
||||
func (o *commonLinkOptions) completeForOperator() (err error) {
|
||||
serviceBindingSupport, err := o.Client.GetKubeClient().IsServiceBindingSupported()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !serviceBindingSupport {
|
||||
return fmt.Errorf("please install Service Binding Operator to be able to create/delete a link\nrefer https://odo.dev/docs/install-service-binding-operator")
|
||||
}
|
||||
|
||||
o.serviceType, o.serviceName, err = svc.IsOperatorServiceNameValid(o.suppliedName)
|
||||
if err != nil {
|
||||
o.serviceName = o.suppliedName
|
||||
@@ -326,7 +317,7 @@ func (o *commonLinkOptions) completeForOperator() (err error) {
|
||||
Spec: servicebinding.ServiceBindingSpec{
|
||||
DetectBindingResources: true,
|
||||
BindAsFiles: o.bindAsFiles,
|
||||
Application: &servicebinding.Application{
|
||||
Application: servicebinding.Application{
|
||||
Ref: servicebinding.Ref{
|
||||
Name: deployment.Name,
|
||||
Group: deploymentGVR.Group,
|
||||
@@ -344,6 +335,9 @@ func (o *commonLinkOptions) validateForOperator() (err error) {
|
||||
var svcFullName string
|
||||
|
||||
if o.isTargetAService {
|
||||
if !o.csvSupport {
|
||||
return fmt.Errorf("operator hub is required for linking to services")
|
||||
}
|
||||
// let's validate if the service exists
|
||||
svcFullName = strings.Join([]string{o.serviceType, o.serviceName}, "/")
|
||||
svcExists, err := svc.OperatorSvcExists(o.KClient, svcFullName)
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
servicebinding "github.com/redhat-developer/service-binding-operator/api/v1alpha1"
|
||||
servicebinding "github.com/redhat-developer/service-binding-operator/apis/binding/v1alpha1"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/openshift/odo/pkg/component"
|
||||
@@ -124,7 +124,7 @@ func (o *LinkOptions) Validate() (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
if o.csvSupport && o.Context.EnvSpecificInfo != nil {
|
||||
if o.Context.EnvSpecificInfo != nil {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
335
pkg/service/link.go
Normal file
335
pkg/service/link.go
Normal file
@@ -0,0 +1,335 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
devfile "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
|
||||
"github.com/devfile/library/pkg/devfile/generator"
|
||||
"github.com/ghodss/yaml"
|
||||
applabels "github.com/openshift/odo/pkg/application/labels"
|
||||
componentlabels "github.com/openshift/odo/pkg/component/labels"
|
||||
"github.com/openshift/odo/pkg/kclient"
|
||||
"github.com/openshift/odo/pkg/log"
|
||||
servicebinding "github.com/redhat-developer/service-binding-operator/apis/binding/v1alpha1"
|
||||
v1 "k8s.io/api/apps/v1"
|
||||
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline"
|
||||
"github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/builder"
|
||||
"github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/context"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
)
|
||||
|
||||
// PushLinks updates Link(s) from Kubernetes Inlined component in a devfile by creating new ones or removing old ones
|
||||
// returns true if the component needs to be restarted (when a link has been created or deleted)
|
||||
// if service binding operator is not present, it will call pushLinksWithoutOperator to create the links without it.
|
||||
func PushLinks(client *kclient.Client, k8sComponents []devfile.Component, labels map[string]string, deployment *v1.Deployment) (bool, error) {
|
||||
serviceBindingSupport, err := client.IsServiceBindingSupported()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if !serviceBindingSupport {
|
||||
return pushLinksWithoutOperator(client, k8sComponents, labels, deployment)
|
||||
}
|
||||
|
||||
return pushLinksWithOperator(client, k8sComponents, labels, deployment)
|
||||
}
|
||||
|
||||
// pushLinksWithOperator creates links or deletes links (if service binding operator is installed) between components and services
|
||||
// returns true if the component needs to be restarted (a secret was generated and added to the deployment)
|
||||
func pushLinksWithOperator(client *kclient.Client, k8sComponents []devfile.Component, labels map[string]string, deployment *v1.Deployment) (bool, error) {
|
||||
|
||||
ownerReference := generator.GetOwnerReference(deployment)
|
||||
deployed, err := ListDeployedServices(client, labels)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
for key, deployedResource := range deployed {
|
||||
if !deployedResource.isLinkResource {
|
||||
delete(deployed, key)
|
||||
}
|
||||
}
|
||||
|
||||
restartNeeded := false
|
||||
|
||||
// create an object on the kubernetes cluster for all the Kubernetes Inlined components
|
||||
for _, c := range k8sComponents {
|
||||
// get the string representation of the YAML definition of a CRD
|
||||
strCRD := c.Kubernetes.Inlined
|
||||
|
||||
// convert the YAML definition into map[string]interface{} since it's needed to create dynamic resource
|
||||
d := NewDynamicCRD()
|
||||
err := yaml.Unmarshal([]byte(strCRD), &d.OriginalCRD)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if !isLinkResource(d.OriginalCRD["kind"].(string)) {
|
||||
// operator hub is not installed on the cluster
|
||||
// or it's a service binding related resource
|
||||
continue
|
||||
}
|
||||
|
||||
crdName, ok := getCRDName(d.OriginalCRD)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
cr, _, err := createOperatorService(client, d, labels, []metav1.OwnerReference{ownerReference})
|
||||
delete(deployed, cr+"/"+crdName)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "already exists") {
|
||||
// this could be the case when "odo push" was executed after making change to code but there was no change to the service itself
|
||||
// TODO: better way to handle this might be introduced by https://github.com/openshift/odo/issues/4553
|
||||
continue // this ensures that services slice is not updated
|
||||
} else {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
name, _ := d.GetServiceNameFromCRD() // ignoring error because invalid yaml won't be inserted into devfile through odo
|
||||
log.Successf("Created link %q using Service Binding Operator on the cluster; component will be restarted", name)
|
||||
restartNeeded = true
|
||||
}
|
||||
|
||||
for key, val := range deployed {
|
||||
if !isLinkResource(val.Kind) {
|
||||
continue
|
||||
}
|
||||
err = DeleteOperatorService(client, key)
|
||||
if err != nil {
|
||||
return false, err
|
||||
|
||||
}
|
||||
|
||||
log.Successf("Deleted link %q using Service Binding Operator on the cluster; component will be restarted", key)
|
||||
restartNeeded = true
|
||||
}
|
||||
|
||||
if !restartNeeded {
|
||||
log.Success("Links are in sync with the cluster, no changes are required")
|
||||
}
|
||||
return restartNeeded, nil
|
||||
}
|
||||
|
||||
// pushLinksWithoutOperator creates links or deletes links (if service binding operator is not installed) between components and services
|
||||
// returns true if the component needs to be restarted (a secret was generated and added to the deployment)
|
||||
func pushLinksWithoutOperator(client *kclient.Client, k8sComponents []devfile.Component, labels map[string]string, deployment *v1.Deployment) (bool, error) {
|
||||
|
||||
// check csv support before proceeding
|
||||
csvSupport, err := IsCSVSupported()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
secrets, err := client.ListSecrets(componentlabels.GetSelector(labels[componentlabels.ComponentLabel], labels[applabels.ApplicationLabel]))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
ownerReferences := generator.GetOwnerReference(deployment)
|
||||
|
||||
clusterLinksMap := make(map[string]string)
|
||||
for _, secret := range secrets {
|
||||
if value, ok := secret.GetLabels()[LinkLabel]; ok {
|
||||
clusterLinksMap[value] = secret.Name
|
||||
}
|
||||
}
|
||||
|
||||
localLinksMap := make(map[string]string)
|
||||
// create an object on the kubernetes cluster for all the Kubernetes Inlined components
|
||||
for _, c := range k8sComponents {
|
||||
// get the string representation of the YAML definition of a CRD
|
||||
strCRD := c.Kubernetes.Inlined
|
||||
|
||||
// convert the YAML definition into map[string]interface{} since it's needed to create dynamic resource
|
||||
d := NewDynamicCRD()
|
||||
err := yaml.Unmarshal([]byte(strCRD), &d.OriginalCRD)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if !isLinkResource(d.OriginalCRD["kind"].(string)) {
|
||||
// not a service binding object, thus continue
|
||||
continue
|
||||
}
|
||||
localLinksMap[c.Name] = strCRD
|
||||
}
|
||||
|
||||
var processingPipeline pipeline.Pipeline
|
||||
|
||||
deploymentGVR, err := client.GetDeploymentAPIVersion()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
var restartRequired bool
|
||||
|
||||
// delete the links not present on the devfile
|
||||
for linkName, secretName := range clusterLinksMap {
|
||||
if _, ok := localLinksMap[linkName]; !ok {
|
||||
|
||||
// recreate parts of the service binding request for deletion
|
||||
var newServiceBinding servicebinding.ServiceBinding
|
||||
newServiceBinding.Name = linkName
|
||||
newServiceBinding.Namespace = client.Namespace
|
||||
newServiceBinding.Spec.Application = servicebinding.Application{
|
||||
Ref: servicebinding.Ref{
|
||||
Name: deployment.Name,
|
||||
Group: deploymentGVR.Group,
|
||||
Version: deploymentGVR.Version,
|
||||
Resource: deploymentGVR.Resource,
|
||||
},
|
||||
}
|
||||
newServiceBinding.Status.Secret = secretName
|
||||
|
||||
// set the deletion time stamp to trigger deletion
|
||||
timeNow := metav1.Now()
|
||||
newServiceBinding.DeletionTimestamp = &timeNow
|
||||
|
||||
// if the pipeline was created before
|
||||
// skip deletion
|
||||
if processingPipeline == nil {
|
||||
processingPipeline, err = getPipeline(client)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
_, err = processingPipeline.Process(&newServiceBinding)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// since the library currently doesn't delete the secret after unbinding
|
||||
// delete the secret manually
|
||||
err = client.DeleteSecret(secretName, client.Namespace)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
restartRequired = true
|
||||
log.Successf("Deleted link %q on the cluster; component will be restarted", linkName)
|
||||
}
|
||||
}
|
||||
|
||||
var serviceCompMap map[string]string
|
||||
|
||||
// create the links
|
||||
for linkName, strCRD := range localLinksMap {
|
||||
if _, ok := clusterLinksMap[linkName]; !ok {
|
||||
if serviceCompMap == nil {
|
||||
// prevent listing of services unless required
|
||||
services, err := client.ListServices("")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// get the services and get match them against the component
|
||||
serviceCompMap = make(map[string]string)
|
||||
for _, service := range services {
|
||||
serviceCompMap[service.Name] = service.Labels[componentlabels.ComponentLabel]
|
||||
}
|
||||
}
|
||||
|
||||
// get the string representation of the YAML definition of a CRD
|
||||
var serviceBinding servicebinding.ServiceBinding
|
||||
err = yaml.Unmarshal([]byte(strCRD), &serviceBinding)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if len(serviceBinding.Spec.Services) != 1 {
|
||||
continue
|
||||
}
|
||||
|
||||
if !csvSupport && !isLinkResource(serviceBinding.Spec.Services[0].Kind) {
|
||||
// ignore service binding objects linked to services if csv support is not present on the cluster
|
||||
continue
|
||||
}
|
||||
|
||||
// set the labels and namespace
|
||||
serviceBinding.SetLabels(labels)
|
||||
serviceBinding.Namespace = client.Namespace
|
||||
serviceBinding.Spec.Services[0].Namespace = &client.Namespace
|
||||
|
||||
_, err = json.MarshalIndent(serviceBinding, " ", " ")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if processingPipeline == nil {
|
||||
processingPipeline, err = getPipeline(client)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
_, err = processingPipeline.Process(&serviceBinding)
|
||||
if err != nil {
|
||||
if kerrors.IsForbidden(err) {
|
||||
// due to https://github.com/redhat-developer/service-binding-operator/issues/1003
|
||||
return false, fmt.Errorf("please install the service binding operator")
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
|
||||
if len(serviceBinding.Status.Secret) == 0 {
|
||||
return false, fmt.Errorf("no secret was provided by service binding's pipleine")
|
||||
}
|
||||
|
||||
// get the generated secret and update it with the labels and owner reference
|
||||
secret, err := client.GetSecret(serviceBinding.Status.Secret, client.Namespace)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
secret.Labels = labels
|
||||
secret.Labels[LinkLabel] = linkName
|
||||
if _, ok := serviceCompMap[serviceBinding.Spec.Services[0].Name]; ok {
|
||||
secret.Labels[ServiceLabel] = serviceCompMap[serviceBinding.Spec.Services[0].Name]
|
||||
} else {
|
||||
secret.Labels[ServiceLabel] = serviceBinding.Spec.Services[0].Name
|
||||
}
|
||||
secret.Labels[ServiceKind] = serviceBinding.Spec.Services[0].Kind
|
||||
if serviceBinding.Spec.Services[0].Kind != "Service" {
|
||||
// the service name is stored as kind-name as `/` is not a valid char for labels of kubernetes secrets
|
||||
secret.Labels[ServiceLabel] = fmt.Sprintf("%v-%v", serviceBinding.Spec.Services[0].Kind, serviceBinding.Spec.Services[0].Name)
|
||||
}
|
||||
secret.SetOwnerReferences([]metav1.OwnerReference{ownerReferences})
|
||||
_, err = client.UpdateSecret(secret, client.Namespace)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
restartRequired = true
|
||||
log.Successf("Created link %q on the cluster; component will be restarted", linkName)
|
||||
}
|
||||
}
|
||||
|
||||
if restartRequired {
|
||||
return true, nil
|
||||
} else {
|
||||
log.Success("Links are in sync with the cluster, no changes are required")
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// getPipeline gets the pipeline to process service binding requests
|
||||
func getPipeline(client *kclient.Client) (pipeline.Pipeline, error) {
|
||||
mgr, err := ctrl.NewManager(client.KubeClientConfig, ctrl.Options{
|
||||
Scheme: runtime.NewScheme(),
|
||||
// disable the health probes to prevent binding to them
|
||||
HealthProbeBindAddress: "0",
|
||||
// disable the prometheus metrics
|
||||
MetricsBindAddress: "0",
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return builder.DefaultBuilder.WithContextProvider(context.Provider(client.DynamicClient, context.ResourceLookup(mgr.GetRESTMapper()))).Build(), nil
|
||||
}
|
||||
@@ -5,8 +5,6 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
|
||||
devfile "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
|
||||
"github.com/devfile/library/pkg/devfile/parser/data/v2/common"
|
||||
parsercommon "github.com/devfile/library/pkg/devfile/parser/data/v2/common"
|
||||
@@ -28,13 +26,24 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/devfile/library/pkg/devfile/parser"
|
||||
servicebinding "github.com/redhat-developer/service-binding-operator/api/v1alpha1"
|
||||
servicebinding "github.com/redhat-developer/service-binding-operator/apis/binding/v1alpha1"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
)
|
||||
|
||||
const provisionedAndBoundStatus = "ProvisionedAndBound"
|
||||
const provisionedAndLinkedStatus = "ProvisionedAndLinked"
|
||||
const apiVersion = "odo.dev/v1alpha1"
|
||||
|
||||
// LinkLabel is the name of the name of the link in the devfile
|
||||
const LinkLabel = "app.kubernetes.io/link-name"
|
||||
|
||||
// ServiceLabel is the name of the service in the service binding object
|
||||
const ServiceLabel = "app.kubernetes.io/service-name"
|
||||
|
||||
// ServiceKind is the kind of the service in the service binding object
|
||||
const ServiceKind = "app.kubernetes.io/service-kind"
|
||||
|
||||
// NewServicePlanParameter creates a new ServicePlanParameter instance with the specified state
|
||||
func NewServicePlanParameter(name, typeName, defaultValue string, required bool) ServicePlanParameter {
|
||||
return ServicePlanParameter{
|
||||
@@ -106,7 +115,7 @@ func doesCRExist(kind string, csvs *olm.ClusterServiceVersionList) (olm.ClusterS
|
||||
|
||||
// CreateOperatorService creates new service (actually a Deployment) from OperatorHub
|
||||
func CreateOperatorService(client *kclient.Client, group, version, resource string, CustomResourceDefinition map[string]interface{}) error {
|
||||
err := client.CreateDynamicResource(CustomResourceDefinition, group, version, resource)
|
||||
err := client.CreateDynamicResource(CustomResourceDefinition, nil, group, version, resource)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to create operator backed service")
|
||||
}
|
||||
@@ -933,42 +942,26 @@ func (d *DynamicCRD) AddComponentLabelsToCRD(labels map[string]string) {
|
||||
metaMap["labels"] = labels
|
||||
}
|
||||
|
||||
// PushServiceFromKubernetesInlineComponents updates service(s) from Kubernetes Inlined component in a devfile by creating new ones or removing old ones
|
||||
// returns true if the component needs to be restarted (when a service binding has been created or deleted)
|
||||
func PushServiceFromKubernetesInlineComponents(client *kclient.Client, k8sComponents []devfile.Component, labels map[string]string) (bool, error) {
|
||||
// PushServices updates service(s) from Kubernetes Inlined component in a devfile by creating new ones or removing old ones
|
||||
func PushServices(client *kclient.Client, k8sComponents []devfile.Component, labels map[string]string) error {
|
||||
|
||||
// check csv support before proceeding
|
||||
csvSupported, err := IsCSVSupported()
|
||||
if err != nil || !csvSupported {
|
||||
return false, err
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
type DeployedInfo struct {
|
||||
DoesDeleteRestartsComponent bool
|
||||
Kind string
|
||||
Name string
|
||||
deployed, err := ListDeployedServices(client, labels)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
deployed := map[string]DeployedInfo{}
|
||||
|
||||
deployedServices, _, err := ListOperatorServices(client)
|
||||
if err != nil && err != kclient.ErrNoSuchOperator {
|
||||
// We ignore ErrNoSuchOperator error as we can deduce Operator Services are not installed
|
||||
return false, err
|
||||
}
|
||||
for _, svc := range deployedServices {
|
||||
name := svc.GetName()
|
||||
kind := svc.GetKind()
|
||||
deployedLabels := svc.GetLabels()
|
||||
if deployedLabels[applabels.ManagedBy] == "odo" && deployedLabels[componentlabels.ComponentLabel] == labels[componentlabels.ComponentLabel] {
|
||||
deployed[kind+"/"+name] = DeployedInfo{
|
||||
DoesDeleteRestartsComponent: isLinkResource(kind),
|
||||
Kind: kind,
|
||||
Name: name,
|
||||
}
|
||||
for key, deployedResource := range deployed {
|
||||
if deployedResource.isLinkResource {
|
||||
delete(deployed, key)
|
||||
}
|
||||
}
|
||||
needRestart := false
|
||||
|
||||
madeChange := false
|
||||
|
||||
// create an object on the kubernetes cluster for all the Kubernetes Inlined components
|
||||
@@ -980,90 +973,101 @@ func PushServiceFromKubernetesInlineComponents(client *kclient.Client, k8sCompon
|
||||
d := NewDynamicCRD()
|
||||
err := yaml.Unmarshal([]byte(strCRD), &d.OriginalCRD)
|
||||
if err != nil {
|
||||
return false, err
|
||||
return err
|
||||
}
|
||||
|
||||
cr, csv, err := GetCSV(client, d.OriginalCRD)
|
||||
if err != nil {
|
||||
return false, err
|
||||
if !csvSupported || (isLinkResource(d.OriginalCRD["kind"].(string))) {
|
||||
// operator hub is not installed on the cluster
|
||||
// or it's a service binding related resource
|
||||
continue
|
||||
}
|
||||
|
||||
var group, version, kind, resource string
|
||||
for _, crd := range csv.Spec.CustomResourceDefinitions.Owned {
|
||||
if crd.Kind == cr {
|
||||
group, version, kind, resource, err = getGVKRFromCR(crd)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// add labels to the CRD before creation
|
||||
d.AddComponentLabelsToCRD(labels)
|
||||
|
||||
crdName, ok := getCRDName(d.OriginalCRD)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, found := deployed[cr+"/"+crdName]; !found && isLinkResource(cr) {
|
||||
// If creating the ServiceBinding, the component will restart
|
||||
needRestart = true
|
||||
}
|
||||
|
||||
cr, kind, err := createOperatorService(client, d, labels, []metav1.OwnerReference{})
|
||||
delete(deployed, cr+"/"+crdName)
|
||||
|
||||
// create the service on cluster
|
||||
err = client.CreateDynamicResource(d.OriginalCRD, group, version, resource)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "already exists") {
|
||||
// this could be the case when "odo push" was executed after making change to code but there was no change to the service itself
|
||||
// TODO: better way to handle this might be introduced by https://github.com/openshift/odo/issues/4553
|
||||
continue // this ensures that services slice is not updated
|
||||
} else {
|
||||
return false, err
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
name, _ := d.GetServiceNameFromCRD() // ignoring error because invalid yaml won't be inserted into devfile through odo
|
||||
if isLinkResource(cr) {
|
||||
log.Successf("Created link %q on the cluster; component will be restarted", name)
|
||||
} else {
|
||||
log.Successf("Created service %q on the cluster; refer %q to know how to link it to the component", strings.Join([]string{kind, name}, "/"), "odo link -h")
|
||||
}
|
||||
log.Successf("Created service %q on the cluster; refer %q to know how to link it to the component", strings.Join([]string{kind, name}, "/"), "odo link -h")
|
||||
madeChange = true
|
||||
}
|
||||
|
||||
for key, val := range deployed {
|
||||
if !csvSupported || (isLinkResource(val.Kind)) {
|
||||
continue
|
||||
}
|
||||
err = DeleteOperatorService(client, key)
|
||||
if err != nil {
|
||||
return false, err
|
||||
return err
|
||||
|
||||
}
|
||||
|
||||
if isLinkResource(val.Kind) {
|
||||
log.Successf("Deleted link %q on the cluster; component will be restarted", val.Name)
|
||||
} else {
|
||||
log.Successf("Deleted service %q from the cluster", key)
|
||||
}
|
||||
log.Successf("Deleted service %q from the cluster", key)
|
||||
madeChange = true
|
||||
|
||||
if val.DoesDeleteRestartsComponent {
|
||||
needRestart = true
|
||||
}
|
||||
}
|
||||
|
||||
if !madeChange {
|
||||
log.Success("Services and Links are in sync with the cluster, no changes are required")
|
||||
log.Success("Services are in sync with the cluster, no changes are required")
|
||||
}
|
||||
|
||||
return needRestart, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateKubernetesInlineComponentsOwnerReferences adds an owner reference to an inlined Kubernetes resource
|
||||
// DeployedInfo holds information about the services present on the cluster
|
||||
type DeployedInfo struct {
|
||||
Kind string
|
||||
Name string
|
||||
isLinkResource bool
|
||||
}
|
||||
|
||||
func ListDeployedServices(client *kclient.Client, labels map[string]string) (map[string]DeployedInfo, error) {
|
||||
deployed := map[string]DeployedInfo{}
|
||||
|
||||
deployedServices, _, err := ListOperatorServices(client)
|
||||
if err != nil && err != kclient.ErrNoSuchOperator {
|
||||
// We ignore ErrNoSuchOperator error as we can deduce Operator Services are not installed
|
||||
return nil, err
|
||||
}
|
||||
for _, svc := range deployedServices {
|
||||
name := svc.GetName()
|
||||
kind := svc.GetKind()
|
||||
deployedLabels := svc.GetLabels()
|
||||
if deployedLabels[applabels.ManagedBy] == "odo" && deployedLabels[componentlabels.ComponentLabel] == labels[componentlabels.ComponentLabel] {
|
||||
deployed[kind+"/"+name] = DeployedInfo{
|
||||
Kind: kind,
|
||||
Name: name,
|
||||
isLinkResource: isLinkResource(kind),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return deployed, nil
|
||||
}
|
||||
|
||||
// UpdateServicesWithOwnerReferences adds an owner reference to an inlined Kubernetes resource (except service binding objects)
|
||||
// if not already present in the list of owner references
|
||||
func UpdateKubernetesInlineComponentsOwnerReferences(client *kclient.Client, k8sComponents []devfile.Component, ownerReference metav1.OwnerReference) error {
|
||||
func UpdateServicesWithOwnerReferences(client *kclient.Client, k8sComponents []devfile.Component, ownerReference metav1.OwnerReference) error {
|
||||
csvSupport, err := client.IsCSVSupported()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !csvSupport {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, c := range k8sComponents {
|
||||
// get the string representation of the YAML definition of a CRD
|
||||
strCRD := c.Kubernetes.Inlined
|
||||
@@ -1075,6 +1079,11 @@ func UpdateKubernetesInlineComponentsOwnerReferences(client *kclient.Client, k8s
|
||||
return err
|
||||
}
|
||||
|
||||
if isLinkResource(d.OriginalCRD["kind"].(string)) {
|
||||
// ignore service binding resources
|
||||
continue
|
||||
}
|
||||
|
||||
cr, csv, err := GetCSV(client, d.OriginalCRD)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -1136,3 +1145,34 @@ func getCRDName(crd map[string]interface{}) (string, bool) {
|
||||
func isLinkResource(kind string) bool {
|
||||
return kind == "ServiceBinding"
|
||||
}
|
||||
|
||||
// createOperatorService creates the given operator on the cluster
|
||||
// it returns the CR,Kind and errors
|
||||
func createOperatorService(client *kclient.Client, d *DynamicCRD, labels map[string]string, ownerReferences []metav1.OwnerReference) (string, string, error) {
|
||||
cr, csv, err := GetCSV(client, d.OriginalCRD)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
var group, version, kind, resource string
|
||||
for _, crd := range csv.Spec.CustomResourceDefinitions.Owned {
|
||||
if crd.Kind == cr {
|
||||
group, version, kind, resource, err = getGVKRFromCR(crd)
|
||||
if err != nil {
|
||||
return cr, "", err
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// add labels to the CRD before creation
|
||||
d.AddComponentLabelsToCRD(labels)
|
||||
|
||||
// create the service on cluster
|
||||
err = client.CreateDynamicResource(d.OriginalCRD, ownerReferences, group, version, resource)
|
||||
if err != nil {
|
||||
// return the cr name for deletion from the push map in the push code
|
||||
return cr, "", err
|
||||
}
|
||||
return cr, kind, err
|
||||
}
|
||||
|
||||
@@ -32,15 +32,12 @@ EOF
|
||||
}
|
||||
|
||||
if [ $KUBERNETES == "true" ]; then
|
||||
# install "redis-oprator" using "kubectl" in "operators" namespace; use "operatorhubio-catalog" catalog soure from "olm" namespace
|
||||
# install "redis-oprator" using "kubectl" in "operators" namespace; use "operatorhubio-catalog" catalog source from "olm" namespace
|
||||
install_redis_operator kubectl operators operatorhubio-catalog olm
|
||||
|
||||
# install "service-binding-operator" using "kubectl" in "operators" namespace; use "operatorhubio-catalog" catalog soure from "olm" namespace
|
||||
install_service_binding_operator kubectl operators service-binding-operator operatorhubio-catalog olm
|
||||
else
|
||||
# install "redis-oprator" using "oc" in "openshift-operators" namespace; use "community-operators" catalog soure from "openshift-marketplace" namespace
|
||||
# install "redis-oprator" using "oc" in "openshift-operators" namespace; use "community-operators" catalog source from "openshift-marketplace" namespace
|
||||
install_redis_operator oc openshift-operators community-operators openshift-marketplace
|
||||
|
||||
# install "service-binding-operator" using "oc" in "openshift-operators" namespace; use "redhat-operators" catalog soure from "openshift-marketplace" namespace
|
||||
# install "service-binding-operator" using "oc" in "openshift-operators" namespace; use "redhat-operators" catalog source from "openshift-marketplace" namespace
|
||||
install_service_binding_operator oc openshift-operators rh-service-binding-operator redhat-operators openshift-marketplace
|
||||
fi
|
||||
@@ -47,6 +47,8 @@ components:
|
||||
kind: Redis
|
||||
metadata:
|
||||
name: myredis
|
||||
annotations:
|
||||
service.binding/name: path={.metadata.name}
|
||||
spec:
|
||||
redisExporter:
|
||||
enabled: true
|
||||
|
||||
@@ -19,6 +19,7 @@ type CliRunner interface {
|
||||
DeleteNamespaceProject(projectName string)
|
||||
DeletePod(podName string, projectName string)
|
||||
GetEnvsDevFileDeployment(componentName, appName, projectName string) map[string]string
|
||||
GetEnvRefNames(componentName, appName, projectName string) []string
|
||||
GetPVCSize(compName, storageName, namespace string) string
|
||||
GetAllPVCNames(namespace string) []string
|
||||
GetPodInitContainers(compName, namespace string) []string
|
||||
@@ -31,4 +32,5 @@ type CliRunner interface {
|
||||
WaitForRunnerCmdOut(args []string, timeout int, errOnFail bool, check func(output string) bool, includeStdErr ...bool) bool
|
||||
PodsShouldBeRunning(project string, regex string)
|
||||
CreateSecret(secretName, secretPass, project string)
|
||||
GetSecrets(project string) string
|
||||
}
|
||||
|
||||
@@ -319,3 +319,13 @@ func (kubectl KubectlRunner) WaitForRunnerCmdOut(args []string, timeout int, err
|
||||
func (kubectl KubectlRunner) CreateSecret(secretName, secretPass, project string) {
|
||||
Cmd(kubectl.path, "create", "secret", "generic", secretName, "--from-literal=password="+secretPass, "-n", project).ShouldPass()
|
||||
}
|
||||
|
||||
// GetSecrets gets all the secrets belonging to the project
|
||||
func (kubectl KubectlRunner) GetSecrets(project string) string {
|
||||
return GetSecrets(kubectl.path, project)
|
||||
}
|
||||
|
||||
// GetEnvRefNames gets the ref values from the envFroms of the deployment belonging to the given data
|
||||
func (kubectl KubectlRunner) GetEnvRefNames(componentName, appName, projectName string) []string {
|
||||
return GetEnvRefNames(kubectl.path, componentName, appName, projectName)
|
||||
}
|
||||
|
||||
@@ -542,6 +542,11 @@ func (oc OcRunner) GetEnvsDevFileDeployment(componentName, appName, projectName
|
||||
return mapOutput
|
||||
}
|
||||
|
||||
// GetEnvRefNames gets the ref values from the envFroms of the deployment belonging to the given data
|
||||
func (oc OcRunner) GetEnvRefNames(componentName, appName, projectName string) []string {
|
||||
return GetEnvRefNames(oc.path, componentName, appName, projectName)
|
||||
}
|
||||
|
||||
// WaitForDCRollout wait for DeploymentConfig to finish active rollout
|
||||
// timeout is a maximum wait time in seconds
|
||||
func (oc OcRunner) WaitForDCRollout(dcName string, project string, timeout time.Duration) {
|
||||
@@ -758,3 +763,8 @@ func (oc OcRunner) WaitForRunnerCmdOut(args []string, timeout int, errOnFail boo
|
||||
func (oc OcRunner) CreateSecret(secretName, secretPass, project string) {
|
||||
Cmd(oc.path, "create", "secret", "generic", secretName, "--from-literal=password="+secretPass, "-n", project).ShouldPass()
|
||||
}
|
||||
|
||||
// GetSecrets gets all the secrets belonging to the project
|
||||
func (oc OcRunner) GetSecrets(project string) string {
|
||||
return GetSecrets(oc.path, project)
|
||||
}
|
||||
|
||||
@@ -90,3 +90,25 @@ func GetAnnotationsDeployment(path, componentName, appName, projectName string)
|
||||
}
|
||||
return mapOutput
|
||||
}
|
||||
|
||||
// GetSecrets gets all the secrets belonging to the project
|
||||
func GetSecrets(path, project string) string {
|
||||
session := CmdRunner(path, "get", "secrets", "--namespace", project)
|
||||
Eventually(session).Should(gexec.Exit(0))
|
||||
output := string(session.Wait().Out.Contents())
|
||||
return output
|
||||
}
|
||||
|
||||
// GetEnvRefNames gets the ref values from the envFroms of the deployment belonging to the given data
|
||||
func GetEnvRefNames(path, componentName, appName, projectName string) []string {
|
||||
selector := fmt.Sprintf("--selector=%s=%s,%s=%s", labels.ComponentLabel, componentName, applabels.ApplicationLabel, appName)
|
||||
output := Cmd(path, "get", "deployment", selector, "--namespace", projectName,
|
||||
"-o", "jsonpath='{range .items[0].spec.template.spec.containers[0].envFrom[*]}{.secretRef.name}{\"\\n\"}{end}'").ShouldPass().Out()
|
||||
|
||||
var result []string
|
||||
for _, line := range strings.Split(output, "\n") {
|
||||
line = strings.TrimPrefix(line, "'")
|
||||
result = append(result, strings.TrimSpace(line))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
@@ -17,7 +18,6 @@ var _ = Describe("odo link command tests for OperatorHub", func() {
|
||||
|
||||
BeforeEach(func() {
|
||||
commonVar = helper.CommonBeforeEach()
|
||||
helper.Chdir(commonVar.Context)
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
@@ -32,7 +32,7 @@ var _ = Describe("odo link command tests for OperatorHub", func() {
|
||||
BeforeEach(func() {
|
||||
// wait till odo can see that all operators installed by setup script in the namespace
|
||||
odoArgs := []string{"catalog", "list", "services"}
|
||||
operators := []string{"redis-operator", "service-binding-operator"}
|
||||
operators := []string{"redis-operator"}
|
||||
for _, operator := range operators {
|
||||
helper.WaitForCmdOut("odo", odoArgs, 5, true, func(output string) bool {
|
||||
return strings.Contains(output, operator)
|
||||
@@ -53,51 +53,51 @@ var _ = Describe("odo link command tests for OperatorHub", func() {
|
||||
BeforeEach(func() {
|
||||
helper.CopyExample(filepath.Join("source", "nodejs"), commonVar.Context)
|
||||
componentName = "cmp-" + helper.RandString(6)
|
||||
helper.Cmd("odo", "create", "nodejs", componentName).ShouldPass()
|
||||
helper.Cmd("odo", "config", "set", "Memory", "300M", "-f").ShouldPass()
|
||||
helper.Cmd("odo", "create", "nodejs", componentName, "--context", commonVar.Context, "--project", commonVar.Project).ShouldPass()
|
||||
helper.Cmd("odo", "config", "set", "Memory", "300M", "-f", "--context", commonVar.Context).ShouldPass()
|
||||
|
||||
serviceName := "service-" + helper.RandString(6)
|
||||
svcFullName = strings.Join([]string{"Redis", serviceName}, "/")
|
||||
helper.Cmd("odo", "service", "create", redisCluster, serviceName, "--project", commonVar.Project).ShouldPass()
|
||||
helper.Cmd("odo", "service", "create", redisCluster, serviceName, "--context", commonVar.Context).ShouldPass()
|
||||
|
||||
helper.Cmd("odo", "push").ShouldPass()
|
||||
helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass()
|
||||
name := commonVar.CliRunner.GetRunningPodNameByComponent(componentName, commonVar.Project)
|
||||
Expect(name).To(Not(BeEmpty()))
|
||||
})
|
||||
|
||||
It("should find files in component container", func() {
|
||||
helper.Cmd("odo", "exec", "--", "ls", "/project/server.js").ShouldPass()
|
||||
helper.Cmd("odo", "exec", "--context", commonVar.Context, "--", "ls", "/project/server.js").ShouldPass()
|
||||
})
|
||||
|
||||
When("a link between the component and the service is created", func() {
|
||||
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("odo", "link", svcFullName).ShouldPass()
|
||||
helper.Cmd("odo", "link", svcFullName, "--context", commonVar.Context).ShouldPass()
|
||||
})
|
||||
|
||||
It("should find the link in odo describe", func() {
|
||||
stdOut := helper.Cmd("odo", "describe").ShouldPass().Out()
|
||||
stdOut := helper.Cmd("odo", "describe", "--context", commonVar.Context).ShouldPass().Out()
|
||||
Expect(stdOut).To(ContainSubstring(svcFullName))
|
||||
})
|
||||
|
||||
When("odo push is executed", func() {
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("odo", "push").ShouldPass()
|
||||
helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass()
|
||||
name := commonVar.CliRunner.GetRunningPodNameByComponent(componentName, commonVar.Project)
|
||||
Expect(name).To(Not(BeEmpty()))
|
||||
})
|
||||
|
||||
It("should find files in component container", func() {
|
||||
helper.Cmd("odo", "exec", "--", "ls", "/project/server.js").ShouldPass()
|
||||
helper.Cmd("odo", "exec", "--context", commonVar.Context, "--", "ls", "/project/server.js").ShouldPass()
|
||||
})
|
||||
|
||||
It("should find the link environment variable", func() {
|
||||
stdOut := helper.Cmd("odo", "exec", "--", "sh", "-c", "echo $REDIS_CLUSTERIP").ShouldPass().Out()
|
||||
stdOut := helper.Cmd("odo", "exec", "--context", commonVar.Context, "--", "sh", "-c", "echo $REDIS_CLUSTERIP").ShouldPass().Out()
|
||||
Expect(stdOut).To(Not(BeEmpty()))
|
||||
})
|
||||
|
||||
It("should find the link in odo describe", func() {
|
||||
stdOut := helper.Cmd("odo", "describe").ShouldPass().Out()
|
||||
stdOut := helper.Cmd("odo", "describe", "--context", commonVar.Context).ShouldPass().Out()
|
||||
Expect(stdOut).To(ContainSubstring(svcFullName))
|
||||
Expect(stdOut).To(ContainSubstring("Environment Variables"))
|
||||
Expect(stdOut).To(ContainSubstring("REDIS_CLUSTERIP"))
|
||||
@@ -110,31 +110,31 @@ var _ = Describe("odo link command tests for OperatorHub", func() {
|
||||
var bindingName string
|
||||
BeforeEach(func() {
|
||||
bindingName = "sbr-" + helper.RandString(6)
|
||||
helper.Cmd("odo", "link", svcFullName, "--bind-as-files", "--name", bindingName).ShouldPass()
|
||||
helper.Cmd("odo", "link", svcFullName, "--bind-as-files", "--name", bindingName, "--context", commonVar.Context).ShouldPass()
|
||||
})
|
||||
|
||||
It("should dislay the link in odo describe", func() {
|
||||
stdOut := helper.Cmd("odo", "describe").ShouldPass().Out()
|
||||
stdOut := helper.Cmd("odo", "describe", "--context", commonVar.Context).ShouldPass().Out()
|
||||
Expect(stdOut).To(ContainSubstring(svcFullName))
|
||||
})
|
||||
|
||||
When("odo push is executed", func() {
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("odo", "push").ShouldPass()
|
||||
helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass()
|
||||
name := commonVar.CliRunner.GetRunningPodNameByComponent(componentName, commonVar.Project)
|
||||
Expect(name).To(Not(BeEmpty()))
|
||||
})
|
||||
|
||||
It("should find files in component container", func() {
|
||||
helper.Cmd("odo", "exec", "--", "ls", "/project/server.js").ShouldPass()
|
||||
helper.Cmd("odo", "exec", "--context", commonVar.Context, "--", "ls", "/project/server.js").ShouldPass()
|
||||
})
|
||||
|
||||
It("should find bindings for service", func() {
|
||||
helper.Cmd("odo", "exec", "--", "ls", "/bindings/"+bindingName+"/clusterIP").ShouldPass()
|
||||
helper.Cmd("odo", "exec", "--context", commonVar.Context, "--", "ls", "/bindings/"+bindingName+"/clusterIP").ShouldPass()
|
||||
})
|
||||
|
||||
It("should display the link in odo describe", func() {
|
||||
stdOut := helper.Cmd("odo", "describe").ShouldPass().Out()
|
||||
stdOut := helper.Cmd("odo", "describe", "--context", commonVar.Context).ShouldPass().Out()
|
||||
Expect(stdOut).To(ContainSubstring(svcFullName))
|
||||
Expect(stdOut).To(ContainSubstring("Files"))
|
||||
Expect(stdOut).To(ContainSubstring("/bindings/" + bindingName + "/clusterIP"))
|
||||
@@ -149,22 +149,25 @@ var _ = Describe("odo link command tests for OperatorHub", func() {
|
||||
componentName := "api" // this is the name of the component in the devfile
|
||||
helper.CopyExample(filepath.Join("source", "nodejs"), commonVar.Context)
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile-with-link.yaml"), filepath.Join(commonVar.Context, "devfile.yaml"))
|
||||
helper.Cmd("odo", "create", componentName).ShouldPass()
|
||||
helper.Cmd("odo", "create", componentName, "--project", commonVar.Project, "--context", commonVar.Context).ShouldPass()
|
||||
|
||||
helper.Cmd("odo", "push").ShouldPass()
|
||||
helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass()
|
||||
name := commonVar.CliRunner.GetRunningPodNameByComponent(componentName, commonVar.Project)
|
||||
Expect(name).To(Not(BeEmpty()))
|
||||
})
|
||||
|
||||
It("should find files in component container", func() {
|
||||
helper.Cmd("odo", "exec", "--", "ls", "/project/server.js").ShouldPass()
|
||||
helper.Cmd("odo", "exec", "--context", commonVar.Context, "--", "ls", "/project/server.js").ShouldPass()
|
||||
})
|
||||
|
||||
It("should find bindings for service", func() {
|
||||
helper.Cmd("odo", "exec", "--", "ls", "/bindings/redis-link/clusterIP").ShouldPass()
|
||||
helper.Cmd("odo", "exec", "--context", commonVar.Context, "--", "ls", "/bindings/redis-link/clusterIP").ShouldPass()
|
||||
})
|
||||
|
||||
It("should find owner references on link and service", func() {
|
||||
if os.Getenv("KUBERNETES") == "true" {
|
||||
Skip("This is a OpenShift specific scenario, skipping")
|
||||
}
|
||||
args := []string{"get", "servicebinding", "redis-link", "-o", "jsonpath='{.metadata.ownerReferences.*.name}'", "-n", commonVar.Project}
|
||||
commonVar.CliRunner.WaitForRunnerCmdOut(args, 1, true, func(output string) bool {
|
||||
return strings.Contains(output, "api-app")
|
||||
@@ -177,4 +180,121 @@ var _ = Describe("odo link command tests for OperatorHub", func() {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
When("one component is deployed", func() {
|
||||
var context0 string
|
||||
var cmp0 string
|
||||
|
||||
BeforeEach(func() {
|
||||
context0 = helper.CreateNewContext()
|
||||
cmp0 = helper.RandString(5)
|
||||
|
||||
helper.Cmd("odo", "create", "nodejs", cmp0, "--context", context0).ShouldPass()
|
||||
|
||||
helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), context0)
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(context0, "devfile.yaml"))
|
||||
|
||||
helper.Cmd("odo", "push", "--context", context0).ShouldPass()
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
helper.Cmd("odo", "delete", "-f", "--context", context0).ShouldPass()
|
||||
helper.DeleteDir(context0)
|
||||
})
|
||||
|
||||
It("should fail when linking to itself", func() {
|
||||
stdOut := helper.Cmd("odo", "link", cmp0, "--context", context0).ShouldFail().Err()
|
||||
helper.MatchAllInOutput(stdOut, []string{cmp0, "cannot be linked with itself"})
|
||||
})
|
||||
|
||||
It("should fail if the component doesn't exist and the service name doesn't adhere to the <service-type>/<service-name> format", func() {
|
||||
helper.Cmd("odo", "link", "Redis").ShouldFail()
|
||||
helper.Cmd("odo", "link", "Redis/").ShouldFail()
|
||||
helper.Cmd("odo", "link", "/redis-standalone").ShouldFail()
|
||||
})
|
||||
|
||||
When("another component is deployed", func() {
|
||||
var context1 string
|
||||
var cmp1 string
|
||||
|
||||
BeforeEach(func() {
|
||||
context1 = helper.CreateNewContext()
|
||||
cmp1 = helper.RandString(5)
|
||||
|
||||
helper.Cmd("odo", "create", "nodejs", cmp1, "--context", context1).ShouldPass()
|
||||
|
||||
helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), context1)
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfileNestedCompCommands.yaml"), filepath.Join(context1, "devfile.yaml"))
|
||||
|
||||
helper.Cmd("odo", "push", "--context", context1).ShouldPass()
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
helper.Cmd("odo", "delete", "-f", "--context", context1).ShouldPass()
|
||||
helper.DeleteDir(context1)
|
||||
})
|
||||
|
||||
It("should link the two components successfully with service binding operator", func() {
|
||||
|
||||
if os.Getenv("KUBERNETES") == "true" {
|
||||
// service binding operator is not installed on kubernetes
|
||||
Skip("This is a OpenShift specific scenario, skipping")
|
||||
}
|
||||
|
||||
helper.Cmd("odo", "link", cmp1, "--context", context0).ShouldPass()
|
||||
helper.Cmd("odo", "push", "--context", context0).ShouldPass()
|
||||
|
||||
// check the link exists with the specific name
|
||||
ocArgs := []string{"get", "servicebinding", strings.Join([]string{cmp0, cmp1}, "-"), "-o", "jsonpath='{.status.secret}'", "-n", commonVar.Project}
|
||||
helper.WaitForCmdOut("oc", ocArgs, 1, true, func(output string) bool {
|
||||
return strings.Contains(output, strings.Join([]string{cmp0, cmp1}, "-"))
|
||||
})
|
||||
|
||||
// delete the link and undeploy it
|
||||
helper.Cmd("odo", "unlink", cmp1, "--context", context0).ShouldPass()
|
||||
helper.Cmd("odo", "push", "--context", context0).ShouldPass()
|
||||
commonVar.CliRunner.WaitAndCheckForTerminatingState("servicebinding", commonVar.Project, 1)
|
||||
})
|
||||
|
||||
It("should link the two components successfully without service binding operator", func() {
|
||||
|
||||
if os.Getenv("KUBERNETES") != "true" {
|
||||
// service binding operator is not installed on kubernetes
|
||||
Skip("This is a Kubernetes specific scenario, skipping")
|
||||
}
|
||||
|
||||
helper.Cmd("odo", "link", cmp1, "--context", context0).ShouldPass()
|
||||
helper.Cmd("odo", "push", "--context", context0).ShouldPass()
|
||||
|
||||
// check the secrets exists with the specific name
|
||||
secrets := commonVar.CliRunner.GetSecrets(commonVar.Project)
|
||||
Expect(secrets).To(ContainSubstring(fmt.Sprintf("%v-%v", cmp0, cmp1)))
|
||||
|
||||
envFromValues := commonVar.CliRunner.GetEnvRefNames(cmp0, "app", commonVar.Project)
|
||||
envFound := false
|
||||
for i := range envFromValues {
|
||||
if strings.Contains(envFromValues[i], fmt.Sprintf("%v-%v", cmp0, cmp1)) {
|
||||
envFound = true
|
||||
}
|
||||
}
|
||||
Expect(envFound).To(BeTrue())
|
||||
|
||||
// delete the link and undeploy it
|
||||
helper.Cmd("odo", "unlink", cmp1, "--context", context0).ShouldPass()
|
||||
helper.Cmd("odo", "push", "--context", context0).ShouldPass()
|
||||
|
||||
// check the secrets exists with the specific name
|
||||
secrets = commonVar.CliRunner.GetSecrets(commonVar.Project)
|
||||
Expect(secrets).NotTo(ContainSubstring(fmt.Sprintf("%v-%v", cmp0, cmp1)))
|
||||
envFromValues = commonVar.CliRunner.GetEnvRefNames(cmp0, "app", commonVar.Project)
|
||||
envFound = false
|
||||
for i := range envFromValues {
|
||||
if strings.Contains(envFromValues[i], fmt.Sprintf("%v-%v", cmp0, cmp1)) {
|
||||
envFound = true
|
||||
}
|
||||
}
|
||||
Expect(envFound).To(BeFalse())
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -33,7 +33,10 @@ var _ = Describe("odo service command tests for OperatorHub", func() {
|
||||
BeforeEach(func() {
|
||||
// wait till odo can see that all operators installed by setup script in the namespace
|
||||
odoArgs := []string{"catalog", "list", "services"}
|
||||
operators := []string{"redis-operator", "service-binding-operator"}
|
||||
operators := []string{"redis-operator"}
|
||||
if os.Getenv("KUBERNETES") != "true" {
|
||||
operators = append(operators, "service-binding-operator")
|
||||
}
|
||||
for _, operator := range operators {
|
||||
helper.WaitForCmdOut("odo", odoArgs, 5, true, func(output string) bool {
|
||||
return strings.Contains(output, operator)
|
||||
@@ -69,13 +72,13 @@ var _ = Describe("odo service command tests for OperatorHub", func() {
|
||||
helper.CopyExample(filepath.Join("source", "nodejs"), commonVar.Context)
|
||||
// change the app name to avoid conflicts
|
||||
appName := helper.RandString(5)
|
||||
helper.Cmd("odo", "create", "nodejs", "--app", appName).ShouldPass().Out()
|
||||
helper.Cmd("odo", "config", "set", "Memory", "300M", "-f").ShouldPass()
|
||||
helper.Cmd("odo", "create", "nodejs", "--app", appName, "--context", commonVar.Context).ShouldPass().Out()
|
||||
helper.Cmd("odo", "config", "set", "Memory", "300M", "-f", "--context", commonVar.Context).ShouldPass()
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
// we do this because for these specific tests we dont delete the project
|
||||
helper.Cmd("odo", "delete", "--all", "-f").ShouldPass().Out()
|
||||
helper.Cmd("odo", "delete", "--all", "-f", "--context", commonVar.Context).ShouldPass().Out()
|
||||
})
|
||||
|
||||
When("creating a postgres operand with params", func() {
|
||||
@@ -85,18 +88,18 @@ var _ = Describe("odo service command tests for OperatorHub", func() {
|
||||
operandName = helper.RandString(10)
|
||||
helper.Cmd("odo", "service", "create", postgresDatabase, operandName, "-p",
|
||||
"databaseName=odo", "-p", "size=1", "-p", "databaseUser=odo", "-p",
|
||||
"databaseStorageRequest=1Gi", "-p", "databasePassword=odopasswd").ShouldPass().Out()
|
||||
"databaseStorageRequest=1Gi", "-p", "databasePassword=odopasswd", "--context", commonVar.Context).ShouldPass().Out()
|
||||
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
helper.Cmd("odo", "service", "delete", fmt.Sprintf("Database/%s", operandName), "-f").ShouldPass().Out()
|
||||
helper.Cmd("odo", "push").ShouldPass().Out()
|
||||
helper.Cmd("odo", "service", "delete", fmt.Sprintf("Database/%s", operandName), "-f", "--context", commonVar.Context).ShouldPass().Out()
|
||||
helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass().Out()
|
||||
})
|
||||
|
||||
When("odo push is executed", func() {
|
||||
BeforeEach(func() {
|
||||
helper.Cmd("odo", "push").ShouldPass().Out()
|
||||
helper.Cmd("odo", "push", "--context", commonVar.Context).ShouldPass().Out()
|
||||
})
|
||||
|
||||
It("should create pods in running state", func() {
|
||||
@@ -105,7 +108,7 @@ var _ = Describe("odo service command tests for OperatorHub", func() {
|
||||
|
||||
It("should list the service", func() {
|
||||
// now test listing of the service using odo
|
||||
stdOut := helper.Cmd("odo", "service", "list").ShouldPass().Out()
|
||||
stdOut := helper.Cmd("odo", "service", "list", "--context", commonVar.Context).ShouldPass().Out()
|
||||
Expect(stdOut).To(ContainSubstring(fmt.Sprintf("Database/%s", operandName)))
|
||||
})
|
||||
})
|
||||
@@ -168,9 +171,11 @@ var _ = Describe("odo service command tests for OperatorHub", func() {
|
||||
|
||||
When("a nodejs component is created", func() {
|
||||
|
||||
var cmpName string
|
||||
BeforeEach(func() {
|
||||
cmpName = helper.RandString(4)
|
||||
helper.CopyExample(filepath.Join("source", "nodejs"), commonVar.Context)
|
||||
helper.Cmd("odo", "create", "nodejs").ShouldPass()
|
||||
helper.Cmd("odo", "create", "nodejs", cmpName).ShouldPass()
|
||||
helper.Cmd("odo", "config", "set", "Memory", "300M", "-f").ShouldPass()
|
||||
})
|
||||
|
||||
@@ -190,9 +195,6 @@ var _ = Describe("odo service command tests for OperatorHub", func() {
|
||||
})
|
||||
|
||||
It("should fail if the provided service doesn't exist in the namespace", func() {
|
||||
if os.Getenv("KUBERNETES") == "true" {
|
||||
Skip("This is a OpenShift specific scenario, skipping")
|
||||
}
|
||||
stdOut := helper.Cmd("odo", "link", "Redis/redis-standalone").ShouldFail().Err()
|
||||
Expect(stdOut).To(ContainSubstring("couldn't find service named %q", "Redis/redis-standalone"))
|
||||
})
|
||||
@@ -294,9 +296,6 @@ var _ = Describe("odo service command tests for OperatorHub", func() {
|
||||
When("a link is created with the service", func() {
|
||||
var stdOut string
|
||||
BeforeEach(func() {
|
||||
if os.Getenv("KUBERNETES") == "true" {
|
||||
Skip("This is a OpenShift specific scenario, skipping")
|
||||
}
|
||||
stdOut = helper.Cmd("odo", "link", "Redis/redis").ShouldPass().Out()
|
||||
})
|
||||
|
||||
@@ -311,9 +310,6 @@ var _ = Describe("odo service command tests for OperatorHub", func() {
|
||||
|
||||
When("the link is deleted", func() {
|
||||
BeforeEach(func() {
|
||||
if os.Getenv("KUBERNETES") == "true" {
|
||||
Skip("This is a OpenShift specific scenario, skipping")
|
||||
}
|
||||
stdOut = helper.Cmd("odo", "unlink", "Redis/redis").ShouldPass().Out()
|
||||
})
|
||||
|
||||
@@ -464,10 +460,14 @@ var _ = Describe("odo service command tests for OperatorHub", func() {
|
||||
})
|
||||
|
||||
It("should create the link with the specified name", func() {
|
||||
args := []string{"get", "servicebinding", linkName, "-n", commonVar.Project}
|
||||
commonVar.CliRunner.WaitForRunnerCmdOut(args, 1, true, func(output string) bool {
|
||||
return strings.Contains(output, linkName)
|
||||
})
|
||||
envFromValues := commonVar.CliRunner.GetEnvRefNames(cmpName, "app", commonVar.Project)
|
||||
envFound := false
|
||||
for i := range envFromValues {
|
||||
if strings.Contains(envFromValues[i], linkName) {
|
||||
envFound = true
|
||||
}
|
||||
}
|
||||
Expect(envFound).To(BeTrue())
|
||||
})
|
||||
})
|
||||
|
||||
@@ -487,11 +487,22 @@ var _ = Describe("odo service command tests for OperatorHub", func() {
|
||||
helper.Cmd("odo", "push").ShouldPass()
|
||||
})
|
||||
|
||||
It("should create a servicebinding resource with bindAsFiles set to true", func() {
|
||||
args := []string{"get", "servicebinding", linkName, "-o", "jsonpath='{.spec.bindAsFiles}'", "-n", commonVar.Project}
|
||||
commonVar.CliRunner.WaitForRunnerCmdOut(args, 1, true, func(output string) bool {
|
||||
return strings.Contains(output, "true")
|
||||
})
|
||||
It("should create a link with bindAsFiles set to true", func() {
|
||||
// check the volume name and mount paths for the container
|
||||
deploymentName, err := util.NamespaceKubernetesObject(cmpName, "app")
|
||||
if err != nil {
|
||||
Expect(err).To(BeNil())
|
||||
}
|
||||
volNamesAndPaths := commonVar.CliRunner.GetVolumeMountNamesandPathsFromContainer(deploymentName, "runtime", commonVar.Project)
|
||||
mountFound := false
|
||||
volNamesAndPathsArr := strings.Fields(volNamesAndPaths)
|
||||
for _, volNamesAndPath := range volNamesAndPathsArr {
|
||||
volNamesAndPathArr := strings.Split(volNamesAndPath, ":")
|
||||
if strings.Contains(volNamesAndPathArr[0], linkName) {
|
||||
mountFound = true
|
||||
}
|
||||
}
|
||||
Expect(mountFound).To(BeTrue())
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -547,83 +558,5 @@ spec:`
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
When("one component is deployed", func() {
|
||||
var context0 string
|
||||
var cmp0 string
|
||||
|
||||
BeforeEach(func() {
|
||||
if os.Getenv("KUBERNETES") == "true" {
|
||||
Skip("This is a OpenShift specific scenario, skipping")
|
||||
}
|
||||
|
||||
context0 = helper.CreateNewContext()
|
||||
cmp0 = helper.RandString(5)
|
||||
|
||||
helper.Cmd("odo", "create", "nodejs", cmp0, "--context", context0).ShouldPass()
|
||||
helper.Cmd("odo", "config", "set", "Memory", "300M", "-f", "--context", context0).ShouldPass()
|
||||
|
||||
helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), context0)
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(context0, "devfile.yaml"))
|
||||
|
||||
helper.Cmd("odo", "push", "--context", context0).ShouldPass()
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
helper.Cmd("odo", "delete", "-f", "--context", context0).ShouldPass()
|
||||
helper.DeleteDir(context0)
|
||||
})
|
||||
|
||||
It("should fail when linking to itself", func() {
|
||||
stdOut := helper.Cmd("odo", "link", cmp0, "--context", context0).ShouldFail().Err()
|
||||
helper.MatchAllInOutput(stdOut, []string{cmp0, "cannot be linked with itself"})
|
||||
})
|
||||
|
||||
It("should fail if the component doesn't exist and the service name doesn't adhere to the <service-type>/<service-name> format", func() {
|
||||
helper.Cmd("odo", "link", "Redis").ShouldFail()
|
||||
helper.Cmd("odo", "link", "Redis/").ShouldFail()
|
||||
helper.Cmd("odo", "link", "/redis-standalone").ShouldFail()
|
||||
})
|
||||
|
||||
When("another component is deployed", func() {
|
||||
var context1 string
|
||||
var cmp1 string
|
||||
|
||||
BeforeEach(func() {
|
||||
context1 = helper.CreateNewContext()
|
||||
cmp1 = helper.RandString(5)
|
||||
|
||||
helper.Cmd("odo", "create", "nodejs", cmp1, "--context", context1).ShouldPass()
|
||||
helper.Cmd("odo", "config", "set", "Memory", "300M", "-f", "--context", context1).ShouldPass()
|
||||
|
||||
helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), context1)
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfileNestedCompCommands.yaml"), filepath.Join(context1, "devfile.yaml"))
|
||||
|
||||
helper.Cmd("odo", "push", "--context", context1).ShouldPass()
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
helper.Cmd("odo", "delete", "-f", "--context", context1).ShouldPass()
|
||||
helper.DeleteDir(context1)
|
||||
})
|
||||
|
||||
It("should link the two components successfully", func() {
|
||||
|
||||
helper.Cmd("odo", "link", cmp1, "--context", context0).ShouldPass()
|
||||
helper.Cmd("odo", "push", "--context", context0).ShouldPass()
|
||||
|
||||
// check the link exists with the specific name
|
||||
ocArgs := []string{"get", "servicebinding", strings.Join([]string{cmp0, cmp1}, "-"), "-o", "jsonpath='{.status.secret}'", "-n", commonVar.Project}
|
||||
helper.WaitForCmdOut("oc", ocArgs, 1, true, func(output string) bool {
|
||||
return strings.Contains(output, strings.Join([]string{cmp0, cmp1}, "-"))
|
||||
})
|
||||
|
||||
// delete the link and undeploy it
|
||||
helper.Cmd("odo", "unlink", cmp1, "--context", context0).ShouldPass()
|
||||
helper.Cmd("odo", "push", "--context", context0).ShouldPass()
|
||||
commonVar.CliRunner.WaitAndCheckForTerminatingState("servicebinding", commonVar.Project, 1)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -18,40 +18,10 @@ package v1alpha1
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
const (
|
||||
// BindingReady indicates that the overall sbr succeeded
|
||||
BindingReady string = "Ready"
|
||||
// CollectionReady indicates readiness for collection and persistance of intermediate manifests
|
||||
CollectionReady string = "CollectionReady"
|
||||
// InjectionReady indicates readiness to change application manifests to use those intermediate manifests
|
||||
// If status is true, it indicates that the binding succeeded
|
||||
InjectionReady string = "InjectionReady"
|
||||
// EmptyServiceSelectorsReason is used when the ServiceBinding has empty
|
||||
// services.
|
||||
EmptyServiceSelectorsReason = "EmptyServiceSelectors"
|
||||
// EmptyApplicationReason is used when the ServiceBinding has empty
|
||||
// application.
|
||||
EmptyApplicationReason = "EmptyApplication"
|
||||
// ApplicationNotFoundReason is used when the application is not found.
|
||||
ApplicationNotFoundReason = "ApplicationNotFound"
|
||||
// ServiceNotFoundReason is used when the service is not found.
|
||||
ServiceNotFoundReason = "ServiceNotFound"
|
||||
|
||||
BindingInjectedReason = "BindingInjected"
|
||||
|
||||
DataCollectedReason = "DataCollected"
|
||||
|
||||
// NamingStrategyError is used when naming strategy/template used is incorrect
|
||||
NamingStrategyError = "NamingStrategyError"
|
||||
|
||||
finalizerName = "finalizer.servicebinding.openshift.io"
|
||||
)
|
||||
|
||||
var templates = map[string]string{
|
||||
"none": "{{ .name }}",
|
||||
"uppercase": "{{ .service.kind | upper }}_{{ .name | upper }}",
|
||||
@@ -85,8 +55,7 @@ type ServiceBindingSpec struct {
|
||||
|
||||
// Application is used to identify the application connecting to the
|
||||
// backing service operator.
|
||||
// +optional
|
||||
Application *Application `json:"application,omitempty"`
|
||||
Application Application `json:"application"`
|
||||
|
||||
// DetectBindingResources is flag used to bind all non-bindable variables from
|
||||
// different subresources owned by backing operator CR.
|
||||
@@ -250,6 +219,10 @@ func (spec *ServiceBindingSpec) NamingTemplate() string {
|
||||
}
|
||||
}
|
||||
|
||||
func (sb *ServiceBinding) HasDeletionTimestamp() bool {
|
||||
return !sb.DeletionTimestamp.IsZero()
|
||||
}
|
||||
|
||||
// Returns GVR of reference if available, otherwise error
|
||||
func (ref *Ref) GroupVersionResource() (*schema.GroupVersionResource, error) {
|
||||
if ref.Resource == "" {
|
||||
@@ -274,24 +247,6 @@ func (ref *Ref) GroupVersionKind() (*schema.GroupVersionKind, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (sb *ServiceBinding) MaybeAddFinalizer() bool {
|
||||
finalizers := sb.GetFinalizers()
|
||||
for _, f := range finalizers {
|
||||
if f == finalizerName {
|
||||
return false
|
||||
}
|
||||
}
|
||||
sb.SetFinalizers(append(finalizers, finalizerName))
|
||||
return true
|
||||
}
|
||||
|
||||
func (sb *ServiceBinding) MaybeRemoveFinalizer() bool {
|
||||
finalizers := sb.GetFinalizers()
|
||||
for i, f := range finalizers {
|
||||
if f == finalizerName {
|
||||
sb.SetFinalizers(append(finalizers[:i], finalizers[i+1:]...))
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
func (r *ServiceBinding) StatusConditions() []metav1.Condition {
|
||||
return r.Status.Conditions
|
||||
}
|
||||
57
vendor/github.com/redhat-developer/service-binding-operator/apis/binding/v1alpha1/servicebinding_webhook.go
generated
vendored
Normal file
57
vendor/github.com/redhat-developer/service-binding-operator/apis/binding/v1alpha1/servicebinding_webhook.go
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
Copyright 2021.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"github.com/redhat-developer/service-binding-operator/apis"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/webhook"
|
||||
)
|
||||
|
||||
// log is for logging in this package.
|
||||
var log = logf.Log.WithName("WebHook ServiceBinding")
|
||||
|
||||
func (r *ServiceBinding) SetupWebhookWithManager(mgr ctrl.Manager) error {
|
||||
return ctrl.NewWebhookManagedBy(mgr).
|
||||
For(r).
|
||||
Complete()
|
||||
}
|
||||
|
||||
// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
|
||||
|
||||
// TODO(user): change verbs to "verbs=create;update;delete" if you want to enable deletion validation.
|
||||
// +kubebuilder:webhook:path=/validate-binding-operators-coreos-com-v1alpha1-servicebinding,mutating=false,failurePolicy=fail,sideEffects=None,groups=binding.operators.coreos.com,resources=servicebindings,verbs=update,versions=v1alpha1,name=vservicebinding.kb.io,admissionReviewVersions={v1beta1}
|
||||
|
||||
var _ webhook.Validator = &ServiceBinding{}
|
||||
|
||||
// ValidateCreate implements webhook.Validator so a webhook will be registered for the type
|
||||
func (r *ServiceBinding) ValidateCreate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
|
||||
func (r *ServiceBinding) ValidateUpdate(old runtime.Object) error {
|
||||
err := apis.CanUpdateBinding(r)
|
||||
if err != nil {
|
||||
log.Error(err, "Update failed")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// ValidateDelete implements webhook.Validator so a webhook will be registered for the type
|
||||
func (r *ServiceBinding) ValidateDelete() error {
|
||||
return nil
|
||||
}
|
||||
@@ -22,7 +22,7 @@ package v1alpha1
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
@@ -212,11 +212,7 @@ func (in *ServiceBindingSpec) DeepCopyInto(out *ServiceBindingSpec) {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.Application != nil {
|
||||
in, out := &in.Application, &out.Application
|
||||
*out = new(Application)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
in.Application.DeepCopyInto(&out.Application)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceBindingSpec.
|
||||
51
vendor/github.com/redhat-developer/service-binding-operator/apis/common.go
generated
vendored
Normal file
51
vendor/github.com/redhat-developer/service-binding-operator/apis/common.go
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
package apis
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
const finalizerName = "finalizer.servicebinding.openshift.io"
|
||||
|
||||
func MaybeAddFinalizer(obj Object) bool {
|
||||
finalizers := obj.GetFinalizers()
|
||||
for _, f := range finalizers {
|
||||
if f == finalizerName {
|
||||
return false
|
||||
}
|
||||
}
|
||||
obj.SetFinalizers(append(finalizers, finalizerName))
|
||||
return true
|
||||
}
|
||||
|
||||
func MaybeRemoveFinalizer(obj Object) bool {
|
||||
finalizers := obj.GetFinalizers()
|
||||
for i, f := range finalizers {
|
||||
if f == finalizerName {
|
||||
obj.SetFinalizers(append(finalizers[:i], finalizers[i+1:]...))
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type Object interface {
|
||||
runtime.Object
|
||||
GetFinalizers() []string
|
||||
SetFinalizers([]string)
|
||||
HasDeletionTimestamp() bool
|
||||
StatusConditions() []metav1.Condition
|
||||
}
|
||||
|
||||
func CanUpdateBinding(obj Object) error {
|
||||
if obj.HasDeletionTimestamp() {
|
||||
return nil
|
||||
}
|
||||
if meta.IsStatusConditionTrue(obj.StatusConditions(), BindingReady) {
|
||||
return errors.New("cannot update Service Binding if 'Ready' condition is True. If you want to rebind to another service/application, remove this binding and create a new one.")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,6 +1,40 @@
|
||||
package v1alpha1
|
||||
package apis
|
||||
|
||||
import v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
import (
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
const (
|
||||
// BindingReady indicates that the overall sbr succeeded
|
||||
BindingReady string = "Ready"
|
||||
|
||||
// CollectionReady indicates readiness for collection and persistance of intermediate manifests
|
||||
CollectionReady string = "CollectionReady"
|
||||
|
||||
// InjectionReady indicates readiness to change application manifests to use those intermediate manifests
|
||||
// If status is true, it indicates that the binding succeeded
|
||||
InjectionReady string = "InjectionReady"
|
||||
|
||||
// EmptyServiceSelectorsReason is used when the ServiceBinding has empty
|
||||
// services.
|
||||
EmptyApplicationReason = "EmptyApplication"
|
||||
|
||||
// EmptyApplicationReason is used when the ServiceBinding has empty
|
||||
// application.
|
||||
ApplicationNotFoundReason = "ApplicationNotFound"
|
||||
|
||||
// ApplicationNotFoundReason is used when the application is not found.
|
||||
ServiceNotFoundReason = "ServiceNotFound"
|
||||
|
||||
// ServiceNotFoundReason is used when the service is not found.
|
||||
BindingInjectedReason = "BindingInjected"
|
||||
|
||||
// DataCollectedReason indicates that bindings are collected successfully
|
||||
DataCollectedReason = "DataCollected"
|
||||
|
||||
// RequiredBindingNotFound when some mandatory bindings are missing
|
||||
RequiredBindingNotFound = "RequiredBindingNotFound"
|
||||
)
|
||||
|
||||
type conditionsBuilder struct {
|
||||
cndType string
|
||||
40
vendor/github.com/redhat-developer/service-binding-operator/apis/spec/v1alpha2/groupversion_info.go
generated
vendored
Normal file
40
vendor/github.com/redhat-developer/service-binding-operator/apis/spec/v1alpha2/groupversion_info.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
Copyright 2021.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package v1alpha2 contains API Schema definitions for the spec v1alpha2 API group
|
||||
// +kubebuilder:object:generate=true
|
||||
// +groupName=service.binding
|
||||
package v1alpha2
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"sigs.k8s.io/controller-runtime/pkg/scheme"
|
||||
)
|
||||
|
||||
var (
|
||||
// GroupVersion is group version used to register these objects
|
||||
GroupVersion = schema.GroupVersion{Group: "service.binding", Version: "v1alpha2"}
|
||||
|
||||
GroupVersionResource = GroupVersion.WithResource("servicebindings")
|
||||
|
||||
GroupVersionKind = GroupVersion.WithKind("ServiceBinding")
|
||||
|
||||
// SchemeBuilder is used to add go types to the GroupVersionKind scheme
|
||||
SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
|
||||
|
||||
// AddToScheme adds the types in this group-version to the given scheme.
|
||||
AddToScheme = SchemeBuilder.AddToScheme
|
||||
)
|
||||
166
vendor/github.com/redhat-developer/service-binding-operator/apis/spec/v1alpha2/servicebinding_types.go
generated
vendored
Normal file
166
vendor/github.com/redhat-developer/service-binding-operator/apis/spec/v1alpha2/servicebinding_types.go
generated
vendored
Normal file
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
Copyright 2021.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1alpha2
|
||||
|
||||
import (
|
||||
"errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
// ServiceBindingApplicationReference defines a subset of corev1.ObjectReference with extensions
|
||||
type ServiceBindingApplicationReference struct {
|
||||
// API version of the referent.
|
||||
APIVersion string `json:"apiVersion"`
|
||||
// Kind of the referent.
|
||||
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||
Kind string `json:"kind"`
|
||||
// Name of the referent.
|
||||
// More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
Name string `json:"name,omitempty"`
|
||||
// Selector is a query that selects the application or applications to bind the service to
|
||||
Selector metav1.LabelSelector `json:"selector,omitempty"`
|
||||
// Containers describes which containers in a Pod should be bound to
|
||||
Containers []string `json:"containers,omitempty"`
|
||||
}
|
||||
|
||||
// ServiceBindingServiceReference defines a subset of corev1.ObjectReference
|
||||
type ServiceBindingServiceReference struct {
|
||||
// API version of the referent.
|
||||
APIVersion string `json:"apiVersion"`
|
||||
// Kind of the referent.
|
||||
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||
Kind string `json:"kind"`
|
||||
// Name of the referent.
|
||||
// More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// ServiceBindingSecretReference defines a mirror of corev1.LocalObjectReference
|
||||
type ServiceBindingSecretReference struct {
|
||||
// Name of the referent secret.
|
||||
// More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// EnvMapping defines a mapping from the value of a Secret entry to an environment variable
|
||||
type EnvMapping struct {
|
||||
// Name is the name of the environment variable
|
||||
Name string `json:"name"`
|
||||
// Key is the key in the Secret that will be exposed
|
||||
Key string `json:"key"`
|
||||
}
|
||||
|
||||
// ServiceBindingSpec defines the desired state of ServiceBinding
|
||||
type ServiceBindingSpec struct {
|
||||
// Name is the name of the service as projected into the application container. Defaults to .metadata.name.
|
||||
// +kubebuilder:validation:Pattern=`^[a-z0-9\-\.]*$`
|
||||
// +kubebuilder:validation:MaxLength=253
|
||||
Name string `json:"name,omitempty"`
|
||||
// Type is the type of the service as projected into the application container
|
||||
Type string `json:"type,omitempty"`
|
||||
// Provider is the provider of the service as projected into the application container
|
||||
Provider string `json:"provider,omitempty"`
|
||||
// Application is a reference to an object
|
||||
Application ServiceBindingApplicationReference `json:"application"`
|
||||
// Service is a reference to an object that fulfills the ProvisionedService duck type
|
||||
Service ServiceBindingServiceReference `json:"service"`
|
||||
// Env is the collection of mappings from Secret entries to environment variables
|
||||
Env []EnvMapping `json:"env,omitempty"`
|
||||
}
|
||||
|
||||
// ServiceBindingStatus defines the observed state of ServiceBinding
|
||||
type ServiceBindingStatus struct {
|
||||
// ObservedGeneration is the 'Generation' of the ServiceBinding that
|
||||
// was last processed by the controller.
|
||||
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
|
||||
|
||||
// Conditions are the conditions of this ServiceBinding
|
||||
Conditions []metav1.Condition `json:"conditions,omitempty"`
|
||||
|
||||
// Binding exposes the projected secret for this ServiceBinding
|
||||
Binding *ServiceBindingSecretReference `json:"binding,omitempty"`
|
||||
}
|
||||
|
||||
// +operator-sdk:gen-csv:customresourcedefinitions.displayName="Service Binding (spec API)"
|
||||
// +kubebuilder:object:root=true
|
||||
// +kubebuilder:storageversion
|
||||
// +kubebuilder:subresource:status
|
||||
// +kubebuilder:printcolumn:name="Ready",type=string,JSONPath=`.status.conditions[?(@.type=="Ready")].status`
|
||||
// +kubebuilder:printcolumn:name="Reason",type=string,JSONPath=`.status.conditions[?(@.type=="Ready")].reason`
|
||||
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
|
||||
// ServiceBinding is the Schema for the servicebindings API
|
||||
type ServiceBinding struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec ServiceBindingSpec `json:"spec,omitempty"`
|
||||
Status ServiceBindingStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
|
||||
// ServiceBindingList contains a list of ServiceBinding
|
||||
type ServiceBindingList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
|
||||
Items []ServiceBinding `json:"items"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
SchemeBuilder.Register(&ServiceBinding{}, &ServiceBindingList{})
|
||||
}
|
||||
|
||||
func (ref *ServiceBindingServiceReference) GroupVersionResource() (*schema.GroupVersionResource, error) {
|
||||
return nil, errors.New("Resource undefined")
|
||||
}
|
||||
|
||||
func (ref *ServiceBindingServiceReference) GroupVersionKind() (*schema.GroupVersionKind, error) {
|
||||
typeMeta := &metav1.TypeMeta{Kind: ref.Kind, APIVersion: ref.APIVersion}
|
||||
gvk := typeMeta.GroupVersionKind()
|
||||
return &gvk, nil
|
||||
}
|
||||
|
||||
func (ref *ServiceBindingApplicationReference) GroupVersionResource() (*schema.GroupVersionResource, error) {
|
||||
return nil, errors.New("Resource undefined")
|
||||
}
|
||||
|
||||
func (ref *ServiceBindingApplicationReference) GroupVersionKind() (*schema.GroupVersionKind, error) {
|
||||
typeMeta := &metav1.TypeMeta{Kind: ref.Kind, APIVersion: ref.APIVersion}
|
||||
gvk := typeMeta.GroupVersionKind()
|
||||
return &gvk, nil
|
||||
}
|
||||
|
||||
func (sb *ServiceBinding) AsOwnerReference() metav1.OwnerReference {
|
||||
var ownerRefController bool = true
|
||||
return metav1.OwnerReference{
|
||||
Name: sb.Name,
|
||||
UID: sb.UID,
|
||||
Kind: sb.Kind,
|
||||
APIVersion: sb.APIVersion,
|
||||
Controller: &ownerRefController,
|
||||
}
|
||||
}
|
||||
|
||||
func (sb *ServiceBinding) HasDeletionTimestamp() bool {
|
||||
return !sb.DeletionTimestamp.IsZero()
|
||||
}
|
||||
|
||||
func (r *ServiceBinding) StatusConditions() []metav1.Condition {
|
||||
return r.Status.Conditions
|
||||
}
|
||||
61
vendor/github.com/redhat-developer/service-binding-operator/apis/spec/v1alpha2/servicebinding_webhook.go
generated
vendored
Normal file
61
vendor/github.com/redhat-developer/service-binding-operator/apis/spec/v1alpha2/servicebinding_webhook.go
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
Copyright 2021.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either expr@wip
|
||||
ess or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1alpha2
|
||||
|
||||
import (
|
||||
"github.com/redhat-developer/service-binding-operator/apis"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/webhook"
|
||||
)
|
||||
|
||||
// log is for logging in this package.
|
||||
var log = logf.Log.WithName("WebHook Spec ServiceBinding")
|
||||
|
||||
func (r *ServiceBinding) SetupWebhookWithManager(mgr ctrl.Manager) error {
|
||||
return ctrl.NewWebhookManagedBy(mgr).
|
||||
For(r).
|
||||
Complete()
|
||||
}
|
||||
|
||||
// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
|
||||
|
||||
// TODO(user): change verbs to "verbs=create;update;delete" if you want to enable deletion validation.
|
||||
// +kubebuilder:webhook:path=/validate-service-binding-v1alpha2-servicebinding,mutating=false,failurePolicy=fail,sideEffects=None,groups=service.binding,resources=servicebindings,verbs=update,versions=v1alpha2,name=vspecservicebinding.kb.io,admissionReviewVersions={v1beta1}
|
||||
|
||||
var _ webhook.Validator = &ServiceBinding{}
|
||||
|
||||
// ValidateCreate implements webhook.Validator so a webhook will be registered for the type
|
||||
func (r *ServiceBinding) ValidateCreate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
|
||||
func (r *ServiceBinding) ValidateUpdate(old runtime.Object) error {
|
||||
err := apis.CanUpdateBinding(r)
|
||||
if err != nil {
|
||||
log.Error(err, "Update failed")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// ValidateDelete implements webhook.Validator so a webhook will be registered for the type
|
||||
func (r *ServiceBinding) ValidateDelete() error {
|
||||
return nil
|
||||
}
|
||||
200
vendor/github.com/redhat-developer/service-binding-operator/apis/spec/v1alpha2/zz_generated.deepcopy.go
generated
vendored
Normal file
200
vendor/github.com/redhat-developer/service-binding-operator/apis/spec/v1alpha2/zz_generated.deepcopy.go
generated
vendored
Normal file
@@ -0,0 +1,200 @@
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright 2021.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by controller-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha2
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *EnvMapping) DeepCopyInto(out *EnvMapping) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvMapping.
|
||||
func (in *EnvMapping) DeepCopy() *EnvMapping {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(EnvMapping)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ServiceBinding) DeepCopyInto(out *ServiceBinding) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceBinding.
|
||||
func (in *ServiceBinding) DeepCopy() *ServiceBinding {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ServiceBinding)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *ServiceBinding) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ServiceBindingApplicationReference) DeepCopyInto(out *ServiceBindingApplicationReference) {
|
||||
*out = *in
|
||||
in.Selector.DeepCopyInto(&out.Selector)
|
||||
if in.Containers != nil {
|
||||
in, out := &in.Containers, &out.Containers
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceBindingApplicationReference.
|
||||
func (in *ServiceBindingApplicationReference) DeepCopy() *ServiceBindingApplicationReference {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ServiceBindingApplicationReference)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ServiceBindingList) DeepCopyInto(out *ServiceBindingList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]ServiceBinding, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceBindingList.
|
||||
func (in *ServiceBindingList) DeepCopy() *ServiceBindingList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ServiceBindingList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *ServiceBindingList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ServiceBindingSecretReference) DeepCopyInto(out *ServiceBindingSecretReference) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceBindingSecretReference.
|
||||
func (in *ServiceBindingSecretReference) DeepCopy() *ServiceBindingSecretReference {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ServiceBindingSecretReference)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ServiceBindingServiceReference) DeepCopyInto(out *ServiceBindingServiceReference) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceBindingServiceReference.
|
||||
func (in *ServiceBindingServiceReference) DeepCopy() *ServiceBindingServiceReference {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ServiceBindingServiceReference)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ServiceBindingSpec) DeepCopyInto(out *ServiceBindingSpec) {
|
||||
*out = *in
|
||||
in.Application.DeepCopyInto(&out.Application)
|
||||
out.Service = in.Service
|
||||
if in.Env != nil {
|
||||
in, out := &in.Env, &out.Env
|
||||
*out = make([]EnvMapping, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceBindingSpec.
|
||||
func (in *ServiceBindingSpec) DeepCopy() *ServiceBindingSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ServiceBindingSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ServiceBindingStatus) DeepCopyInto(out *ServiceBindingStatus) {
|
||||
*out = *in
|
||||
if in.Conditions != nil {
|
||||
in, out := &in.Conditions, &out.Conditions
|
||||
*out = make([]v1.Condition, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.Binding != nil {
|
||||
in, out := &in.Binding, &out.Binding
|
||||
*out = new(ServiceBindingSecretReference)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceBindingStatus.
|
||||
func (in *ServiceBindingStatus) DeepCopy() *ServiceBindingStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ServiceBindingStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
133
vendor/github.com/redhat-developer/service-binding-operator/pkg/binding/annotationmapper.go
generated
vendored
Normal file
133
vendor/github.com/redhat-developer/service-binding-operator/pkg/binding/annotationmapper.go
generated
vendored
Normal file
@@ -0,0 +1,133 @@
|
||||
package binding
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type UnstructuredResourceReader func(namespace string, name string) (*unstructured.Unstructured, error)
|
||||
|
||||
type secretConfigMapReader struct {
|
||||
configMapReader UnstructuredResourceReader
|
||||
secretReader UnstructuredResourceReader
|
||||
}
|
||||
|
||||
type annotationBackedDefinitionBuilder struct {
|
||||
*secretConfigMapReader
|
||||
name string
|
||||
value string
|
||||
}
|
||||
|
||||
var _ DefinitionBuilder = (*annotationBackedDefinitionBuilder)(nil)
|
||||
|
||||
type modelKey string
|
||||
|
||||
const (
|
||||
pathModelKey modelKey = "path"
|
||||
objectTypeModelKey modelKey = "objectType"
|
||||
sourceKeyModelKey modelKey = "sourceKey"
|
||||
sourceValueModelKey modelKey = "sourceValue"
|
||||
elementTypeModelKey modelKey = "elementType"
|
||||
AnnotationPrefix = "service.binding"
|
||||
)
|
||||
|
||||
func NewDefinitionBuilder(annotationName string, annotationValue string, configMapReader UnstructuredResourceReader, secretReader UnstructuredResourceReader) *annotationBackedDefinitionBuilder {
|
||||
return &annotationBackedDefinitionBuilder{
|
||||
name: annotationName,
|
||||
value: annotationValue,
|
||||
secretConfigMapReader: &secretConfigMapReader{
|
||||
configMapReader: configMapReader,
|
||||
secretReader: secretReader,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (m *annotationBackedDefinitionBuilder) outputName() (string, error) {
|
||||
// bail out in the case the annotation name doesn't start with "service.binding"
|
||||
if m.name != AnnotationPrefix && !strings.HasPrefix(m.name, AnnotationPrefix+"/") {
|
||||
return "", fmt.Errorf("can't process annotation with name %q", m.name)
|
||||
}
|
||||
|
||||
if p := strings.SplitN(m.name, "/", 2); len(p) > 1 && len(p[1]) > 0 {
|
||||
return p[1], nil
|
||||
}
|
||||
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (m *annotationBackedDefinitionBuilder) Build() (Definition, error) {
|
||||
|
||||
outputName, err := m.outputName()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mod, err := newModel(m.value)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not create binding model for annotation key %s and value %s", m.name, m.value)
|
||||
}
|
||||
|
||||
switch {
|
||||
case mod.isStringElementType() && mod.isStringObjectType():
|
||||
return &stringDefinition{
|
||||
outputName: outputName,
|
||||
definition: definition{
|
||||
path: mod.path,
|
||||
},
|
||||
}, nil
|
||||
|
||||
case mod.isStringElementType() && mod.hasDataField():
|
||||
return &stringFromDataFieldDefinition{
|
||||
secretConfigMapReader: m.secretConfigMapReader,
|
||||
objectType: mod.objectType,
|
||||
outputName: outputName,
|
||||
definition: definition{
|
||||
path: mod.path,
|
||||
},
|
||||
sourceKey: mod.sourceKey,
|
||||
}, nil
|
||||
|
||||
case mod.isMapElementType() && mod.hasDataField():
|
||||
return &mapFromDataFieldDefinition{
|
||||
secretConfigMapReader: m.secretConfigMapReader,
|
||||
objectType: mod.objectType,
|
||||
outputName: outputName,
|
||||
definition: definition{
|
||||
path: mod.path,
|
||||
},
|
||||
sourceValue: mod.sourceValue,
|
||||
}, nil
|
||||
|
||||
case mod.isMapElementType() && mod.isStringObjectType():
|
||||
return &stringOfMapDefinition{
|
||||
outputName: outputName,
|
||||
definition: definition{
|
||||
path: mod.path,
|
||||
},
|
||||
}, nil
|
||||
|
||||
case mod.isSliceOfMapsElementType():
|
||||
return &sliceOfMapsFromPathDefinition{
|
||||
outputName: outputName,
|
||||
definition: definition{
|
||||
path: mod.path,
|
||||
},
|
||||
sourceKey: mod.sourceKey,
|
||||
sourceValue: mod.sourceValue,
|
||||
}, nil
|
||||
|
||||
case mod.isSliceOfStringsElementType():
|
||||
return &sliceOfStringsFromPathDefinition{
|
||||
outputName: outputName,
|
||||
definition: definition{
|
||||
path: mod.path,
|
||||
},
|
||||
sourceValue: mod.sourceValue,
|
||||
}, nil
|
||||
}
|
||||
|
||||
panic(fmt.Sprintf("Annotation %s=%s not implemented!", m.name, m.value))
|
||||
}
|
||||
30
vendor/github.com/redhat-developer/service-binding-operator/pkg/binding/bindinginfo.go
generated
vendored
Normal file
30
vendor/github.com/redhat-developer/service-binding-operator/pkg/binding/bindinginfo.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
package binding
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type ErrInvalidAnnotationPrefix string
|
||||
|
||||
func (e ErrInvalidAnnotationPrefix) Error() string {
|
||||
return fmt.Sprintf("invalid annotation prefix: %s", string(e))
|
||||
}
|
||||
|
||||
func IsErrInvalidAnnotationPrefix(err error) bool {
|
||||
_, ok := err.(ErrInvalidAnnotationPrefix)
|
||||
return ok
|
||||
}
|
||||
|
||||
var ErrInvalidAnnotationName = errors.New("invalid annotation name")
|
||||
|
||||
type ErrEmptyAnnotationName string
|
||||
|
||||
func (e ErrEmptyAnnotationName) Error() string {
|
||||
return fmt.Sprintf("empty annotation name: %s", string(e))
|
||||
}
|
||||
|
||||
func IsErrEmptyAnnotationName(err error) bool {
|
||||
_, ok := err.(ErrEmptyAnnotationName)
|
||||
return ok
|
||||
}
|
||||
322
vendor/github.com/redhat-developer/service-binding-operator/pkg/binding/definition.go
generated
vendored
Normal file
322
vendor/github.com/redhat-developer/service-binding-operator/pkg/binding/definition.go
generated
vendored
Normal file
@@ -0,0 +1,322 @@
|
||||
package binding
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
type objectType string
|
||||
|
||||
type elementType string
|
||||
|
||||
const (
|
||||
// configMapObjectType indicates the path contains a name for a ConfigMap containing the binding
|
||||
// data.
|
||||
configMapObjectType objectType = "ConfigMap"
|
||||
// secretObjectType indicates the path contains a name for a Secret containing the binding data.
|
||||
secretObjectType objectType = "Secret"
|
||||
// stringObjectType indicates the path contains a value string.
|
||||
stringObjectType objectType = "string"
|
||||
// emptyObjectType is used as default value when the objectType key is present in the string
|
||||
// provided by the user but no value has been provided; can be used by the user to force the
|
||||
// system to use the default objectType.
|
||||
emptyObjectType objectType = ""
|
||||
|
||||
// mapElementType indicates the value found at path is a map[string]interface{}.
|
||||
mapElementType elementType = "map"
|
||||
// sliceOfMapsElementType indicates the value found at path is a slice of maps.
|
||||
sliceOfMapsElementType elementType = "sliceOfMaps"
|
||||
// sliceOfStringsElementType indicates the value found at path is a slice of strings.
|
||||
sliceOfStringsElementType elementType = "sliceOfStrings"
|
||||
// stringElementType indicates the value found at path is a string.
|
||||
stringElementType elementType = "string"
|
||||
)
|
||||
|
||||
//go:generate mockgen -destination=mocks/mocks.go -package=mocks . Definition,Value
|
||||
|
||||
type Definition interface {
|
||||
Apply(u *unstructured.Unstructured) (Value, error)
|
||||
GetPath() string
|
||||
}
|
||||
|
||||
type DefinitionBuilder interface {
|
||||
Build() (Definition, error)
|
||||
}
|
||||
|
||||
type definition struct {
|
||||
path string
|
||||
}
|
||||
|
||||
func (d *definition) GetPath() string {
|
||||
return d.path
|
||||
}
|
||||
|
||||
type stringDefinition struct {
|
||||
outputName string
|
||||
definition
|
||||
}
|
||||
|
||||
var _ Definition = (*stringDefinition)(nil)
|
||||
|
||||
func (d *stringDefinition) Apply(u *unstructured.Unstructured) (Value, error) {
|
||||
if d.outputName == "" {
|
||||
return nil, fmt.Errorf("cannot use generic service.binding annotation for string elements, need to specify binding key like service.binding/foo")
|
||||
}
|
||||
val, err := getValuesByJSONPath(u.Object, d.path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(val) != 1 {
|
||||
return nil, fmt.Errorf("only one value should be returned for %v but we got %v", d.path, val)
|
||||
}
|
||||
|
||||
m := map[string]interface{}{
|
||||
d.outputName: val[0].Interface(),
|
||||
}
|
||||
|
||||
return &value{v: m}, nil
|
||||
}
|
||||
|
||||
type stringFromDataFieldDefinition struct {
|
||||
secretConfigMapReader *secretConfigMapReader
|
||||
objectType objectType
|
||||
outputName string
|
||||
definition
|
||||
sourceKey string
|
||||
}
|
||||
|
||||
var _ Definition = (*stringFromDataFieldDefinition)(nil)
|
||||
|
||||
func (d *stringFromDataFieldDefinition) Apply(u *unstructured.Unstructured) (Value, error) {
|
||||
if d.secretConfigMapReader == nil {
|
||||
return nil, errors.New("kubeClient required for this functionality")
|
||||
}
|
||||
|
||||
res, err := getValuesByJSONPath(u.Object, d.path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(res) != 1 {
|
||||
return nil, fmt.Errorf("only one value should be returned for %v but we got %v", d.path, res)
|
||||
}
|
||||
resourceName := res[0].String()
|
||||
|
||||
var otherObj *unstructured.Unstructured
|
||||
if d.objectType == secretObjectType {
|
||||
otherObj, err = d.secretConfigMapReader.secretReader(u.GetNamespace(), resourceName)
|
||||
} else if d.objectType == configMapObjectType {
|
||||
otherObj, err = d.secretConfigMapReader.configMapReader(u.GetNamespace(), resourceName)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
val, ok, err := unstructured.NestedString(otherObj.Object, "data", d.sourceKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !ok {
|
||||
return nil, errors.New("not found")
|
||||
}
|
||||
if d.objectType == secretObjectType {
|
||||
n, err := base64.StdEncoding.DecodeString(val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
val = string(n)
|
||||
}
|
||||
v := map[string]interface{}{
|
||||
"": val,
|
||||
}
|
||||
return &value{v: v}, nil
|
||||
}
|
||||
|
||||
type mapFromDataFieldDefinition struct {
|
||||
secretConfigMapReader *secretConfigMapReader
|
||||
objectType objectType
|
||||
outputName string
|
||||
sourceValue string
|
||||
definition
|
||||
}
|
||||
|
||||
var _ Definition = (*mapFromDataFieldDefinition)(nil)
|
||||
|
||||
func (d *mapFromDataFieldDefinition) Apply(u *unstructured.Unstructured) (Value, error) {
|
||||
if d.secretConfigMapReader == nil {
|
||||
return nil, errors.New("kubeClient required for this functionality")
|
||||
}
|
||||
|
||||
res, err := getValuesByJSONPath(u.Object, d.path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(res) != 1 {
|
||||
return nil, fmt.Errorf("only one value should be returned for %v but we got %v", d.path, res)
|
||||
}
|
||||
resourceName := res[0].Elem().String()
|
||||
|
||||
var otherObj *unstructured.Unstructured
|
||||
if d.objectType == secretObjectType {
|
||||
otherObj, err = d.secretConfigMapReader.secretReader(u.GetNamespace(), resourceName)
|
||||
} else if d.objectType == configMapObjectType {
|
||||
otherObj, err = d.secretConfigMapReader.configMapReader(u.GetNamespace(), resourceName)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
val, ok, err := unstructured.NestedStringMap(otherObj.Object, "data")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !ok {
|
||||
return nil, errors.New("not found")
|
||||
}
|
||||
|
||||
outputVal := make(map[string]string)
|
||||
|
||||
for k, v := range val {
|
||||
if len(d.sourceValue) > 0 && k != d.sourceValue {
|
||||
continue
|
||||
}
|
||||
var n string
|
||||
if d.objectType == secretObjectType {
|
||||
b, err := base64.StdEncoding.DecodeString(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
n = string(b)
|
||||
} else {
|
||||
n = v
|
||||
}
|
||||
if len(d.sourceValue) > 0 && len(d.outputName) > 0 {
|
||||
outputVal[d.outputName] = string(n)
|
||||
} else {
|
||||
outputVal[k] = string(n)
|
||||
}
|
||||
}
|
||||
|
||||
return &value{v: outputVal}, nil
|
||||
}
|
||||
|
||||
type stringOfMapDefinition struct {
|
||||
outputName string
|
||||
definition
|
||||
}
|
||||
|
||||
var _ Definition = (*stringOfMapDefinition)(nil)
|
||||
|
||||
func (d *stringOfMapDefinition) Apply(u *unstructured.Unstructured) (Value, error) {
|
||||
val, err := getValuesByJSONPath(u.Object, d.path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(val) != 1 {
|
||||
return nil, fmt.Errorf("only one value should be returned for %v but we got %v", d.path, val)
|
||||
}
|
||||
|
||||
valMap, ok := val[0].Interface().(map[string]interface{})
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("returned value for %v should be map, but we got %v", d.path, val[0].Interface())
|
||||
}
|
||||
|
||||
outputName := d.outputName
|
||||
|
||||
if outputName != "" {
|
||||
return &value{v: map[string]interface{}{
|
||||
outputName: valMap,
|
||||
}}, nil
|
||||
}
|
||||
return &value{v: valMap}, nil
|
||||
}
|
||||
|
||||
type sliceOfMapsFromPathDefinition struct {
|
||||
outputName string
|
||||
definition
|
||||
sourceKey string
|
||||
sourceValue string
|
||||
}
|
||||
|
||||
var _ Definition = (*sliceOfMapsFromPathDefinition)(nil)
|
||||
|
||||
func (d *sliceOfMapsFromPathDefinition) Apply(u *unstructured.Unstructured) (Value, error) {
|
||||
val, err := getValuesByJSONPath(u.Object, d.path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := make(map[string]interface{})
|
||||
for _, vv := range val {
|
||||
for k, v := range collectSourceValuesWithKey(vv.Interface(), d.sourceValue, d.sourceKey) {
|
||||
res[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
if d.outputName == "" {
|
||||
return &value{v: res}, nil
|
||||
}
|
||||
return &value{v: map[string]interface{}{d.outputName: res}}, nil
|
||||
}
|
||||
|
||||
func collectSourceValuesWithKey(i interface{}, sourceValue string, sourceKey string) map[string]interface{} {
|
||||
res := make(map[string]interface{})
|
||||
switch v := i.(type) {
|
||||
case map[string]interface{}:
|
||||
key := v[sourceKey]
|
||||
res[fmt.Sprintf("%v", key)] = v[sourceValue]
|
||||
case []interface{}:
|
||||
for _, item := range v {
|
||||
for k, v := range collectSourceValuesWithKey(item, sourceValue, sourceKey) {
|
||||
res[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
type sliceOfStringsFromPathDefinition struct {
|
||||
outputName string
|
||||
definition
|
||||
sourceValue string
|
||||
}
|
||||
|
||||
var _ Definition = (*sliceOfStringsFromPathDefinition)(nil)
|
||||
|
||||
func (d *sliceOfStringsFromPathDefinition) Apply(u *unstructured.Unstructured) (Value, error) {
|
||||
val, err := getValuesByJSONPath(u.Object, d.path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var res []interface{}
|
||||
for _, e := range val {
|
||||
res = append(res, collectSourceValues(e.Interface(), d.sourceValue)...)
|
||||
}
|
||||
|
||||
return &value{v: map[string]interface{}{d.outputName: res}}, nil
|
||||
}
|
||||
|
||||
func collectSourceValues(i interface{}, sourceValue string) []interface{} {
|
||||
var res []interface{}
|
||||
switch v := i.(type) {
|
||||
case map[string]interface{}:
|
||||
if sourceValue != "" {
|
||||
res = append(res, v[sourceValue])
|
||||
}
|
||||
case []interface{}:
|
||||
for _, item := range v {
|
||||
res = append(res, collectSourceValues(item, sourceValue)...)
|
||||
}
|
||||
case string:
|
||||
if sourceValue == "" {
|
||||
res = append(res, v)
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
29
vendor/github.com/redhat-developer/service-binding-operator/pkg/binding/jsonpath.go
generated
vendored
Normal file
29
vendor/github.com/redhat-developer/service-binding-operator/pkg/binding/jsonpath.go
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
package binding
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"k8s.io/client-go/util/jsonpath"
|
||||
)
|
||||
|
||||
// getValuesByJSONPath returns values from the given map matching the provided JSONPath
|
||||
// 'path' argument takes JSONPath expressions enclosed by curly braces {}
|
||||
// see https://kubernetes.io/docs/reference/kubectl/jsonpath/ for more details
|
||||
// It returns zero or more filtered values back,
|
||||
// or error if the jsonpath is invalid or it cannot be applied on the given map
|
||||
func getValuesByJSONPath(obj map[string]interface{}, path string) ([]reflect.Value, error) {
|
||||
j := jsonpath.New("")
|
||||
err := j.Parse(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result, err := j.FindResults(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(result) > 1 {
|
||||
return nil, fmt.Errorf("more than one item found in the result: %v", result)
|
||||
}
|
||||
return result[0], nil
|
||||
}
|
||||
125
vendor/github.com/redhat-developer/service-binding-operator/pkg/binding/model.go
generated
vendored
Normal file
125
vendor/github.com/redhat-developer/service-binding-operator/pkg/binding/model.go
generated
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
package binding
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type model struct {
|
||||
path string
|
||||
elementType elementType
|
||||
objectType objectType
|
||||
sourceKey string
|
||||
sourceValue string
|
||||
bindAs BindingType
|
||||
}
|
||||
|
||||
func (m *model) isStringElementType() bool {
|
||||
return m.elementType == stringElementType
|
||||
}
|
||||
|
||||
func (m *model) isStringObjectType() bool {
|
||||
return m.objectType == stringObjectType
|
||||
}
|
||||
|
||||
func (m *model) isMapElementType() bool {
|
||||
return m.elementType == mapElementType
|
||||
}
|
||||
|
||||
func (m *model) isSliceOfMapsElementType() bool {
|
||||
return m.elementType == sliceOfMapsElementType
|
||||
}
|
||||
|
||||
func (m *model) isSliceOfStringsElementType() bool {
|
||||
return m.elementType == sliceOfStringsElementType
|
||||
}
|
||||
|
||||
func (m *model) hasDataField() bool {
|
||||
return m.objectType == secretObjectType || m.objectType == configMapObjectType
|
||||
}
|
||||
|
||||
var keys = []modelKey{pathModelKey, objectTypeModelKey, elementTypeModelKey, sourceKeyModelKey, sourceValueModelKey}
|
||||
|
||||
func newModel(annotationValue string) (*model, error) {
|
||||
|
||||
raw := make(map[modelKey]string)
|
||||
|
||||
for _, kv := range strings.Split(annotationValue, ",") {
|
||||
for i := range keys {
|
||||
k := keys[i]
|
||||
prefix := fmt.Sprintf("%v=", k)
|
||||
if strings.HasPrefix(kv, prefix) {
|
||||
raw[k] = kv[len(prefix):]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// assert PathModelKey is present
|
||||
path, found := raw[pathModelKey]
|
||||
if !found {
|
||||
return nil, fmt.Errorf("path not found: %q", annotationValue)
|
||||
}
|
||||
if !strings.HasPrefix(path, "{") || !strings.HasSuffix(path, "}") {
|
||||
return nil, fmt.Errorf("path has invalid syntax: %q", path)
|
||||
}
|
||||
|
||||
// ensure ObjectTypeModelKey has a default value
|
||||
var objType objectType
|
||||
if rawObjectType, found := raw[objectTypeModelKey]; !found {
|
||||
objType = stringObjectType
|
||||
} else {
|
||||
// in the case the key is present but the value isn't (for example, "objectType=,") the
|
||||
// default string object type should be set
|
||||
if objType = objectType(rawObjectType); objType == emptyObjectType {
|
||||
objType = stringObjectType
|
||||
}
|
||||
}
|
||||
|
||||
// ensure sourceKey has a default value
|
||||
sourceKey, found := raw[sourceKeyModelKey]
|
||||
if !found {
|
||||
sourceKey = ""
|
||||
}
|
||||
|
||||
sourceValue, found := raw[sourceValueModelKey]
|
||||
if !found {
|
||||
sourceValue, found = raw[sourceKeyModelKey]
|
||||
if !found {
|
||||
sourceValue = ""
|
||||
}
|
||||
}
|
||||
|
||||
// hasData indicates the configured or inferred objectType is either a Secret or ConfigMap
|
||||
hasData := objType == secretObjectType || objType == configMapObjectType
|
||||
// hasSourceKey indicates a value for sourceKey has been informed
|
||||
|
||||
var eltType elementType
|
||||
if rawEltType, found := raw[elementTypeModelKey]; found {
|
||||
// the input string contains an elementType configuration, use it
|
||||
eltType = elementType(rawEltType)
|
||||
} else if hasData {
|
||||
// the input doesn't contain an elementType configuration, does contain a sourceKey
|
||||
// configuration, and is either a Secret or ConfigMap
|
||||
eltType = mapElementType
|
||||
} else {
|
||||
// elementType configuration hasn't been informed and there's no extra hints, assume it is a
|
||||
// string element
|
||||
eltType = stringElementType
|
||||
}
|
||||
|
||||
// ensure an error is returned if not all required information is available for sliceOfMaps
|
||||
// element type
|
||||
if eltType == sliceOfMapsElementType && (len(sourceValue) == 0 || len(sourceKey) == 0) {
|
||||
return nil, errors.New("sliceOfMaps elementType requires sourceKey and sourceValue to be present")
|
||||
}
|
||||
|
||||
return &model{
|
||||
path: path,
|
||||
elementType: eltType,
|
||||
objectType: objType,
|
||||
sourceValue: sourceValue,
|
||||
sourceKey: sourceKey,
|
||||
bindAs: TypeEnvVar,
|
||||
}, nil
|
||||
}
|
||||
118
vendor/github.com/redhat-developer/service-binding-operator/pkg/binding/spec.go
generated
vendored
Normal file
118
vendor/github.com/redhat-developer/service-binding-operator/pkg/binding/spec.go
generated
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
package binding
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/dynamic"
|
||||
)
|
||||
|
||||
// bindingType encodes the medium the binding should deliver the configuration value.
|
||||
type BindingType string
|
||||
|
||||
const (
|
||||
// TypeVolumeMount indicates the binding should happen through a volume mount.
|
||||
TypeVolumeMount BindingType = "volumemount"
|
||||
// TypeEnvVar indicates the binding should happen through environment variables.
|
||||
TypeEnvVar BindingType = "env"
|
||||
)
|
||||
|
||||
// result contains data that has been collected by an annotation handler.
|
||||
type result struct {
|
||||
// Data contains the annotation data collected by an annotation handler inside a deep structure
|
||||
// with its root being the value specified in the Path field.
|
||||
Data map[string]interface{}
|
||||
// Type indicates where the Object field should be injected in the application; can be either
|
||||
// "env" or "volumemount".
|
||||
Type BindingType
|
||||
// Path is the nested location the collected data can be found in the Data field.
|
||||
Path string
|
||||
// RawData contains the annotation data collected by an annotation handler
|
||||
// inside a deep structure with its root being composed by the path where
|
||||
// the external resource name was extracted and the path within the external
|
||||
// resource.
|
||||
RawData map[string]interface{}
|
||||
}
|
||||
|
||||
type errHandlerNotFound string
|
||||
|
||||
func (e errHandlerNotFound) Error() string {
|
||||
return fmt.Sprintf("could not find handler for annotation value %q", string(e))
|
||||
}
|
||||
|
||||
func IsErrHandlerNotFound(err error) bool {
|
||||
_, ok := err.(errHandlerNotFound)
|
||||
return ok
|
||||
}
|
||||
|
||||
type SpecHandler struct {
|
||||
kubeClient dynamic.Interface
|
||||
obj unstructured.Unstructured
|
||||
annotationKey string
|
||||
annotationValue string
|
||||
}
|
||||
|
||||
func configMapsReader(client dynamic.Interface) UnstructuredResourceReader {
|
||||
return func(namespace string, name string) (*unstructured.Unstructured, error) {
|
||||
return client.Resource(schema.GroupVersionResource{Group: "", Version: "v1", Resource: "configmaps"}).Namespace(namespace).Get(context.TODO(), name, v1.GetOptions{})
|
||||
}
|
||||
}
|
||||
|
||||
func secretsReader(client dynamic.Interface) UnstructuredResourceReader {
|
||||
return func(namespace string, name string) (*unstructured.Unstructured, error) {
|
||||
return client.Resource(schema.GroupVersionResource{Group: "", Version: "v1", Resource: "secrets"}).Namespace(namespace).Get(context.TODO(), name, v1.GetOptions{})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SpecHandler) Handle() (result, error) {
|
||||
builder := NewDefinitionBuilder(s.annotationKey, s.annotationValue, configMapsReader(s.kubeClient), secretsReader(s.kubeClient))
|
||||
|
||||
d, err := builder.Build()
|
||||
if err != nil {
|
||||
return result{}, err
|
||||
}
|
||||
|
||||
val, err := d.Apply(&s.obj)
|
||||
if err != nil {
|
||||
return result{}, err
|
||||
}
|
||||
|
||||
v := val.Get()
|
||||
|
||||
out := make(map[string]interface{})
|
||||
|
||||
switch t := v.(type) {
|
||||
case map[string]string:
|
||||
for k, v := range t {
|
||||
out[k] = v
|
||||
}
|
||||
case map[string]interface{}:
|
||||
for k, v := range t {
|
||||
out[k] = v
|
||||
}
|
||||
case map[interface{}]interface{}:
|
||||
for k, v := range t {
|
||||
out[fmt.Sprintf("%v", k)] = v
|
||||
}
|
||||
}
|
||||
|
||||
return result{
|
||||
Data: out,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func NewSpecHandler(
|
||||
kubeClient dynamic.Interface,
|
||||
annotationKey string,
|
||||
annotationValue string,
|
||||
obj unstructured.Unstructured,
|
||||
) (*SpecHandler, error) {
|
||||
return &SpecHandler{
|
||||
kubeClient: kubeClient,
|
||||
obj: obj,
|
||||
annotationKey: annotationKey,
|
||||
annotationValue: annotationValue,
|
||||
}, nil
|
||||
}
|
||||
15
vendor/github.com/redhat-developer/service-binding-operator/pkg/binding/value.go
generated
vendored
Normal file
15
vendor/github.com/redhat-developer/service-binding-operator/pkg/binding/value.go
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
package binding
|
||||
|
||||
type Value interface {
|
||||
Get() interface{}
|
||||
}
|
||||
|
||||
type value struct {
|
||||
v interface{}
|
||||
}
|
||||
|
||||
var _ Value = (*value)(nil)
|
||||
|
||||
func (v *value) Get() interface{} {
|
||||
return v.v
|
||||
}
|
||||
19
vendor/github.com/redhat-developer/service-binding-operator/pkg/client/kubernetes/api.go
generated
vendored
Normal file
19
vendor/github.com/redhat-developer/service-binding-operator/pkg/client/kubernetes/api.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
type ConfigMapReader interface {
|
||||
ReadConfigMap(namespace string, name string) (*unstructured.Unstructured, error)
|
||||
}
|
||||
|
||||
type SecretReader interface {
|
||||
ReadSecret(namespace string, name string) (*unstructured.Unstructured, error)
|
||||
}
|
||||
|
||||
type Referable interface {
|
||||
GroupVersionResource() (*schema.GroupVersionResource, error)
|
||||
GroupVersionKind() (*schema.GroupVersionKind, error)
|
||||
}
|
||||
60
vendor/github.com/redhat-developer/service-binding-operator/pkg/converter/unstructured.go
generated
vendored
Normal file
60
vendor/github.com/redhat-developer/service-binding-operator/pkg/converter/unstructured.go
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
package converter
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
// ToUnstructured converts a runtime object into Unstructured, and can return errors related to it.
|
||||
func ToUnstructured(obj interface{}) (*unstructured.Unstructured, error) {
|
||||
data, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &unstructured.Unstructured{Object: data}, nil
|
||||
}
|
||||
|
||||
// ToUnstructuredAsGVK converts a runtime object into Unstructured, and set as given GVK. It can
|
||||
// return errors related to conversion.
|
||||
func ToUnstructuredAsGVK(
|
||||
obj interface{},
|
||||
gvk schema.GroupVersionKind,
|
||||
) (*unstructured.Unstructured, error) {
|
||||
u, err := ToUnstructured(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u.SetGroupVersionKind(gvk)
|
||||
return u, nil
|
||||
}
|
||||
|
||||
// NestedResources returns slice of resources of the type specified by obj arg on the given path inside the given resource represented by a map
|
||||
// Additionally the function gives an indication if specified resource is found or error if the found slice does not contain resources of the given type
|
||||
func NestedResources(obj interface{}, resource map[string]interface{}, path ...string) ([]map[string]interface{}, bool, error) {
|
||||
val, found, err := unstructured.NestedFieldNoCopy(resource, path...)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
if !found {
|
||||
return nil, found, nil
|
||||
}
|
||||
valSlice, ok := val.([]interface{})
|
||||
if !ok {
|
||||
return nil, true, errors.New("not a slice")
|
||||
}
|
||||
var containers []map[string]interface{}
|
||||
for _, item := range valSlice {
|
||||
u, ok := item.(map[string]interface{})
|
||||
if !ok {
|
||||
return nil, true, errors.New("not a map")
|
||||
}
|
||||
err := runtime.DefaultUnstructuredConverter.FromUnstructured(u, obj)
|
||||
if err != nil {
|
||||
return nil, true, err
|
||||
}
|
||||
containers = append(containers, u)
|
||||
}
|
||||
return containers, true, nil
|
||||
}
|
||||
52
vendor/github.com/redhat-developer/service-binding-operator/pkg/naming/naming.go
generated
vendored
Normal file
52
vendor/github.com/redhat-developer/service-binding-operator/pkg/naming/naming.go
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
package naming
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"html/template"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var TemplateError = errors.New("please check the namingStrategy template provided")
|
||||
|
||||
var templateFunctions = map[string]interface{}{
|
||||
"upper": strings.ToUpper,
|
||||
"title": strings.Title,
|
||||
"lower": strings.ToLower,
|
||||
}
|
||||
|
||||
type namingTemplate struct {
|
||||
template *template.Template
|
||||
data map[string]interface{}
|
||||
namingTemplate string
|
||||
}
|
||||
|
||||
// NewTemplate creates template instance which handles how binding names should be prepared
|
||||
// templateStr is being used to format binding name.
|
||||
func NewTemplate(templateStr string, data map[string]interface{}) (*namingTemplate, error) {
|
||||
t, err := template.New("template").Funcs(templateFunctions).Parse(templateStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &namingTemplate{
|
||||
template: t,
|
||||
namingTemplate: templateStr,
|
||||
data: data,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetBindingName prepares binding name which accepts binding name from the OLM descriptor/annotation
|
||||
// namingTemplate uses string template provided to build final binding name.
|
||||
func (n *namingTemplate) GetBindingName(bindingName string) (string, error) {
|
||||
d := map[string]interface{}{
|
||||
"service": n.data,
|
||||
"name": bindingName,
|
||||
}
|
||||
|
||||
var tpl bytes.Buffer
|
||||
err := n.template.Execute(&tpl, d)
|
||||
if err != nil {
|
||||
return "", TemplateError
|
||||
}
|
||||
return tpl.String(), nil
|
||||
}
|
||||
201
vendor/github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/api.go
generated
vendored
Normal file
201
vendor/github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/api.go
generated
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
package pipeline
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
|
||||
"github.com/redhat-developer/service-binding-operator/pkg/binding"
|
||||
"github.com/redhat-developer/service-binding-operator/pkg/client/kubernetes"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
//go:generate mockgen -destination=mocks/mocks_pipeline.go -package=mocks . Context,Service,CRD,Application,ContextProvider,Handler
|
||||
|
||||
// Reconciliation pipeline
|
||||
type Pipeline interface {
|
||||
|
||||
// Reconcile given service binding
|
||||
// Returns true if processing should be repeated
|
||||
// and optional error if occurred
|
||||
// important: even if error occurred it might not be needed to retry processing
|
||||
Process(binding interface{}) (bool, error)
|
||||
}
|
||||
|
||||
// A pipeline stage
|
||||
type Handler interface {
|
||||
Handle(ctx Context)
|
||||
}
|
||||
|
||||
// Pipeline flow control
|
||||
type FlowStatus struct {
|
||||
Retry bool
|
||||
Stop bool
|
||||
Err error
|
||||
}
|
||||
|
||||
type HasResource interface {
|
||||
Resource() *unstructured.Unstructured
|
||||
}
|
||||
|
||||
// Service to be bound
|
||||
type Service interface {
|
||||
|
||||
// Service resource
|
||||
HasResource
|
||||
|
||||
// Return CRD for this service, otherwise nil if not backed by CRD
|
||||
// Error might be returned if occurred during the operation
|
||||
CustomResourceDefinition() (CRD, error)
|
||||
|
||||
// Resources owned by the service, if any
|
||||
// Error might be returned if occurred during the operation
|
||||
OwnedResources() ([]*unstructured.Unstructured, error)
|
||||
|
||||
// Attach binding definition to service
|
||||
AddBindingDef(def binding.Definition)
|
||||
|
||||
// All binding definitions attached to the service
|
||||
BindingDefs() []binding.Definition
|
||||
|
||||
// Optional service id
|
||||
Id() *string
|
||||
}
|
||||
|
||||
// Application to be bound to service(s)
|
||||
type Application interface {
|
||||
|
||||
// Application resource
|
||||
HasResource
|
||||
|
||||
// dot-separated path inside the application resource locating container resources
|
||||
// the returned value follows foo.bar.bla convention
|
||||
// it cannot be empty
|
||||
ContainersPath() string
|
||||
|
||||
// optional dot-separated path inside the application resource locating field where intermediate binding secret ref should be injected
|
||||
// the returns value follows foo.bar.bla convention, but it can be empty
|
||||
SecretPath() string
|
||||
|
||||
BindableContainers() ([]map[string]interface{}, error)
|
||||
}
|
||||
|
||||
// Custom Resource Definition
|
||||
type CRD interface {
|
||||
|
||||
// CRD resource
|
||||
HasResource
|
||||
|
||||
// optional Descriptor attached to ClusterServiceVersion resource
|
||||
Descriptor() (*olmv1alpha1.CRDDescription, error)
|
||||
}
|
||||
|
||||
// Pipeline context passed to each handler
|
||||
type Context interface {
|
||||
BindingName() string
|
||||
|
||||
// Services referred by binding
|
||||
// if reading fails, return error
|
||||
Services() ([]Service, error)
|
||||
|
||||
// Applications referred by binding
|
||||
// if no application found, return an error
|
||||
Applications() ([]Application, error)
|
||||
|
||||
// Returns true if binding is about to be removed
|
||||
UnbindRequested() bool
|
||||
|
||||
BindingSecretName() string
|
||||
|
||||
// Return true if bindings should be projected as files inside application containers
|
||||
BindAsFiles() bool
|
||||
|
||||
// Path where bindings should be mounted inside application containers
|
||||
MountPath() string
|
||||
|
||||
// Template that should be applied on collected binding names, prior projection
|
||||
NamingTemplate() string
|
||||
|
||||
// Additional bindings that will be projected into application containers
|
||||
// entry key is the future binding name
|
||||
// entry value contains template that generates binding value
|
||||
Mappings() map[string]string
|
||||
|
||||
// Add binding item to the context
|
||||
AddBindingItem(item *BindingItem)
|
||||
|
||||
// Add bindings to the context
|
||||
AddBindings(bindings Bindings)
|
||||
|
||||
// List binding items that should be projected into application containers
|
||||
BindingItems() BindingItems
|
||||
|
||||
// EnvBindings returns list of (env variable name, binding name) pairs
|
||||
// describing what binding should be injected as env var as well
|
||||
EnvBindings() []*EnvBinding
|
||||
|
||||
// Indicates that the binding should be retried at some later time
|
||||
// The current processing stops and context gets closed
|
||||
RetryProcessing(reason error)
|
||||
|
||||
// Indicates that en error has occurred while processing the binding
|
||||
Error(err error)
|
||||
|
||||
// Stops processing
|
||||
StopProcessing()
|
||||
|
||||
// Closes the context, persisting changed resources
|
||||
// Returns error if occurrs
|
||||
Close() error
|
||||
|
||||
// Sets context condition
|
||||
SetCondition(condition *metav1.Condition)
|
||||
|
||||
kubernetes.ConfigMapReader
|
||||
kubernetes.SecretReader
|
||||
|
||||
FlowStatus() FlowStatus
|
||||
}
|
||||
|
||||
// Provides context for a given service binding
|
||||
type ContextProvider interface {
|
||||
Get(binding interface{}) (Context, error)
|
||||
}
|
||||
|
||||
type HandlerFunc func(ctx Context)
|
||||
|
||||
func (f HandlerFunc) Handle(ctx Context) {
|
||||
f(ctx)
|
||||
}
|
||||
|
||||
type BindingItems []*BindingItem
|
||||
|
||||
type BindingItem struct {
|
||||
Name string
|
||||
Value interface{}
|
||||
Source Service
|
||||
}
|
||||
|
||||
type EnvBinding struct {
|
||||
Var string
|
||||
Name string
|
||||
}
|
||||
|
||||
// a collection of bindings
|
||||
type Bindings interface {
|
||||
// available bindgins
|
||||
Items() (BindingItems, error)
|
||||
|
||||
// reference to resource holding the bindings, nil if not persisted in a resource
|
||||
Source() *v1.ObjectReference
|
||||
}
|
||||
|
||||
// Returns map representation of given list of binding items
|
||||
func (items *BindingItems) AsMap() map[string]string {
|
||||
result := make(map[string]string)
|
||||
|
||||
for _, i := range *items {
|
||||
result[i.Name] = fmt.Sprintf("%v", i.Value)
|
||||
}
|
||||
return result
|
||||
}
|
||||
98
vendor/github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/builder/pipeline.go
generated
vendored
Normal file
98
vendor/github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/builder/pipeline.go
generated
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
package builder
|
||||
|
||||
import (
|
||||
"github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline"
|
||||
"github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/handler/collect"
|
||||
"github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/handler/mapping"
|
||||
"github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/handler/naming"
|
||||
"github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/handler/project"
|
||||
)
|
||||
|
||||
var _ pipeline.Pipeline = &impl{}
|
||||
|
||||
type impl struct {
|
||||
ctxProvider pipeline.ContextProvider
|
||||
handlers []pipeline.Handler
|
||||
}
|
||||
|
||||
func (i *impl) Process(binding interface{}) (bool, error) {
|
||||
ctx, err := i.ctxProvider.Get(binding)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
var status pipeline.FlowStatus
|
||||
for _, h := range i.handlers {
|
||||
h.Handle(ctx)
|
||||
status = ctx.FlowStatus()
|
||||
if status.Stop {
|
||||
break
|
||||
}
|
||||
}
|
||||
err = ctx.Close()
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
return status.Retry, status.Err
|
||||
}
|
||||
|
||||
type builder struct {
|
||||
ctxProvider pipeline.ContextProvider
|
||||
handlers []pipeline.Handler
|
||||
}
|
||||
|
||||
func (b *builder) WithContextProvider(ctxProvider pipeline.ContextProvider) *builder {
|
||||
b.ctxProvider = ctxProvider
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *builder) WithHandlers(h ...pipeline.Handler) *builder {
|
||||
b.handlers = append(b.handlers, h...)
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *builder) Build() pipeline.Pipeline {
|
||||
return &impl{
|
||||
handlers: b.handlers,
|
||||
ctxProvider: b.ctxProvider,
|
||||
}
|
||||
}
|
||||
|
||||
func Builder() *builder {
|
||||
return &builder{}
|
||||
}
|
||||
|
||||
var defaultFlow = []pipeline.Handler{
|
||||
pipeline.HandlerFunc(project.Unbind),
|
||||
pipeline.HandlerFunc(collect.PreFlight),
|
||||
pipeline.HandlerFunc(collect.ProvisionedService),
|
||||
pipeline.HandlerFunc(collect.DirectSecretReference),
|
||||
pipeline.HandlerFunc(collect.BindingDefinitions),
|
||||
pipeline.HandlerFunc(collect.BindingItems),
|
||||
pipeline.HandlerFunc(collect.OwnedResources),
|
||||
pipeline.HandlerFunc(mapping.Handle),
|
||||
pipeline.HandlerFunc(naming.Handle),
|
||||
pipeline.HandlerFunc(project.PreFlightCheck()),
|
||||
pipeline.HandlerFunc(project.InjectSecretRef),
|
||||
pipeline.HandlerFunc(project.BindingsAsEnv),
|
||||
pipeline.HandlerFunc(project.BindingsAsFiles),
|
||||
pipeline.HandlerFunc(project.PostFlightCheck),
|
||||
}
|
||||
|
||||
var specFlow = []pipeline.Handler{
|
||||
pipeline.HandlerFunc(project.Unbind),
|
||||
pipeline.HandlerFunc(collect.PreFlight),
|
||||
pipeline.HandlerFunc(collect.ProvisionedService),
|
||||
pipeline.HandlerFunc(collect.DirectSecretReference),
|
||||
pipeline.HandlerFunc(collect.BindingDefinitions),
|
||||
pipeline.HandlerFunc(collect.BindingItems),
|
||||
pipeline.HandlerFunc(project.PreFlightCheck("type")),
|
||||
pipeline.HandlerFunc(project.BindingsAsEnv),
|
||||
pipeline.HandlerFunc(project.BindingsAsFiles),
|
||||
pipeline.HandlerFunc(project.PostFlightCheck),
|
||||
}
|
||||
|
||||
var (
|
||||
DefaultBuilder = Builder().WithHandlers(defaultFlow...)
|
||||
|
||||
SpecBuilder = Builder().WithHandlers(specFlow...)
|
||||
)
|
||||
80
vendor/github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/context/application.go
generated
vendored
Normal file
80
vendor/github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/context/application.go
generated
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
package context
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/redhat-developer/service-binding-operator/apis/binding/v1alpha1"
|
||||
"github.com/redhat-developer/service-binding-operator/pkg/converter"
|
||||
"github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const defaultContainerPath = "spec.template.spec.containers"
|
||||
|
||||
var _ pipeline.Application = &application{}
|
||||
|
||||
type application struct {
|
||||
gvr *schema.GroupVersionResource
|
||||
persistedResource *unstructured.Unstructured
|
||||
resource *unstructured.Unstructured
|
||||
bindingPath *v1alpha1.BindingPath
|
||||
bindableContainerNames sets.String
|
||||
}
|
||||
|
||||
func (a *application) SecretPath() string {
|
||||
if a.bindingPath != nil {
|
||||
return a.bindingPath.SecretPath
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (a *application) Resource() *unstructured.Unstructured {
|
||||
if a.resource == nil {
|
||||
a.resource = a.persistedResource.DeepCopy()
|
||||
}
|
||||
return a.resource
|
||||
}
|
||||
|
||||
func (a *application) ContainersPath() string {
|
||||
if a.bindingPath == nil || a.bindingPath.ContainersPath == "" {
|
||||
return defaultContainerPath
|
||||
}
|
||||
return a.bindingPath.ContainersPath
|
||||
}
|
||||
|
||||
func (a *application) IsUpdated() bool {
|
||||
return !reflect.DeepEqual(a.persistedResource, a.resource)
|
||||
}
|
||||
|
||||
func (a *application) BindableContainers() ([]map[string]interface{}, error) {
|
||||
path := strings.Split(a.ContainersPath(), ".")
|
||||
containers, found, err := converter.NestedResources(&corev1.Container{}, a.Resource().Object, path...)
|
||||
if !found {
|
||||
err = errors.New("no containers found in application resource")
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
initPath := append(path[:len(path)-1], "initContainers")
|
||||
initContainers, found, err := converter.NestedResources(&corev1.Container{}, a.Resource().Object, initPath...)
|
||||
if found && err == nil {
|
||||
containers = append(containers, initContainers...)
|
||||
}
|
||||
|
||||
if len(a.bindableContainerNames) == 0 {
|
||||
return containers, err
|
||||
}
|
||||
filteredContainers := make([]map[string]interface{}, 0, len(containers))
|
||||
for _, c := range containers {
|
||||
cname, ok := c["name"]
|
||||
if ok && a.bindableContainerNames.Has(fmt.Sprintf("%v", cname)) {
|
||||
filteredContainers = append(filteredContainers, c)
|
||||
}
|
||||
}
|
||||
return filteredContainers, nil
|
||||
}
|
||||
31
vendor/github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/context/flow_ctrl.go
generated
vendored
Normal file
31
vendor/github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/context/flow_ctrl.go
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
package context
|
||||
|
||||
import "github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline"
|
||||
|
||||
type flowCtrl struct {
|
||||
retry bool
|
||||
stop bool
|
||||
err error
|
||||
}
|
||||
|
||||
func (i *flowCtrl) FlowStatus() pipeline.FlowStatus {
|
||||
return pipeline.FlowStatus{
|
||||
Retry: i.retry,
|
||||
Stop: i.stop,
|
||||
Err: i.err,
|
||||
}
|
||||
}
|
||||
|
||||
func (i *flowCtrl) RetryProcessing(reason error) {
|
||||
i.retry = true
|
||||
i.stop = true
|
||||
i.err = reason
|
||||
}
|
||||
|
||||
func (i *flowCtrl) Error(err error) {
|
||||
i.err = err
|
||||
}
|
||||
|
||||
func (i *flowCtrl) StopProcessing() {
|
||||
i.stop = true
|
||||
}
|
||||
387
vendor/github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/context/impl.go
generated
vendored
Normal file
387
vendor/github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/context/impl.go
generated
vendored
Normal file
@@ -0,0 +1,387 @@
|
||||
package context
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha1"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/redhat-developer/service-binding-operator/apis"
|
||||
"github.com/redhat-developer/service-binding-operator/apis/binding/v1alpha1"
|
||||
"sort"
|
||||
|
||||
"github.com/redhat-developer/service-binding-operator/pkg/converter"
|
||||
"github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline"
|
||||
"github.com/redhat-developer/service-binding-operator/pkg/util"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/dynamic"
|
||||
)
|
||||
|
||||
var _ pipeline.Context = &bindingImpl{}
|
||||
|
||||
type impl struct {
|
||||
client dynamic.Interface
|
||||
|
||||
typeLookup K8STypeLookup
|
||||
|
||||
//nolint
|
||||
services []*service
|
||||
|
||||
applications []*application
|
||||
|
||||
bindingItems pipeline.BindingItems
|
||||
|
||||
bindings []pipeline.Bindings
|
||||
|
||||
conditions map[string]*metav1.Condition
|
||||
|
||||
flowCtrl
|
||||
|
||||
bindingMeta *metav1.ObjectMeta
|
||||
|
||||
statusSecretName func() string
|
||||
|
||||
setStatusSecretName func(name string)
|
||||
|
||||
unstructuredBinding func() (*unstructured.Unstructured, error)
|
||||
|
||||
statusConditions func() *[]metav1.Condition
|
||||
|
||||
ownerReference func() metav1.OwnerReference
|
||||
|
||||
groupVersionResource func() schema.GroupVersionResource
|
||||
}
|
||||
|
||||
type bindingImpl struct {
|
||||
impl
|
||||
serviceBinding *v1alpha1.ServiceBinding
|
||||
}
|
||||
|
||||
func (i *impl) UnbindRequested() bool {
|
||||
return !i.bindingMeta.DeletionTimestamp.IsZero()
|
||||
}
|
||||
|
||||
type provider struct {
|
||||
client dynamic.Interface
|
||||
typeLookup K8STypeLookup
|
||||
get func(binding interface{}) (pipeline.Context, error)
|
||||
}
|
||||
|
||||
func (p *provider) Get(binding interface{}) (pipeline.Context, error) {
|
||||
return p.get(binding)
|
||||
}
|
||||
|
||||
var Provider = func(client dynamic.Interface, typeLookup K8STypeLookup) pipeline.ContextProvider {
|
||||
return &provider{
|
||||
client: client,
|
||||
typeLookup: typeLookup,
|
||||
get: func(binding interface{}) (pipeline.Context, error) {
|
||||
switch sb := binding.(type) {
|
||||
case *v1alpha1.ServiceBinding:
|
||||
return &bindingImpl{
|
||||
impl: impl{
|
||||
conditions: make(map[string]*metav1.Condition),
|
||||
client: client,
|
||||
typeLookup: typeLookup,
|
||||
bindingMeta: &sb.ObjectMeta,
|
||||
statusSecretName: func() string {
|
||||
return sb.Status.Secret
|
||||
},
|
||||
setStatusSecretName: func(name string) {
|
||||
sb.Status.Secret = name
|
||||
},
|
||||
unstructuredBinding: func() (*unstructured.Unstructured, error) {
|
||||
return converter.ToUnstructured(sb)
|
||||
},
|
||||
statusConditions: func() *[]metav1.Condition {
|
||||
return &sb.Status.Conditions
|
||||
},
|
||||
ownerReference: func() metav1.OwnerReference {
|
||||
return sb.AsOwnerReference()
|
||||
},
|
||||
groupVersionResource: func() schema.GroupVersionResource {
|
||||
return v1alpha1.GroupVersionResource
|
||||
},
|
||||
},
|
||||
serviceBinding: sb,
|
||||
}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("cannot create context for passed instance %v", binding)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (i *bindingImpl) BindingName() string {
|
||||
return i.bindingMeta.GetName()
|
||||
}
|
||||
|
||||
func (i *bindingImpl) EnvBindings() []*pipeline.EnvBinding {
|
||||
return make([]*pipeline.EnvBinding, 0)
|
||||
}
|
||||
|
||||
func (i *bindingImpl) MountPath() string {
|
||||
return i.serviceBinding.Spec.MountPath
|
||||
}
|
||||
|
||||
func (i *bindingImpl) Mappings() map[string]string {
|
||||
result := make(map[string]string)
|
||||
for _, m := range i.serviceBinding.Spec.Mappings {
|
||||
result[m.Name] = m.Value
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (i *bindingImpl) Services() ([]pipeline.Service, error) {
|
||||
if i.services == nil {
|
||||
serviceRefs := i.serviceBinding.Spec.Services
|
||||
for idx := 0; idx < len(serviceRefs); idx++ {
|
||||
serviceRef := serviceRefs[idx]
|
||||
gvr, err := i.typeLookup.ResourceForReferable(&serviceRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if serviceRef.Namespace == nil {
|
||||
serviceRef.Namespace = &i.serviceBinding.Namespace
|
||||
}
|
||||
u, err := i.client.Resource(*gvr).Namespace(*serviceRef.Namespace).Get(context.Background(), serviceRef.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
i.services = append(i.services, &service{client: i.client, resource: u, groupVersionResource: gvr, namespace: *serviceRef.Namespace, id: serviceRef.Id, lookForOwnedResources: i.serviceBinding.Spec.DetectBindingResources})
|
||||
}
|
||||
}
|
||||
services := make([]pipeline.Service, len(i.services))
|
||||
for idx := 0; idx < len(i.services); idx++ {
|
||||
services[idx] = i.services[idx]
|
||||
}
|
||||
return services, nil
|
||||
}
|
||||
|
||||
// Application return a list of applications.
|
||||
// And if no application found, return an error
|
||||
func (i *bindingImpl) Applications() ([]pipeline.Application, error) {
|
||||
if i.applications == nil {
|
||||
ref := i.serviceBinding.Spec.Application
|
||||
gvr, err := i.typeLookup.ResourceForReferable(&ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if i.serviceBinding.Spec.Application.Name != "" {
|
||||
u, err := i.client.Resource(*gvr).Namespace(i.serviceBinding.Namespace).Get(context.Background(), ref.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, emptyApplicationsErr{err}
|
||||
}
|
||||
i.applications = append(i.applications, &application{gvr: gvr, persistedResource: u, bindingPath: i.serviceBinding.Spec.Application.BindingPath})
|
||||
}
|
||||
if i.serviceBinding.Spec.Application.LabelSelector != nil && i.serviceBinding.Spec.Application.LabelSelector.MatchLabels != nil {
|
||||
matchLabels := i.serviceBinding.Spec.Application.LabelSelector.MatchLabels
|
||||
opts := metav1.ListOptions{
|
||||
LabelSelector: labels.Set(matchLabels).String(),
|
||||
}
|
||||
|
||||
objList, err := i.client.Resource(*gvr).Namespace(i.serviceBinding.Namespace).List(context.Background(), opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(objList.Items) == 0 {
|
||||
return nil, emptyApplicationsErr{}
|
||||
}
|
||||
|
||||
for index := range objList.Items {
|
||||
i.applications = append(i.applications, &application{gvr: gvr, persistedResource: &(objList.Items[index]), bindingPath: i.serviceBinding.Spec.Application.BindingPath})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result := make([]pipeline.Application, len(i.applications))
|
||||
for l, a := range i.applications {
|
||||
result[l] = a
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type emptyApplicationsErr struct {
|
||||
originalErr error
|
||||
}
|
||||
|
||||
func (e emptyApplicationsErr) Error() string {
|
||||
if e.originalErr != nil {
|
||||
return "cannot find application resources for the given reference: " + e.originalErr.Error()
|
||||
}
|
||||
return "cannot find application resources for the given reference"
|
||||
}
|
||||
|
||||
func (i *impl) AddBindingItem(item *pipeline.BindingItem) {
|
||||
i.bindingItems = append(i.bindingItems, item)
|
||||
}
|
||||
|
||||
func (i *impl) BindingItems() pipeline.BindingItems {
|
||||
var allItems pipeline.BindingItems
|
||||
for _, b := range i.bindings {
|
||||
items, err := b.Items()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
allItems = append(allItems, items...)
|
||||
}
|
||||
if len(i.bindingItems) > 0 {
|
||||
allItems = append(allItems, i.bindingItems...)
|
||||
}
|
||||
return allItems
|
||||
}
|
||||
|
||||
func (i *impl) BindingSecretName() string {
|
||||
name, _ := i.bindingSecretName()
|
||||
return name
|
||||
}
|
||||
|
||||
func (i *impl) bindingSecretName() (string, bool) {
|
||||
if i.UnbindRequested() {
|
||||
return i.statusSecretName(), true
|
||||
}
|
||||
if i.bindingItems == nil && len(i.bindings) == 1 {
|
||||
ref := i.bindings[0].Source()
|
||||
if ref != nil && ref.Namespace == i.bindingMeta.GetNamespace() {
|
||||
return ref.Name, true
|
||||
}
|
||||
}
|
||||
data := i.bindingItemMap()
|
||||
keys := make([]string, 0, len(data))
|
||||
for k := range data {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
hash := sha1.New()
|
||||
for _, k := range keys {
|
||||
_, _ = hash.Write([]byte(k))
|
||||
_, _ = hash.Write([]byte(data[k]))
|
||||
}
|
||||
return i.bindingMeta.Name + "-" + string(hex.EncodeToString(hash.Sum(nil))[:8]), false
|
||||
}
|
||||
|
||||
func (i *impl) bindingItemMap() map[string]string {
|
||||
data := make(map[string]string)
|
||||
for _, b := range i.bindings {
|
||||
items, err := b.Items()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
util.MergeMaps(data, items.AsMap())
|
||||
}
|
||||
if len(i.bindingItems) > 0 {
|
||||
util.MergeMaps(data, i.bindingItems.AsMap())
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
func (i *bindingImpl) NamingTemplate() string {
|
||||
return i.serviceBinding.Spec.NamingTemplate()
|
||||
}
|
||||
|
||||
func (i *bindingImpl) BindAsFiles() bool {
|
||||
return i.serviceBinding.Spec.BindAsFiles
|
||||
}
|
||||
|
||||
func (i *impl) persistBinding() error {
|
||||
if i.bindingMeta.UID == "" {
|
||||
return nil
|
||||
}
|
||||
for _, c := range i.conditions {
|
||||
meta.SetStatusCondition(i.statusConditions(), *c)
|
||||
}
|
||||
u, err := i.unstructuredBinding()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client := i.client.Resource(i.groupVersionResource()).Namespace(i.bindingMeta.Namespace)
|
||||
_, err = client.UpdateStatus(context.Background(), u, metav1.UpdateOptions{})
|
||||
return err
|
||||
}
|
||||
|
||||
func (i *impl) persistSecret() (string, error) {
|
||||
name, secretExist := i.bindingSecretName()
|
||||
if secretExist {
|
||||
return name, nil
|
||||
}
|
||||
data := i.bindingItemMap()
|
||||
if len(data) == 0 {
|
||||
return "", nil
|
||||
}
|
||||
secret := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: i.bindingMeta.Namespace,
|
||||
Name: name,
|
||||
},
|
||||
StringData: data,
|
||||
}
|
||||
if i.bindingMeta.UID != "" {
|
||||
secret.OwnerReferences = []metav1.OwnerReference{i.ownerReference()}
|
||||
}
|
||||
u, err := converter.ToUnstructuredAsGVK(secret, corev1.SchemeGroupVersion.WithKind("Secret"))
|
||||
if err != nil {
|
||||
return name, err
|
||||
}
|
||||
|
||||
secretClient := i.client.Resource(corev1.SchemeGroupVersion.WithResource("secrets")).Namespace(i.bindingMeta.Namespace)
|
||||
|
||||
_, err = secretClient.Get(context.Background(), name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
_, err = secretClient.Create(context.Background(), u, metav1.CreateOptions{})
|
||||
return name, err
|
||||
}
|
||||
return name, err
|
||||
}
|
||||
_, err = secretClient.Update(context.Background(), u, metav1.UpdateOptions{})
|
||||
return name, err
|
||||
}
|
||||
|
||||
func (i *impl) Close() error {
|
||||
if i.err != nil {
|
||||
i.SetCondition(apis.Conditions().NotBindingReady().Reason("ProcessingError").Msg(i.err.Error()).Build())
|
||||
return i.persistBinding()
|
||||
}
|
||||
secretName, err := i.persistSecret()
|
||||
if err != nil {
|
||||
i.SetCondition(apis.Conditions().NotBindingReady().Reason("ErrorPersistingSecret").Msg(err.Error()).Build())
|
||||
_ = i.persistBinding()
|
||||
return err
|
||||
}
|
||||
if secretName != "" {
|
||||
i.setStatusSecretName(secretName)
|
||||
}
|
||||
for _, app := range i.applications {
|
||||
if app.IsUpdated() {
|
||||
_, err = i.client.Resource(*app.gvr).Namespace(i.bindingMeta.Namespace).Update(context.Background(), app.Resource(), metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
i.SetCondition(apis.Conditions().NotBindingReady().Reason("ApplicationUpdateError").Msg(err.Error()).Build())
|
||||
_ = i.persistBinding()
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
i.SetCondition(apis.Conditions().BindingReady().Reason("ApplicationsBound").Build())
|
||||
return i.persistBinding()
|
||||
}
|
||||
|
||||
func (i *impl) SetCondition(condition *metav1.Condition) {
|
||||
i.conditions[condition.Type] = condition
|
||||
}
|
||||
|
||||
func (i *impl) ReadConfigMap(namespace string, name string) (*unstructured.Unstructured, error) {
|
||||
return i.client.Resource(schema.GroupVersionResource{Group: "", Version: "v1", Resource: "configmaps"}).Namespace(namespace).Get(context.Background(), name, metav1.GetOptions{})
|
||||
}
|
||||
|
||||
func (i *impl) ReadSecret(namespace string, name string) (*unstructured.Unstructured, error) {
|
||||
return i.client.Resource(schema.GroupVersionResource{Group: "", Version: "v1", Resource: "secrets"}).Namespace(namespace).Get(context.Background(), name, metav1.GetOptions{})
|
||||
}
|
||||
|
||||
func (i *impl) AddBindings(bindings pipeline.Bindings) {
|
||||
i.bindings = append(i.bindings, bindings)
|
||||
}
|
||||
50
vendor/github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/context/resource_lookup.go
generated
vendored
Normal file
50
vendor/github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/context/resource_lookup.go
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
package context
|
||||
|
||||
import (
|
||||
"github.com/redhat-developer/service-binding-operator/pkg/client/kubernetes"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
//go:generate mockgen -destination=mocks/mocks.go -package=mocks . K8STypeLookup
|
||||
|
||||
type K8STypeLookup interface {
|
||||
ResourceForReferable(obj kubernetes.Referable) (*schema.GroupVersionResource, error)
|
||||
ResourceForKind(gvk schema.GroupVersionKind) (*schema.GroupVersionResource, error)
|
||||
KindForResource(gvr schema.GroupVersionResource) (*schema.GroupVersionKind, error)
|
||||
}
|
||||
|
||||
type resourceLookup struct {
|
||||
restMapper meta.RESTMapper
|
||||
}
|
||||
|
||||
func ResourceLookup(restMapper meta.RESTMapper) K8STypeLookup {
|
||||
return &resourceLookup{
|
||||
restMapper: restMapper,
|
||||
}
|
||||
}
|
||||
|
||||
func (i *resourceLookup) ResourceForReferable(obj kubernetes.Referable) (*schema.GroupVersionResource, error) {
|
||||
gvr, err := obj.GroupVersionResource()
|
||||
if err == nil {
|
||||
return gvr, nil
|
||||
}
|
||||
gvk, err := obj.GroupVersionKind()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return i.ResourceForKind(*gvk)
|
||||
}
|
||||
|
||||
func (i *resourceLookup) ResourceForKind(gvk schema.GroupVersionKind) (*schema.GroupVersionResource, error) {
|
||||
mapping, err := i.restMapper.RESTMapping(gvk.GroupKind(), gvk.Version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mapping.Resource, nil
|
||||
}
|
||||
|
||||
func (i *resourceLookup) KindForResource(gvr schema.GroupVersionResource) (*schema.GroupVersionKind, error) {
|
||||
gvk, err := i.restMapper.KindFor(gvr)
|
||||
return &gvk, err
|
||||
}
|
||||
174
vendor/github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/context/service.go
generated
vendored
Normal file
174
vendor/github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/context/service.go
generated
vendored
Normal file
@@ -0,0 +1,174 @@
|
||||
package context
|
||||
|
||||
import (
|
||||
"context"
|
||||
e "errors"
|
||||
olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
|
||||
"github.com/redhat-developer/service-binding-operator/pkg/binding"
|
||||
"github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
var _ pipeline.Service = &service{}
|
||||
|
||||
var crdGVRs = []schema.GroupVersionResource{
|
||||
{
|
||||
Group: "apiextensions.k8s.io",
|
||||
Version: "v1",
|
||||
Resource: "customresourcedefinitions",
|
||||
},
|
||||
{
|
||||
Group: "apiextensions.k8s.io",
|
||||
Version: "v1beta1",
|
||||
Resource: "customresourcedefinitions",
|
||||
},
|
||||
}
|
||||
|
||||
var bindableResourceGVRs = []schema.GroupVersionResource{
|
||||
{Group: "", Version: "v1", Resource: "configmaps"},
|
||||
{Group: "", Version: "v1", Resource: "secrets"},
|
||||
{Group: "", Version: "v1", Resource: "services"},
|
||||
{Group: "route.openshift.io", Version: "v1", Resource: "routes"},
|
||||
}
|
||||
|
||||
type service struct {
|
||||
client dynamic.Interface
|
||||
namespace string
|
||||
resource *unstructured.Unstructured
|
||||
groupVersionResource *schema.GroupVersionResource
|
||||
crd *customResourceDefinition
|
||||
crdLookup bool
|
||||
lookForOwnedResources bool
|
||||
bindingDefinitions []binding.Definition
|
||||
id *string
|
||||
}
|
||||
|
||||
func (s *service) OwnedResources() ([]*unstructured.Unstructured, error) {
|
||||
uid := s.Resource().GetUID()
|
||||
var result []*unstructured.Unstructured
|
||||
if !s.lookForOwnedResources {
|
||||
return result, nil
|
||||
}
|
||||
for _, gvr := range bindableResourceGVRs {
|
||||
list, err := s.client.Resource(gvr).Namespace(s.namespace).List(context.Background(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
for i := range list.Items {
|
||||
item := list.Items[i]
|
||||
for _, ownerRef := range item.GetOwnerReferences() {
|
||||
if reflect.DeepEqual(ownerRef.UID, uid) {
|
||||
result = append(result, &item)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *service) Id() *string {
|
||||
return s.id
|
||||
}
|
||||
|
||||
func (s *service) Resource() *unstructured.Unstructured {
|
||||
return s.resource
|
||||
}
|
||||
|
||||
func (s *service) CustomResourceDefinition() (pipeline.CRD, error) {
|
||||
if s.crd == nil {
|
||||
if s.crdLookup {
|
||||
return nil, nil
|
||||
}
|
||||
var err error
|
||||
var u *unstructured.Unstructured
|
||||
for _, crd := range crdGVRs {
|
||||
u, err = s.client.Resource(crd).Get(context.Background(), s.groupVersionResource.GroupResource().String(), metav1.GetOptions{})
|
||||
if err == nil {
|
||||
s.crd = &customResourceDefinition{resource: u, client: s.client, ns: s.namespace, serviceGVR: s.groupVersionResource}
|
||||
return s.crd, nil
|
||||
}
|
||||
}
|
||||
if errors.IsNotFound(err) {
|
||||
s.crdLookup = true
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return s.crd, nil
|
||||
}
|
||||
|
||||
func (s *service) AddBindingDef(def binding.Definition) {
|
||||
s.bindingDefinitions = append(s.bindingDefinitions, def)
|
||||
}
|
||||
|
||||
func (s *service) BindingDefs() []binding.Definition {
|
||||
return s.bindingDefinitions
|
||||
}
|
||||
|
||||
type customResourceDefinition struct {
|
||||
resource *unstructured.Unstructured
|
||||
serviceGVR *schema.GroupVersionResource
|
||||
client dynamic.Interface
|
||||
ns string
|
||||
}
|
||||
|
||||
func (c *customResourceDefinition) Resource() *unstructured.Unstructured {
|
||||
return c.resource
|
||||
}
|
||||
|
||||
func (c *customResourceDefinition) kind() string {
|
||||
val, found, _ := unstructured.NestedString(c.resource.Object, "spec", "names", "kind")
|
||||
if found {
|
||||
return val
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (c *customResourceDefinition) Descriptor() (*olmv1alpha1.CRDDescription, error) {
|
||||
csvs, err := c.client.Resource(olmv1alpha1.SchemeGroupVersion.WithResource("clusterserviceversions")).Namespace(c.ns).List(context.Background(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if len(csvs.Items) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
for _, csv := range csvs.Items {
|
||||
ownedPath := []string{"spec", "customresourcedefinitions", "owned"}
|
||||
|
||||
ownedCRDs, exists, err := unstructured.NestedSlice(csv.Object, ownedPath...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !exists {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, crd := range ownedCRDs {
|
||||
crdDesciption := &olmv1alpha1.CRDDescription{}
|
||||
data, ok := crd.(map[string]interface{})
|
||||
if !ok {
|
||||
return nil, e.New("cannot cast to map")
|
||||
}
|
||||
err := runtime.DefaultUnstructuredConverter.FromUnstructured(data, crdDesciption)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if crdDesciption.Name == c.Resource().GetName() && crdDesciption.Kind == c.kind() && crdDesciption.Version == c.serviceGVR.Version {
|
||||
return crdDesciption, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
174
vendor/github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/context/spec_binding_impl.go
generated
vendored
Normal file
174
vendor/github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/context/spec_binding_impl.go
generated
vendored
Normal file
@@ -0,0 +1,174 @@
|
||||
package context
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/redhat-developer/service-binding-operator/apis/spec/v1alpha2"
|
||||
"github.com/redhat-developer/service-binding-operator/pkg/converter"
|
||||
"github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/client-go/dynamic"
|
||||
)
|
||||
|
||||
var _ pipeline.Context = &specImpl{}
|
||||
|
||||
var SpecProvider = func(client dynamic.Interface, typeLookup K8STypeLookup) pipeline.ContextProvider {
|
||||
return &provider{
|
||||
client: client,
|
||||
typeLookup: typeLookup,
|
||||
get: func(binding interface{}) (pipeline.Context, error) {
|
||||
switch sb := binding.(type) {
|
||||
case *v1alpha2.ServiceBinding:
|
||||
if sb.Generation != 0 {
|
||||
sb.Status.ObservedGeneration = sb.Generation
|
||||
}
|
||||
ctx := &specImpl{
|
||||
impl: impl{
|
||||
conditions: make(map[string]*metav1.Condition),
|
||||
client: client,
|
||||
typeLookup: typeLookup,
|
||||
bindingMeta: &sb.ObjectMeta,
|
||||
statusSecretName: func() string {
|
||||
if sb.Status.Binding == nil {
|
||||
return ""
|
||||
}
|
||||
return sb.Status.Binding.Name
|
||||
},
|
||||
setStatusSecretName: func(name string) {
|
||||
sb.Status.Binding = &v1alpha2.ServiceBindingSecretReference{Name: name}
|
||||
},
|
||||
unstructuredBinding: func() (*unstructured.Unstructured, error) {
|
||||
return converter.ToUnstructured(sb)
|
||||
},
|
||||
statusConditions: func() *[]metav1.Condition {
|
||||
return &sb.Status.Conditions
|
||||
},
|
||||
ownerReference: func() metav1.OwnerReference {
|
||||
return sb.AsOwnerReference()
|
||||
},
|
||||
groupVersionResource: func() schema.GroupVersionResource {
|
||||
return v1alpha2.GroupVersionResource
|
||||
},
|
||||
},
|
||||
serviceBinding: sb,
|
||||
}
|
||||
if sb.Spec.Type != "" {
|
||||
ctx.AddBindingItem(&pipeline.BindingItem{Name: "type", Value: sb.Spec.Type})
|
||||
}
|
||||
if sb.Spec.Provider != "" {
|
||||
ctx.AddBindingItem(&pipeline.BindingItem{Name: "provider", Value: sb.Spec.Provider})
|
||||
}
|
||||
return ctx, nil
|
||||
}
|
||||
return nil, fmt.Errorf("cannot create context for passed instance %v", binding)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type specImpl struct {
|
||||
impl
|
||||
serviceBinding *v1alpha2.ServiceBinding
|
||||
}
|
||||
|
||||
func (i *specImpl) BindingName() string {
|
||||
if i.serviceBinding.Spec.Name != "" {
|
||||
return i.serviceBinding.Spec.Name
|
||||
}
|
||||
return i.bindingMeta.Name
|
||||
}
|
||||
|
||||
func (i *specImpl) EnvBindings() []*pipeline.EnvBinding {
|
||||
if len(i.serviceBinding.Spec.Env) == 0 {
|
||||
return make([]*pipeline.EnvBinding, 0)
|
||||
}
|
||||
result := make([]*pipeline.EnvBinding, 0, len(i.serviceBinding.Spec.Env))
|
||||
for _, e := range i.serviceBinding.Spec.Env {
|
||||
result = append(result, &pipeline.EnvBinding{Var: e.Name, Name: e.Key})
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (i *specImpl) Services() ([]pipeline.Service, error) {
|
||||
if i.services == nil {
|
||||
serviceRef := i.serviceBinding.Spec.Service
|
||||
|
||||
gvr, err := i.typeLookup.ResourceForReferable(&serviceRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u, err := i.client.Resource(*gvr).Namespace(i.serviceBinding.Namespace).Get(context.Background(), serviceRef.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
i.services = append(i.services, &service{client: i.client, resource: u, groupVersionResource: gvr, namespace: i.serviceBinding.Namespace})
|
||||
}
|
||||
services := make([]pipeline.Service, len(i.services))
|
||||
for idx := 0; idx < len(i.services); idx++ {
|
||||
services[idx] = i.services[idx]
|
||||
}
|
||||
return services, nil
|
||||
|
||||
}
|
||||
|
||||
func (i *specImpl) Applications() ([]pipeline.Application, error) {
|
||||
if i.applications == nil {
|
||||
ref := i.serviceBinding.Spec.Application
|
||||
gvr, err := i.typeLookup.ResourceForReferable(&ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if i.serviceBinding.Spec.Application.Name != "" {
|
||||
u, err := i.client.Resource(*gvr).Namespace(i.serviceBinding.Namespace).Get(context.Background(), ref.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, emptyApplicationsErr{err}
|
||||
}
|
||||
i.applications = append(i.applications, &application{gvr: gvr, persistedResource: u, bindableContainerNames: sets.NewString(i.serviceBinding.Spec.Application.Containers...)})
|
||||
}
|
||||
if i.serviceBinding.Spec.Application.Selector.MatchLabels != nil {
|
||||
matchLabels := i.serviceBinding.Spec.Application.Selector.MatchLabels
|
||||
opts := metav1.ListOptions{
|
||||
LabelSelector: labels.Set(matchLabels).String(),
|
||||
}
|
||||
|
||||
objList, err := i.client.Resource(*gvr).Namespace(i.serviceBinding.Namespace).List(context.Background(), opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(objList.Items) == 0 {
|
||||
return nil, emptyApplicationsErr{}
|
||||
}
|
||||
|
||||
for index := range objList.Items {
|
||||
i.applications = append(i.applications, &application{gvr: gvr, persistedResource: &(objList.Items[index]), bindableContainerNames: sets.NewString(i.serviceBinding.Spec.Application.Containers...)})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result := make([]pipeline.Application, len(i.applications))
|
||||
for l, a := range i.applications {
|
||||
result[l] = a
|
||||
}
|
||||
return result, nil
|
||||
|
||||
}
|
||||
|
||||
func (s *specImpl) BindAsFiles() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *specImpl) MountPath() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (s *specImpl) NamingTemplate() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (s *specImpl) Mappings() map[string]string {
|
||||
return make(map[string]string)
|
||||
}
|
||||
336
vendor/github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/handler/collect/impl.go
generated
vendored
Normal file
336
vendor/github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/handler/collect/impl.go
generated
vendored
Normal file
@@ -0,0 +1,336 @@
|
||||
package collect
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
|
||||
"github.com/redhat-developer/service-binding-operator/apis"
|
||||
"github.com/redhat-developer/service-binding-operator/pkg/binding"
|
||||
"github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline"
|
||||
"github.com/redhat-developer/service-binding-operator/pkg/util"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
var DataNotMap = errors.New("Returned data are not a map, skip collecting")
|
||||
|
||||
const (
|
||||
ErrorReadingServicesReason = "ErrorReadingServices"
|
||||
ErrorReadingCRD = "ErrorReadingCRD"
|
||||
ErrorReadingDescriptorReason = "ErrorReadingDescriptor"
|
||||
ErrorReadingBindingReason = "ErrorReadingBinding"
|
||||
ErrorReadingSecret = "ErrorReadingSecret"
|
||||
)
|
||||
|
||||
func PreFlight(ctx pipeline.Context) {
|
||||
_, err := ctx.Services()
|
||||
if err != nil {
|
||||
requestRetry(ctx, ErrorReadingServicesReason, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func BindingDefinitions(ctx pipeline.Context) {
|
||||
services, _ := ctx.Services()
|
||||
|
||||
for _, service := range services {
|
||||
anns := make(map[string]string)
|
||||
crd, err := service.CustomResourceDefinition()
|
||||
if err != nil {
|
||||
requestRetry(ctx, ErrorReadingCRD, err)
|
||||
return
|
||||
}
|
||||
if crd != nil {
|
||||
descr, err := crd.Descriptor()
|
||||
if err != nil {
|
||||
requestRetry(ctx, ErrorReadingDescriptorReason, err)
|
||||
return
|
||||
}
|
||||
if descr != nil {
|
||||
util.MergeMaps(anns, bindingAnnotations(descr))
|
||||
}
|
||||
util.MergeMaps(anns, crd.Resource().GetAnnotations())
|
||||
}
|
||||
|
||||
util.MergeMaps(anns, service.Resource().GetAnnotations())
|
||||
|
||||
for k, v := range anns {
|
||||
definition, err := makeBindingDefinition(k, v, ctx)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
service.AddBindingDef(definition)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BindingItems(ctx pipeline.Context) {
|
||||
services, _ := ctx.Services()
|
||||
|
||||
for _, service := range services {
|
||||
serviceResource := service.Resource()
|
||||
for _, bd := range service.BindingDefs() {
|
||||
bindingValue, err := bd.Apply(serviceResource)
|
||||
if err != nil {
|
||||
requestRetry(ctx, ErrorReadingBindingReason, err)
|
||||
return
|
||||
}
|
||||
val := bindingValue.Get()
|
||||
v := reflect.ValueOf(val)
|
||||
if v.Kind() != reflect.Map {
|
||||
requestRetry(ctx, "DataNotMap", DataNotMap)
|
||||
return
|
||||
}
|
||||
for _, n := range v.MapKeys() {
|
||||
collectItems("", ctx, service, n, v.MapIndex(n).Interface())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const ProvisionedServiceAnnotationKey = "service.binding/provisioned-service"
|
||||
|
||||
func ProvisionedService(ctx pipeline.Context) {
|
||||
services, _ := ctx.Services()
|
||||
|
||||
for _, service := range services {
|
||||
res := service.Resource()
|
||||
secretName, found, err := unstructured.NestedString(res.Object, "status", "binding", "name")
|
||||
if err != nil {
|
||||
requestRetry(ctx, ErrorReadingBindingReason, err)
|
||||
return
|
||||
}
|
||||
if found {
|
||||
if secretName != "" {
|
||||
secret, err := ctx.ReadSecret(res.GetNamespace(), secretName)
|
||||
if err != nil {
|
||||
requestRetry(ctx, ErrorReadingSecret, err)
|
||||
return
|
||||
}
|
||||
ctx.AddBindings(&pipeline.SecretBackedBindings{Service: service, Secret: secret})
|
||||
}
|
||||
} else {
|
||||
crd, err := service.CustomResourceDefinition()
|
||||
if err != nil {
|
||||
requestRetry(ctx, ErrorReadingCRD, err)
|
||||
return
|
||||
}
|
||||
if crd == nil {
|
||||
continue
|
||||
}
|
||||
v, ok := crd.Resource().GetAnnotations()[ProvisionedServiceAnnotationKey]
|
||||
if ok && v == "true" {
|
||||
requestRetry(ctx, ErrorReadingBindingReason, fmt.Errorf("CRD of service %v/%v indicates provisioned service, but no secret name provided under .status.binding.name", res.GetNamespace(), res.GetName()))
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func DirectSecretReference(ctx pipeline.Context) {
|
||||
// Error is ignored as this check is there in the PreFlight stage.
|
||||
// That stage was created to perform common checks for all followup stages.
|
||||
services, _ := ctx.Services()
|
||||
|
||||
for _, service := range services {
|
||||
res := service.Resource()
|
||||
if res.GetKind() == "Secret" && res.GetAPIVersion() == "v1" && res.GroupVersionKind().Group == "" {
|
||||
annotations := res.GetAnnotations()
|
||||
for k := range annotations {
|
||||
if strings.HasPrefix(k, binding.AnnotationPrefix) {
|
||||
return
|
||||
}
|
||||
}
|
||||
name := res.GetName()
|
||||
secret, err := ctx.ReadSecret(res.GetNamespace(), name)
|
||||
if err != nil {
|
||||
requestRetry(ctx, ErrorReadingSecret, err)
|
||||
return
|
||||
}
|
||||
ctx.AddBindings(&pipeline.SecretBackedBindings{Service: service, Secret: secret})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type pathMapping struct {
|
||||
input string
|
||||
transform func(interface{}) (interface{}, error)
|
||||
output string
|
||||
}
|
||||
|
||||
var bindableResources = map[schema.GroupVersionKind]pathMapping{
|
||||
schema.GroupVersionKind{Group: "", Version: "v1", Kind: "ConfigMap"}: {
|
||||
input: "data",
|
||||
output: "",
|
||||
},
|
||||
schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Secret"}: {
|
||||
input: "data",
|
||||
transform: func(i interface{}) (interface{}, error) {
|
||||
v := reflect.ValueOf(i)
|
||||
if v.Kind() != reflect.Map {
|
||||
return nil, errors.New("data is not map")
|
||||
}
|
||||
result := map[string]string{}
|
||||
|
||||
for _, n := range v.MapKeys() {
|
||||
b, err := base64.StdEncoding.DecodeString(fmt.Sprintf("%v", v.MapIndex(n).Interface()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
key := fmt.Sprintf("%v", n.Interface())
|
||||
result[key] = string(b)
|
||||
}
|
||||
return result, nil
|
||||
},
|
||||
output: "",
|
||||
},
|
||||
schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Service"}: {
|
||||
input: "spec.clusterIP",
|
||||
output: "clusterIP",
|
||||
},
|
||||
schema.GroupVersionKind{
|
||||
Group: "route.openshift.io",
|
||||
Version: "v1",
|
||||
Kind: "Route",
|
||||
}: {
|
||||
input: "spec.host",
|
||||
output: "host",
|
||||
},
|
||||
}
|
||||
|
||||
func OwnedResources(ctx pipeline.Context) {
|
||||
services, err := ctx.Services()
|
||||
if err != nil {
|
||||
requestRetry(ctx, ErrorReadingServicesReason, err)
|
||||
return
|
||||
}
|
||||
for _, service := range services {
|
||||
ownedResources, err := service.OwnedResources()
|
||||
if err != nil {
|
||||
requestRetry(ctx, ErrorReadingServicesReason, err)
|
||||
return
|
||||
}
|
||||
for _, res := range ownedResources {
|
||||
pathMapping, ok := bindableResources[res.GroupVersionKind()]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
val, found, err := unstructured.NestedFieldNoCopy(res.Object, strings.Split(pathMapping.input, ".")...)
|
||||
if !found {
|
||||
err = errors.New("Not found")
|
||||
}
|
||||
if err != nil {
|
||||
requestRetry(ctx, ErrorReadingServicesReason, err)
|
||||
return
|
||||
}
|
||||
if pathMapping.transform != nil {
|
||||
val, err = pathMapping.transform(val)
|
||||
if err != nil {
|
||||
requestRetry(ctx, ErrorReadingServicesReason, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
collectItems("", ctx, service, reflect.ValueOf(pathMapping.output), val)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func collectItems(prefix string, ctx pipeline.Context, service pipeline.Service, k reflect.Value, val interface{}) {
|
||||
v := reflect.ValueOf(val)
|
||||
switch v.Kind() {
|
||||
case reflect.Map:
|
||||
p := prefix + k.String() + "_"
|
||||
if p == "_" {
|
||||
p = ""
|
||||
}
|
||||
for _, n := range v.MapKeys() {
|
||||
collectItems(p, ctx, service, n, v.MapIndex(n).Interface())
|
||||
}
|
||||
case reflect.Slice:
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
ctx.AddBindingItem(&pipeline.BindingItem{Name: fmt.Sprintf("%v_%v", prefix+k.String(), i), Value: v.Index(i).Interface(), Source: service})
|
||||
}
|
||||
default:
|
||||
ctx.AddBindingItem(&pipeline.BindingItem{Name: prefix + k.String(), Value: v.Interface(), Source: service})
|
||||
}
|
||||
}
|
||||
|
||||
func requestRetry(ctx pipeline.Context, reason string, err error) {
|
||||
ctx.RetryProcessing(err)
|
||||
ctx.SetCondition(notCollectionReadyCond(reason, err))
|
||||
}
|
||||
|
||||
func notCollectionReadyCond(reason string, err error) *metav1.Condition {
|
||||
return apis.Conditions().NotCollectionReady().Reason(reason).Msg(err.Error()).Build()
|
||||
}
|
||||
|
||||
func makeBindingDefinition(key string, value string, ctx pipeline.Context) (binding.Definition, error) {
|
||||
return binding.NewDefinitionBuilder(key,
|
||||
value,
|
||||
func(namespace string, name string) (*unstructured.Unstructured, error) {
|
||||
return ctx.ReadConfigMap(namespace, name)
|
||||
},
|
||||
func(namespace string, name string) (*unstructured.Unstructured, error) {
|
||||
return ctx.ReadSecret(namespace, name)
|
||||
}).Build()
|
||||
}
|
||||
|
||||
func bindingAnnotations(crdDescription *olmv1alpha1.CRDDescription) map[string]string {
|
||||
anns := make(map[string]string)
|
||||
for _, sd := range crdDescription.StatusDescriptors {
|
||||
objectType := getObjectType(sd.XDescriptors)
|
||||
for _, xd := range sd.XDescriptors {
|
||||
loadDescriptor(anns, sd.Path, xd, "status", objectType)
|
||||
}
|
||||
}
|
||||
|
||||
for _, sd := range crdDescription.SpecDescriptors {
|
||||
objectType := getObjectType(sd.XDescriptors)
|
||||
for _, xd := range sd.XDescriptors {
|
||||
loadDescriptor(anns, sd.Path, xd, "spec", objectType)
|
||||
}
|
||||
}
|
||||
return anns
|
||||
}
|
||||
|
||||
func getObjectType(descriptors []string) string {
|
||||
typeAnno := "urn:alm:descriptor:io.kubernetes:"
|
||||
for _, desc := range descriptors {
|
||||
if strings.HasPrefix(desc, typeAnno) {
|
||||
return strings.TrimPrefix(desc, typeAnno)
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func loadDescriptor(anns map[string]string, path string, descriptor string, root string, objectType string) {
|
||||
if !strings.HasPrefix(descriptor, binding.AnnotationPrefix) {
|
||||
return
|
||||
}
|
||||
|
||||
keys := strings.Split(descriptor, ":")
|
||||
key := binding.AnnotationPrefix
|
||||
value := ""
|
||||
|
||||
if len(keys) > 1 {
|
||||
key += "/" + keys[1]
|
||||
} else {
|
||||
key += "/" + path
|
||||
}
|
||||
|
||||
p := []string{fmt.Sprintf("path={.%s.%s}", root, path)}
|
||||
if len(keys) > 1 {
|
||||
p = append(p, keys[2:]...)
|
||||
}
|
||||
if objectType != "" {
|
||||
p = append(p, []string{fmt.Sprintf("objectType=%s", objectType)}...)
|
||||
}
|
||||
|
||||
value += strings.Join(p, ",")
|
||||
anns[key] = value
|
||||
}
|
||||
49
vendor/github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/handler/mapping/impl.go
generated
vendored
Normal file
49
vendor/github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/handler/mapping/impl.go
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
package mapping
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
func Handle(ctx pipeline.Context) {
|
||||
bindingItems := ctx.BindingItems()
|
||||
templateVars := make(map[string]interface{})
|
||||
|
||||
services, _ := ctx.Services()
|
||||
for _, s := range services {
|
||||
if s.Id() != nil {
|
||||
templateVars[*s.Id()] = s.Resource().Object
|
||||
}
|
||||
}
|
||||
for _, bi := range bindingItems {
|
||||
templateVars[bi.Name] = bi.Value
|
||||
}
|
||||
|
||||
for name, valueTemplate := range ctx.Mappings() {
|
||||
tmpl, err := template.New("mappings").Funcs(template.FuncMap{"json": marshalToJSON}).Parse(valueTemplate)
|
||||
if err != nil {
|
||||
ctx.StopProcessing()
|
||||
ctx.Error(err)
|
||||
return
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
err = tmpl.Execute(&buf, templateVars)
|
||||
if err != nil {
|
||||
ctx.StopProcessing()
|
||||
ctx.Error(err)
|
||||
return
|
||||
}
|
||||
ctx.AddBindingItem(&pipeline.BindingItem{Name: name, Value: buf.String()})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func marshalToJSON(m interface{}) (string, error) {
|
||||
bytes, err := json.Marshal(m)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(bytes), nil
|
||||
}
|
||||
40
vendor/github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/handler/naming/impl.go
generated
vendored
Normal file
40
vendor/github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/handler/naming/impl.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
package naming
|
||||
|
||||
import (
|
||||
"github.com/redhat-developer/service-binding-operator/apis"
|
||||
"github.com/redhat-developer/service-binding-operator/pkg/naming"
|
||||
"github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline"
|
||||
)
|
||||
|
||||
const StrategyError = "NamingStrategyError"
|
||||
|
||||
func Handle(ctx pipeline.Context) {
|
||||
for _, item := range ctx.BindingItems() {
|
||||
if item.Source != nil {
|
||||
template, err := naming.NewTemplate(ctx.NamingTemplate(), templateData(item.Source))
|
||||
if err != nil {
|
||||
stop(ctx, err)
|
||||
return
|
||||
}
|
||||
item.Name, err = template.GetBindingName(item.Name)
|
||||
if err != nil {
|
||||
stop(ctx, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func templateData(service pipeline.Service) map[string]interface{} {
|
||||
res := service.Resource()
|
||||
return map[string]interface{}{
|
||||
"kind": res.GetKind(),
|
||||
"name": res.GetName(),
|
||||
}
|
||||
}
|
||||
|
||||
func stop(ctx pipeline.Context, err error) {
|
||||
ctx.Error(err)
|
||||
ctx.StopProcessing()
|
||||
ctx.SetCondition(apis.Conditions().NotCollectionReady().Reason(StrategyError).Msg(err.Error()).Build())
|
||||
}
|
||||
402
vendor/github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/handler/project/impl.go
generated
vendored
Normal file
402
vendor/github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/handler/project/impl.go
generated
vendored
Normal file
@@ -0,0 +1,402 @@
|
||||
package project
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/redhat-developer/service-binding-operator/apis"
|
||||
"github.com/redhat-developer/service-binding-operator/pkg/converter"
|
||||
"github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"path"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func PreFlightCheck(mandatoryBindingKeys ...string) func(pipeline.Context) {
|
||||
return func(ctx pipeline.Context) {
|
||||
ctx.SetCondition(apis.Conditions().CollectionReady().DataCollected().Build())
|
||||
applications, err := ctx.Applications()
|
||||
if err != nil {
|
||||
ctx.RetryProcessing(err)
|
||||
ctx.SetCondition(apis.Conditions().NotInjectionReady().ApplicationNotFound().Msg(err.Error()).Build())
|
||||
return
|
||||
}
|
||||
if len(applications) == 0 {
|
||||
ctx.SetCondition(apis.Conditions().NotInjectionReady().Reason(apis.EmptyApplicationReason).Build())
|
||||
ctx.StopProcessing()
|
||||
return
|
||||
}
|
||||
if len(mandatoryBindingKeys) > 0 {
|
||||
items := ctx.BindingItems()
|
||||
itemMap := items.AsMap()
|
||||
for _, bk := range mandatoryBindingKeys {
|
||||
if _, found := itemMap[bk]; !found {
|
||||
err := fmt.Errorf("Mandatory binding '%v' not found", bk)
|
||||
ctx.SetCondition(apis.Conditions().NotInjectionReady().Reason(apis.RequiredBindingNotFound).Msg(err.Error()).Build())
|
||||
ctx.Error(err)
|
||||
ctx.StopProcessing()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func PostFlightCheck(ctx pipeline.Context) {
|
||||
ctx.SetCondition(apis.Conditions().InjectionReady().Reason("ApplicationUpdated").Build())
|
||||
}
|
||||
|
||||
func InjectSecretRef(ctx pipeline.Context) {
|
||||
applications, _ := ctx.Applications()
|
||||
for _, app := range applications {
|
||||
secretPath := app.SecretPath()
|
||||
if secretPath == "" {
|
||||
continue
|
||||
}
|
||||
err := unstructured.SetNestedField(app.Resource().Object, ctx.BindingSecretName(), strings.Split(secretPath, ".")...)
|
||||
if err != nil {
|
||||
stop(ctx, err)
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func BindingsAsEnv(ctx pipeline.Context) {
|
||||
envBindings := ctx.EnvBindings()
|
||||
if ctx.BindAsFiles() && len(envBindings) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
secretName := ctx.BindingSecretName()
|
||||
var envVars []interface{}
|
||||
if len(envBindings) > 0 {
|
||||
envVars = make([]interface{}, 0, len(envBindings))
|
||||
for _, e := range envBindings {
|
||||
u, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&corev1.EnvVar{
|
||||
Name: e.Var,
|
||||
ValueFrom: &corev1.EnvVarSource{
|
||||
SecretKeyRef: &corev1.SecretKeySelector{
|
||||
LocalObjectReference: corev1.LocalObjectReference{
|
||||
Name: secretName,
|
||||
},
|
||||
Key: e.Name,
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
stop(ctx, err)
|
||||
return
|
||||
}
|
||||
envVars = append(envVars, u)
|
||||
}
|
||||
}
|
||||
applications, _ := ctx.Applications()
|
||||
envFromSecret := corev1.EnvFromSource{
|
||||
SecretRef: &corev1.SecretEnvSource{
|
||||
LocalObjectReference: corev1.LocalObjectReference{
|
||||
Name: secretName,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, app := range applications {
|
||||
if app.SecretPath() != "" {
|
||||
continue
|
||||
}
|
||||
containerResources, err := app.BindableContainers()
|
||||
if containerResources == nil && err == nil {
|
||||
err = errors.New("Containers not found in app resource")
|
||||
}
|
||||
if err != nil {
|
||||
stop(ctx, err)
|
||||
return
|
||||
}
|
||||
for _, container := range containerResources {
|
||||
if !ctx.BindAsFiles() {
|
||||
envFrom, found := container["envFrom"]
|
||||
if !found {
|
||||
|
||||
u, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&envFromSecret)
|
||||
if err != nil {
|
||||
stop(ctx, err)
|
||||
return
|
||||
}
|
||||
container["envFrom"] = []interface{}{u}
|
||||
continue
|
||||
}
|
||||
envFromSlice, ok := envFrom.([]interface{})
|
||||
if !ok {
|
||||
stop(ctx, errors.New("envFrom not a slice"))
|
||||
return
|
||||
}
|
||||
u, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&envFromSecret)
|
||||
if err != nil {
|
||||
stop(ctx, err)
|
||||
return
|
||||
}
|
||||
container["envFrom"] = append(envFromSlice, u)
|
||||
continue
|
||||
}
|
||||
env, found := container["env"]
|
||||
if !found {
|
||||
container["env"] = envVars
|
||||
continue
|
||||
}
|
||||
envSlice, ok := env.([]interface{})
|
||||
if !ok {
|
||||
stop(ctx, errors.New("env not a slice"))
|
||||
return
|
||||
}
|
||||
container["env"] = append(envSlice, envVars...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var volumesPath = []string{"spec", "template", "spec", "volumes"}
|
||||
|
||||
func BindingsAsFiles(ctx pipeline.Context) {
|
||||
if !ctx.BindAsFiles() {
|
||||
return
|
||||
}
|
||||
secretName := ctx.BindingSecretName()
|
||||
bindingName := ctx.BindingName()
|
||||
applications, _ := ctx.Applications()
|
||||
for _, app := range applications {
|
||||
if app.SecretPath() != "" {
|
||||
continue
|
||||
}
|
||||
appResource := app.Resource()
|
||||
volumerResources, found, err := converter.NestedResources(&corev1.Volume{}, appResource.Object, volumesPath...)
|
||||
if err != nil {
|
||||
stop(ctx, err)
|
||||
return
|
||||
}
|
||||
|
||||
volume, err := runtime.DefaultUnstructuredConverter.ToUnstructured(
|
||||
&corev1.Volume{
|
||||
Name: bindingName,
|
||||
VolumeSource: corev1.VolumeSource{
|
||||
Secret: &corev1.SecretVolumeSource{
|
||||
SecretName: secretName,
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
stop(ctx, err)
|
||||
return
|
||||
}
|
||||
if found {
|
||||
var newVolumes []interface{}
|
||||
exist := false
|
||||
for _, v := range volumerResources {
|
||||
if v["name"] == volume["name"] {
|
||||
exist = true
|
||||
if !reflect.DeepEqual(v["secret"], volume["secret"]) {
|
||||
newVolumes = append(newVolumes, volume)
|
||||
} else {
|
||||
newVolumes = append(newVolumes, v)
|
||||
}
|
||||
} else {
|
||||
newVolumes = append(newVolumes, v)
|
||||
}
|
||||
}
|
||||
if !exist {
|
||||
newVolumes = append(newVolumes, volume)
|
||||
}
|
||||
if err = unstructured.SetNestedSlice(appResource.Object, newVolumes, volumesPath...); err != nil {
|
||||
stop(ctx, err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if err = unstructured.SetNestedSlice(appResource.Object, []interface{}{volume}, volumesPath...); err != nil {
|
||||
stop(ctx, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
containerResources, err := app.BindableContainers()
|
||||
if containerResources == nil && err == nil {
|
||||
err = errors.New("Containers not found in app resource")
|
||||
}
|
||||
if err != nil {
|
||||
stop(ctx, err)
|
||||
return
|
||||
}
|
||||
for _, container := range containerResources {
|
||||
mountPath, err := mountPath(container, ctx)
|
||||
if err != nil {
|
||||
stop(ctx, err)
|
||||
return
|
||||
}
|
||||
volumeMounts, found, err := converter.NestedResources(&corev1.VolumeMount{}, container, "volumeMounts")
|
||||
if err != nil {
|
||||
stop(ctx, err)
|
||||
return
|
||||
}
|
||||
u, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&corev1.VolumeMount{
|
||||
Name: bindingName,
|
||||
MountPath: mountPath,
|
||||
})
|
||||
if err != nil {
|
||||
stop(ctx, err)
|
||||
return
|
||||
}
|
||||
if found {
|
||||
var newVolumeMounts []interface{}
|
||||
exist := false
|
||||
for _, vm := range volumeMounts {
|
||||
if vm["name"] == u["name"] {
|
||||
exist = true
|
||||
if !reflect.DeepEqual(vm, u) {
|
||||
newVolumeMounts = append(newVolumeMounts, u)
|
||||
} else {
|
||||
newVolumeMounts = append(newVolumeMounts, vm)
|
||||
}
|
||||
} else {
|
||||
newVolumeMounts = append(newVolumeMounts, vm)
|
||||
}
|
||||
}
|
||||
if !exist {
|
||||
newVolumeMounts = append(newVolumeMounts, u)
|
||||
}
|
||||
container["volumeMounts"] = newVolumeMounts
|
||||
} else {
|
||||
if err := unstructured.SetNestedField(container, []interface{}{u}, "volumeMounts"); err != nil {
|
||||
stop(ctx, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func Unbind(ctx pipeline.Context) {
|
||||
if !ctx.UnbindRequested() {
|
||||
return
|
||||
}
|
||||
applications, err := ctx.Applications()
|
||||
if err != nil || len(applications) == 0 {
|
||||
ctx.StopProcessing()
|
||||
return
|
||||
}
|
||||
secretName := ctx.BindingSecretName()
|
||||
bindingName := ctx.BindingName()
|
||||
if secretName == "" {
|
||||
ctx.StopProcessing()
|
||||
return
|
||||
}
|
||||
for _, app := range applications {
|
||||
appResource := app.Resource()
|
||||
podSpec, found, err := unstructured.NestedFieldNoCopy(appResource.Object, volumesPath[:len(volumesPath)-1]...)
|
||||
if !found || err != nil {
|
||||
continue
|
||||
}
|
||||
podSpecMap, ok := podSpec.(map[string]interface{})
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
volumeResources, found, _ := converter.NestedResources(&corev1.Volume{}, podSpecMap, "volumes")
|
||||
if found {
|
||||
for i, vol := range volumeResources {
|
||||
if val, found, err := unstructured.NestedString(vol, "name"); found && err == nil && val == bindingName {
|
||||
s := append(volumeResources[:i], volumeResources[i+1:]...)
|
||||
if len(s) == 0 {
|
||||
delete(podSpecMap, "volumes")
|
||||
} else {
|
||||
podSpecMap["volumes"] = s
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
containerResources, err := app.BindableContainers()
|
||||
if containerResources == nil && err == nil {
|
||||
ctx.StopProcessing()
|
||||
return
|
||||
}
|
||||
for _, container := range containerResources {
|
||||
envFrom, found, _ := converter.NestedResources(&corev1.EnvFromSource{}, container, "envFrom")
|
||||
if found {
|
||||
for i, envSource := range envFrom {
|
||||
if val, found, err := unstructured.NestedString(envSource, "secretRef", "name"); found && err == nil && val == secretName {
|
||||
s := append(envFrom[:i], envFrom[i+1:]...)
|
||||
if len(s) == 0 {
|
||||
delete(container, "envFrom")
|
||||
} else {
|
||||
container["envFrom"] = s
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
volumeMounts, found, _ := converter.NestedResources(&corev1.VolumeMount{}, container, "volumeMounts")
|
||||
if found {
|
||||
for i, vm := range volumeMounts {
|
||||
if val, found, err := unstructured.NestedString(vm, "name"); found && err == nil && val == bindingName {
|
||||
s := append(volumeMounts[:i], volumeMounts[i+1:]...)
|
||||
if len(s) == 0 {
|
||||
delete(container, "volumeMounts")
|
||||
} else {
|
||||
container["volumeMounts"] = s
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx.StopProcessing()
|
||||
}
|
||||
|
||||
const bindingRootEnvVar = "SERVICE_BINDING_ROOT"
|
||||
|
||||
func mountPath(container map[string]interface{}, ctx pipeline.Context) (string, error) {
|
||||
envs, found, err := converter.NestedResources(&corev1.EnvVar{}, container, "env")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
bindingRoot := ""
|
||||
if found {
|
||||
for _, e := range envs {
|
||||
if e["name"] == bindingRootEnvVar {
|
||||
bindingRoot = fmt.Sprintf("%v", e["value"])
|
||||
return path.Join(bindingRoot, ctx.BindingName()), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mp := ctx.MountPath()
|
||||
if mp == "" {
|
||||
bindingRoot = "/bindings"
|
||||
mp = path.Join(bindingRoot, ctx.BindingName())
|
||||
} else {
|
||||
return mp, nil
|
||||
}
|
||||
|
||||
u, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&corev1.EnvVar{
|
||||
Name: bindingRootEnvVar,
|
||||
Value: bindingRoot,
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
envs = append(envs, u)
|
||||
if found {
|
||||
container["env"] = append(envs, u)
|
||||
} else {
|
||||
if err := unstructured.SetNestedField(container, []interface{}{u}, "env"); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
return mp, nil
|
||||
|
||||
}
|
||||
|
||||
func stop(ctx pipeline.Context, err error) {
|
||||
ctx.StopProcessing()
|
||||
ctx.Error(err)
|
||||
ctx.SetCondition(apis.Conditions().NotInjectionReady().Reason("Error").Msg(err.Error()).Build())
|
||||
}
|
||||
68
vendor/github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/secretbackedbindings.go
generated
vendored
Normal file
68
vendor/github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/secretbackedbindings.go
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
package pipeline
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
var _ Bindings = &SecretBackedBindings{}
|
||||
|
||||
// bindings whose life-cycle is bound to k8s secret
|
||||
type SecretBackedBindings struct {
|
||||
// service associated to the bindings
|
||||
Service Service
|
||||
|
||||
// secret containing the bindings
|
||||
// each binding correspond to a (key, value) pair
|
||||
Secret *unstructured.Unstructured
|
||||
items BindingItems
|
||||
}
|
||||
|
||||
func (s *SecretBackedBindings) Items() (BindingItems, error) {
|
||||
if s.items != nil {
|
||||
return s.items, nil
|
||||
}
|
||||
data, found, err := unstructured.NestedStringMap(s.Secret.Object, "data")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if found {
|
||||
for k, v := range data {
|
||||
val, err := base64.StdEncoding.DecodeString(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.items = append(s.items, &BindingItem{
|
||||
Name: k,
|
||||
Value: string(val),
|
||||
Source: s.Service,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
s.items = make([]*BindingItem, 0)
|
||||
}
|
||||
return s.items, nil
|
||||
}
|
||||
|
||||
func (s *SecretBackedBindings) Source() *corev1.ObjectReference {
|
||||
ref := &corev1.ObjectReference{
|
||||
Kind: s.Secret.GetKind(),
|
||||
APIVersion: s.Secret.GetAPIVersion(),
|
||||
Name: s.Secret.GetName(),
|
||||
Namespace: s.Secret.GetNamespace(),
|
||||
}
|
||||
if s.items == nil {
|
||||
return ref
|
||||
}
|
||||
val, found, err := unstructured.NestedStringMap(s.Secret.Object, "data")
|
||||
if err != nil || !found {
|
||||
return nil
|
||||
}
|
||||
for _, item := range s.items {
|
||||
if _, ok := val[item.Name]; !ok {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return ref
|
||||
}
|
||||
8
vendor/github.com/redhat-developer/service-binding-operator/pkg/util/util.go
generated
vendored
Normal file
8
vendor/github.com/redhat-developer/service-binding-operator/pkg/util/util.go
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
package util
|
||||
|
||||
func MergeMaps(dest map[string]string, src map[string]string) map[string]string {
|
||||
for k, v := range src {
|
||||
dest[k] = v
|
||||
}
|
||||
return dest
|
||||
}
|
||||
202
vendor/gomodules.xyz/jsonpatch/v2/LICENSE
vendored
Normal file
202
vendor/gomodules.xyz/jsonpatch/v2/LICENSE
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
9
vendor/gomodules.xyz/jsonpatch/v2/go.mod
vendored
Normal file
9
vendor/gomodules.xyz/jsonpatch/v2/go.mod
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
module gomodules.xyz/jsonpatch/v2
|
||||
|
||||
go 1.12
|
||||
|
||||
require (
|
||||
github.com/evanphx/json-patch v4.5.0+incompatible
|
||||
github.com/pkg/errors v0.8.1 // indirect
|
||||
github.com/stretchr/testify v1.3.0
|
||||
)
|
||||
11
vendor/gomodules.xyz/jsonpatch/v2/go.sum
vendored
Normal file
11
vendor/gomodules.xyz/jsonpatch/v2/go.sum
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M=
|
||||
github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
336
vendor/gomodules.xyz/jsonpatch/v2/jsonpatch.go
vendored
Normal file
336
vendor/gomodules.xyz/jsonpatch/v2/jsonpatch.go
vendored
Normal file
@@ -0,0 +1,336 @@
|
||||
package jsonpatch
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var errBadJSONDoc = fmt.Errorf("invalid JSON Document")
|
||||
|
||||
type JsonPatchOperation = Operation
|
||||
|
||||
type Operation struct {
|
||||
Operation string `json:"op"`
|
||||
Path string `json:"path"`
|
||||
Value interface{} `json:"value,omitempty"`
|
||||
}
|
||||
|
||||
func (j *Operation) Json() string {
|
||||
b, _ := json.Marshal(j)
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func (j *Operation) MarshalJSON() ([]byte, error) {
|
||||
var b bytes.Buffer
|
||||
b.WriteString("{")
|
||||
b.WriteString(fmt.Sprintf(`"op":"%s"`, j.Operation))
|
||||
b.WriteString(fmt.Sprintf(`,"path":"%s"`, j.Path))
|
||||
// Consider omitting Value for non-nullable operations.
|
||||
if j.Value != nil || j.Operation == "replace" || j.Operation == "add" {
|
||||
v, err := json.Marshal(j.Value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b.WriteString(`,"value":`)
|
||||
b.Write(v)
|
||||
}
|
||||
b.WriteString("}")
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
|
||||
type ByPath []Operation
|
||||
|
||||
func (a ByPath) Len() int { return len(a) }
|
||||
func (a ByPath) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a ByPath) Less(i, j int) bool { return a[i].Path < a[j].Path }
|
||||
|
||||
func NewOperation(op, path string, value interface{}) Operation {
|
||||
return Operation{Operation: op, Path: path, Value: value}
|
||||
}
|
||||
|
||||
// CreatePatch creates a patch as specified in http://jsonpatch.com/
|
||||
//
|
||||
// 'a' is original, 'b' is the modified document. Both are to be given as json encoded content.
|
||||
// The function will return an array of JsonPatchOperations
|
||||
//
|
||||
// An error will be returned if any of the two documents are invalid.
|
||||
func CreatePatch(a, b []byte) ([]Operation, error) {
|
||||
var aI interface{}
|
||||
var bI interface{}
|
||||
err := json.Unmarshal(a, &aI)
|
||||
if err != nil {
|
||||
return nil, errBadJSONDoc
|
||||
}
|
||||
err = json.Unmarshal(b, &bI)
|
||||
if err != nil {
|
||||
return nil, errBadJSONDoc
|
||||
}
|
||||
return handleValues(aI, bI, "", []Operation{})
|
||||
}
|
||||
|
||||
// Returns true if the values matches (must be json types)
|
||||
// The types of the values must match, otherwise it will always return false
|
||||
// If two map[string]interface{} are given, all elements must match.
|
||||
func matchesValue(av, bv interface{}) bool {
|
||||
if reflect.TypeOf(av) != reflect.TypeOf(bv) {
|
||||
return false
|
||||
}
|
||||
switch at := av.(type) {
|
||||
case string:
|
||||
bt, ok := bv.(string)
|
||||
if ok && bt == at {
|
||||
return true
|
||||
}
|
||||
case float64:
|
||||
bt, ok := bv.(float64)
|
||||
if ok && bt == at {
|
||||
return true
|
||||
}
|
||||
case bool:
|
||||
bt, ok := bv.(bool)
|
||||
if ok && bt == at {
|
||||
return true
|
||||
}
|
||||
case map[string]interface{}:
|
||||
bt, ok := bv.(map[string]interface{})
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
for key := range at {
|
||||
if !matchesValue(at[key], bt[key]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
for key := range bt {
|
||||
if !matchesValue(at[key], bt[key]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
case []interface{}:
|
||||
bt, ok := bv.([]interface{})
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if len(bt) != len(at) {
|
||||
return false
|
||||
}
|
||||
for key := range at {
|
||||
if !matchesValue(at[key], bt[key]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
for key := range bt {
|
||||
if !matchesValue(at[key], bt[key]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// From http://tools.ietf.org/html/rfc6901#section-4 :
|
||||
//
|
||||
// Evaluation of each reference token begins by decoding any escaped
|
||||
// character sequence. This is performed by first transforming any
|
||||
// occurrence of the sequence '~1' to '/', and then transforming any
|
||||
// occurrence of the sequence '~0' to '~'.
|
||||
// TODO decode support:
|
||||
// var rfc6901Decoder = strings.NewReplacer("~1", "/", "~0", "~")
|
||||
|
||||
var rfc6901Encoder = strings.NewReplacer("~", "~0", "/", "~1")
|
||||
|
||||
func makePath(path string, newPart interface{}) string {
|
||||
key := rfc6901Encoder.Replace(fmt.Sprintf("%v", newPart))
|
||||
if path == "" {
|
||||
return "/" + key
|
||||
}
|
||||
if strings.HasSuffix(path, "/") {
|
||||
return path + key
|
||||
}
|
||||
return path + "/" + key
|
||||
}
|
||||
|
||||
// diff returns the (recursive) difference between a and b as an array of JsonPatchOperations.
|
||||
func diff(a, b map[string]interface{}, path string, patch []Operation) ([]Operation, error) {
|
||||
for key, bv := range b {
|
||||
p := makePath(path, key)
|
||||
av, ok := a[key]
|
||||
// value was added
|
||||
if !ok {
|
||||
patch = append(patch, NewOperation("add", p, bv))
|
||||
continue
|
||||
}
|
||||
// Types are the same, compare values
|
||||
var err error
|
||||
patch, err = handleValues(av, bv, p, patch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
// Now add all deleted values as nil
|
||||
for key := range a {
|
||||
_, found := b[key]
|
||||
if !found {
|
||||
p := makePath(path, key)
|
||||
|
||||
patch = append(patch, NewOperation("remove", p, nil))
|
||||
}
|
||||
}
|
||||
return patch, nil
|
||||
}
|
||||
|
||||
func handleValues(av, bv interface{}, p string, patch []Operation) ([]Operation, error) {
|
||||
{
|
||||
at := reflect.TypeOf(av)
|
||||
bt := reflect.TypeOf(bv)
|
||||
if at == nil && bt == nil {
|
||||
// do nothing
|
||||
return patch, nil
|
||||
} else if at == nil && bt != nil {
|
||||
return append(patch, NewOperation("add", p, bv)), nil
|
||||
} else if at != bt {
|
||||
// If types have changed, replace completely (preserves null in destination)
|
||||
return append(patch, NewOperation("replace", p, bv)), nil
|
||||
}
|
||||
}
|
||||
|
||||
var err error
|
||||
switch at := av.(type) {
|
||||
case map[string]interface{}:
|
||||
bt := bv.(map[string]interface{})
|
||||
patch, err = diff(at, bt, p, patch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case string, float64, bool:
|
||||
if !matchesValue(av, bv) {
|
||||
patch = append(patch, NewOperation("replace", p, bv))
|
||||
}
|
||||
case []interface{}:
|
||||
bt := bv.([]interface{})
|
||||
if isSimpleArray(at) && isSimpleArray(bt) {
|
||||
patch = append(patch, compareEditDistance(at, bt, p)...)
|
||||
} else {
|
||||
n := min(len(at), len(bt))
|
||||
for i := len(at) - 1; i >= n; i-- {
|
||||
patch = append(patch, NewOperation("remove", makePath(p, i), nil))
|
||||
}
|
||||
for i := n; i < len(bt); i++ {
|
||||
patch = append(patch, NewOperation("add", makePath(p, i), bt[i]))
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
var err error
|
||||
patch, err = handleValues(at[i], bt[i], makePath(p, i), patch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
panic(fmt.Sprintf("Unknown type:%T ", av))
|
||||
}
|
||||
return patch, nil
|
||||
}
|
||||
|
||||
func isBasicType(a interface{}) bool {
|
||||
switch a.(type) {
|
||||
case string, float64, bool:
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func isSimpleArray(a []interface{}) bool {
|
||||
for i := range a {
|
||||
switch a[i].(type) {
|
||||
case string, float64, bool:
|
||||
default:
|
||||
val := reflect.ValueOf(a[i])
|
||||
if val.Kind() == reflect.Map {
|
||||
for _, k := range val.MapKeys() {
|
||||
av := val.MapIndex(k)
|
||||
if av.Kind() == reflect.Ptr || av.Kind() == reflect.Interface {
|
||||
if av.IsNil() {
|
||||
continue
|
||||
}
|
||||
av = av.Elem()
|
||||
}
|
||||
if av.Kind() != reflect.String && av.Kind() != reflect.Float64 && av.Kind() != reflect.Bool {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// https://en.wikipedia.org/wiki/Wagner%E2%80%93Fischer_algorithm
|
||||
// Adapted from https://github.com/texttheater/golang-levenshtein
|
||||
func compareEditDistance(s, t []interface{}, p string) []Operation {
|
||||
m := len(s)
|
||||
n := len(t)
|
||||
|
||||
d := make([][]int, m+1)
|
||||
for i := 0; i <= m; i++ {
|
||||
d[i] = make([]int, n+1)
|
||||
d[i][0] = i
|
||||
}
|
||||
for j := 0; j <= n; j++ {
|
||||
d[0][j] = j
|
||||
}
|
||||
|
||||
for j := 1; j <= n; j++ {
|
||||
for i := 1; i <= m; i++ {
|
||||
if reflect.DeepEqual(s[i-1], t[j-1]) {
|
||||
d[i][j] = d[i-1][j-1] // no op required
|
||||
} else {
|
||||
del := d[i-1][j] + 1
|
||||
add := d[i][j-1] + 1
|
||||
rep := d[i-1][j-1] + 1
|
||||
d[i][j] = min(rep, min(add, del))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return backtrace(s, t, p, m, n, d)
|
||||
}
|
||||
|
||||
func min(x int, y int) int {
|
||||
if y < x {
|
||||
return y
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
func backtrace(s, t []interface{}, p string, i int, j int, matrix [][]int) []Operation {
|
||||
if i > 0 && matrix[i-1][j]+1 == matrix[i][j] {
|
||||
op := NewOperation("remove", makePath(p, i-1), nil)
|
||||
return append([]Operation{op}, backtrace(s, t, p, i-1, j, matrix)...)
|
||||
}
|
||||
if j > 0 && matrix[i][j-1]+1 == matrix[i][j] {
|
||||
op := NewOperation("add", makePath(p, i), t[j-1])
|
||||
return append([]Operation{op}, backtrace(s, t, p, i, j-1, matrix)...)
|
||||
}
|
||||
if i > 0 && j > 0 && matrix[i-1][j-1]+1 == matrix[i][j] {
|
||||
if isBasicType(s[0]) {
|
||||
op := NewOperation("replace", makePath(p, i-1), t[j-1])
|
||||
return append([]Operation{op}, backtrace(s, t, p, i-1, j-1, matrix)...)
|
||||
}
|
||||
|
||||
p2, _ := handleValues(s[i-1], t[j-1], makePath(p, i-1), []Operation{})
|
||||
return append(p2, backtrace(s, t, p, i-1, j-1, matrix)...)
|
||||
}
|
||||
if i > 0 && j > 0 && matrix[i-1][j-1] == matrix[i][j] {
|
||||
return backtrace(s, t, p, i-1, j-1, matrix)
|
||||
}
|
||||
return []Operation{}
|
||||
}
|
||||
5
vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1/.import-restrictions
generated
vendored
Normal file
5
vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1/.import-restrictions
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
inverseRules:
|
||||
# Allow use of this package in all k8s.io packages.
|
||||
- selectorRegexp: k8s[.]io
|
||||
allowedPrefixes:
|
||||
- ''
|
||||
59
vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1/conversion.go
generated
vendored
Normal file
59
vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1/conversion.go
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/conversion"
|
||||
"k8s.io/apimachinery/pkg/util/json"
|
||||
|
||||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
|
||||
)
|
||||
|
||||
func Convert_apiextensions_JSONSchemaProps_To_v1beta1_JSONSchemaProps(in *apiextensions.JSONSchemaProps, out *JSONSchemaProps, s conversion.Scope) error {
|
||||
if err := autoConvert_apiextensions_JSONSchemaProps_To_v1beta1_JSONSchemaProps(in, out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Default != nil && *(in.Default) == nil {
|
||||
out.Default = nil
|
||||
}
|
||||
if in.Example != nil && *(in.Example) == nil {
|
||||
out.Example = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_apiextensions_JSON_To_v1beta1_JSON(in *apiextensions.JSON, out *JSON, s conversion.Scope) error {
|
||||
raw, err := json.Marshal(*in)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
out.Raw = raw
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_v1beta1_JSON_To_apiextensions_JSON(in *JSON, out *apiextensions.JSON, s conversion.Scope) error {
|
||||
if in != nil {
|
||||
var i interface{}
|
||||
if err := json.Unmarshal(in.Raw, &i); err != nil {
|
||||
return err
|
||||
}
|
||||
*out = i
|
||||
} else {
|
||||
out = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
270
vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1/deepcopy.go
generated
vendored
Normal file
270
vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1/deepcopy.go
generated
vendored
Normal file
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1beta1
|
||||
|
||||
// TODO: Update this after a tag is created for interface fields in DeepCopy
|
||||
func (in *JSONSchemaProps) DeepCopy() *JSONSchemaProps {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(JSONSchemaProps)
|
||||
*out = *in
|
||||
|
||||
if in.Ref != nil {
|
||||
in, out := &in.Ref, &out.Ref
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(string)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
if in.Maximum != nil {
|
||||
in, out := &in.Maximum, &out.Maximum
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(float64)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
if in.Minimum != nil {
|
||||
in, out := &in.Minimum, &out.Minimum
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(float64)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
if in.MaxLength != nil {
|
||||
in, out := &in.MaxLength, &out.MaxLength
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(int64)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
if in.MinLength != nil {
|
||||
in, out := &in.MinLength, &out.MinLength
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(int64)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
if in.MaxItems != nil {
|
||||
in, out := &in.MaxItems, &out.MaxItems
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(int64)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
if in.MinItems != nil {
|
||||
in, out := &in.MinItems, &out.MinItems
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(int64)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
if in.MultipleOf != nil {
|
||||
in, out := &in.MultipleOf, &out.MultipleOf
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(float64)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
if in.MaxProperties != nil {
|
||||
in, out := &in.MaxProperties, &out.MaxProperties
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(int64)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
if in.MinProperties != nil {
|
||||
in, out := &in.MinProperties, &out.MinProperties
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(int64)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
if in.Required != nil {
|
||||
in, out := &in.Required, &out.Required
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(JSONSchemaPropsOrArray)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
if in.AllOf != nil {
|
||||
in, out := &in.AllOf, &out.AllOf
|
||||
*out = make([]JSONSchemaProps, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
|
||||
if in.OneOf != nil {
|
||||
in, out := &in.OneOf, &out.OneOf
|
||||
*out = make([]JSONSchemaProps, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.AnyOf != nil {
|
||||
in, out := &in.AnyOf, &out.AnyOf
|
||||
*out = make([]JSONSchemaProps, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
|
||||
if in.Not != nil {
|
||||
in, out := &in.Not, &out.Not
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(JSONSchemaProps)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
if in.Properties != nil {
|
||||
in, out := &in.Properties, &out.Properties
|
||||
*out = make(map[string]JSONSchemaProps, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = *val.DeepCopy()
|
||||
}
|
||||
}
|
||||
|
||||
if in.AdditionalProperties != nil {
|
||||
in, out := &in.AdditionalProperties, &out.AdditionalProperties
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(JSONSchemaPropsOrBool)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
if in.PatternProperties != nil {
|
||||
in, out := &in.PatternProperties, &out.PatternProperties
|
||||
*out = make(map[string]JSONSchemaProps, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = *val.DeepCopy()
|
||||
}
|
||||
}
|
||||
|
||||
if in.Dependencies != nil {
|
||||
in, out := &in.Dependencies, &out.Dependencies
|
||||
*out = make(JSONSchemaDependencies, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = *val.DeepCopy()
|
||||
}
|
||||
}
|
||||
|
||||
if in.AdditionalItems != nil {
|
||||
in, out := &in.AdditionalItems, &out.AdditionalItems
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(JSONSchemaPropsOrBool)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
if in.Definitions != nil {
|
||||
in, out := &in.Definitions, &out.Definitions
|
||||
*out = make(JSONSchemaDefinitions, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = *val.DeepCopy()
|
||||
}
|
||||
}
|
||||
|
||||
if in.ExternalDocs != nil {
|
||||
in, out := &in.ExternalDocs, &out.ExternalDocs
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(ExternalDocumentation)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
if in.XPreserveUnknownFields != nil {
|
||||
in, out := &in.XPreserveUnknownFields, &out.XPreserveUnknownFields
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
if in.XListMapKeys != nil {
|
||||
in, out := &in.XListMapKeys, &out.XListMapKeys
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
|
||||
if in.XListType != nil {
|
||||
in, out := &in.XListType, &out.XListType
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(string)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
if in.XMapType != nil {
|
||||
in, out := &in.XMapType, &out.XMapType
|
||||
*out = new(string)
|
||||
**out = **in
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
82
vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1/defaults.go
generated
vendored
Normal file
82
vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1/defaults.go
generated
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
utilpointer "k8s.io/utils/pointer"
|
||||
)
|
||||
|
||||
func addDefaultingFuncs(scheme *runtime.Scheme) error {
|
||||
return RegisterDefaults(scheme)
|
||||
}
|
||||
|
||||
func SetDefaults_CustomResourceDefinition(obj *CustomResourceDefinition) {
|
||||
SetDefaults_CustomResourceDefinitionSpec(&obj.Spec)
|
||||
if len(obj.Status.StoredVersions) == 0 {
|
||||
for _, v := range obj.Spec.Versions {
|
||||
if v.Storage {
|
||||
obj.Status.StoredVersions = append(obj.Status.StoredVersions, v.Name)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func SetDefaults_CustomResourceDefinitionSpec(obj *CustomResourceDefinitionSpec) {
|
||||
if len(obj.Scope) == 0 {
|
||||
obj.Scope = NamespaceScoped
|
||||
}
|
||||
if len(obj.Names.Singular) == 0 {
|
||||
obj.Names.Singular = strings.ToLower(obj.Names.Kind)
|
||||
}
|
||||
if len(obj.Names.ListKind) == 0 && len(obj.Names.Kind) > 0 {
|
||||
obj.Names.ListKind = obj.Names.Kind + "List"
|
||||
}
|
||||
// If there is no list of versions, create on using deprecated Version field.
|
||||
if len(obj.Versions) == 0 && len(obj.Version) != 0 {
|
||||
obj.Versions = []CustomResourceDefinitionVersion{{
|
||||
Name: obj.Version,
|
||||
Storage: true,
|
||||
Served: true,
|
||||
}}
|
||||
}
|
||||
// For backward compatibility set the version field to the first item in versions list.
|
||||
if len(obj.Version) == 0 && len(obj.Versions) != 0 {
|
||||
obj.Version = obj.Versions[0].Name
|
||||
}
|
||||
if obj.Conversion == nil {
|
||||
obj.Conversion = &CustomResourceConversion{
|
||||
Strategy: NoneConverter,
|
||||
}
|
||||
}
|
||||
if obj.Conversion.Strategy == WebhookConverter && len(obj.Conversion.ConversionReviewVersions) == 0 {
|
||||
obj.Conversion.ConversionReviewVersions = []string{SchemeGroupVersion.Version}
|
||||
}
|
||||
if obj.PreserveUnknownFields == nil {
|
||||
obj.PreserveUnknownFields = utilpointer.BoolPtr(true)
|
||||
}
|
||||
}
|
||||
|
||||
// SetDefaults_ServiceReference sets defaults for Webhook's ServiceReference
|
||||
func SetDefaults_ServiceReference(obj *ServiceReference) {
|
||||
if obj.Port == nil {
|
||||
obj.Port = utilpointer.Int32Ptr(443)
|
||||
}
|
||||
}
|
||||
26
vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1/doc.go
generated
vendored
Normal file
26
vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1/doc.go
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// +k8s:deepcopy-gen=package
|
||||
// +k8s:protobuf-gen=package
|
||||
// +k8s:conversion-gen=k8s.io/apiextensions-apiserver/pkg/apis/apiextensions
|
||||
// +k8s:defaulter-gen=TypeMeta
|
||||
// +k8s:openapi-gen=true
|
||||
// +k8s:prerelease-lifecycle-gen=true
|
||||
// +groupName=apiextensions.k8s.io
|
||||
|
||||
// Package v1beta1 is the v1beta1 version of the API.
|
||||
package v1beta1 // import "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
||||
9103
vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1/generated.pb.go
generated
vendored
Normal file
9103
vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1/generated.pb.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
686
vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1/generated.proto
generated
vendored
Normal file
686
vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1/generated.proto
generated
vendored
Normal file
@@ -0,0 +1,686 @@
|
||||
/*
|
||||
Copyright The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
// This file was autogenerated by go-to-protobuf. Do not edit it manually!
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
package k8s.io.apiextensions_apiserver.pkg.apis.apiextensions.v1beta1;
|
||||
|
||||
import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto";
|
||||
import "k8s.io/apimachinery/pkg/runtime/generated.proto";
|
||||
import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto";
|
||||
|
||||
// Package-wide variables from generator "generated".
|
||||
option go_package = "v1beta1";
|
||||
|
||||
// ConversionRequest describes the conversion request parameters.
|
||||
message ConversionRequest {
|
||||
// uid is an identifier for the individual request/response. It allows distinguishing instances of requests which are
|
||||
// otherwise identical (parallel requests, etc).
|
||||
// The UID is meant to track the round trip (request/response) between the Kubernetes API server and the webhook, not the user request.
|
||||
// It is suitable for correlating log entries between the webhook and apiserver, for either auditing or debugging.
|
||||
optional string uid = 1;
|
||||
|
||||
// desiredAPIVersion is the version to convert given objects to. e.g. "myapi.example.com/v1"
|
||||
optional string desiredAPIVersion = 2;
|
||||
|
||||
// objects is the list of custom resource objects to be converted.
|
||||
repeated k8s.io.apimachinery.pkg.runtime.RawExtension objects = 3;
|
||||
}
|
||||
|
||||
// ConversionResponse describes a conversion response.
|
||||
message ConversionResponse {
|
||||
// uid is an identifier for the individual request/response.
|
||||
// This should be copied over from the corresponding `request.uid`.
|
||||
optional string uid = 1;
|
||||
|
||||
// convertedObjects is the list of converted version of `request.objects` if the `result` is successful, otherwise empty.
|
||||
// The webhook is expected to set `apiVersion` of these objects to the `request.desiredAPIVersion`. The list
|
||||
// must also have the same size as the input list with the same objects in the same order (equal kind, metadata.uid, metadata.name and metadata.namespace).
|
||||
// The webhook is allowed to mutate labels and annotations. Any other change to the metadata is silently ignored.
|
||||
repeated k8s.io.apimachinery.pkg.runtime.RawExtension convertedObjects = 2;
|
||||
|
||||
// result contains the result of conversion with extra details if the conversion failed. `result.status` determines if
|
||||
// the conversion failed or succeeded. The `result.status` field is required and represents the success or failure of the
|
||||
// conversion. A successful conversion must set `result.status` to `Success`. A failed conversion must set
|
||||
// `result.status` to `Failure` and provide more details in `result.message` and return http status 200. The `result.message`
|
||||
// will be used to construct an error message for the end user.
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.Status result = 3;
|
||||
}
|
||||
|
||||
// ConversionReview describes a conversion request/response.
|
||||
message ConversionReview {
|
||||
// request describes the attributes for the conversion request.
|
||||
// +optional
|
||||
optional ConversionRequest request = 1;
|
||||
|
||||
// response describes the attributes for the conversion response.
|
||||
// +optional
|
||||
optional ConversionResponse response = 2;
|
||||
}
|
||||
|
||||
// CustomResourceColumnDefinition specifies a column for server side printing.
|
||||
message CustomResourceColumnDefinition {
|
||||
// name is a human readable name for the column.
|
||||
optional string name = 1;
|
||||
|
||||
// type is an OpenAPI type definition for this column.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types for details.
|
||||
optional string type = 2;
|
||||
|
||||
// format is an optional OpenAPI type definition for this column. The 'name' format is applied
|
||||
// to the primary identifier column to assist in clients identifying column is the resource name.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types for details.
|
||||
// +optional
|
||||
optional string format = 3;
|
||||
|
||||
// description is a human readable description of this column.
|
||||
// +optional
|
||||
optional string description = 4;
|
||||
|
||||
// priority is an integer defining the relative importance of this column compared to others. Lower
|
||||
// numbers are considered higher priority. Columns that may be omitted in limited space scenarios
|
||||
// should be given a priority greater than 0.
|
||||
// +optional
|
||||
optional int32 priority = 5;
|
||||
|
||||
// JSONPath is a simple JSON path (i.e. with array notation) which is evaluated against
|
||||
// each custom resource to produce the value for this column.
|
||||
optional string JSONPath = 6;
|
||||
}
|
||||
|
||||
// CustomResourceConversion describes how to convert different versions of a CR.
|
||||
message CustomResourceConversion {
|
||||
// strategy specifies how custom resources are converted between versions. Allowed values are:
|
||||
// - `None`: The converter only change the apiVersion and would not touch any other field in the custom resource.
|
||||
// - `Webhook`: API Server will call to an external webhook to do the conversion. Additional information
|
||||
// is needed for this option. This requires spec.preserveUnknownFields to be false, and spec.conversion.webhookClientConfig to be set.
|
||||
optional string strategy = 1;
|
||||
|
||||
// webhookClientConfig is the instructions for how to call the webhook if strategy is `Webhook`.
|
||||
// Required when `strategy` is set to `Webhook`.
|
||||
// +optional
|
||||
optional WebhookClientConfig webhookClientConfig = 2;
|
||||
|
||||
// conversionReviewVersions is an ordered list of preferred `ConversionReview`
|
||||
// versions the Webhook expects. The API server will use the first version in
|
||||
// the list which it supports. If none of the versions specified in this list
|
||||
// are supported by API server, conversion will fail for the custom resource.
|
||||
// If a persisted Webhook configuration specifies allowed versions and does not
|
||||
// include any versions known to the API Server, calls to the webhook will fail.
|
||||
// Defaults to `["v1beta1"]`.
|
||||
// +optional
|
||||
repeated string conversionReviewVersions = 3;
|
||||
}
|
||||
|
||||
// CustomResourceDefinition represents a resource that should be exposed on the API server. Its name MUST be in the format
|
||||
// <.spec.name>.<.spec.group>.
|
||||
// Deprecated in v1.16, planned for removal in v1.22. Use apiextensions.k8s.io/v1 CustomResourceDefinition instead.
|
||||
message CustomResourceDefinition {
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1;
|
||||
|
||||
// spec describes how the user wants the resources to appear
|
||||
optional CustomResourceDefinitionSpec spec = 2;
|
||||
|
||||
// status indicates the actual state of the CustomResourceDefinition
|
||||
// +optional
|
||||
optional CustomResourceDefinitionStatus status = 3;
|
||||
}
|
||||
|
||||
// CustomResourceDefinitionCondition contains details for the current condition of this pod.
|
||||
message CustomResourceDefinitionCondition {
|
||||
// type is the type of the condition. Types include Established, NamesAccepted and Terminating.
|
||||
optional string type = 1;
|
||||
|
||||
// status is the status of the condition.
|
||||
// Can be True, False, Unknown.
|
||||
optional string status = 2;
|
||||
|
||||
// lastTransitionTime last time the condition transitioned from one status to another.
|
||||
// +optional
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastTransitionTime = 3;
|
||||
|
||||
// reason is a unique, one-word, CamelCase reason for the condition's last transition.
|
||||
// +optional
|
||||
optional string reason = 4;
|
||||
|
||||
// message is a human-readable message indicating details about last transition.
|
||||
// +optional
|
||||
optional string message = 5;
|
||||
}
|
||||
|
||||
// CustomResourceDefinitionList is a list of CustomResourceDefinition objects.
|
||||
message CustomResourceDefinitionList {
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1;
|
||||
|
||||
// items list individual CustomResourceDefinition objects
|
||||
repeated CustomResourceDefinition items = 2;
|
||||
}
|
||||
|
||||
// CustomResourceDefinitionNames indicates the names to serve this CustomResourceDefinition
|
||||
message CustomResourceDefinitionNames {
|
||||
// plural is the plural name of the resource to serve.
|
||||
// The custom resources are served under `/apis/<group>/<version>/.../<plural>`.
|
||||
// Must match the name of the CustomResourceDefinition (in the form `<names.plural>.<group>`).
|
||||
// Must be all lowercase.
|
||||
optional string plural = 1;
|
||||
|
||||
// singular is the singular name of the resource. It must be all lowercase. Defaults to lowercased `kind`.
|
||||
// +optional
|
||||
optional string singular = 2;
|
||||
|
||||
// shortNames are short names for the resource, exposed in API discovery documents,
|
||||
// and used by clients to support invocations like `kubectl get <shortname>`.
|
||||
// It must be all lowercase.
|
||||
// +optional
|
||||
repeated string shortNames = 3;
|
||||
|
||||
// kind is the serialized kind of the resource. It is normally CamelCase and singular.
|
||||
// Custom resource instances will use this value as the `kind` attribute in API calls.
|
||||
optional string kind = 4;
|
||||
|
||||
// listKind is the serialized kind of the list for this resource. Defaults to "`kind`List".
|
||||
// +optional
|
||||
optional string listKind = 5;
|
||||
|
||||
// categories is a list of grouped resources this custom resource belongs to (e.g. 'all').
|
||||
// This is published in API discovery documents, and used by clients to support invocations like
|
||||
// `kubectl get all`.
|
||||
// +optional
|
||||
repeated string categories = 6;
|
||||
}
|
||||
|
||||
// CustomResourceDefinitionSpec describes how a user wants their resource to appear
|
||||
message CustomResourceDefinitionSpec {
|
||||
// group is the API group of the defined custom resource.
|
||||
// The custom resources are served under `/apis/<group>/...`.
|
||||
// Must match the name of the CustomResourceDefinition (in the form `<names.plural>.<group>`).
|
||||
optional string group = 1;
|
||||
|
||||
// version is the API version of the defined custom resource.
|
||||
// The custom resources are served under `/apis/<group>/<version>/...`.
|
||||
// Must match the name of the first item in the `versions` list if `version` and `versions` are both specified.
|
||||
// Optional if `versions` is specified.
|
||||
// Deprecated: use `versions` instead.
|
||||
// +optional
|
||||
optional string version = 2;
|
||||
|
||||
// names specify the resource and kind names for the custom resource.
|
||||
optional CustomResourceDefinitionNames names = 3;
|
||||
|
||||
// scope indicates whether the defined custom resource is cluster- or namespace-scoped.
|
||||
// Allowed values are `Cluster` and `Namespaced`. Default is `Namespaced`.
|
||||
optional string scope = 4;
|
||||
|
||||
// validation describes the schema used for validation and pruning of the custom resource.
|
||||
// If present, this validation schema is used to validate all versions.
|
||||
// Top-level and per-version schemas are mutually exclusive.
|
||||
// +optional
|
||||
optional CustomResourceValidation validation = 5;
|
||||
|
||||
// subresources specify what subresources the defined custom resource has.
|
||||
// If present, this field configures subresources for all versions.
|
||||
// Top-level and per-version subresources are mutually exclusive.
|
||||
// +optional
|
||||
optional CustomResourceSubresources subresources = 6;
|
||||
|
||||
// versions is the list of all API versions of the defined custom resource.
|
||||
// Optional if `version` is specified.
|
||||
// The name of the first item in the `versions` list must match the `version` field if `version` and `versions` are both specified.
|
||||
// Version names are used to compute the order in which served versions are listed in API discovery.
|
||||
// If the version string is "kube-like", it will sort above non "kube-like" version strings, which are ordered
|
||||
// lexicographically. "Kube-like" versions start with a "v", then are followed by a number (the major version),
|
||||
// then optionally the string "alpha" or "beta" and another number (the minor version). These are sorted first
|
||||
// by GA > beta > alpha (where GA is a version with no suffix such as beta or alpha), and then by comparing
|
||||
// major version, then minor version. An example sorted list of versions:
|
||||
// v10, v2, v1, v11beta2, v10beta3, v3beta1, v12alpha1, v11alpha2, foo1, foo10.
|
||||
// +optional
|
||||
repeated CustomResourceDefinitionVersion versions = 7;
|
||||
|
||||
// additionalPrinterColumns specifies additional columns returned in Table output.
|
||||
// See https://kubernetes.io/docs/reference/using-api/api-concepts/#receiving-resources-as-tables for details.
|
||||
// If present, this field configures columns for all versions.
|
||||
// Top-level and per-version columns are mutually exclusive.
|
||||
// If no top-level or per-version columns are specified, a single column displaying the age of the custom resource is used.
|
||||
// +optional
|
||||
repeated CustomResourceColumnDefinition additionalPrinterColumns = 8;
|
||||
|
||||
// conversion defines conversion settings for the CRD.
|
||||
// +optional
|
||||
optional CustomResourceConversion conversion = 9;
|
||||
|
||||
// preserveUnknownFields indicates that object fields which are not specified
|
||||
// in the OpenAPI schema should be preserved when persisting to storage.
|
||||
// apiVersion, kind, metadata and known fields inside metadata are always preserved.
|
||||
// If false, schemas must be defined for all versions.
|
||||
// Defaults to true in v1beta for backwards compatibility.
|
||||
// Deprecated: will be required to be false in v1. Preservation of unknown fields can be specified
|
||||
// in the validation schema using the `x-kubernetes-preserve-unknown-fields: true` extension.
|
||||
// See https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/#pruning-versus-preserving-unknown-fields for details.
|
||||
// +optional
|
||||
optional bool preserveUnknownFields = 10;
|
||||
}
|
||||
|
||||
// CustomResourceDefinitionStatus indicates the state of the CustomResourceDefinition
|
||||
message CustomResourceDefinitionStatus {
|
||||
// conditions indicate state for particular aspects of a CustomResourceDefinition
|
||||
// +optional
|
||||
repeated CustomResourceDefinitionCondition conditions = 1;
|
||||
|
||||
// acceptedNames are the names that are actually being used to serve discovery.
|
||||
// They may be different than the names in spec.
|
||||
// +optional
|
||||
optional CustomResourceDefinitionNames acceptedNames = 2;
|
||||
|
||||
// storedVersions lists all versions of CustomResources that were ever persisted. Tracking these
|
||||
// versions allows a migration path for stored versions in etcd. The field is mutable
|
||||
// so a migration controller can finish a migration to another version (ensuring
|
||||
// no old objects are left in storage), and then remove the rest of the
|
||||
// versions from this list.
|
||||
// Versions may not be removed from `spec.versions` while they exist in this list.
|
||||
// +optional
|
||||
repeated string storedVersions = 3;
|
||||
}
|
||||
|
||||
// CustomResourceDefinitionVersion describes a version for CRD.
|
||||
message CustomResourceDefinitionVersion {
|
||||
// name is the version name, e.g. “v1”, “v2beta1”, etc.
|
||||
// The custom resources are served under this version at `/apis/<group>/<version>/...` if `served` is true.
|
||||
optional string name = 1;
|
||||
|
||||
// served is a flag enabling/disabling this version from being served via REST APIs
|
||||
optional bool served = 2;
|
||||
|
||||
// storage indicates this version should be used when persisting custom resources to storage.
|
||||
// There must be exactly one version with storage=true.
|
||||
optional bool storage = 3;
|
||||
|
||||
// deprecated indicates this version of the custom resource API is deprecated.
|
||||
// When set to true, API requests to this version receive a warning header in the server response.
|
||||
// Defaults to false.
|
||||
// +optional
|
||||
optional bool deprecated = 7;
|
||||
|
||||
// deprecationWarning overrides the default warning returned to API clients.
|
||||
// May only be set when `deprecated` is true.
|
||||
// The default warning indicates this version is deprecated and recommends use
|
||||
// of the newest served version of equal or greater stability, if one exists.
|
||||
// +optional
|
||||
optional string deprecationWarning = 8;
|
||||
|
||||
// schema describes the schema used for validation and pruning of this version of the custom resource.
|
||||
// Top-level and per-version schemas are mutually exclusive.
|
||||
// Per-version schemas must not all be set to identical values (top-level validation schema should be used instead).
|
||||
// +optional
|
||||
optional CustomResourceValidation schema = 4;
|
||||
|
||||
// subresources specify what subresources this version of the defined custom resource have.
|
||||
// Top-level and per-version subresources are mutually exclusive.
|
||||
// Per-version subresources must not all be set to identical values (top-level subresources should be used instead).
|
||||
// +optional
|
||||
optional CustomResourceSubresources subresources = 5;
|
||||
|
||||
// additionalPrinterColumns specifies additional columns returned in Table output.
|
||||
// See https://kubernetes.io/docs/reference/using-api/api-concepts/#receiving-resources-as-tables for details.
|
||||
// Top-level and per-version columns are mutually exclusive.
|
||||
// Per-version columns must not all be set to identical values (top-level columns should be used instead).
|
||||
// If no top-level or per-version columns are specified, a single column displaying the age of the custom resource is used.
|
||||
// +optional
|
||||
repeated CustomResourceColumnDefinition additionalPrinterColumns = 6;
|
||||
}
|
||||
|
||||
// CustomResourceSubresourceScale defines how to serve the scale subresource for CustomResources.
|
||||
message CustomResourceSubresourceScale {
|
||||
// specReplicasPath defines the JSON path inside of a custom resource that corresponds to Scale `spec.replicas`.
|
||||
// Only JSON paths without the array notation are allowed.
|
||||
// Must be a JSON Path under `.spec`.
|
||||
// If there is no value under the given path in the custom resource, the `/scale` subresource will return an error on GET.
|
||||
optional string specReplicasPath = 1;
|
||||
|
||||
// statusReplicasPath defines the JSON path inside of a custom resource that corresponds to Scale `status.replicas`.
|
||||
// Only JSON paths without the array notation are allowed.
|
||||
// Must be a JSON Path under `.status`.
|
||||
// If there is no value under the given path in the custom resource, the `status.replicas` value in the `/scale` subresource
|
||||
// will default to 0.
|
||||
optional string statusReplicasPath = 2;
|
||||
|
||||
// labelSelectorPath defines the JSON path inside of a custom resource that corresponds to Scale `status.selector`.
|
||||
// Only JSON paths without the array notation are allowed.
|
||||
// Must be a JSON Path under `.status` or `.spec`.
|
||||
// Must be set to work with HorizontalPodAutoscaler.
|
||||
// The field pointed by this JSON path must be a string field (not a complex selector struct)
|
||||
// which contains a serialized label selector in string form.
|
||||
// More info: https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions#scale-subresource
|
||||
// If there is no value under the given path in the custom resource, the `status.selector` value in the `/scale`
|
||||
// subresource will default to the empty string.
|
||||
// +optional
|
||||
optional string labelSelectorPath = 3;
|
||||
}
|
||||
|
||||
// CustomResourceSubresourceStatus defines how to serve the status subresource for CustomResources.
|
||||
// Status is represented by the `.status` JSON path inside of a CustomResource. When set,
|
||||
// * exposes a /status subresource for the custom resource
|
||||
// * PUT requests to the /status subresource take a custom resource object, and ignore changes to anything except the status stanza
|
||||
// * PUT/POST/PATCH requests to the custom resource ignore changes to the status stanza
|
||||
message CustomResourceSubresourceStatus {
|
||||
}
|
||||
|
||||
// CustomResourceSubresources defines the status and scale subresources for CustomResources.
|
||||
message CustomResourceSubresources {
|
||||
// status indicates the custom resource should serve a `/status` subresource.
|
||||
// When enabled:
|
||||
// 1. requests to the custom resource primary endpoint ignore changes to the `status` stanza of the object.
|
||||
// 2. requests to the custom resource `/status` subresource ignore changes to anything other than the `status` stanza of the object.
|
||||
// +optional
|
||||
optional CustomResourceSubresourceStatus status = 1;
|
||||
|
||||
// scale indicates the custom resource should serve a `/scale` subresource that returns an `autoscaling/v1` Scale object.
|
||||
// +optional
|
||||
optional CustomResourceSubresourceScale scale = 2;
|
||||
}
|
||||
|
||||
// CustomResourceValidation is a list of validation methods for CustomResources.
|
||||
message CustomResourceValidation {
|
||||
// openAPIV3Schema is the OpenAPI v3 schema to use for validation and pruning.
|
||||
// +optional
|
||||
optional JSONSchemaProps openAPIV3Schema = 1;
|
||||
}
|
||||
|
||||
// ExternalDocumentation allows referencing an external resource for extended documentation.
|
||||
message ExternalDocumentation {
|
||||
optional string description = 1;
|
||||
|
||||
optional string url = 2;
|
||||
}
|
||||
|
||||
// JSON represents any valid JSON value.
|
||||
// These types are supported: bool, int64, float64, string, []interface{}, map[string]interface{} and nil.
|
||||
message JSON {
|
||||
optional bytes raw = 1;
|
||||
}
|
||||
|
||||
// JSONSchemaProps is a JSON-Schema following Specification Draft 4 (http://json-schema.org/).
|
||||
message JSONSchemaProps {
|
||||
optional string id = 1;
|
||||
|
||||
optional string schema = 2;
|
||||
|
||||
optional string ref = 3;
|
||||
|
||||
optional string description = 4;
|
||||
|
||||
optional string type = 5;
|
||||
|
||||
// format is an OpenAPI v3 format string. Unknown formats are ignored. The following formats are validated:
|
||||
//
|
||||
// - bsonobjectid: a bson object ID, i.e. a 24 characters hex string
|
||||
// - uri: an URI as parsed by Golang net/url.ParseRequestURI
|
||||
// - email: an email address as parsed by Golang net/mail.ParseAddress
|
||||
// - hostname: a valid representation for an Internet host name, as defined by RFC 1034, section 3.1 [RFC1034].
|
||||
// - ipv4: an IPv4 IP as parsed by Golang net.ParseIP
|
||||
// - ipv6: an IPv6 IP as parsed by Golang net.ParseIP
|
||||
// - cidr: a CIDR as parsed by Golang net.ParseCIDR
|
||||
// - mac: a MAC address as parsed by Golang net.ParseMAC
|
||||
// - uuid: an UUID that allows uppercase defined by the regex (?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$
|
||||
// - uuid3: an UUID3 that allows uppercase defined by the regex (?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?3[0-9a-f]{3}-?[0-9a-f]{4}-?[0-9a-f]{12}$
|
||||
// - uuid4: an UUID4 that allows uppercase defined by the regex (?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?4[0-9a-f]{3}-?[89ab][0-9a-f]{3}-?[0-9a-f]{12}$
|
||||
// - uuid5: an UUID5 that allows uppercase defined by the regex (?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?5[0-9a-f]{3}-?[89ab][0-9a-f]{3}-?[0-9a-f]{12}$
|
||||
// - isbn: an ISBN10 or ISBN13 number string like "0321751043" or "978-0321751041"
|
||||
// - isbn10: an ISBN10 number string like "0321751043"
|
||||
// - isbn13: an ISBN13 number string like "978-0321751041"
|
||||
// - creditcard: a credit card number defined by the regex ^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\\d{3})\\d{11})$ with any non digit characters mixed in
|
||||
// - ssn: a U.S. social security number following the regex ^\\d{3}[- ]?\\d{2}[- ]?\\d{4}$
|
||||
// - hexcolor: an hexadecimal color code like "#FFFFFF: following the regex ^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$
|
||||
// - rgbcolor: an RGB color code like rgb like "rgb(255,255,2559"
|
||||
// - byte: base64 encoded binary data
|
||||
// - password: any kind of string
|
||||
// - date: a date string like "2006-01-02" as defined by full-date in RFC3339
|
||||
// - duration: a duration string like "22 ns" as parsed by Golang time.ParseDuration or compatible with Scala duration format
|
||||
// - datetime: a date time string like "2014-12-15T19:30:20.000Z" as defined by date-time in RFC3339.
|
||||
optional string format = 6;
|
||||
|
||||
optional string title = 7;
|
||||
|
||||
// default is a default value for undefined object fields.
|
||||
// Defaulting is a beta feature under the CustomResourceDefaulting feature gate.
|
||||
// CustomResourceDefinitions with defaults must be created using the v1 (or newer) CustomResourceDefinition API.
|
||||
optional JSON default = 8;
|
||||
|
||||
optional double maximum = 9;
|
||||
|
||||
optional bool exclusiveMaximum = 10;
|
||||
|
||||
optional double minimum = 11;
|
||||
|
||||
optional bool exclusiveMinimum = 12;
|
||||
|
||||
optional int64 maxLength = 13;
|
||||
|
||||
optional int64 minLength = 14;
|
||||
|
||||
optional string pattern = 15;
|
||||
|
||||
optional int64 maxItems = 16;
|
||||
|
||||
optional int64 minItems = 17;
|
||||
|
||||
optional bool uniqueItems = 18;
|
||||
|
||||
optional double multipleOf = 19;
|
||||
|
||||
repeated JSON enum = 20;
|
||||
|
||||
optional int64 maxProperties = 21;
|
||||
|
||||
optional int64 minProperties = 22;
|
||||
|
||||
repeated string required = 23;
|
||||
|
||||
optional JSONSchemaPropsOrArray items = 24;
|
||||
|
||||
repeated JSONSchemaProps allOf = 25;
|
||||
|
||||
repeated JSONSchemaProps oneOf = 26;
|
||||
|
||||
repeated JSONSchemaProps anyOf = 27;
|
||||
|
||||
optional JSONSchemaProps not = 28;
|
||||
|
||||
map<string, JSONSchemaProps> properties = 29;
|
||||
|
||||
optional JSONSchemaPropsOrBool additionalProperties = 30;
|
||||
|
||||
map<string, JSONSchemaProps> patternProperties = 31;
|
||||
|
||||
map<string, JSONSchemaPropsOrStringArray> dependencies = 32;
|
||||
|
||||
optional JSONSchemaPropsOrBool additionalItems = 33;
|
||||
|
||||
map<string, JSONSchemaProps> definitions = 34;
|
||||
|
||||
optional ExternalDocumentation externalDocs = 35;
|
||||
|
||||
optional JSON example = 36;
|
||||
|
||||
optional bool nullable = 37;
|
||||
|
||||
// x-kubernetes-preserve-unknown-fields stops the API server
|
||||
// decoding step from pruning fields which are not specified
|
||||
// in the validation schema. This affects fields recursively,
|
||||
// but switches back to normal pruning behaviour if nested
|
||||
// properties or additionalProperties are specified in the schema.
|
||||
// This can either be true or undefined. False is forbidden.
|
||||
optional bool xKubernetesPreserveUnknownFields = 38;
|
||||
|
||||
// x-kubernetes-embedded-resource defines that the value is an
|
||||
// embedded Kubernetes runtime.Object, with TypeMeta and
|
||||
// ObjectMeta. The type must be object. It is allowed to further
|
||||
// restrict the embedded object. kind, apiVersion and metadata
|
||||
// are validated automatically. x-kubernetes-preserve-unknown-fields
|
||||
// is allowed to be true, but does not have to be if the object
|
||||
// is fully specified (up to kind, apiVersion, metadata).
|
||||
optional bool xKubernetesEmbeddedResource = 39;
|
||||
|
||||
// x-kubernetes-int-or-string specifies that this value is
|
||||
// either an integer or a string. If this is true, an empty
|
||||
// type is allowed and type as child of anyOf is permitted
|
||||
// if following one of the following patterns:
|
||||
//
|
||||
// 1) anyOf:
|
||||
// - type: integer
|
||||
// - type: string
|
||||
// 2) allOf:
|
||||
// - anyOf:
|
||||
// - type: integer
|
||||
// - type: string
|
||||
// - ... zero or more
|
||||
optional bool xKubernetesIntOrString = 40;
|
||||
|
||||
// x-kubernetes-list-map-keys annotates an array with the x-kubernetes-list-type `map` by specifying the keys used
|
||||
// as the index of the map.
|
||||
//
|
||||
// This tag MUST only be used on lists that have the "x-kubernetes-list-type"
|
||||
// extension set to "map". Also, the values specified for this attribute must
|
||||
// be a scalar typed field of the child structure (no nesting is supported).
|
||||
//
|
||||
// The properties specified must either be required or have a default value,
|
||||
// to ensure those properties are present for all list items.
|
||||
//
|
||||
// +optional
|
||||
repeated string xKubernetesListMapKeys = 41;
|
||||
|
||||
// x-kubernetes-list-type annotates an array to further describe its topology.
|
||||
// This extension must only be used on lists and may have 3 possible values:
|
||||
//
|
||||
// 1) `atomic`: the list is treated as a single entity, like a scalar.
|
||||
// Atomic lists will be entirely replaced when updated. This extension
|
||||
// may be used on any type of list (struct, scalar, ...).
|
||||
// 2) `set`:
|
||||
// Sets are lists that must not have multiple items with the same value. Each
|
||||
// value must be a scalar, an object with x-kubernetes-map-type `atomic` or an
|
||||
// array with x-kubernetes-list-type `atomic`.
|
||||
// 3) `map`:
|
||||
// These lists are like maps in that their elements have a non-index key
|
||||
// used to identify them. Order is preserved upon merge. The map tag
|
||||
// must only be used on a list with elements of type object.
|
||||
// Defaults to atomic for arrays.
|
||||
// +optional
|
||||
optional string xKubernetesListType = 42;
|
||||
|
||||
// x-kubernetes-map-type annotates an object to further describe its topology.
|
||||
// This extension must only be used when type is object and may have 2 possible values:
|
||||
//
|
||||
// 1) `granular`:
|
||||
// These maps are actual maps (key-value pairs) and each fields are independent
|
||||
// from each other (they can each be manipulated by separate actors). This is
|
||||
// the default behaviour for all maps.
|
||||
// 2) `atomic`: the list is treated as a single entity, like a scalar.
|
||||
// Atomic maps will be entirely replaced when updated.
|
||||
// +optional
|
||||
optional string xKubernetesMapType = 43;
|
||||
}
|
||||
|
||||
// JSONSchemaPropsOrArray represents a value that can either be a JSONSchemaProps
|
||||
// or an array of JSONSchemaProps. Mainly here for serialization purposes.
|
||||
message JSONSchemaPropsOrArray {
|
||||
optional JSONSchemaProps schema = 1;
|
||||
|
||||
repeated JSONSchemaProps jSONSchemas = 2;
|
||||
}
|
||||
|
||||
// JSONSchemaPropsOrBool represents JSONSchemaProps or a boolean value.
|
||||
// Defaults to true for the boolean property.
|
||||
message JSONSchemaPropsOrBool {
|
||||
optional bool allows = 1;
|
||||
|
||||
optional JSONSchemaProps schema = 2;
|
||||
}
|
||||
|
||||
// JSONSchemaPropsOrStringArray represents a JSONSchemaProps or a string array.
|
||||
message JSONSchemaPropsOrStringArray {
|
||||
optional JSONSchemaProps schema = 1;
|
||||
|
||||
repeated string property = 2;
|
||||
}
|
||||
|
||||
// ServiceReference holds a reference to Service.legacy.k8s.io
|
||||
message ServiceReference {
|
||||
// namespace is the namespace of the service.
|
||||
// Required
|
||||
optional string namespace = 1;
|
||||
|
||||
// name is the name of the service.
|
||||
// Required
|
||||
optional string name = 2;
|
||||
|
||||
// path is an optional URL path at which the webhook will be contacted.
|
||||
// +optional
|
||||
optional string path = 3;
|
||||
|
||||
// port is an optional service port at which the webhook will be contacted.
|
||||
// `port` should be a valid port number (1-65535, inclusive).
|
||||
// Defaults to 443 for backward compatibility.
|
||||
// +optional
|
||||
optional int32 port = 4;
|
||||
}
|
||||
|
||||
// WebhookClientConfig contains the information to make a TLS connection with the webhook.
|
||||
message WebhookClientConfig {
|
||||
// url gives the location of the webhook, in standard URL form
|
||||
// (`scheme://host:port/path`). Exactly one of `url` or `service`
|
||||
// must be specified.
|
||||
//
|
||||
// The `host` should not refer to a service running in the cluster; use
|
||||
// the `service` field instead. The host might be resolved via external
|
||||
// DNS in some apiservers (e.g., `kube-apiserver` cannot resolve
|
||||
// in-cluster DNS as that would be a layering violation). `host` may
|
||||
// also be an IP address.
|
||||
//
|
||||
// Please note that using `localhost` or `127.0.0.1` as a `host` is
|
||||
// risky unless you take great care to run this webhook on all hosts
|
||||
// which run an apiserver which might need to make calls to this
|
||||
// webhook. Such installs are likely to be non-portable, i.e., not easy
|
||||
// to turn up in a new cluster.
|
||||
//
|
||||
// The scheme must be "https"; the URL must begin with "https://".
|
||||
//
|
||||
// A path is optional, and if present may be any string permissible in
|
||||
// a URL. You may use the path to pass an arbitrary string to the
|
||||
// webhook, for example, a cluster identifier.
|
||||
//
|
||||
// Attempting to use a user or basic auth e.g. "user:password@" is not
|
||||
// allowed. Fragments ("#...") and query parameters ("?...") are not
|
||||
// allowed, either.
|
||||
//
|
||||
// +optional
|
||||
optional string url = 3;
|
||||
|
||||
// service is a reference to the service for this webhook. Either
|
||||
// service or url must be specified.
|
||||
//
|
||||
// If the webhook is running within the cluster, then you should use `service`.
|
||||
//
|
||||
// +optional
|
||||
optional ServiceReference service = 1;
|
||||
|
||||
// caBundle is a PEM encoded CA bundle which will be used to validate the webhook's server certificate.
|
||||
// If unspecified, system trust roots on the apiserver are used.
|
||||
// +optional
|
||||
optional bytes caBundle = 2;
|
||||
}
|
||||
|
||||
135
vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1/marshal.go
generated
vendored
Normal file
135
vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1/marshal.go
generated
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/json"
|
||||
)
|
||||
|
||||
var jsTrue = []byte("true")
|
||||
var jsFalse = []byte("false")
|
||||
|
||||
func (s JSONSchemaPropsOrBool) MarshalJSON() ([]byte, error) {
|
||||
if s.Schema != nil {
|
||||
return json.Marshal(s.Schema)
|
||||
}
|
||||
|
||||
if s.Schema == nil && !s.Allows {
|
||||
return jsFalse, nil
|
||||
}
|
||||
return jsTrue, nil
|
||||
}
|
||||
|
||||
func (s *JSONSchemaPropsOrBool) UnmarshalJSON(data []byte) error {
|
||||
var nw JSONSchemaPropsOrBool
|
||||
switch {
|
||||
case len(data) == 0:
|
||||
case data[0] == '{':
|
||||
var sch JSONSchemaProps
|
||||
if err := json.Unmarshal(data, &sch); err != nil {
|
||||
return err
|
||||
}
|
||||
nw.Allows = true
|
||||
nw.Schema = &sch
|
||||
case len(data) == 4 && string(data) == "true":
|
||||
nw.Allows = true
|
||||
case len(data) == 5 && string(data) == "false":
|
||||
nw.Allows = false
|
||||
default:
|
||||
return errors.New("boolean or JSON schema expected")
|
||||
}
|
||||
*s = nw
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s JSONSchemaPropsOrStringArray) MarshalJSON() ([]byte, error) {
|
||||
if len(s.Property) > 0 {
|
||||
return json.Marshal(s.Property)
|
||||
}
|
||||
if s.Schema != nil {
|
||||
return json.Marshal(s.Schema)
|
||||
}
|
||||
return []byte("null"), nil
|
||||
}
|
||||
|
||||
func (s *JSONSchemaPropsOrStringArray) UnmarshalJSON(data []byte) error {
|
||||
var first byte
|
||||
if len(data) > 1 {
|
||||
first = data[0]
|
||||
}
|
||||
var nw JSONSchemaPropsOrStringArray
|
||||
if first == '{' {
|
||||
var sch JSONSchemaProps
|
||||
if err := json.Unmarshal(data, &sch); err != nil {
|
||||
return err
|
||||
}
|
||||
nw.Schema = &sch
|
||||
}
|
||||
if first == '[' {
|
||||
if err := json.Unmarshal(data, &nw.Property); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
*s = nw
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s JSONSchemaPropsOrArray) MarshalJSON() ([]byte, error) {
|
||||
if len(s.JSONSchemas) > 0 {
|
||||
return json.Marshal(s.JSONSchemas)
|
||||
}
|
||||
return json.Marshal(s.Schema)
|
||||
}
|
||||
|
||||
func (s *JSONSchemaPropsOrArray) UnmarshalJSON(data []byte) error {
|
||||
var nw JSONSchemaPropsOrArray
|
||||
var first byte
|
||||
if len(data) > 1 {
|
||||
first = data[0]
|
||||
}
|
||||
if first == '{' {
|
||||
var sch JSONSchemaProps
|
||||
if err := json.Unmarshal(data, &sch); err != nil {
|
||||
return err
|
||||
}
|
||||
nw.Schema = &sch
|
||||
}
|
||||
if first == '[' {
|
||||
if err := json.Unmarshal(data, &nw.JSONSchemas); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
*s = nw
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s JSON) MarshalJSON() ([]byte, error) {
|
||||
if len(s.Raw) > 0 {
|
||||
return s.Raw, nil
|
||||
}
|
||||
return []byte("null"), nil
|
||||
|
||||
}
|
||||
|
||||
func (s *JSON) UnmarshalJSON(data []byte) error {
|
||||
if len(data) > 0 && string(data) != "null" {
|
||||
s.Raw = data
|
||||
}
|
||||
return nil
|
||||
}
|
||||
62
vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1/register.go
generated
vendored
Normal file
62
vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1/register.go
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
const GroupName = "apiextensions.k8s.io"
|
||||
|
||||
// SchemeGroupVersion is group version used to register these objects
|
||||
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1beta1"}
|
||||
|
||||
// Kind takes an unqualified kind and returns back a Group qualified GroupKind
|
||||
func Kind(kind string) schema.GroupKind {
|
||||
return SchemeGroupVersion.WithKind(kind).GroupKind()
|
||||
}
|
||||
|
||||
// Resource takes an unqualified resource and returns back a Group qualified GroupResource
|
||||
func Resource(resource string) schema.GroupResource {
|
||||
return SchemeGroupVersion.WithResource(resource).GroupResource()
|
||||
}
|
||||
|
||||
var (
|
||||
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, addDefaultingFuncs)
|
||||
localSchemeBuilder = &SchemeBuilder
|
||||
AddToScheme = localSchemeBuilder.AddToScheme
|
||||
)
|
||||
|
||||
// Adds the list of known types to the given scheme.
|
||||
func addKnownTypes(scheme *runtime.Scheme) error {
|
||||
scheme.AddKnownTypes(SchemeGroupVersion,
|
||||
&CustomResourceDefinition{},
|
||||
&CustomResourceDefinitionList{},
|
||||
&ConversionReview{},
|
||||
)
|
||||
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
// We only register manually written functions here. The registration of the
|
||||
// generated functions takes place in the generated files. The separation
|
||||
// makes the code compile even when the generated files are missing.
|
||||
localSchemeBuilder.Register(addDefaultingFuncs)
|
||||
}
|
||||
522
vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1/types.go
generated
vendored
Normal file
522
vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1/types.go
generated
vendored
Normal file
@@ -0,0 +1,522 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
// ConversionStrategyType describes different conversion types.
|
||||
type ConversionStrategyType string
|
||||
|
||||
const (
|
||||
// KubeAPIApprovedAnnotation is an annotation that must be set to create a CRD for the k8s.io, *.k8s.io, kubernetes.io, or *.kubernetes.io namespaces.
|
||||
// The value should be a link to a URL where the current spec was approved, so updates to the spec should also update the URL.
|
||||
// If the API is unapproved, you may set the annotation to a string starting with `"unapproved"`. For instance, `"unapproved, temporarily squatting"` or `"unapproved, experimental-only"`. This is discouraged.
|
||||
KubeAPIApprovedAnnotation = "api-approved.kubernetes.io"
|
||||
|
||||
// NoneConverter is a converter that only sets apiversion of the CR and leave everything else unchanged.
|
||||
NoneConverter ConversionStrategyType = "None"
|
||||
// WebhookConverter is a converter that calls to an external webhook to convert the CR.
|
||||
WebhookConverter ConversionStrategyType = "Webhook"
|
||||
)
|
||||
|
||||
// CustomResourceDefinitionSpec describes how a user wants their resource to appear
|
||||
type CustomResourceDefinitionSpec struct {
|
||||
// group is the API group of the defined custom resource.
|
||||
// The custom resources are served under `/apis/<group>/...`.
|
||||
// Must match the name of the CustomResourceDefinition (in the form `<names.plural>.<group>`).
|
||||
Group string `json:"group" protobuf:"bytes,1,opt,name=group"`
|
||||
// version is the API version of the defined custom resource.
|
||||
// The custom resources are served under `/apis/<group>/<version>/...`.
|
||||
// Must match the name of the first item in the `versions` list if `version` and `versions` are both specified.
|
||||
// Optional if `versions` is specified.
|
||||
// Deprecated: use `versions` instead.
|
||||
// +optional
|
||||
Version string `json:"version,omitempty" protobuf:"bytes,2,opt,name=version"`
|
||||
// names specify the resource and kind names for the custom resource.
|
||||
Names CustomResourceDefinitionNames `json:"names" protobuf:"bytes,3,opt,name=names"`
|
||||
// scope indicates whether the defined custom resource is cluster- or namespace-scoped.
|
||||
// Allowed values are `Cluster` and `Namespaced`. Default is `Namespaced`.
|
||||
Scope ResourceScope `json:"scope" protobuf:"bytes,4,opt,name=scope,casttype=ResourceScope"`
|
||||
// validation describes the schema used for validation and pruning of the custom resource.
|
||||
// If present, this validation schema is used to validate all versions.
|
||||
// Top-level and per-version schemas are mutually exclusive.
|
||||
// +optional
|
||||
Validation *CustomResourceValidation `json:"validation,omitempty" protobuf:"bytes,5,opt,name=validation"`
|
||||
// subresources specify what subresources the defined custom resource has.
|
||||
// If present, this field configures subresources for all versions.
|
||||
// Top-level and per-version subresources are mutually exclusive.
|
||||
// +optional
|
||||
Subresources *CustomResourceSubresources `json:"subresources,omitempty" protobuf:"bytes,6,opt,name=subresources"`
|
||||
// versions is the list of all API versions of the defined custom resource.
|
||||
// Optional if `version` is specified.
|
||||
// The name of the first item in the `versions` list must match the `version` field if `version` and `versions` are both specified.
|
||||
// Version names are used to compute the order in which served versions are listed in API discovery.
|
||||
// If the version string is "kube-like", it will sort above non "kube-like" version strings, which are ordered
|
||||
// lexicographically. "Kube-like" versions start with a "v", then are followed by a number (the major version),
|
||||
// then optionally the string "alpha" or "beta" and another number (the minor version). These are sorted first
|
||||
// by GA > beta > alpha (where GA is a version with no suffix such as beta or alpha), and then by comparing
|
||||
// major version, then minor version. An example sorted list of versions:
|
||||
// v10, v2, v1, v11beta2, v10beta3, v3beta1, v12alpha1, v11alpha2, foo1, foo10.
|
||||
// +optional
|
||||
Versions []CustomResourceDefinitionVersion `json:"versions,omitempty" protobuf:"bytes,7,rep,name=versions"`
|
||||
// additionalPrinterColumns specifies additional columns returned in Table output.
|
||||
// See https://kubernetes.io/docs/reference/using-api/api-concepts/#receiving-resources-as-tables for details.
|
||||
// If present, this field configures columns for all versions.
|
||||
// Top-level and per-version columns are mutually exclusive.
|
||||
// If no top-level or per-version columns are specified, a single column displaying the age of the custom resource is used.
|
||||
// +optional
|
||||
AdditionalPrinterColumns []CustomResourceColumnDefinition `json:"additionalPrinterColumns,omitempty" protobuf:"bytes,8,rep,name=additionalPrinterColumns"`
|
||||
|
||||
// conversion defines conversion settings for the CRD.
|
||||
// +optional
|
||||
Conversion *CustomResourceConversion `json:"conversion,omitempty" protobuf:"bytes,9,opt,name=conversion"`
|
||||
|
||||
// preserveUnknownFields indicates that object fields which are not specified
|
||||
// in the OpenAPI schema should be preserved when persisting to storage.
|
||||
// apiVersion, kind, metadata and known fields inside metadata are always preserved.
|
||||
// If false, schemas must be defined for all versions.
|
||||
// Defaults to true in v1beta for backwards compatibility.
|
||||
// Deprecated: will be required to be false in v1. Preservation of unknown fields can be specified
|
||||
// in the validation schema using the `x-kubernetes-preserve-unknown-fields: true` extension.
|
||||
// See https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/#pruning-versus-preserving-unknown-fields for details.
|
||||
// +optional
|
||||
PreserveUnknownFields *bool `json:"preserveUnknownFields,omitempty" protobuf:"varint,10,opt,name=preserveUnknownFields"`
|
||||
}
|
||||
|
||||
// CustomResourceConversion describes how to convert different versions of a CR.
|
||||
type CustomResourceConversion struct {
|
||||
// strategy specifies how custom resources are converted between versions. Allowed values are:
|
||||
// - `None`: The converter only change the apiVersion and would not touch any other field in the custom resource.
|
||||
// - `Webhook`: API Server will call to an external webhook to do the conversion. Additional information
|
||||
// is needed for this option. This requires spec.preserveUnknownFields to be false, and spec.conversion.webhookClientConfig to be set.
|
||||
Strategy ConversionStrategyType `json:"strategy" protobuf:"bytes,1,name=strategy"`
|
||||
|
||||
// webhookClientConfig is the instructions for how to call the webhook if strategy is `Webhook`.
|
||||
// Required when `strategy` is set to `Webhook`.
|
||||
// +optional
|
||||
WebhookClientConfig *WebhookClientConfig `json:"webhookClientConfig,omitempty" protobuf:"bytes,2,name=webhookClientConfig"`
|
||||
|
||||
// conversionReviewVersions is an ordered list of preferred `ConversionReview`
|
||||
// versions the Webhook expects. The API server will use the first version in
|
||||
// the list which it supports. If none of the versions specified in this list
|
||||
// are supported by API server, conversion will fail for the custom resource.
|
||||
// If a persisted Webhook configuration specifies allowed versions and does not
|
||||
// include any versions known to the API Server, calls to the webhook will fail.
|
||||
// Defaults to `["v1beta1"]`.
|
||||
// +optional
|
||||
ConversionReviewVersions []string `json:"conversionReviewVersions,omitempty" protobuf:"bytes,3,rep,name=conversionReviewVersions"`
|
||||
}
|
||||
|
||||
// WebhookClientConfig contains the information to make a TLS connection with the webhook.
|
||||
type WebhookClientConfig struct {
|
||||
// url gives the location of the webhook, in standard URL form
|
||||
// (`scheme://host:port/path`). Exactly one of `url` or `service`
|
||||
// must be specified.
|
||||
//
|
||||
// The `host` should not refer to a service running in the cluster; use
|
||||
// the `service` field instead. The host might be resolved via external
|
||||
// DNS in some apiservers (e.g., `kube-apiserver` cannot resolve
|
||||
// in-cluster DNS as that would be a layering violation). `host` may
|
||||
// also be an IP address.
|
||||
//
|
||||
// Please note that using `localhost` or `127.0.0.1` as a `host` is
|
||||
// risky unless you take great care to run this webhook on all hosts
|
||||
// which run an apiserver which might need to make calls to this
|
||||
// webhook. Such installs are likely to be non-portable, i.e., not easy
|
||||
// to turn up in a new cluster.
|
||||
//
|
||||
// The scheme must be "https"; the URL must begin with "https://".
|
||||
//
|
||||
// A path is optional, and if present may be any string permissible in
|
||||
// a URL. You may use the path to pass an arbitrary string to the
|
||||
// webhook, for example, a cluster identifier.
|
||||
//
|
||||
// Attempting to use a user or basic auth e.g. "user:password@" is not
|
||||
// allowed. Fragments ("#...") and query parameters ("?...") are not
|
||||
// allowed, either.
|
||||
//
|
||||
// +optional
|
||||
URL *string `json:"url,omitempty" protobuf:"bytes,3,opt,name=url"`
|
||||
|
||||
// service is a reference to the service for this webhook. Either
|
||||
// service or url must be specified.
|
||||
//
|
||||
// If the webhook is running within the cluster, then you should use `service`.
|
||||
//
|
||||
// +optional
|
||||
Service *ServiceReference `json:"service,omitempty" protobuf:"bytes,1,opt,name=service"`
|
||||
|
||||
// caBundle is a PEM encoded CA bundle which will be used to validate the webhook's server certificate.
|
||||
// If unspecified, system trust roots on the apiserver are used.
|
||||
// +optional
|
||||
CABundle []byte `json:"caBundle,omitempty" protobuf:"bytes,2,opt,name=caBundle"`
|
||||
}
|
||||
|
||||
// ServiceReference holds a reference to Service.legacy.k8s.io
|
||||
type ServiceReference struct {
|
||||
// namespace is the namespace of the service.
|
||||
// Required
|
||||
Namespace string `json:"namespace" protobuf:"bytes,1,opt,name=namespace"`
|
||||
// name is the name of the service.
|
||||
// Required
|
||||
Name string `json:"name" protobuf:"bytes,2,opt,name=name"`
|
||||
|
||||
// path is an optional URL path at which the webhook will be contacted.
|
||||
// +optional
|
||||
Path *string `json:"path,omitempty" protobuf:"bytes,3,opt,name=path"`
|
||||
|
||||
// port is an optional service port at which the webhook will be contacted.
|
||||
// `port` should be a valid port number (1-65535, inclusive).
|
||||
// Defaults to 443 for backward compatibility.
|
||||
// +optional
|
||||
Port *int32 `json:"port,omitempty" protobuf:"varint,4,opt,name=port"`
|
||||
}
|
||||
|
||||
// CustomResourceDefinitionVersion describes a version for CRD.
|
||||
type CustomResourceDefinitionVersion struct {
|
||||
// name is the version name, e.g. “v1”, “v2beta1”, etc.
|
||||
// The custom resources are served under this version at `/apis/<group>/<version>/...` if `served` is true.
|
||||
Name string `json:"name" protobuf:"bytes,1,opt,name=name"`
|
||||
// served is a flag enabling/disabling this version from being served via REST APIs
|
||||
Served bool `json:"served" protobuf:"varint,2,opt,name=served"`
|
||||
// storage indicates this version should be used when persisting custom resources to storage.
|
||||
// There must be exactly one version with storage=true.
|
||||
Storage bool `json:"storage" protobuf:"varint,3,opt,name=storage"`
|
||||
// deprecated indicates this version of the custom resource API is deprecated.
|
||||
// When set to true, API requests to this version receive a warning header in the server response.
|
||||
// Defaults to false.
|
||||
// +optional
|
||||
Deprecated bool `json:"deprecated,omitempty" protobuf:"varint,7,opt,name=deprecated"`
|
||||
// deprecationWarning overrides the default warning returned to API clients.
|
||||
// May only be set when `deprecated` is true.
|
||||
// The default warning indicates this version is deprecated and recommends use
|
||||
// of the newest served version of equal or greater stability, if one exists.
|
||||
// +optional
|
||||
DeprecationWarning *string `json:"deprecationWarning,omitempty" protobuf:"bytes,8,opt,name=deprecationWarning"`
|
||||
// schema describes the schema used for validation and pruning of this version of the custom resource.
|
||||
// Top-level and per-version schemas are mutually exclusive.
|
||||
// Per-version schemas must not all be set to identical values (top-level validation schema should be used instead).
|
||||
// +optional
|
||||
Schema *CustomResourceValidation `json:"schema,omitempty" protobuf:"bytes,4,opt,name=schema"`
|
||||
// subresources specify what subresources this version of the defined custom resource have.
|
||||
// Top-level and per-version subresources are mutually exclusive.
|
||||
// Per-version subresources must not all be set to identical values (top-level subresources should be used instead).
|
||||
// +optional
|
||||
Subresources *CustomResourceSubresources `json:"subresources,omitempty" protobuf:"bytes,5,opt,name=subresources"`
|
||||
// additionalPrinterColumns specifies additional columns returned in Table output.
|
||||
// See https://kubernetes.io/docs/reference/using-api/api-concepts/#receiving-resources-as-tables for details.
|
||||
// Top-level and per-version columns are mutually exclusive.
|
||||
// Per-version columns must not all be set to identical values (top-level columns should be used instead).
|
||||
// If no top-level or per-version columns are specified, a single column displaying the age of the custom resource is used.
|
||||
// +optional
|
||||
AdditionalPrinterColumns []CustomResourceColumnDefinition `json:"additionalPrinterColumns,omitempty" protobuf:"bytes,6,rep,name=additionalPrinterColumns"`
|
||||
}
|
||||
|
||||
// CustomResourceColumnDefinition specifies a column for server side printing.
|
||||
type CustomResourceColumnDefinition struct {
|
||||
// name is a human readable name for the column.
|
||||
Name string `json:"name" protobuf:"bytes,1,opt,name=name"`
|
||||
// type is an OpenAPI type definition for this column.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types for details.
|
||||
Type string `json:"type" protobuf:"bytes,2,opt,name=type"`
|
||||
// format is an optional OpenAPI type definition for this column. The 'name' format is applied
|
||||
// to the primary identifier column to assist in clients identifying column is the resource name.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types for details.
|
||||
// +optional
|
||||
Format string `json:"format,omitempty" protobuf:"bytes,3,opt,name=format"`
|
||||
// description is a human readable description of this column.
|
||||
// +optional
|
||||
Description string `json:"description,omitempty" protobuf:"bytes,4,opt,name=description"`
|
||||
// priority is an integer defining the relative importance of this column compared to others. Lower
|
||||
// numbers are considered higher priority. Columns that may be omitted in limited space scenarios
|
||||
// should be given a priority greater than 0.
|
||||
// +optional
|
||||
Priority int32 `json:"priority,omitempty" protobuf:"bytes,5,opt,name=priority"`
|
||||
// JSONPath is a simple JSON path (i.e. with array notation) which is evaluated against
|
||||
// each custom resource to produce the value for this column.
|
||||
JSONPath string `json:"JSONPath" protobuf:"bytes,6,opt,name=JSONPath"`
|
||||
}
|
||||
|
||||
// CustomResourceDefinitionNames indicates the names to serve this CustomResourceDefinition
|
||||
type CustomResourceDefinitionNames struct {
|
||||
// plural is the plural name of the resource to serve.
|
||||
// The custom resources are served under `/apis/<group>/<version>/.../<plural>`.
|
||||
// Must match the name of the CustomResourceDefinition (in the form `<names.plural>.<group>`).
|
||||
// Must be all lowercase.
|
||||
Plural string `json:"plural" protobuf:"bytes,1,opt,name=plural"`
|
||||
// singular is the singular name of the resource. It must be all lowercase. Defaults to lowercased `kind`.
|
||||
// +optional
|
||||
Singular string `json:"singular,omitempty" protobuf:"bytes,2,opt,name=singular"`
|
||||
// shortNames are short names for the resource, exposed in API discovery documents,
|
||||
// and used by clients to support invocations like `kubectl get <shortname>`.
|
||||
// It must be all lowercase.
|
||||
// +optional
|
||||
ShortNames []string `json:"shortNames,omitempty" protobuf:"bytes,3,opt,name=shortNames"`
|
||||
// kind is the serialized kind of the resource. It is normally CamelCase and singular.
|
||||
// Custom resource instances will use this value as the `kind` attribute in API calls.
|
||||
Kind string `json:"kind" protobuf:"bytes,4,opt,name=kind"`
|
||||
// listKind is the serialized kind of the list for this resource. Defaults to "`kind`List".
|
||||
// +optional
|
||||
ListKind string `json:"listKind,omitempty" protobuf:"bytes,5,opt,name=listKind"`
|
||||
// categories is a list of grouped resources this custom resource belongs to (e.g. 'all').
|
||||
// This is published in API discovery documents, and used by clients to support invocations like
|
||||
// `kubectl get all`.
|
||||
// +optional
|
||||
Categories []string `json:"categories,omitempty" protobuf:"bytes,6,rep,name=categories"`
|
||||
}
|
||||
|
||||
// ResourceScope is an enum defining the different scopes available to a custom resource
|
||||
type ResourceScope string
|
||||
|
||||
const (
|
||||
ClusterScoped ResourceScope = "Cluster"
|
||||
NamespaceScoped ResourceScope = "Namespaced"
|
||||
)
|
||||
|
||||
type ConditionStatus string
|
||||
|
||||
// These are valid condition statuses. "ConditionTrue" means a resource is in the condition.
|
||||
// "ConditionFalse" means a resource is not in the condition. "ConditionUnknown" means kubernetes
|
||||
// can't decide if a resource is in the condition or not. In the future, we could add other
|
||||
// intermediate conditions, e.g. ConditionDegraded.
|
||||
const (
|
||||
ConditionTrue ConditionStatus = "True"
|
||||
ConditionFalse ConditionStatus = "False"
|
||||
ConditionUnknown ConditionStatus = "Unknown"
|
||||
)
|
||||
|
||||
// CustomResourceDefinitionConditionType is a valid value for CustomResourceDefinitionCondition.Type
|
||||
type CustomResourceDefinitionConditionType string
|
||||
|
||||
const (
|
||||
// Established means that the resource has become active. A resource is established when all names are
|
||||
// accepted without a conflict for the first time. A resource stays established until deleted, even during
|
||||
// a later NamesAccepted due to changed names. Note that not all names can be changed.
|
||||
Established CustomResourceDefinitionConditionType = "Established"
|
||||
// NamesAccepted means the names chosen for this CustomResourceDefinition do not conflict with others in
|
||||
// the group and are therefore accepted.
|
||||
NamesAccepted CustomResourceDefinitionConditionType = "NamesAccepted"
|
||||
// NonStructuralSchema means that one or more OpenAPI schema is not structural.
|
||||
//
|
||||
// A schema is structural if it specifies types for all values, with the only exceptions of those with
|
||||
// - x-kubernetes-int-or-string: true — for fields which can be integer or string
|
||||
// - x-kubernetes-preserve-unknown-fields: true — for raw, unspecified JSON values
|
||||
// and there is no type, additionalProperties, default, nullable or x-kubernetes-* vendor extenions
|
||||
// specified under allOf, anyOf, oneOf or not.
|
||||
//
|
||||
// Non-structural schemas will not be allowed anymore in v1 API groups. Moreover, new features will not be
|
||||
// available for non-structural CRDs:
|
||||
// - pruning
|
||||
// - defaulting
|
||||
// - read-only
|
||||
// - OpenAPI publishing
|
||||
// - webhook conversion
|
||||
NonStructuralSchema CustomResourceDefinitionConditionType = "NonStructuralSchema"
|
||||
// Terminating means that the CustomResourceDefinition has been deleted and is cleaning up.
|
||||
Terminating CustomResourceDefinitionConditionType = "Terminating"
|
||||
// KubernetesAPIApprovalPolicyConformant indicates that an API in *.k8s.io or *.kubernetes.io is or is not approved. For CRDs
|
||||
// outside those groups, this condition will not be set. For CRDs inside those groups, the condition will
|
||||
// be true if .metadata.annotations["api-approved.kubernetes.io"] is set to a URL, otherwise it will be false.
|
||||
// See https://github.com/kubernetes/enhancements/pull/1111 for more details.
|
||||
KubernetesAPIApprovalPolicyConformant CustomResourceDefinitionConditionType = "KubernetesAPIApprovalPolicyConformant"
|
||||
)
|
||||
|
||||
// CustomResourceDefinitionCondition contains details for the current condition of this pod.
|
||||
type CustomResourceDefinitionCondition struct {
|
||||
// type is the type of the condition. Types include Established, NamesAccepted and Terminating.
|
||||
Type CustomResourceDefinitionConditionType `json:"type" protobuf:"bytes,1,opt,name=type,casttype=CustomResourceDefinitionConditionType"`
|
||||
// status is the status of the condition.
|
||||
// Can be True, False, Unknown.
|
||||
Status ConditionStatus `json:"status" protobuf:"bytes,2,opt,name=status,casttype=ConditionStatus"`
|
||||
// lastTransitionTime last time the condition transitioned from one status to another.
|
||||
// +optional
|
||||
LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty" protobuf:"bytes,3,opt,name=lastTransitionTime"`
|
||||
// reason is a unique, one-word, CamelCase reason for the condition's last transition.
|
||||
// +optional
|
||||
Reason string `json:"reason,omitempty" protobuf:"bytes,4,opt,name=reason"`
|
||||
// message is a human-readable message indicating details about last transition.
|
||||
// +optional
|
||||
Message string `json:"message,omitempty" protobuf:"bytes,5,opt,name=message"`
|
||||
}
|
||||
|
||||
// CustomResourceDefinitionStatus indicates the state of the CustomResourceDefinition
|
||||
type CustomResourceDefinitionStatus struct {
|
||||
// conditions indicate state for particular aspects of a CustomResourceDefinition
|
||||
// +optional
|
||||
Conditions []CustomResourceDefinitionCondition `json:"conditions" protobuf:"bytes,1,opt,name=conditions"`
|
||||
|
||||
// acceptedNames are the names that are actually being used to serve discovery.
|
||||
// They may be different than the names in spec.
|
||||
// +optional
|
||||
AcceptedNames CustomResourceDefinitionNames `json:"acceptedNames" protobuf:"bytes,2,opt,name=acceptedNames"`
|
||||
|
||||
// storedVersions lists all versions of CustomResources that were ever persisted. Tracking these
|
||||
// versions allows a migration path for stored versions in etcd. The field is mutable
|
||||
// so a migration controller can finish a migration to another version (ensuring
|
||||
// no old objects are left in storage), and then remove the rest of the
|
||||
// versions from this list.
|
||||
// Versions may not be removed from `spec.versions` while they exist in this list.
|
||||
// +optional
|
||||
StoredVersions []string `json:"storedVersions" protobuf:"bytes,3,rep,name=storedVersions"`
|
||||
}
|
||||
|
||||
// CustomResourceCleanupFinalizer is the name of the finalizer which will delete instances of
|
||||
// a CustomResourceDefinition
|
||||
const CustomResourceCleanupFinalizer = "customresourcecleanup.apiextensions.k8s.io"
|
||||
|
||||
// +genclient
|
||||
// +genclient:nonNamespaced
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
// +k8s:prerelease-lifecycle-gen:introduced=1.7
|
||||
// +k8s:prerelease-lifecycle-gen:deprecated=1.16
|
||||
// +k8s:prerelease-lifecycle-gen:removed=1.22
|
||||
// +k8s:prerelease-lifecycle-gen:replacement=apiextensions.k8s.io,v1,CustomResourceDefinition
|
||||
|
||||
// CustomResourceDefinition represents a resource that should be exposed on the API server. Its name MUST be in the format
|
||||
// <.spec.name>.<.spec.group>.
|
||||
// Deprecated in v1.16, planned for removal in v1.22. Use apiextensions.k8s.io/v1 CustomResourceDefinition instead.
|
||||
type CustomResourceDefinition struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
|
||||
// spec describes how the user wants the resources to appear
|
||||
Spec CustomResourceDefinitionSpec `json:"spec" protobuf:"bytes,2,opt,name=spec"`
|
||||
// status indicates the actual state of the CustomResourceDefinition
|
||||
// +optional
|
||||
Status CustomResourceDefinitionStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
// +k8s:prerelease-lifecycle-gen:introduced=1.7
|
||||
// +k8s:prerelease-lifecycle-gen:deprecated=1.16
|
||||
// +k8s:prerelease-lifecycle-gen:removed=1.22
|
||||
// +k8s:prerelease-lifecycle-gen:replacement=apiextensions.k8s.io,v1,CustomResourceDefinitionList
|
||||
|
||||
// CustomResourceDefinitionList is a list of CustomResourceDefinition objects.
|
||||
type CustomResourceDefinitionList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
|
||||
// items list individual CustomResourceDefinition objects
|
||||
Items []CustomResourceDefinition `json:"items" protobuf:"bytes,2,rep,name=items"`
|
||||
}
|
||||
|
||||
// CustomResourceValidation is a list of validation methods for CustomResources.
|
||||
type CustomResourceValidation struct {
|
||||
// openAPIV3Schema is the OpenAPI v3 schema to use for validation and pruning.
|
||||
// +optional
|
||||
OpenAPIV3Schema *JSONSchemaProps `json:"openAPIV3Schema,omitempty" protobuf:"bytes,1,opt,name=openAPIV3Schema"`
|
||||
}
|
||||
|
||||
// CustomResourceSubresources defines the status and scale subresources for CustomResources.
|
||||
type CustomResourceSubresources struct {
|
||||
// status indicates the custom resource should serve a `/status` subresource.
|
||||
// When enabled:
|
||||
// 1. requests to the custom resource primary endpoint ignore changes to the `status` stanza of the object.
|
||||
// 2. requests to the custom resource `/status` subresource ignore changes to anything other than the `status` stanza of the object.
|
||||
// +optional
|
||||
Status *CustomResourceSubresourceStatus `json:"status,omitempty" protobuf:"bytes,1,opt,name=status"`
|
||||
// scale indicates the custom resource should serve a `/scale` subresource that returns an `autoscaling/v1` Scale object.
|
||||
// +optional
|
||||
Scale *CustomResourceSubresourceScale `json:"scale,omitempty" protobuf:"bytes,2,opt,name=scale"`
|
||||
}
|
||||
|
||||
// CustomResourceSubresourceStatus defines how to serve the status subresource for CustomResources.
|
||||
// Status is represented by the `.status` JSON path inside of a CustomResource. When set,
|
||||
// * exposes a /status subresource for the custom resource
|
||||
// * PUT requests to the /status subresource take a custom resource object, and ignore changes to anything except the status stanza
|
||||
// * PUT/POST/PATCH requests to the custom resource ignore changes to the status stanza
|
||||
type CustomResourceSubresourceStatus struct{}
|
||||
|
||||
// CustomResourceSubresourceScale defines how to serve the scale subresource for CustomResources.
|
||||
type CustomResourceSubresourceScale struct {
|
||||
// specReplicasPath defines the JSON path inside of a custom resource that corresponds to Scale `spec.replicas`.
|
||||
// Only JSON paths without the array notation are allowed.
|
||||
// Must be a JSON Path under `.spec`.
|
||||
// If there is no value under the given path in the custom resource, the `/scale` subresource will return an error on GET.
|
||||
SpecReplicasPath string `json:"specReplicasPath" protobuf:"bytes,1,name=specReplicasPath"`
|
||||
// statusReplicasPath defines the JSON path inside of a custom resource that corresponds to Scale `status.replicas`.
|
||||
// Only JSON paths without the array notation are allowed.
|
||||
// Must be a JSON Path under `.status`.
|
||||
// If there is no value under the given path in the custom resource, the `status.replicas` value in the `/scale` subresource
|
||||
// will default to 0.
|
||||
StatusReplicasPath string `json:"statusReplicasPath" protobuf:"bytes,2,opt,name=statusReplicasPath"`
|
||||
// labelSelectorPath defines the JSON path inside of a custom resource that corresponds to Scale `status.selector`.
|
||||
// Only JSON paths without the array notation are allowed.
|
||||
// Must be a JSON Path under `.status` or `.spec`.
|
||||
// Must be set to work with HorizontalPodAutoscaler.
|
||||
// The field pointed by this JSON path must be a string field (not a complex selector struct)
|
||||
// which contains a serialized label selector in string form.
|
||||
// More info: https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions#scale-subresource
|
||||
// If there is no value under the given path in the custom resource, the `status.selector` value in the `/scale`
|
||||
// subresource will default to the empty string.
|
||||
// +optional
|
||||
LabelSelectorPath *string `json:"labelSelectorPath,omitempty" protobuf:"bytes,3,opt,name=labelSelectorPath"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
// +k8s:prerelease-lifecycle-gen:introduced=1.13
|
||||
// +k8s:prerelease-lifecycle-gen:deprecated=1.19
|
||||
// This API is never served. It is used for outbound requests from apiservers. This will ensure it never gets served accidentally
|
||||
// and having the generator against this group will protect future APIs which may be served.
|
||||
// +k8s:prerelease-lifecycle-gen:replacement=apiextensions.k8s.io,v1,ConversionReview
|
||||
|
||||
// ConversionReview describes a conversion request/response.
|
||||
type ConversionReview struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
// request describes the attributes for the conversion request.
|
||||
// +optional
|
||||
Request *ConversionRequest `json:"request,omitempty" protobuf:"bytes,1,opt,name=request"`
|
||||
// response describes the attributes for the conversion response.
|
||||
// +optional
|
||||
Response *ConversionResponse `json:"response,omitempty" protobuf:"bytes,2,opt,name=response"`
|
||||
}
|
||||
|
||||
// ConversionRequest describes the conversion request parameters.
|
||||
type ConversionRequest struct {
|
||||
// uid is an identifier for the individual request/response. It allows distinguishing instances of requests which are
|
||||
// otherwise identical (parallel requests, etc).
|
||||
// The UID is meant to track the round trip (request/response) between the Kubernetes API server and the webhook, not the user request.
|
||||
// It is suitable for correlating log entries between the webhook and apiserver, for either auditing or debugging.
|
||||
UID types.UID `json:"uid" protobuf:"bytes,1,name=uid"`
|
||||
// desiredAPIVersion is the version to convert given objects to. e.g. "myapi.example.com/v1"
|
||||
DesiredAPIVersion string `json:"desiredAPIVersion" protobuf:"bytes,2,name=desiredAPIVersion"`
|
||||
// objects is the list of custom resource objects to be converted.
|
||||
Objects []runtime.RawExtension `json:"objects" protobuf:"bytes,3,rep,name=objects"`
|
||||
}
|
||||
|
||||
// ConversionResponse describes a conversion response.
|
||||
type ConversionResponse struct {
|
||||
// uid is an identifier for the individual request/response.
|
||||
// This should be copied over from the corresponding `request.uid`.
|
||||
UID types.UID `json:"uid" protobuf:"bytes,1,name=uid"`
|
||||
// convertedObjects is the list of converted version of `request.objects` if the `result` is successful, otherwise empty.
|
||||
// The webhook is expected to set `apiVersion` of these objects to the `request.desiredAPIVersion`. The list
|
||||
// must also have the same size as the input list with the same objects in the same order (equal kind, metadata.uid, metadata.name and metadata.namespace).
|
||||
// The webhook is allowed to mutate labels and annotations. Any other change to the metadata is silently ignored.
|
||||
ConvertedObjects []runtime.RawExtension `json:"convertedObjects" protobuf:"bytes,2,rep,name=convertedObjects"`
|
||||
// result contains the result of conversion with extra details if the conversion failed. `result.status` determines if
|
||||
// the conversion failed or succeeded. The `result.status` field is required and represents the success or failure of the
|
||||
// conversion. A successful conversion must set `result.status` to `Success`. A failed conversion must set
|
||||
// `result.status` to `Failure` and provide more details in `result.message` and return http status 200. The `result.message`
|
||||
// will be used to construct an error message for the end user.
|
||||
Result metav1.Status `json:"result" protobuf:"bytes,3,name=result"`
|
||||
}
|
||||
257
vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1/types_jsonschema.go
generated
vendored
Normal file
257
vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1/types_jsonschema.go
generated
vendored
Normal file
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1beta1
|
||||
|
||||
// JSONSchemaProps is a JSON-Schema following Specification Draft 4 (http://json-schema.org/).
|
||||
type JSONSchemaProps struct {
|
||||
ID string `json:"id,omitempty" protobuf:"bytes,1,opt,name=id"`
|
||||
Schema JSONSchemaURL `json:"$schema,omitempty" protobuf:"bytes,2,opt,name=schema"`
|
||||
Ref *string `json:"$ref,omitempty" protobuf:"bytes,3,opt,name=ref"`
|
||||
Description string `json:"description,omitempty" protobuf:"bytes,4,opt,name=description"`
|
||||
Type string `json:"type,omitempty" protobuf:"bytes,5,opt,name=type"`
|
||||
|
||||
// format is an OpenAPI v3 format string. Unknown formats are ignored. The following formats are validated:
|
||||
//
|
||||
// - bsonobjectid: a bson object ID, i.e. a 24 characters hex string
|
||||
// - uri: an URI as parsed by Golang net/url.ParseRequestURI
|
||||
// - email: an email address as parsed by Golang net/mail.ParseAddress
|
||||
// - hostname: a valid representation for an Internet host name, as defined by RFC 1034, section 3.1 [RFC1034].
|
||||
// - ipv4: an IPv4 IP as parsed by Golang net.ParseIP
|
||||
// - ipv6: an IPv6 IP as parsed by Golang net.ParseIP
|
||||
// - cidr: a CIDR as parsed by Golang net.ParseCIDR
|
||||
// - mac: a MAC address as parsed by Golang net.ParseMAC
|
||||
// - uuid: an UUID that allows uppercase defined by the regex (?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$
|
||||
// - uuid3: an UUID3 that allows uppercase defined by the regex (?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?3[0-9a-f]{3}-?[0-9a-f]{4}-?[0-9a-f]{12}$
|
||||
// - uuid4: an UUID4 that allows uppercase defined by the regex (?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?4[0-9a-f]{3}-?[89ab][0-9a-f]{3}-?[0-9a-f]{12}$
|
||||
// - uuid5: an UUID5 that allows uppercase defined by the regex (?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?5[0-9a-f]{3}-?[89ab][0-9a-f]{3}-?[0-9a-f]{12}$
|
||||
// - isbn: an ISBN10 or ISBN13 number string like "0321751043" or "978-0321751041"
|
||||
// - isbn10: an ISBN10 number string like "0321751043"
|
||||
// - isbn13: an ISBN13 number string like "978-0321751041"
|
||||
// - creditcard: a credit card number defined by the regex ^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\\d{3})\\d{11})$ with any non digit characters mixed in
|
||||
// - ssn: a U.S. social security number following the regex ^\\d{3}[- ]?\\d{2}[- ]?\\d{4}$
|
||||
// - hexcolor: an hexadecimal color code like "#FFFFFF: following the regex ^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$
|
||||
// - rgbcolor: an RGB color code like rgb like "rgb(255,255,2559"
|
||||
// - byte: base64 encoded binary data
|
||||
// - password: any kind of string
|
||||
// - date: a date string like "2006-01-02" as defined by full-date in RFC3339
|
||||
// - duration: a duration string like "22 ns" as parsed by Golang time.ParseDuration or compatible with Scala duration format
|
||||
// - datetime: a date time string like "2014-12-15T19:30:20.000Z" as defined by date-time in RFC3339.
|
||||
Format string `json:"format,omitempty" protobuf:"bytes,6,opt,name=format"`
|
||||
|
||||
Title string `json:"title,omitempty" protobuf:"bytes,7,opt,name=title"`
|
||||
// default is a default value for undefined object fields.
|
||||
// Defaulting is a beta feature under the CustomResourceDefaulting feature gate.
|
||||
// CustomResourceDefinitions with defaults must be created using the v1 (or newer) CustomResourceDefinition API.
|
||||
Default *JSON `json:"default,omitempty" protobuf:"bytes,8,opt,name=default"`
|
||||
Maximum *float64 `json:"maximum,omitempty" protobuf:"bytes,9,opt,name=maximum"`
|
||||
ExclusiveMaximum bool `json:"exclusiveMaximum,omitempty" protobuf:"bytes,10,opt,name=exclusiveMaximum"`
|
||||
Minimum *float64 `json:"minimum,omitempty" protobuf:"bytes,11,opt,name=minimum"`
|
||||
ExclusiveMinimum bool `json:"exclusiveMinimum,omitempty" protobuf:"bytes,12,opt,name=exclusiveMinimum"`
|
||||
MaxLength *int64 `json:"maxLength,omitempty" protobuf:"bytes,13,opt,name=maxLength"`
|
||||
MinLength *int64 `json:"minLength,omitempty" protobuf:"bytes,14,opt,name=minLength"`
|
||||
Pattern string `json:"pattern,omitempty" protobuf:"bytes,15,opt,name=pattern"`
|
||||
MaxItems *int64 `json:"maxItems,omitempty" protobuf:"bytes,16,opt,name=maxItems"`
|
||||
MinItems *int64 `json:"minItems,omitempty" protobuf:"bytes,17,opt,name=minItems"`
|
||||
UniqueItems bool `json:"uniqueItems,omitempty" protobuf:"bytes,18,opt,name=uniqueItems"`
|
||||
MultipleOf *float64 `json:"multipleOf,omitempty" protobuf:"bytes,19,opt,name=multipleOf"`
|
||||
Enum []JSON `json:"enum,omitempty" protobuf:"bytes,20,rep,name=enum"`
|
||||
MaxProperties *int64 `json:"maxProperties,omitempty" protobuf:"bytes,21,opt,name=maxProperties"`
|
||||
MinProperties *int64 `json:"minProperties,omitempty" protobuf:"bytes,22,opt,name=minProperties"`
|
||||
Required []string `json:"required,omitempty" protobuf:"bytes,23,rep,name=required"`
|
||||
Items *JSONSchemaPropsOrArray `json:"items,omitempty" protobuf:"bytes,24,opt,name=items"`
|
||||
AllOf []JSONSchemaProps `json:"allOf,omitempty" protobuf:"bytes,25,rep,name=allOf"`
|
||||
OneOf []JSONSchemaProps `json:"oneOf,omitempty" protobuf:"bytes,26,rep,name=oneOf"`
|
||||
AnyOf []JSONSchemaProps `json:"anyOf,omitempty" protobuf:"bytes,27,rep,name=anyOf"`
|
||||
Not *JSONSchemaProps `json:"not,omitempty" protobuf:"bytes,28,opt,name=not"`
|
||||
Properties map[string]JSONSchemaProps `json:"properties,omitempty" protobuf:"bytes,29,rep,name=properties"`
|
||||
AdditionalProperties *JSONSchemaPropsOrBool `json:"additionalProperties,omitempty" protobuf:"bytes,30,opt,name=additionalProperties"`
|
||||
PatternProperties map[string]JSONSchemaProps `json:"patternProperties,omitempty" protobuf:"bytes,31,rep,name=patternProperties"`
|
||||
Dependencies JSONSchemaDependencies `json:"dependencies,omitempty" protobuf:"bytes,32,opt,name=dependencies"`
|
||||
AdditionalItems *JSONSchemaPropsOrBool `json:"additionalItems,omitempty" protobuf:"bytes,33,opt,name=additionalItems"`
|
||||
Definitions JSONSchemaDefinitions `json:"definitions,omitempty" protobuf:"bytes,34,opt,name=definitions"`
|
||||
ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty" protobuf:"bytes,35,opt,name=externalDocs"`
|
||||
Example *JSON `json:"example,omitempty" protobuf:"bytes,36,opt,name=example"`
|
||||
Nullable bool `json:"nullable,omitempty" protobuf:"bytes,37,opt,name=nullable"`
|
||||
|
||||
// x-kubernetes-preserve-unknown-fields stops the API server
|
||||
// decoding step from pruning fields which are not specified
|
||||
// in the validation schema. This affects fields recursively,
|
||||
// but switches back to normal pruning behaviour if nested
|
||||
// properties or additionalProperties are specified in the schema.
|
||||
// This can either be true or undefined. False is forbidden.
|
||||
XPreserveUnknownFields *bool `json:"x-kubernetes-preserve-unknown-fields,omitempty" protobuf:"bytes,38,opt,name=xKubernetesPreserveUnknownFields"`
|
||||
|
||||
// x-kubernetes-embedded-resource defines that the value is an
|
||||
// embedded Kubernetes runtime.Object, with TypeMeta and
|
||||
// ObjectMeta. The type must be object. It is allowed to further
|
||||
// restrict the embedded object. kind, apiVersion and metadata
|
||||
// are validated automatically. x-kubernetes-preserve-unknown-fields
|
||||
// is allowed to be true, but does not have to be if the object
|
||||
// is fully specified (up to kind, apiVersion, metadata).
|
||||
XEmbeddedResource bool `json:"x-kubernetes-embedded-resource,omitempty" protobuf:"bytes,39,opt,name=xKubernetesEmbeddedResource"`
|
||||
|
||||
// x-kubernetes-int-or-string specifies that this value is
|
||||
// either an integer or a string. If this is true, an empty
|
||||
// type is allowed and type as child of anyOf is permitted
|
||||
// if following one of the following patterns:
|
||||
//
|
||||
// 1) anyOf:
|
||||
// - type: integer
|
||||
// - type: string
|
||||
// 2) allOf:
|
||||
// - anyOf:
|
||||
// - type: integer
|
||||
// - type: string
|
||||
// - ... zero or more
|
||||
XIntOrString bool `json:"x-kubernetes-int-or-string,omitempty" protobuf:"bytes,40,opt,name=xKubernetesIntOrString"`
|
||||
|
||||
// x-kubernetes-list-map-keys annotates an array with the x-kubernetes-list-type `map` by specifying the keys used
|
||||
// as the index of the map.
|
||||
//
|
||||
// This tag MUST only be used on lists that have the "x-kubernetes-list-type"
|
||||
// extension set to "map". Also, the values specified for this attribute must
|
||||
// be a scalar typed field of the child structure (no nesting is supported).
|
||||
//
|
||||
// The properties specified must either be required or have a default value,
|
||||
// to ensure those properties are present for all list items.
|
||||
//
|
||||
// +optional
|
||||
XListMapKeys []string `json:"x-kubernetes-list-map-keys,omitempty" protobuf:"bytes,41,rep,name=xKubernetesListMapKeys"`
|
||||
|
||||
// x-kubernetes-list-type annotates an array to further describe its topology.
|
||||
// This extension must only be used on lists and may have 3 possible values:
|
||||
//
|
||||
// 1) `atomic`: the list is treated as a single entity, like a scalar.
|
||||
// Atomic lists will be entirely replaced when updated. This extension
|
||||
// may be used on any type of list (struct, scalar, ...).
|
||||
// 2) `set`:
|
||||
// Sets are lists that must not have multiple items with the same value. Each
|
||||
// value must be a scalar, an object with x-kubernetes-map-type `atomic` or an
|
||||
// array with x-kubernetes-list-type `atomic`.
|
||||
// 3) `map`:
|
||||
// These lists are like maps in that their elements have a non-index key
|
||||
// used to identify them. Order is preserved upon merge. The map tag
|
||||
// must only be used on a list with elements of type object.
|
||||
// Defaults to atomic for arrays.
|
||||
// +optional
|
||||
XListType *string `json:"x-kubernetes-list-type,omitempty" protobuf:"bytes,42,opt,name=xKubernetesListType"`
|
||||
|
||||
// x-kubernetes-map-type annotates an object to further describe its topology.
|
||||
// This extension must only be used when type is object and may have 2 possible values:
|
||||
//
|
||||
// 1) `granular`:
|
||||
// These maps are actual maps (key-value pairs) and each fields are independent
|
||||
// from each other (they can each be manipulated by separate actors). This is
|
||||
// the default behaviour for all maps.
|
||||
// 2) `atomic`: the list is treated as a single entity, like a scalar.
|
||||
// Atomic maps will be entirely replaced when updated.
|
||||
// +optional
|
||||
XMapType *string `json:"x-kubernetes-map-type,omitempty" protobuf:"bytes,43,opt,name=xKubernetesMapType"`
|
||||
}
|
||||
|
||||
// JSON represents any valid JSON value.
|
||||
// These types are supported: bool, int64, float64, string, []interface{}, map[string]interface{} and nil.
|
||||
type JSON struct {
|
||||
Raw []byte `protobuf:"bytes,1,opt,name=raw"`
|
||||
}
|
||||
|
||||
// OpenAPISchemaType is used by the kube-openapi generator when constructing
|
||||
// the OpenAPI spec of this type.
|
||||
//
|
||||
// See: https://github.com/kubernetes/kube-openapi/tree/master/pkg/generators
|
||||
func (_ JSON) OpenAPISchemaType() []string {
|
||||
// TODO: return actual types when anyOf is supported
|
||||
return nil
|
||||
}
|
||||
|
||||
// OpenAPISchemaFormat is used by the kube-openapi generator when constructing
|
||||
// the OpenAPI spec of this type.
|
||||
func (_ JSON) OpenAPISchemaFormat() string { return "" }
|
||||
|
||||
// JSONSchemaURL represents a schema url.
|
||||
type JSONSchemaURL string
|
||||
|
||||
// JSONSchemaPropsOrArray represents a value that can either be a JSONSchemaProps
|
||||
// or an array of JSONSchemaProps. Mainly here for serialization purposes.
|
||||
type JSONSchemaPropsOrArray struct {
|
||||
Schema *JSONSchemaProps `protobuf:"bytes,1,opt,name=schema"`
|
||||
JSONSchemas []JSONSchemaProps `protobuf:"bytes,2,rep,name=jSONSchemas"`
|
||||
}
|
||||
|
||||
// OpenAPISchemaType is used by the kube-openapi generator when constructing
|
||||
// the OpenAPI spec of this type.
|
||||
//
|
||||
// See: https://github.com/kubernetes/kube-openapi/tree/master/pkg/generators
|
||||
func (_ JSONSchemaPropsOrArray) OpenAPISchemaType() []string {
|
||||
// TODO: return actual types when anyOf is supported
|
||||
return nil
|
||||
}
|
||||
|
||||
// OpenAPISchemaFormat is used by the kube-openapi generator when constructing
|
||||
// the OpenAPI spec of this type.
|
||||
func (_ JSONSchemaPropsOrArray) OpenAPISchemaFormat() string { return "" }
|
||||
|
||||
// JSONSchemaPropsOrBool represents JSONSchemaProps or a boolean value.
|
||||
// Defaults to true for the boolean property.
|
||||
type JSONSchemaPropsOrBool struct {
|
||||
Allows bool `protobuf:"varint,1,opt,name=allows"`
|
||||
Schema *JSONSchemaProps `protobuf:"bytes,2,opt,name=schema"`
|
||||
}
|
||||
|
||||
// OpenAPISchemaType is used by the kube-openapi generator when constructing
|
||||
// the OpenAPI spec of this type.
|
||||
//
|
||||
// See: https://github.com/kubernetes/kube-openapi/tree/master/pkg/generators
|
||||
func (_ JSONSchemaPropsOrBool) OpenAPISchemaType() []string {
|
||||
// TODO: return actual types when anyOf is supported
|
||||
return nil
|
||||
}
|
||||
|
||||
// OpenAPISchemaFormat is used by the kube-openapi generator when constructing
|
||||
// the OpenAPI spec of this type.
|
||||
func (_ JSONSchemaPropsOrBool) OpenAPISchemaFormat() string { return "" }
|
||||
|
||||
// JSONSchemaDependencies represent a dependencies property.
|
||||
type JSONSchemaDependencies map[string]JSONSchemaPropsOrStringArray
|
||||
|
||||
// JSONSchemaPropsOrStringArray represents a JSONSchemaProps or a string array.
|
||||
type JSONSchemaPropsOrStringArray struct {
|
||||
Schema *JSONSchemaProps `protobuf:"bytes,1,opt,name=schema"`
|
||||
Property []string `protobuf:"bytes,2,rep,name=property"`
|
||||
}
|
||||
|
||||
// OpenAPISchemaType is used by the kube-openapi generator when constructing
|
||||
// the OpenAPI spec of this type.
|
||||
//
|
||||
// See: https://github.com/kubernetes/kube-openapi/tree/master/pkg/generators
|
||||
func (_ JSONSchemaPropsOrStringArray) OpenAPISchemaType() []string {
|
||||
// TODO: return actual types when anyOf is supported
|
||||
return nil
|
||||
}
|
||||
|
||||
// OpenAPISchemaFormat is used by the kube-openapi generator when constructing
|
||||
// the OpenAPI spec of this type.
|
||||
func (_ JSONSchemaPropsOrStringArray) OpenAPISchemaFormat() string { return "" }
|
||||
|
||||
// JSONSchemaDefinitions contains the models explicitly defined in this spec.
|
||||
type JSONSchemaDefinitions map[string]JSONSchemaProps
|
||||
|
||||
// ExternalDocumentation allows referencing an external resource for extended documentation.
|
||||
type ExternalDocumentation struct {
|
||||
Description string `json:"description,omitempty" protobuf:"bytes,1,opt,name=description"`
|
||||
URL string `json:"url,omitempty" protobuf:"bytes,2,opt,name=url"`
|
||||
}
|
||||
1331
vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1/zz_generated.conversion.go
generated
vendored
Normal file
1331
vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1/zz_generated.conversion.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
667
vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1/zz_generated.deepcopy.go
generated
vendored
Normal file
667
vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1/zz_generated.deepcopy.go
generated
vendored
Normal file
@@ -0,0 +1,667 @@
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by deepcopy-gen. DO NOT EDIT.
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ConversionRequest) DeepCopyInto(out *ConversionRequest) {
|
||||
*out = *in
|
||||
if in.Objects != nil {
|
||||
in, out := &in.Objects, &out.Objects
|
||||
*out = make([]runtime.RawExtension, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConversionRequest.
|
||||
func (in *ConversionRequest) DeepCopy() *ConversionRequest {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ConversionRequest)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ConversionResponse) DeepCopyInto(out *ConversionResponse) {
|
||||
*out = *in
|
||||
if in.ConvertedObjects != nil {
|
||||
in, out := &in.ConvertedObjects, &out.ConvertedObjects
|
||||
*out = make([]runtime.RawExtension, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
in.Result.DeepCopyInto(&out.Result)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConversionResponse.
|
||||
func (in *ConversionResponse) DeepCopy() *ConversionResponse {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ConversionResponse)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ConversionReview) DeepCopyInto(out *ConversionReview) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
if in.Request != nil {
|
||||
in, out := &in.Request, &out.Request
|
||||
*out = new(ConversionRequest)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Response != nil {
|
||||
in, out := &in.Response, &out.Response
|
||||
*out = new(ConversionResponse)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConversionReview.
|
||||
func (in *ConversionReview) DeepCopy() *ConversionReview {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ConversionReview)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *ConversionReview) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CustomResourceColumnDefinition) DeepCopyInto(out *CustomResourceColumnDefinition) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceColumnDefinition.
|
||||
func (in *CustomResourceColumnDefinition) DeepCopy() *CustomResourceColumnDefinition {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CustomResourceColumnDefinition)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CustomResourceConversion) DeepCopyInto(out *CustomResourceConversion) {
|
||||
*out = *in
|
||||
if in.WebhookClientConfig != nil {
|
||||
in, out := &in.WebhookClientConfig, &out.WebhookClientConfig
|
||||
*out = new(WebhookClientConfig)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.ConversionReviewVersions != nil {
|
||||
in, out := &in.ConversionReviewVersions, &out.ConversionReviewVersions
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceConversion.
|
||||
func (in *CustomResourceConversion) DeepCopy() *CustomResourceConversion {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CustomResourceConversion)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CustomResourceDefinition) DeepCopyInto(out *CustomResourceDefinition) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceDefinition.
|
||||
func (in *CustomResourceDefinition) DeepCopy() *CustomResourceDefinition {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CustomResourceDefinition)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *CustomResourceDefinition) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CustomResourceDefinitionCondition) DeepCopyInto(out *CustomResourceDefinitionCondition) {
|
||||
*out = *in
|
||||
in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceDefinitionCondition.
|
||||
func (in *CustomResourceDefinitionCondition) DeepCopy() *CustomResourceDefinitionCondition {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CustomResourceDefinitionCondition)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CustomResourceDefinitionList) DeepCopyInto(out *CustomResourceDefinitionList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]CustomResourceDefinition, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceDefinitionList.
|
||||
func (in *CustomResourceDefinitionList) DeepCopy() *CustomResourceDefinitionList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CustomResourceDefinitionList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *CustomResourceDefinitionList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CustomResourceDefinitionNames) DeepCopyInto(out *CustomResourceDefinitionNames) {
|
||||
*out = *in
|
||||
if in.ShortNames != nil {
|
||||
in, out := &in.ShortNames, &out.ShortNames
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Categories != nil {
|
||||
in, out := &in.Categories, &out.Categories
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceDefinitionNames.
|
||||
func (in *CustomResourceDefinitionNames) DeepCopy() *CustomResourceDefinitionNames {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CustomResourceDefinitionNames)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CustomResourceDefinitionSpec) DeepCopyInto(out *CustomResourceDefinitionSpec) {
|
||||
*out = *in
|
||||
in.Names.DeepCopyInto(&out.Names)
|
||||
if in.Validation != nil {
|
||||
in, out := &in.Validation, &out.Validation
|
||||
*out = new(CustomResourceValidation)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Subresources != nil {
|
||||
in, out := &in.Subresources, &out.Subresources
|
||||
*out = new(CustomResourceSubresources)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Versions != nil {
|
||||
in, out := &in.Versions, &out.Versions
|
||||
*out = make([]CustomResourceDefinitionVersion, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.AdditionalPrinterColumns != nil {
|
||||
in, out := &in.AdditionalPrinterColumns, &out.AdditionalPrinterColumns
|
||||
*out = make([]CustomResourceColumnDefinition, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Conversion != nil {
|
||||
in, out := &in.Conversion, &out.Conversion
|
||||
*out = new(CustomResourceConversion)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.PreserveUnknownFields != nil {
|
||||
in, out := &in.PreserveUnknownFields, &out.PreserveUnknownFields
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceDefinitionSpec.
|
||||
func (in *CustomResourceDefinitionSpec) DeepCopy() *CustomResourceDefinitionSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CustomResourceDefinitionSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CustomResourceDefinitionStatus) DeepCopyInto(out *CustomResourceDefinitionStatus) {
|
||||
*out = *in
|
||||
if in.Conditions != nil {
|
||||
in, out := &in.Conditions, &out.Conditions
|
||||
*out = make([]CustomResourceDefinitionCondition, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
in.AcceptedNames.DeepCopyInto(&out.AcceptedNames)
|
||||
if in.StoredVersions != nil {
|
||||
in, out := &in.StoredVersions, &out.StoredVersions
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceDefinitionStatus.
|
||||
func (in *CustomResourceDefinitionStatus) DeepCopy() *CustomResourceDefinitionStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CustomResourceDefinitionStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CustomResourceDefinitionVersion) DeepCopyInto(out *CustomResourceDefinitionVersion) {
|
||||
*out = *in
|
||||
if in.DeprecationWarning != nil {
|
||||
in, out := &in.DeprecationWarning, &out.DeprecationWarning
|
||||
*out = new(string)
|
||||
**out = **in
|
||||
}
|
||||
if in.Schema != nil {
|
||||
in, out := &in.Schema, &out.Schema
|
||||
*out = new(CustomResourceValidation)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Subresources != nil {
|
||||
in, out := &in.Subresources, &out.Subresources
|
||||
*out = new(CustomResourceSubresources)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.AdditionalPrinterColumns != nil {
|
||||
in, out := &in.AdditionalPrinterColumns, &out.AdditionalPrinterColumns
|
||||
*out = make([]CustomResourceColumnDefinition, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceDefinitionVersion.
|
||||
func (in *CustomResourceDefinitionVersion) DeepCopy() *CustomResourceDefinitionVersion {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CustomResourceDefinitionVersion)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CustomResourceSubresourceScale) DeepCopyInto(out *CustomResourceSubresourceScale) {
|
||||
*out = *in
|
||||
if in.LabelSelectorPath != nil {
|
||||
in, out := &in.LabelSelectorPath, &out.LabelSelectorPath
|
||||
*out = new(string)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceSubresourceScale.
|
||||
func (in *CustomResourceSubresourceScale) DeepCopy() *CustomResourceSubresourceScale {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CustomResourceSubresourceScale)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CustomResourceSubresourceStatus) DeepCopyInto(out *CustomResourceSubresourceStatus) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceSubresourceStatus.
|
||||
func (in *CustomResourceSubresourceStatus) DeepCopy() *CustomResourceSubresourceStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CustomResourceSubresourceStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CustomResourceSubresources) DeepCopyInto(out *CustomResourceSubresources) {
|
||||
*out = *in
|
||||
if in.Status != nil {
|
||||
in, out := &in.Status, &out.Status
|
||||
*out = new(CustomResourceSubresourceStatus)
|
||||
**out = **in
|
||||
}
|
||||
if in.Scale != nil {
|
||||
in, out := &in.Scale, &out.Scale
|
||||
*out = new(CustomResourceSubresourceScale)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceSubresources.
|
||||
func (in *CustomResourceSubresources) DeepCopy() *CustomResourceSubresources {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CustomResourceSubresources)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CustomResourceValidation) DeepCopyInto(out *CustomResourceValidation) {
|
||||
*out = *in
|
||||
if in.OpenAPIV3Schema != nil {
|
||||
in, out := &in.OpenAPIV3Schema, &out.OpenAPIV3Schema
|
||||
*out = (*in).DeepCopy()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceValidation.
|
||||
func (in *CustomResourceValidation) DeepCopy() *CustomResourceValidation {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CustomResourceValidation)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ExternalDocumentation) DeepCopyInto(out *ExternalDocumentation) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalDocumentation.
|
||||
func (in *ExternalDocumentation) DeepCopy() *ExternalDocumentation {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ExternalDocumentation)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JSON) DeepCopyInto(out *JSON) {
|
||||
*out = *in
|
||||
if in.Raw != nil {
|
||||
in, out := &in.Raw, &out.Raw
|
||||
*out = make([]byte, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JSON.
|
||||
func (in *JSON) DeepCopy() *JSON {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(JSON)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in JSONSchemaDefinitions) DeepCopyInto(out *JSONSchemaDefinitions) {
|
||||
{
|
||||
in := &in
|
||||
*out = make(JSONSchemaDefinitions, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = *val.DeepCopy()
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JSONSchemaDefinitions.
|
||||
func (in JSONSchemaDefinitions) DeepCopy() JSONSchemaDefinitions {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(JSONSchemaDefinitions)
|
||||
in.DeepCopyInto(out)
|
||||
return *out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in JSONSchemaDependencies) DeepCopyInto(out *JSONSchemaDependencies) {
|
||||
{
|
||||
in := &in
|
||||
*out = make(JSONSchemaDependencies, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = *val.DeepCopy()
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JSONSchemaDependencies.
|
||||
func (in JSONSchemaDependencies) DeepCopy() JSONSchemaDependencies {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(JSONSchemaDependencies)
|
||||
in.DeepCopyInto(out)
|
||||
return *out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JSONSchemaProps) DeepCopyInto(out *JSONSchemaProps) {
|
||||
clone := in.DeepCopy()
|
||||
*out = *clone
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JSONSchemaPropsOrArray) DeepCopyInto(out *JSONSchemaPropsOrArray) {
|
||||
*out = *in
|
||||
if in.Schema != nil {
|
||||
in, out := &in.Schema, &out.Schema
|
||||
*out = (*in).DeepCopy()
|
||||
}
|
||||
if in.JSONSchemas != nil {
|
||||
in, out := &in.JSONSchemas, &out.JSONSchemas
|
||||
*out = make([]JSONSchemaProps, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JSONSchemaPropsOrArray.
|
||||
func (in *JSONSchemaPropsOrArray) DeepCopy() *JSONSchemaPropsOrArray {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(JSONSchemaPropsOrArray)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JSONSchemaPropsOrBool) DeepCopyInto(out *JSONSchemaPropsOrBool) {
|
||||
*out = *in
|
||||
if in.Schema != nil {
|
||||
in, out := &in.Schema, &out.Schema
|
||||
*out = (*in).DeepCopy()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JSONSchemaPropsOrBool.
|
||||
func (in *JSONSchemaPropsOrBool) DeepCopy() *JSONSchemaPropsOrBool {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(JSONSchemaPropsOrBool)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JSONSchemaPropsOrStringArray) DeepCopyInto(out *JSONSchemaPropsOrStringArray) {
|
||||
*out = *in
|
||||
if in.Schema != nil {
|
||||
in, out := &in.Schema, &out.Schema
|
||||
*out = (*in).DeepCopy()
|
||||
}
|
||||
if in.Property != nil {
|
||||
in, out := &in.Property, &out.Property
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JSONSchemaPropsOrStringArray.
|
||||
func (in *JSONSchemaPropsOrStringArray) DeepCopy() *JSONSchemaPropsOrStringArray {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(JSONSchemaPropsOrStringArray)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ServiceReference) DeepCopyInto(out *ServiceReference) {
|
||||
*out = *in
|
||||
if in.Path != nil {
|
||||
in, out := &in.Path, &out.Path
|
||||
*out = new(string)
|
||||
**out = **in
|
||||
}
|
||||
if in.Port != nil {
|
||||
in, out := &in.Port, &out.Port
|
||||
*out = new(int32)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceReference.
|
||||
func (in *ServiceReference) DeepCopy() *ServiceReference {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ServiceReference)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *WebhookClientConfig) DeepCopyInto(out *WebhookClientConfig) {
|
||||
*out = *in
|
||||
if in.URL != nil {
|
||||
in, out := &in.URL, &out.URL
|
||||
*out = new(string)
|
||||
**out = **in
|
||||
}
|
||||
if in.Service != nil {
|
||||
in, out := &in.Service, &out.Service
|
||||
*out = new(ServiceReference)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.CABundle != nil {
|
||||
in, out := &in.CABundle, &out.CABundle
|
||||
*out = make([]byte, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WebhookClientConfig.
|
||||
func (in *WebhookClientConfig) DeepCopy() *WebhookClientConfig {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(WebhookClientConfig)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
55
vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1/zz_generated.defaults.go
generated
vendored
Normal file
55
vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1/zz_generated.defaults.go
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by defaulter-gen. DO NOT EDIT.
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// RegisterDefaults adds defaulters functions to the given scheme.
|
||||
// Public to allow building arbitrary schemes.
|
||||
// All generated defaulters are covering - they call all nested defaulters.
|
||||
func RegisterDefaults(scheme *runtime.Scheme) error {
|
||||
scheme.AddTypeDefaultingFunc(&CustomResourceDefinition{}, func(obj interface{}) { SetObjectDefaults_CustomResourceDefinition(obj.(*CustomResourceDefinition)) })
|
||||
scheme.AddTypeDefaultingFunc(&CustomResourceDefinitionList{}, func(obj interface{}) {
|
||||
SetObjectDefaults_CustomResourceDefinitionList(obj.(*CustomResourceDefinitionList))
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func SetObjectDefaults_CustomResourceDefinition(in *CustomResourceDefinition) {
|
||||
SetDefaults_CustomResourceDefinition(in)
|
||||
SetDefaults_CustomResourceDefinitionSpec(&in.Spec)
|
||||
if in.Spec.Conversion != nil {
|
||||
if in.Spec.Conversion.WebhookClientConfig != nil {
|
||||
if in.Spec.Conversion.WebhookClientConfig.Service != nil {
|
||||
SetDefaults_ServiceReference(in.Spec.Conversion.WebhookClientConfig.Service)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func SetObjectDefaults_CustomResourceDefinitionList(in *CustomResourceDefinitionList) {
|
||||
for i := range in.Items {
|
||||
a := &in.Items[i]
|
||||
SetObjectDefaults_CustomResourceDefinition(a)
|
||||
}
|
||||
}
|
||||
97
vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1/zz_generated.prerelease-lifecycle.go
generated
vendored
Normal file
97
vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1/zz_generated.prerelease-lifecycle.go
generated
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by prerelease-lifecycle-gen. DO NOT EDIT.
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
// APILifecycleIntroduced is an autogenerated function, returning the release in which the API struct was introduced as int versions of major and minor for comparison.
|
||||
// It is controlled by "k8s:prerelease-lifecycle-gen:introduced" tags in types.go.
|
||||
func (in *ConversionReview) APILifecycleIntroduced() (major, minor int) {
|
||||
return 1, 13
|
||||
}
|
||||
|
||||
// APILifecycleDeprecated is an autogenerated function, returning the release in which the API struct was or will be deprecated as int versions of major and minor for comparison.
|
||||
// It is controlled by "k8s:prerelease-lifecycle-gen:deprecated" tags in types.go or "k8s:prerelease-lifecycle-gen:introduced" plus three minor.
|
||||
func (in *ConversionReview) APILifecycleDeprecated() (major, minor int) {
|
||||
return 1, 19
|
||||
}
|
||||
|
||||
// APILifecycleReplacement is an autogenerated function, returning the group, version, and kind that should be used instead of this deprecated type.
|
||||
// It is controlled by "k8s:prerelease-lifecycle-gen:replacement=<group>,<version>,<kind>" tags in types.go.
|
||||
func (in *ConversionReview) APILifecycleReplacement() schema.GroupVersionKind {
|
||||
return schema.GroupVersionKind{Group: "apiextensions.k8s.io", Version: "v1", Kind: "ConversionReview"}
|
||||
}
|
||||
|
||||
// APILifecycleRemoved is an autogenerated function, returning the release in which the API is no longer served as int versions of major and minor for comparison.
|
||||
// It is controlled by "k8s:prerelease-lifecycle-gen:removed" tags in types.go or "k8s:prerelease-lifecycle-gen:deprecated" plus three minor.
|
||||
func (in *ConversionReview) APILifecycleRemoved() (major, minor int) {
|
||||
return 1, 22
|
||||
}
|
||||
|
||||
// APILifecycleIntroduced is an autogenerated function, returning the release in which the API struct was introduced as int versions of major and minor for comparison.
|
||||
// It is controlled by "k8s:prerelease-lifecycle-gen:introduced" tags in types.go.
|
||||
func (in *CustomResourceDefinition) APILifecycleIntroduced() (major, minor int) {
|
||||
return 1, 7
|
||||
}
|
||||
|
||||
// APILifecycleDeprecated is an autogenerated function, returning the release in which the API struct was or will be deprecated as int versions of major and minor for comparison.
|
||||
// It is controlled by "k8s:prerelease-lifecycle-gen:deprecated" tags in types.go or "k8s:prerelease-lifecycle-gen:introduced" plus three minor.
|
||||
func (in *CustomResourceDefinition) APILifecycleDeprecated() (major, minor int) {
|
||||
return 1, 16
|
||||
}
|
||||
|
||||
// APILifecycleReplacement is an autogenerated function, returning the group, version, and kind that should be used instead of this deprecated type.
|
||||
// It is controlled by "k8s:prerelease-lifecycle-gen:replacement=<group>,<version>,<kind>" tags in types.go.
|
||||
func (in *CustomResourceDefinition) APILifecycleReplacement() schema.GroupVersionKind {
|
||||
return schema.GroupVersionKind{Group: "apiextensions.k8s.io", Version: "v1", Kind: "CustomResourceDefinition"}
|
||||
}
|
||||
|
||||
// APILifecycleRemoved is an autogenerated function, returning the release in which the API is no longer served as int versions of major and minor for comparison.
|
||||
// It is controlled by "k8s:prerelease-lifecycle-gen:removed" tags in types.go or "k8s:prerelease-lifecycle-gen:deprecated" plus three minor.
|
||||
func (in *CustomResourceDefinition) APILifecycleRemoved() (major, minor int) {
|
||||
return 1, 22
|
||||
}
|
||||
|
||||
// APILifecycleIntroduced is an autogenerated function, returning the release in which the API struct was introduced as int versions of major and minor for comparison.
|
||||
// It is controlled by "k8s:prerelease-lifecycle-gen:introduced" tags in types.go.
|
||||
func (in *CustomResourceDefinitionList) APILifecycleIntroduced() (major, minor int) {
|
||||
return 1, 7
|
||||
}
|
||||
|
||||
// APILifecycleDeprecated is an autogenerated function, returning the release in which the API struct was or will be deprecated as int versions of major and minor for comparison.
|
||||
// It is controlled by "k8s:prerelease-lifecycle-gen:deprecated" tags in types.go or "k8s:prerelease-lifecycle-gen:introduced" plus three minor.
|
||||
func (in *CustomResourceDefinitionList) APILifecycleDeprecated() (major, minor int) {
|
||||
return 1, 16
|
||||
}
|
||||
|
||||
// APILifecycleReplacement is an autogenerated function, returning the group, version, and kind that should be used instead of this deprecated type.
|
||||
// It is controlled by "k8s:prerelease-lifecycle-gen:replacement=<group>,<version>,<kind>" tags in types.go.
|
||||
func (in *CustomResourceDefinitionList) APILifecycleReplacement() schema.GroupVersionKind {
|
||||
return schema.GroupVersionKind{Group: "apiextensions.k8s.io", Version: "v1", Kind: "CustomResourceDefinitionList"}
|
||||
}
|
||||
|
||||
// APILifecycleRemoved is an autogenerated function, returning the release in which the API is no longer served as int versions of major and minor for comparison.
|
||||
// It is controlled by "k8s:prerelease-lifecycle-gen:removed" tags in types.go or "k8s:prerelease-lifecycle-gen:deprecated" plus three minor.
|
||||
func (in *CustomResourceDefinitionList) APILifecycleRemoved() (major, minor int) {
|
||||
return 1, 22
|
||||
}
|
||||
27
vendor/k8s.io/apimachinery/pkg/util/uuid/uuid.go
generated
vendored
Normal file
27
vendor/k8s.io/apimachinery/pkg/util/uuid/uuid.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"github.com/google/uuid"
|
||||
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
func NewUUID() types.UID {
|
||||
return types.UID(uuid.New().String())
|
||||
}
|
||||
13
vendor/k8s.io/client-go/tools/leaderelection/OWNERS
generated
vendored
Normal file
13
vendor/k8s.io/client-go/tools/leaderelection/OWNERS
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
# See the OWNERS docs at https://go.k8s.io/owners
|
||||
|
||||
approvers:
|
||||
- mikedanese
|
||||
- timothysc
|
||||
reviewers:
|
||||
- wojtek-t
|
||||
- deads2k
|
||||
- mikedanese
|
||||
- gmarek
|
||||
- timothysc
|
||||
- ingvagabund
|
||||
- resouer
|
||||
69
vendor/k8s.io/client-go/tools/leaderelection/healthzadaptor.go
generated
vendored
Normal file
69
vendor/k8s.io/client-go/tools/leaderelection/healthzadaptor.go
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package leaderelection
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// HealthzAdaptor associates the /healthz endpoint with the LeaderElection object.
|
||||
// It helps deal with the /healthz endpoint being set up prior to the LeaderElection.
|
||||
// This contains the code needed to act as an adaptor between the leader
|
||||
// election code the health check code. It allows us to provide health
|
||||
// status about the leader election. Most specifically about if the leader
|
||||
// has failed to renew without exiting the process. In that case we should
|
||||
// report not healthy and rely on the kubelet to take down the process.
|
||||
type HealthzAdaptor struct {
|
||||
pointerLock sync.Mutex
|
||||
le *LeaderElector
|
||||
timeout time.Duration
|
||||
}
|
||||
|
||||
// Name returns the name of the health check we are implementing.
|
||||
func (l *HealthzAdaptor) Name() string {
|
||||
return "leaderElection"
|
||||
}
|
||||
|
||||
// Check is called by the healthz endpoint handler.
|
||||
// It fails (returns an error) if we own the lease but had not been able to renew it.
|
||||
func (l *HealthzAdaptor) Check(req *http.Request) error {
|
||||
l.pointerLock.Lock()
|
||||
defer l.pointerLock.Unlock()
|
||||
if l.le == nil {
|
||||
return nil
|
||||
}
|
||||
return l.le.Check(l.timeout)
|
||||
}
|
||||
|
||||
// SetLeaderElection ties a leader election object to a HealthzAdaptor
|
||||
func (l *HealthzAdaptor) SetLeaderElection(le *LeaderElector) {
|
||||
l.pointerLock.Lock()
|
||||
defer l.pointerLock.Unlock()
|
||||
l.le = le
|
||||
}
|
||||
|
||||
// NewLeaderHealthzAdaptor creates a basic healthz adaptor to monitor a leader election.
|
||||
// timeout determines the time beyond the lease expiry to be allowed for timeout.
|
||||
// checks within the timeout period after the lease expires will still return healthy.
|
||||
func NewLeaderHealthzAdaptor(timeout time.Duration) *HealthzAdaptor {
|
||||
result := &HealthzAdaptor{
|
||||
timeout: timeout,
|
||||
}
|
||||
return result
|
||||
}
|
||||
394
vendor/k8s.io/client-go/tools/leaderelection/leaderelection.go
generated
vendored
Normal file
394
vendor/k8s.io/client-go/tools/leaderelection/leaderelection.go
generated
vendored
Normal file
@@ -0,0 +1,394 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package leaderelection implements leader election of a set of endpoints.
|
||||
// It uses an annotation in the endpoints object to store the record of the
|
||||
// election state. This implementation does not guarantee that only one
|
||||
// client is acting as a leader (a.k.a. fencing).
|
||||
//
|
||||
// A client only acts on timestamps captured locally to infer the state of the
|
||||
// leader election. The client does not consider timestamps in the leader
|
||||
// election record to be accurate because these timestamps may not have been
|
||||
// produced by a local clock. The implemention does not depend on their
|
||||
// accuracy and only uses their change to indicate that another client has
|
||||
// renewed the leader lease. Thus the implementation is tolerant to arbitrary
|
||||
// clock skew, but is not tolerant to arbitrary clock skew rate.
|
||||
//
|
||||
// However the level of tolerance to skew rate can be configured by setting
|
||||
// RenewDeadline and LeaseDuration appropriately. The tolerance expressed as a
|
||||
// maximum tolerated ratio of time passed on the fastest node to time passed on
|
||||
// the slowest node can be approximately achieved with a configuration that sets
|
||||
// the same ratio of LeaseDuration to RenewDeadline. For example if a user wanted
|
||||
// to tolerate some nodes progressing forward in time twice as fast as other nodes,
|
||||
// the user could set LeaseDuration to 60 seconds and RenewDeadline to 30 seconds.
|
||||
//
|
||||
// While not required, some method of clock synchronization between nodes in the
|
||||
// cluster is highly recommended. It's important to keep in mind when configuring
|
||||
// this client that the tolerance to skew rate varies inversely to master
|
||||
// availability.
|
||||
//
|
||||
// Larger clusters often have a more lenient SLA for API latency. This should be
|
||||
// taken into account when configuring the client. The rate of leader transitions
|
||||
// should be monitored and RetryPeriod and LeaseDuration should be increased
|
||||
// until the rate is stable and acceptably low. It's important to keep in mind
|
||||
// when configuring this client that the tolerance to API latency varies inversely
|
||||
// to master availability.
|
||||
//
|
||||
// DISCLAIMER: this is an alpha API. This library will likely change significantly
|
||||
// or even be removed entirely in subsequent releases. Depend on this API at
|
||||
// your own risk.
|
||||
package leaderelection
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/clock"
|
||||
"k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
rl "k8s.io/client-go/tools/leaderelection/resourcelock"
|
||||
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
const (
|
||||
JitterFactor = 1.2
|
||||
)
|
||||
|
||||
// NewLeaderElector creates a LeaderElector from a LeaderElectionConfig
|
||||
func NewLeaderElector(lec LeaderElectionConfig) (*LeaderElector, error) {
|
||||
if lec.LeaseDuration <= lec.RenewDeadline {
|
||||
return nil, fmt.Errorf("leaseDuration must be greater than renewDeadline")
|
||||
}
|
||||
if lec.RenewDeadline <= time.Duration(JitterFactor*float64(lec.RetryPeriod)) {
|
||||
return nil, fmt.Errorf("renewDeadline must be greater than retryPeriod*JitterFactor")
|
||||
}
|
||||
if lec.LeaseDuration < 1 {
|
||||
return nil, fmt.Errorf("leaseDuration must be greater than zero")
|
||||
}
|
||||
if lec.RenewDeadline < 1 {
|
||||
return nil, fmt.Errorf("renewDeadline must be greater than zero")
|
||||
}
|
||||
if lec.RetryPeriod < 1 {
|
||||
return nil, fmt.Errorf("retryPeriod must be greater than zero")
|
||||
}
|
||||
if lec.Callbacks.OnStartedLeading == nil {
|
||||
return nil, fmt.Errorf("OnStartedLeading callback must not be nil")
|
||||
}
|
||||
if lec.Callbacks.OnStoppedLeading == nil {
|
||||
return nil, fmt.Errorf("OnStoppedLeading callback must not be nil")
|
||||
}
|
||||
|
||||
if lec.Lock == nil {
|
||||
return nil, fmt.Errorf("Lock must not be nil.")
|
||||
}
|
||||
le := LeaderElector{
|
||||
config: lec,
|
||||
clock: clock.RealClock{},
|
||||
metrics: globalMetricsFactory.newLeaderMetrics(),
|
||||
}
|
||||
le.metrics.leaderOff(le.config.Name)
|
||||
return &le, nil
|
||||
}
|
||||
|
||||
type LeaderElectionConfig struct {
|
||||
// Lock is the resource that will be used for locking
|
||||
Lock rl.Interface
|
||||
|
||||
// LeaseDuration is the duration that non-leader candidates will
|
||||
// wait to force acquire leadership. This is measured against time of
|
||||
// last observed ack.
|
||||
//
|
||||
// A client needs to wait a full LeaseDuration without observing a change to
|
||||
// the record before it can attempt to take over. When all clients are
|
||||
// shutdown and a new set of clients are started with different names against
|
||||
// the same leader record, they must wait the full LeaseDuration before
|
||||
// attempting to acquire the lease. Thus LeaseDuration should be as short as
|
||||
// possible (within your tolerance for clock skew rate) to avoid a possible
|
||||
// long waits in the scenario.
|
||||
//
|
||||
// Core clients default this value to 15 seconds.
|
||||
LeaseDuration time.Duration
|
||||
// RenewDeadline is the duration that the acting master will retry
|
||||
// refreshing leadership before giving up.
|
||||
//
|
||||
// Core clients default this value to 10 seconds.
|
||||
RenewDeadline time.Duration
|
||||
// RetryPeriod is the duration the LeaderElector clients should wait
|
||||
// between tries of actions.
|
||||
//
|
||||
// Core clients default this value to 2 seconds.
|
||||
RetryPeriod time.Duration
|
||||
|
||||
// Callbacks are callbacks that are triggered during certain lifecycle
|
||||
// events of the LeaderElector
|
||||
Callbacks LeaderCallbacks
|
||||
|
||||
// WatchDog is the associated health checker
|
||||
// WatchDog may be null if its not needed/configured.
|
||||
WatchDog *HealthzAdaptor
|
||||
|
||||
// ReleaseOnCancel should be set true if the lock should be released
|
||||
// when the run context is cancelled. If you set this to true, you must
|
||||
// ensure all code guarded by this lease has successfully completed
|
||||
// prior to cancelling the context, or you may have two processes
|
||||
// simultaneously acting on the critical path.
|
||||
ReleaseOnCancel bool
|
||||
|
||||
// Name is the name of the resource lock for debugging
|
||||
Name string
|
||||
}
|
||||
|
||||
// LeaderCallbacks are callbacks that are triggered during certain
|
||||
// lifecycle events of the LeaderElector. These are invoked asynchronously.
|
||||
//
|
||||
// possible future callbacks:
|
||||
// * OnChallenge()
|
||||
type LeaderCallbacks struct {
|
||||
// OnStartedLeading is called when a LeaderElector client starts leading
|
||||
OnStartedLeading func(context.Context)
|
||||
// OnStoppedLeading is called when a LeaderElector client stops leading
|
||||
OnStoppedLeading func()
|
||||
// OnNewLeader is called when the client observes a leader that is
|
||||
// not the previously observed leader. This includes the first observed
|
||||
// leader when the client starts.
|
||||
OnNewLeader func(identity string)
|
||||
}
|
||||
|
||||
// LeaderElector is a leader election client.
|
||||
type LeaderElector struct {
|
||||
config LeaderElectionConfig
|
||||
// internal bookkeeping
|
||||
observedRecord rl.LeaderElectionRecord
|
||||
observedRawRecord []byte
|
||||
observedTime time.Time
|
||||
// used to implement OnNewLeader(), may lag slightly from the
|
||||
// value observedRecord.HolderIdentity if the transition has
|
||||
// not yet been reported.
|
||||
reportedLeader string
|
||||
|
||||
// clock is wrapper around time to allow for less flaky testing
|
||||
clock clock.Clock
|
||||
|
||||
metrics leaderMetricsAdapter
|
||||
}
|
||||
|
||||
// Run starts the leader election loop. Run will not return
|
||||
// before leader election loop is stopped by ctx or it has
|
||||
// stopped holding the leader lease
|
||||
func (le *LeaderElector) Run(ctx context.Context) {
|
||||
defer runtime.HandleCrash()
|
||||
defer func() {
|
||||
le.config.Callbacks.OnStoppedLeading()
|
||||
}()
|
||||
|
||||
if !le.acquire(ctx) {
|
||||
return // ctx signalled done
|
||||
}
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
go le.config.Callbacks.OnStartedLeading(ctx)
|
||||
le.renew(ctx)
|
||||
}
|
||||
|
||||
// RunOrDie starts a client with the provided config or panics if the config
|
||||
// fails to validate. RunOrDie blocks until leader election loop is
|
||||
// stopped by ctx or it has stopped holding the leader lease
|
||||
func RunOrDie(ctx context.Context, lec LeaderElectionConfig) {
|
||||
le, err := NewLeaderElector(lec)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if lec.WatchDog != nil {
|
||||
lec.WatchDog.SetLeaderElection(le)
|
||||
}
|
||||
le.Run(ctx)
|
||||
}
|
||||
|
||||
// GetLeader returns the identity of the last observed leader or returns the empty string if
|
||||
// no leader has yet been observed.
|
||||
func (le *LeaderElector) GetLeader() string {
|
||||
return le.observedRecord.HolderIdentity
|
||||
}
|
||||
|
||||
// IsLeader returns true if the last observed leader was this client else returns false.
|
||||
func (le *LeaderElector) IsLeader() bool {
|
||||
return le.observedRecord.HolderIdentity == le.config.Lock.Identity()
|
||||
}
|
||||
|
||||
// acquire loops calling tryAcquireOrRenew and returns true immediately when tryAcquireOrRenew succeeds.
|
||||
// Returns false if ctx signals done.
|
||||
func (le *LeaderElector) acquire(ctx context.Context) bool {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
succeeded := false
|
||||
desc := le.config.Lock.Describe()
|
||||
klog.Infof("attempting to acquire leader lease %v...", desc)
|
||||
wait.JitterUntil(func() {
|
||||
succeeded = le.tryAcquireOrRenew(ctx)
|
||||
le.maybeReportTransition()
|
||||
if !succeeded {
|
||||
klog.V(4).Infof("failed to acquire lease %v", desc)
|
||||
return
|
||||
}
|
||||
le.config.Lock.RecordEvent("became leader")
|
||||
le.metrics.leaderOn(le.config.Name)
|
||||
klog.Infof("successfully acquired lease %v", desc)
|
||||
cancel()
|
||||
}, le.config.RetryPeriod, JitterFactor, true, ctx.Done())
|
||||
return succeeded
|
||||
}
|
||||
|
||||
// renew loops calling tryAcquireOrRenew and returns immediately when tryAcquireOrRenew fails or ctx signals done.
|
||||
func (le *LeaderElector) renew(ctx context.Context) {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
wait.Until(func() {
|
||||
timeoutCtx, timeoutCancel := context.WithTimeout(ctx, le.config.RenewDeadline)
|
||||
defer timeoutCancel()
|
||||
err := wait.PollImmediateUntil(le.config.RetryPeriod, func() (bool, error) {
|
||||
return le.tryAcquireOrRenew(timeoutCtx), nil
|
||||
}, timeoutCtx.Done())
|
||||
|
||||
le.maybeReportTransition()
|
||||
desc := le.config.Lock.Describe()
|
||||
if err == nil {
|
||||
klog.V(5).Infof("successfully renewed lease %v", desc)
|
||||
return
|
||||
}
|
||||
le.config.Lock.RecordEvent("stopped leading")
|
||||
le.metrics.leaderOff(le.config.Name)
|
||||
klog.Infof("failed to renew lease %v: %v", desc, err)
|
||||
cancel()
|
||||
}, le.config.RetryPeriod, ctx.Done())
|
||||
|
||||
// if we hold the lease, give it up
|
||||
if le.config.ReleaseOnCancel {
|
||||
le.release()
|
||||
}
|
||||
}
|
||||
|
||||
// release attempts to release the leader lease if we have acquired it.
|
||||
func (le *LeaderElector) release() bool {
|
||||
if !le.IsLeader() {
|
||||
return true
|
||||
}
|
||||
now := metav1.Now()
|
||||
leaderElectionRecord := rl.LeaderElectionRecord{
|
||||
LeaderTransitions: le.observedRecord.LeaderTransitions,
|
||||
LeaseDurationSeconds: 1,
|
||||
RenewTime: now,
|
||||
AcquireTime: now,
|
||||
}
|
||||
if err := le.config.Lock.Update(context.TODO(), leaderElectionRecord); err != nil {
|
||||
klog.Errorf("Failed to release lock: %v", err)
|
||||
return false
|
||||
}
|
||||
le.observedRecord = leaderElectionRecord
|
||||
le.observedTime = le.clock.Now()
|
||||
return true
|
||||
}
|
||||
|
||||
// tryAcquireOrRenew tries to acquire a leader lease if it is not already acquired,
|
||||
// else it tries to renew the lease if it has already been acquired. Returns true
|
||||
// on success else returns false.
|
||||
func (le *LeaderElector) tryAcquireOrRenew(ctx context.Context) bool {
|
||||
now := metav1.Now()
|
||||
leaderElectionRecord := rl.LeaderElectionRecord{
|
||||
HolderIdentity: le.config.Lock.Identity(),
|
||||
LeaseDurationSeconds: int(le.config.LeaseDuration / time.Second),
|
||||
RenewTime: now,
|
||||
AcquireTime: now,
|
||||
}
|
||||
|
||||
// 1. obtain or create the ElectionRecord
|
||||
oldLeaderElectionRecord, oldLeaderElectionRawRecord, err := le.config.Lock.Get(ctx)
|
||||
if err != nil {
|
||||
if !errors.IsNotFound(err) {
|
||||
klog.Errorf("error retrieving resource lock %v: %v", le.config.Lock.Describe(), err)
|
||||
return false
|
||||
}
|
||||
if err = le.config.Lock.Create(ctx, leaderElectionRecord); err != nil {
|
||||
klog.Errorf("error initially creating leader election record: %v", err)
|
||||
return false
|
||||
}
|
||||
le.observedRecord = leaderElectionRecord
|
||||
le.observedTime = le.clock.Now()
|
||||
return true
|
||||
}
|
||||
|
||||
// 2. Record obtained, check the Identity & Time
|
||||
if !bytes.Equal(le.observedRawRecord, oldLeaderElectionRawRecord) {
|
||||
le.observedRecord = *oldLeaderElectionRecord
|
||||
le.observedRawRecord = oldLeaderElectionRawRecord
|
||||
le.observedTime = le.clock.Now()
|
||||
}
|
||||
if len(oldLeaderElectionRecord.HolderIdentity) > 0 &&
|
||||
le.observedTime.Add(le.config.LeaseDuration).After(now.Time) &&
|
||||
!le.IsLeader() {
|
||||
klog.V(4).Infof("lock is held by %v and has not yet expired", oldLeaderElectionRecord.HolderIdentity)
|
||||
return false
|
||||
}
|
||||
|
||||
// 3. We're going to try to update. The leaderElectionRecord is set to it's default
|
||||
// here. Let's correct it before updating.
|
||||
if le.IsLeader() {
|
||||
leaderElectionRecord.AcquireTime = oldLeaderElectionRecord.AcquireTime
|
||||
leaderElectionRecord.LeaderTransitions = oldLeaderElectionRecord.LeaderTransitions
|
||||
} else {
|
||||
leaderElectionRecord.LeaderTransitions = oldLeaderElectionRecord.LeaderTransitions + 1
|
||||
}
|
||||
|
||||
// update the lock itself
|
||||
if err = le.config.Lock.Update(ctx, leaderElectionRecord); err != nil {
|
||||
klog.Errorf("Failed to update lock: %v", err)
|
||||
return false
|
||||
}
|
||||
|
||||
le.observedRecord = leaderElectionRecord
|
||||
le.observedTime = le.clock.Now()
|
||||
return true
|
||||
}
|
||||
|
||||
func (le *LeaderElector) maybeReportTransition() {
|
||||
if le.observedRecord.HolderIdentity == le.reportedLeader {
|
||||
return
|
||||
}
|
||||
le.reportedLeader = le.observedRecord.HolderIdentity
|
||||
if le.config.Callbacks.OnNewLeader != nil {
|
||||
go le.config.Callbacks.OnNewLeader(le.reportedLeader)
|
||||
}
|
||||
}
|
||||
|
||||
// Check will determine if the current lease is expired by more than timeout.
|
||||
func (le *LeaderElector) Check(maxTolerableExpiredLease time.Duration) error {
|
||||
if !le.IsLeader() {
|
||||
// Currently not concerned with the case that we are hot standby
|
||||
return nil
|
||||
}
|
||||
// If we are more than timeout seconds after the lease duration that is past the timeout
|
||||
// on the lease renew. Time to start reporting ourselves as unhealthy. We should have
|
||||
// died but conditions like deadlock can prevent this. (See #70819)
|
||||
if le.clock.Since(le.observedTime) > le.config.LeaseDuration+maxTolerableExpiredLease {
|
||||
return fmt.Errorf("failed election to renew leadership on lease %s", le.config.Name)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
109
vendor/k8s.io/client-go/tools/leaderelection/metrics.go
generated
vendored
Normal file
109
vendor/k8s.io/client-go/tools/leaderelection/metrics.go
generated
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package leaderelection
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
// This file provides abstractions for setting the provider (e.g., prometheus)
|
||||
// of metrics.
|
||||
|
||||
type leaderMetricsAdapter interface {
|
||||
leaderOn(name string)
|
||||
leaderOff(name string)
|
||||
}
|
||||
|
||||
// GaugeMetric represents a single numerical value that can arbitrarily go up
|
||||
// and down.
|
||||
type SwitchMetric interface {
|
||||
On(name string)
|
||||
Off(name string)
|
||||
}
|
||||
|
||||
type noopMetric struct{}
|
||||
|
||||
func (noopMetric) On(name string) {}
|
||||
func (noopMetric) Off(name string) {}
|
||||
|
||||
// defaultLeaderMetrics expects the caller to lock before setting any metrics.
|
||||
type defaultLeaderMetrics struct {
|
||||
// leader's value indicates if the current process is the owner of name lease
|
||||
leader SwitchMetric
|
||||
}
|
||||
|
||||
func (m *defaultLeaderMetrics) leaderOn(name string) {
|
||||
if m == nil {
|
||||
return
|
||||
}
|
||||
m.leader.On(name)
|
||||
}
|
||||
|
||||
func (m *defaultLeaderMetrics) leaderOff(name string) {
|
||||
if m == nil {
|
||||
return
|
||||
}
|
||||
m.leader.Off(name)
|
||||
}
|
||||
|
||||
type noMetrics struct{}
|
||||
|
||||
func (noMetrics) leaderOn(name string) {}
|
||||
func (noMetrics) leaderOff(name string) {}
|
||||
|
||||
// MetricsProvider generates various metrics used by the leader election.
|
||||
type MetricsProvider interface {
|
||||
NewLeaderMetric() SwitchMetric
|
||||
}
|
||||
|
||||
type noopMetricsProvider struct{}
|
||||
|
||||
func (_ noopMetricsProvider) NewLeaderMetric() SwitchMetric {
|
||||
return noopMetric{}
|
||||
}
|
||||
|
||||
var globalMetricsFactory = leaderMetricsFactory{
|
||||
metricsProvider: noopMetricsProvider{},
|
||||
}
|
||||
|
||||
type leaderMetricsFactory struct {
|
||||
metricsProvider MetricsProvider
|
||||
|
||||
onlyOnce sync.Once
|
||||
}
|
||||
|
||||
func (f *leaderMetricsFactory) setProvider(mp MetricsProvider) {
|
||||
f.onlyOnce.Do(func() {
|
||||
f.metricsProvider = mp
|
||||
})
|
||||
}
|
||||
|
||||
func (f *leaderMetricsFactory) newLeaderMetrics() leaderMetricsAdapter {
|
||||
mp := f.metricsProvider
|
||||
if mp == (noopMetricsProvider{}) {
|
||||
return noMetrics{}
|
||||
}
|
||||
return &defaultLeaderMetrics{
|
||||
leader: mp.NewLeaderMetric(),
|
||||
}
|
||||
}
|
||||
|
||||
// SetProvider sets the metrics provider for all subsequently created work
|
||||
// queues. Only the first call has an effect.
|
||||
func SetProvider(metricsProvider MetricsProvider) {
|
||||
globalMetricsFactory.setProvider(metricsProvider)
|
||||
}
|
||||
122
vendor/k8s.io/client-go/tools/leaderelection/resourcelock/configmaplock.go
generated
vendored
Normal file
122
vendor/k8s.io/client-go/tools/leaderelection/resourcelock/configmaplock.go
generated
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package resourcelock
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
)
|
||||
|
||||
// TODO: This is almost a exact replica of Endpoints lock.
|
||||
// going forwards as we self host more and more components
|
||||
// and use ConfigMaps as the means to pass that configuration
|
||||
// data we will likely move to deprecate the Endpoints lock.
|
||||
|
||||
type ConfigMapLock struct {
|
||||
// ConfigMapMeta should contain a Name and a Namespace of a
|
||||
// ConfigMapMeta object that the LeaderElector will attempt to lead.
|
||||
ConfigMapMeta metav1.ObjectMeta
|
||||
Client corev1client.ConfigMapsGetter
|
||||
LockConfig ResourceLockConfig
|
||||
cm *v1.ConfigMap
|
||||
}
|
||||
|
||||
// Get returns the election record from a ConfigMap Annotation
|
||||
func (cml *ConfigMapLock) Get(ctx context.Context) (*LeaderElectionRecord, []byte, error) {
|
||||
var record LeaderElectionRecord
|
||||
var err error
|
||||
cml.cm, err = cml.Client.ConfigMaps(cml.ConfigMapMeta.Namespace).Get(ctx, cml.ConfigMapMeta.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if cml.cm.Annotations == nil {
|
||||
cml.cm.Annotations = make(map[string]string)
|
||||
}
|
||||
recordStr, found := cml.cm.Annotations[LeaderElectionRecordAnnotationKey]
|
||||
recordBytes := []byte(recordStr)
|
||||
if found {
|
||||
if err := json.Unmarshal(recordBytes, &record); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
return &record, recordBytes, nil
|
||||
}
|
||||
|
||||
// Create attempts to create a LeaderElectionRecord annotation
|
||||
func (cml *ConfigMapLock) Create(ctx context.Context, ler LeaderElectionRecord) error {
|
||||
recordBytes, err := json.Marshal(ler)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cml.cm, err = cml.Client.ConfigMaps(cml.ConfigMapMeta.Namespace).Create(ctx, &v1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: cml.ConfigMapMeta.Name,
|
||||
Namespace: cml.ConfigMapMeta.Namespace,
|
||||
Annotations: map[string]string{
|
||||
LeaderElectionRecordAnnotationKey: string(recordBytes),
|
||||
},
|
||||
},
|
||||
}, metav1.CreateOptions{})
|
||||
return err
|
||||
}
|
||||
|
||||
// Update will update an existing annotation on a given resource.
|
||||
func (cml *ConfigMapLock) Update(ctx context.Context, ler LeaderElectionRecord) error {
|
||||
if cml.cm == nil {
|
||||
return errors.New("configmap not initialized, call get or create first")
|
||||
}
|
||||
recordBytes, err := json.Marshal(ler)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if cml.cm.Annotations == nil {
|
||||
cml.cm.Annotations = make(map[string]string)
|
||||
}
|
||||
cml.cm.Annotations[LeaderElectionRecordAnnotationKey] = string(recordBytes)
|
||||
cm, err := cml.Client.ConfigMaps(cml.ConfigMapMeta.Namespace).Update(ctx, cml.cm, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cml.cm = cm
|
||||
return nil
|
||||
}
|
||||
|
||||
// RecordEvent in leader election while adding meta-data
|
||||
func (cml *ConfigMapLock) RecordEvent(s string) {
|
||||
if cml.LockConfig.EventRecorder == nil {
|
||||
return
|
||||
}
|
||||
events := fmt.Sprintf("%v %v", cml.LockConfig.Identity, s)
|
||||
cml.LockConfig.EventRecorder.Eventf(&v1.ConfigMap{ObjectMeta: cml.cm.ObjectMeta}, v1.EventTypeNormal, "LeaderElection", events)
|
||||
}
|
||||
|
||||
// Describe is used to convert details on current resource lock
|
||||
// into a string
|
||||
func (cml *ConfigMapLock) Describe() string {
|
||||
return fmt.Sprintf("%v/%v", cml.ConfigMapMeta.Namespace, cml.ConfigMapMeta.Name)
|
||||
}
|
||||
|
||||
// Identity returns the Identity of the lock
|
||||
func (cml *ConfigMapLock) Identity() string {
|
||||
return cml.LockConfig.Identity
|
||||
}
|
||||
117
vendor/k8s.io/client-go/tools/leaderelection/resourcelock/endpointslock.go
generated
vendored
Normal file
117
vendor/k8s.io/client-go/tools/leaderelection/resourcelock/endpointslock.go
generated
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package resourcelock
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
)
|
||||
|
||||
type EndpointsLock struct {
|
||||
// EndpointsMeta should contain a Name and a Namespace of an
|
||||
// Endpoints object that the LeaderElector will attempt to lead.
|
||||
EndpointsMeta metav1.ObjectMeta
|
||||
Client corev1client.EndpointsGetter
|
||||
LockConfig ResourceLockConfig
|
||||
e *v1.Endpoints
|
||||
}
|
||||
|
||||
// Get returns the election record from a Endpoints Annotation
|
||||
func (el *EndpointsLock) Get(ctx context.Context) (*LeaderElectionRecord, []byte, error) {
|
||||
var record LeaderElectionRecord
|
||||
var err error
|
||||
el.e, err = el.Client.Endpoints(el.EndpointsMeta.Namespace).Get(ctx, el.EndpointsMeta.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if el.e.Annotations == nil {
|
||||
el.e.Annotations = make(map[string]string)
|
||||
}
|
||||
recordStr, found := el.e.Annotations[LeaderElectionRecordAnnotationKey]
|
||||
recordBytes := []byte(recordStr)
|
||||
if found {
|
||||
if err := json.Unmarshal(recordBytes, &record); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
return &record, recordBytes, nil
|
||||
}
|
||||
|
||||
// Create attempts to create a LeaderElectionRecord annotation
|
||||
func (el *EndpointsLock) Create(ctx context.Context, ler LeaderElectionRecord) error {
|
||||
recordBytes, err := json.Marshal(ler)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
el.e, err = el.Client.Endpoints(el.EndpointsMeta.Namespace).Create(ctx, &v1.Endpoints{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: el.EndpointsMeta.Name,
|
||||
Namespace: el.EndpointsMeta.Namespace,
|
||||
Annotations: map[string]string{
|
||||
LeaderElectionRecordAnnotationKey: string(recordBytes),
|
||||
},
|
||||
},
|
||||
}, metav1.CreateOptions{})
|
||||
return err
|
||||
}
|
||||
|
||||
// Update will update and existing annotation on a given resource.
|
||||
func (el *EndpointsLock) Update(ctx context.Context, ler LeaderElectionRecord) error {
|
||||
if el.e == nil {
|
||||
return errors.New("endpoint not initialized, call get or create first")
|
||||
}
|
||||
recordBytes, err := json.Marshal(ler)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if el.e.Annotations == nil {
|
||||
el.e.Annotations = make(map[string]string)
|
||||
}
|
||||
el.e.Annotations[LeaderElectionRecordAnnotationKey] = string(recordBytes)
|
||||
e, err := el.Client.Endpoints(el.EndpointsMeta.Namespace).Update(ctx, el.e, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
el.e = e
|
||||
return nil
|
||||
}
|
||||
|
||||
// RecordEvent in leader election while adding meta-data
|
||||
func (el *EndpointsLock) RecordEvent(s string) {
|
||||
if el.LockConfig.EventRecorder == nil {
|
||||
return
|
||||
}
|
||||
events := fmt.Sprintf("%v %v", el.LockConfig.Identity, s)
|
||||
el.LockConfig.EventRecorder.Eventf(&v1.Endpoints{ObjectMeta: el.e.ObjectMeta}, v1.EventTypeNormal, "LeaderElection", events)
|
||||
}
|
||||
|
||||
// Describe is used to convert details on current resource lock
|
||||
// into a string
|
||||
func (el *EndpointsLock) Describe() string {
|
||||
return fmt.Sprintf("%v/%v", el.EndpointsMeta.Namespace, el.EndpointsMeta.Name)
|
||||
}
|
||||
|
||||
// Identity returns the Identity of the lock
|
||||
func (el *EndpointsLock) Identity() string {
|
||||
return el.LockConfig.Identity
|
||||
}
|
||||
158
vendor/k8s.io/client-go/tools/leaderelection/resourcelock/interface.go
generated
vendored
Normal file
158
vendor/k8s.io/client-go/tools/leaderelection/resourcelock/interface.go
generated
vendored
Normal file
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package resourcelock
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"time"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
coordinationv1 "k8s.io/client-go/kubernetes/typed/coordination/v1"
|
||||
corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
)
|
||||
|
||||
const (
|
||||
LeaderElectionRecordAnnotationKey = "control-plane.alpha.kubernetes.io/leader"
|
||||
EndpointsResourceLock = "endpoints"
|
||||
ConfigMapsResourceLock = "configmaps"
|
||||
LeasesResourceLock = "leases"
|
||||
EndpointsLeasesResourceLock = "endpointsleases"
|
||||
ConfigMapsLeasesResourceLock = "configmapsleases"
|
||||
)
|
||||
|
||||
// LeaderElectionRecord is the record that is stored in the leader election annotation.
|
||||
// This information should be used for observational purposes only and could be replaced
|
||||
// with a random string (e.g. UUID) with only slight modification of this code.
|
||||
// TODO(mikedanese): this should potentially be versioned
|
||||
type LeaderElectionRecord struct {
|
||||
// HolderIdentity is the ID that owns the lease. If empty, no one owns this lease and
|
||||
// all callers may acquire. Versions of this library prior to Kubernetes 1.14 will not
|
||||
// attempt to acquire leases with empty identities and will wait for the full lease
|
||||
// interval to expire before attempting to reacquire. This value is set to empty when
|
||||
// a client voluntarily steps down.
|
||||
HolderIdentity string `json:"holderIdentity"`
|
||||
LeaseDurationSeconds int `json:"leaseDurationSeconds"`
|
||||
AcquireTime metav1.Time `json:"acquireTime"`
|
||||
RenewTime metav1.Time `json:"renewTime"`
|
||||
LeaderTransitions int `json:"leaderTransitions"`
|
||||
}
|
||||
|
||||
// EventRecorder records a change in the ResourceLock.
|
||||
type EventRecorder interface {
|
||||
Eventf(obj runtime.Object, eventType, reason, message string, args ...interface{})
|
||||
}
|
||||
|
||||
// ResourceLockConfig common data that exists across different
|
||||
// resource locks
|
||||
type ResourceLockConfig struct {
|
||||
// Identity is the unique string identifying a lease holder across
|
||||
// all participants in an election.
|
||||
Identity string
|
||||
// EventRecorder is optional.
|
||||
EventRecorder EventRecorder
|
||||
}
|
||||
|
||||
// Interface offers a common interface for locking on arbitrary
|
||||
// resources used in leader election. The Interface is used
|
||||
// to hide the details on specific implementations in order to allow
|
||||
// them to change over time. This interface is strictly for use
|
||||
// by the leaderelection code.
|
||||
type Interface interface {
|
||||
// Get returns the LeaderElectionRecord
|
||||
Get(ctx context.Context) (*LeaderElectionRecord, []byte, error)
|
||||
|
||||
// Create attempts to create a LeaderElectionRecord
|
||||
Create(ctx context.Context, ler LeaderElectionRecord) error
|
||||
|
||||
// Update will update and existing LeaderElectionRecord
|
||||
Update(ctx context.Context, ler LeaderElectionRecord) error
|
||||
|
||||
// RecordEvent is used to record events
|
||||
RecordEvent(string)
|
||||
|
||||
// Identity will return the locks Identity
|
||||
Identity() string
|
||||
|
||||
// Describe is used to convert details on current resource lock
|
||||
// into a string
|
||||
Describe() string
|
||||
}
|
||||
|
||||
// Manufacture will create a lock of a given type according to the input parameters
|
||||
func New(lockType string, ns string, name string, coreClient corev1.CoreV1Interface, coordinationClient coordinationv1.CoordinationV1Interface, rlc ResourceLockConfig) (Interface, error) {
|
||||
endpointsLock := &EndpointsLock{
|
||||
EndpointsMeta: metav1.ObjectMeta{
|
||||
Namespace: ns,
|
||||
Name: name,
|
||||
},
|
||||
Client: coreClient,
|
||||
LockConfig: rlc,
|
||||
}
|
||||
configmapLock := &ConfigMapLock{
|
||||
ConfigMapMeta: metav1.ObjectMeta{
|
||||
Namespace: ns,
|
||||
Name: name,
|
||||
},
|
||||
Client: coreClient,
|
||||
LockConfig: rlc,
|
||||
}
|
||||
leaseLock := &LeaseLock{
|
||||
LeaseMeta: metav1.ObjectMeta{
|
||||
Namespace: ns,
|
||||
Name: name,
|
||||
},
|
||||
Client: coordinationClient,
|
||||
LockConfig: rlc,
|
||||
}
|
||||
switch lockType {
|
||||
case EndpointsResourceLock:
|
||||
return endpointsLock, nil
|
||||
case ConfigMapsResourceLock:
|
||||
return configmapLock, nil
|
||||
case LeasesResourceLock:
|
||||
return leaseLock, nil
|
||||
case EndpointsLeasesResourceLock:
|
||||
return &MultiLock{
|
||||
Primary: endpointsLock,
|
||||
Secondary: leaseLock,
|
||||
}, nil
|
||||
case ConfigMapsLeasesResourceLock:
|
||||
return &MultiLock{
|
||||
Primary: configmapLock,
|
||||
Secondary: leaseLock,
|
||||
}, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("Invalid lock-type %s", lockType)
|
||||
}
|
||||
}
|
||||
|
||||
// NewFromKubeconfig will create a lock of a given type according to the input parameters.
|
||||
func NewFromKubeconfig(lockType string, ns string, name string, rlc ResourceLockConfig, kubeconfig *restclient.Config, renewDeadline time.Duration) (Interface, error) {
|
||||
// shallow copy, do not modify the kubeconfig
|
||||
config := *kubeconfig
|
||||
timeout := ((renewDeadline / time.Millisecond) / 2) * time.Millisecond
|
||||
if timeout < time.Second {
|
||||
timeout = time.Second
|
||||
}
|
||||
config.Timeout = timeout
|
||||
leaderElectionClient := clientset.NewForConfigOrDie(restclient.AddUserAgent(&config, "leader-election"))
|
||||
return New(lockType, ns, name, leaderElectionClient.CoreV1(), leaderElectionClient.CoordinationV1(), rlc)
|
||||
}
|
||||
135
vendor/k8s.io/client-go/tools/leaderelection/resourcelock/leaselock.go
generated
vendored
Normal file
135
vendor/k8s.io/client-go/tools/leaderelection/resourcelock/leaselock.go
generated
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package resourcelock
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
coordinationv1 "k8s.io/api/coordination/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
coordinationv1client "k8s.io/client-go/kubernetes/typed/coordination/v1"
|
||||
)
|
||||
|
||||
type LeaseLock struct {
|
||||
// LeaseMeta should contain a Name and a Namespace of a
|
||||
// LeaseMeta object that the LeaderElector will attempt to lead.
|
||||
LeaseMeta metav1.ObjectMeta
|
||||
Client coordinationv1client.LeasesGetter
|
||||
LockConfig ResourceLockConfig
|
||||
lease *coordinationv1.Lease
|
||||
}
|
||||
|
||||
// Get returns the election record from a Lease spec
|
||||
func (ll *LeaseLock) Get(ctx context.Context) (*LeaderElectionRecord, []byte, error) {
|
||||
var err error
|
||||
ll.lease, err = ll.Client.Leases(ll.LeaseMeta.Namespace).Get(ctx, ll.LeaseMeta.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
record := LeaseSpecToLeaderElectionRecord(&ll.lease.Spec)
|
||||
recordByte, err := json.Marshal(*record)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return record, recordByte, nil
|
||||
}
|
||||
|
||||
// Create attempts to create a Lease
|
||||
func (ll *LeaseLock) Create(ctx context.Context, ler LeaderElectionRecord) error {
|
||||
var err error
|
||||
ll.lease, err = ll.Client.Leases(ll.LeaseMeta.Namespace).Create(ctx, &coordinationv1.Lease{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: ll.LeaseMeta.Name,
|
||||
Namespace: ll.LeaseMeta.Namespace,
|
||||
},
|
||||
Spec: LeaderElectionRecordToLeaseSpec(&ler),
|
||||
}, metav1.CreateOptions{})
|
||||
return err
|
||||
}
|
||||
|
||||
// Update will update an existing Lease spec.
|
||||
func (ll *LeaseLock) Update(ctx context.Context, ler LeaderElectionRecord) error {
|
||||
if ll.lease == nil {
|
||||
return errors.New("lease not initialized, call get or create first")
|
||||
}
|
||||
ll.lease.Spec = LeaderElectionRecordToLeaseSpec(&ler)
|
||||
|
||||
lease, err := ll.Client.Leases(ll.LeaseMeta.Namespace).Update(ctx, ll.lease, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ll.lease = lease
|
||||
return nil
|
||||
}
|
||||
|
||||
// RecordEvent in leader election while adding meta-data
|
||||
func (ll *LeaseLock) RecordEvent(s string) {
|
||||
if ll.LockConfig.EventRecorder == nil {
|
||||
return
|
||||
}
|
||||
events := fmt.Sprintf("%v %v", ll.LockConfig.Identity, s)
|
||||
ll.LockConfig.EventRecorder.Eventf(&coordinationv1.Lease{ObjectMeta: ll.lease.ObjectMeta}, corev1.EventTypeNormal, "LeaderElection", events)
|
||||
}
|
||||
|
||||
// Describe is used to convert details on current resource lock
|
||||
// into a string
|
||||
func (ll *LeaseLock) Describe() string {
|
||||
return fmt.Sprintf("%v/%v", ll.LeaseMeta.Namespace, ll.LeaseMeta.Name)
|
||||
}
|
||||
|
||||
// Identity returns the Identity of the lock
|
||||
func (ll *LeaseLock) Identity() string {
|
||||
return ll.LockConfig.Identity
|
||||
}
|
||||
|
||||
func LeaseSpecToLeaderElectionRecord(spec *coordinationv1.LeaseSpec) *LeaderElectionRecord {
|
||||
var r LeaderElectionRecord
|
||||
if spec.HolderIdentity != nil {
|
||||
r.HolderIdentity = *spec.HolderIdentity
|
||||
}
|
||||
if spec.LeaseDurationSeconds != nil {
|
||||
r.LeaseDurationSeconds = int(*spec.LeaseDurationSeconds)
|
||||
}
|
||||
if spec.LeaseTransitions != nil {
|
||||
r.LeaderTransitions = int(*spec.LeaseTransitions)
|
||||
}
|
||||
if spec.AcquireTime != nil {
|
||||
r.AcquireTime = metav1.Time{spec.AcquireTime.Time}
|
||||
}
|
||||
if spec.RenewTime != nil {
|
||||
r.RenewTime = metav1.Time{spec.RenewTime.Time}
|
||||
}
|
||||
return &r
|
||||
|
||||
}
|
||||
|
||||
func LeaderElectionRecordToLeaseSpec(ler *LeaderElectionRecord) coordinationv1.LeaseSpec {
|
||||
leaseDurationSeconds := int32(ler.LeaseDurationSeconds)
|
||||
leaseTransitions := int32(ler.LeaderTransitions)
|
||||
return coordinationv1.LeaseSpec{
|
||||
HolderIdentity: &ler.HolderIdentity,
|
||||
LeaseDurationSeconds: &leaseDurationSeconds,
|
||||
AcquireTime: &metav1.MicroTime{ler.AcquireTime.Time},
|
||||
RenewTime: &metav1.MicroTime{ler.RenewTime.Time},
|
||||
LeaseTransitions: &leaseTransitions,
|
||||
}
|
||||
}
|
||||
104
vendor/k8s.io/client-go/tools/leaderelection/resourcelock/multilock.go
generated
vendored
Normal file
104
vendor/k8s.io/client-go/tools/leaderelection/resourcelock/multilock.go
generated
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
Copyright 2019 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package resourcelock
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
UnknownLeader = "leaderelection.k8s.io/unknown"
|
||||
)
|
||||
|
||||
// MultiLock is used for lock's migration
|
||||
type MultiLock struct {
|
||||
Primary Interface
|
||||
Secondary Interface
|
||||
}
|
||||
|
||||
// Get returns the older election record of the lock
|
||||
func (ml *MultiLock) Get(ctx context.Context) (*LeaderElectionRecord, []byte, error) {
|
||||
primary, primaryRaw, err := ml.Primary.Get(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
secondary, secondaryRaw, err := ml.Secondary.Get(ctx)
|
||||
if err != nil {
|
||||
// Lock is held by old client
|
||||
if apierrors.IsNotFound(err) && primary.HolderIdentity != ml.Identity() {
|
||||
return primary, primaryRaw, nil
|
||||
}
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if primary.HolderIdentity != secondary.HolderIdentity {
|
||||
primary.HolderIdentity = UnknownLeader
|
||||
primaryRaw, err = json.Marshal(primary)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
return primary, ConcatRawRecord(primaryRaw, secondaryRaw), nil
|
||||
}
|
||||
|
||||
// Create attempts to create both primary lock and secondary lock
|
||||
func (ml *MultiLock) Create(ctx context.Context, ler LeaderElectionRecord) error {
|
||||
err := ml.Primary.Create(ctx, ler)
|
||||
if err != nil && !apierrors.IsAlreadyExists(err) {
|
||||
return err
|
||||
}
|
||||
return ml.Secondary.Create(ctx, ler)
|
||||
}
|
||||
|
||||
// Update will update and existing annotation on both two resources.
|
||||
func (ml *MultiLock) Update(ctx context.Context, ler LeaderElectionRecord) error {
|
||||
err := ml.Primary.Update(ctx, ler)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, _, err = ml.Secondary.Get(ctx)
|
||||
if err != nil && apierrors.IsNotFound(err) {
|
||||
return ml.Secondary.Create(ctx, ler)
|
||||
}
|
||||
return ml.Secondary.Update(ctx, ler)
|
||||
}
|
||||
|
||||
// RecordEvent in leader election while adding meta-data
|
||||
func (ml *MultiLock) RecordEvent(s string) {
|
||||
ml.Primary.RecordEvent(s)
|
||||
ml.Secondary.RecordEvent(s)
|
||||
}
|
||||
|
||||
// Describe is used to convert details on current resource lock
|
||||
// into a string
|
||||
func (ml *MultiLock) Describe() string {
|
||||
return ml.Primary.Describe()
|
||||
}
|
||||
|
||||
// Identity returns the Identity of the lock
|
||||
func (ml *MultiLock) Identity() string {
|
||||
return ml.Primary.Identity()
|
||||
}
|
||||
|
||||
func ConcatRawRecord(primaryRaw, secondaryRaw []byte) []byte {
|
||||
return bytes.Join([][]byte{primaryRaw, secondaryRaw}, []byte(","))
|
||||
}
|
||||
14
vendor/k8s.io/component-base/config/OWNERS
generated
vendored
Normal file
14
vendor/k8s.io/component-base/config/OWNERS
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
# See the OWNERS docs at https://go.k8s.io/owners
|
||||
|
||||
# Disable inheritance as this is an api owners file
|
||||
options:
|
||||
no_parent_owners: true
|
||||
approvers:
|
||||
- api-approvers
|
||||
reviewers:
|
||||
- api-reviewers
|
||||
- luxas
|
||||
- mtaufen
|
||||
- sttts
|
||||
labels:
|
||||
- kind/api-change
|
||||
19
vendor/k8s.io/component-base/config/doc.go
generated
vendored
Normal file
19
vendor/k8s.io/component-base/config/doc.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// +k8s:deepcopy-gen=package
|
||||
|
||||
package config // import "k8s.io/component-base/config"
|
||||
91
vendor/k8s.io/component-base/config/types.go
generated
vendored
Normal file
91
vendor/k8s.io/component-base/config/types.go
generated
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// ClientConnectionConfiguration contains details for constructing a client.
|
||||
type ClientConnectionConfiguration struct {
|
||||
// kubeconfig is the path to a KubeConfig file.
|
||||
Kubeconfig string
|
||||
// acceptContentTypes defines the Accept header sent by clients when connecting to a server, overriding the
|
||||
// default value of 'application/json'. This field will control all connections to the server used by a particular
|
||||
// client.
|
||||
AcceptContentTypes string
|
||||
// contentType is the content type used when sending data to the server from this client.
|
||||
ContentType string
|
||||
// qps controls the number of queries per second allowed for this connection.
|
||||
QPS float32
|
||||
// burst allows extra queries to accumulate when a client is exceeding its rate.
|
||||
Burst int32
|
||||
}
|
||||
|
||||
// LeaderElectionConfiguration defines the configuration of leader election
|
||||
// clients for components that can run with leader election enabled.
|
||||
type LeaderElectionConfiguration struct {
|
||||
// leaderElect enables a leader election client to gain leadership
|
||||
// before executing the main loop. Enable this when running replicated
|
||||
// components for high availability.
|
||||
LeaderElect bool
|
||||
// leaseDuration is the duration that non-leader candidates will wait
|
||||
// after observing a leadership renewal until attempting to acquire
|
||||
// leadership of a led but unrenewed leader slot. This is effectively the
|
||||
// maximum duration that a leader can be stopped before it is replaced
|
||||
// by another candidate. This is only applicable if leader election is
|
||||
// enabled.
|
||||
LeaseDuration metav1.Duration
|
||||
// renewDeadline is the interval between attempts by the acting master to
|
||||
// renew a leadership slot before it stops leading. This must be less
|
||||
// than or equal to the lease duration. This is only applicable if leader
|
||||
// election is enabled.
|
||||
RenewDeadline metav1.Duration
|
||||
// retryPeriod is the duration the clients should wait between attempting
|
||||
// acquisition and renewal of a leadership. This is only applicable if
|
||||
// leader election is enabled.
|
||||
RetryPeriod metav1.Duration
|
||||
// resourceLock indicates the resource object type that will be used to lock
|
||||
// during leader election cycles.
|
||||
ResourceLock string
|
||||
// resourceName indicates the name of resource object that will be used to lock
|
||||
// during leader election cycles.
|
||||
ResourceName string
|
||||
// resourceName indicates the namespace of resource object that will be used to lock
|
||||
// during leader election cycles.
|
||||
ResourceNamespace string
|
||||
}
|
||||
|
||||
// DebuggingConfiguration holds configuration for Debugging related features.
|
||||
type DebuggingConfiguration struct {
|
||||
// enableProfiling enables profiling via web interface host:port/debug/pprof/
|
||||
EnableProfiling bool
|
||||
// enableContentionProfiling enables lock contention profiling, if
|
||||
// enableProfiling is true.
|
||||
EnableContentionProfiling bool
|
||||
}
|
||||
|
||||
// LoggingConfiguration contains logging options
|
||||
// Refer [Logs Options](https://github.com/kubernetes/component-base/blob/master/logs/options.go) for more information.
|
||||
type LoggingConfiguration struct {
|
||||
// Format Flag specifies the structure of log messages.
|
||||
// default value of format is `text`
|
||||
Format string
|
||||
// [Experimental] When enabled prevents logging of fields tagged as sensitive (passwords, keys, tokens).
|
||||
// Runtime log sanitization may introduce significant computation overhead and therefore should not be enabled in production.`)
|
||||
Sanitization bool
|
||||
}
|
||||
61
vendor/k8s.io/component-base/config/v1alpha1/conversion.go
generated
vendored
Normal file
61
vendor/k8s.io/component-base/config/v1alpha1/conversion.go
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/conversion"
|
||||
"k8s.io/component-base/config"
|
||||
)
|
||||
|
||||
// Important! The public back-and-forth conversion functions for the types in this generic
|
||||
// package with ComponentConfig types need to be manually exposed like this in order for
|
||||
// other packages that reference this package to be able to call these conversion functions
|
||||
// in an autogenerated manner.
|
||||
// TODO: Fix the bug in conversion-gen so it automatically discovers these Convert_* functions
|
||||
// in autogenerated code as well.
|
||||
|
||||
func Convert_v1alpha1_ClientConnectionConfiguration_To_config_ClientConnectionConfiguration(in *ClientConnectionConfiguration, out *config.ClientConnectionConfiguration, s conversion.Scope) error {
|
||||
return autoConvert_v1alpha1_ClientConnectionConfiguration_To_config_ClientConnectionConfiguration(in, out, s)
|
||||
}
|
||||
|
||||
func Convert_config_ClientConnectionConfiguration_To_v1alpha1_ClientConnectionConfiguration(in *config.ClientConnectionConfiguration, out *ClientConnectionConfiguration, s conversion.Scope) error {
|
||||
return autoConvert_config_ClientConnectionConfiguration_To_v1alpha1_ClientConnectionConfiguration(in, out, s)
|
||||
}
|
||||
|
||||
func Convert_v1alpha1_DebuggingConfiguration_To_config_DebuggingConfiguration(in *DebuggingConfiguration, out *config.DebuggingConfiguration, s conversion.Scope) error {
|
||||
return autoConvert_v1alpha1_DebuggingConfiguration_To_config_DebuggingConfiguration(in, out, s)
|
||||
}
|
||||
|
||||
func Convert_config_DebuggingConfiguration_To_v1alpha1_DebuggingConfiguration(in *config.DebuggingConfiguration, out *DebuggingConfiguration, s conversion.Scope) error {
|
||||
return autoConvert_config_DebuggingConfiguration_To_v1alpha1_DebuggingConfiguration(in, out, s)
|
||||
}
|
||||
|
||||
func Convert_v1alpha1_LeaderElectionConfiguration_To_config_LeaderElectionConfiguration(in *LeaderElectionConfiguration, out *config.LeaderElectionConfiguration, s conversion.Scope) error {
|
||||
return autoConvert_v1alpha1_LeaderElectionConfiguration_To_config_LeaderElectionConfiguration(in, out, s)
|
||||
}
|
||||
|
||||
func Convert_config_LeaderElectionConfiguration_To_v1alpha1_LeaderElectionConfiguration(in *config.LeaderElectionConfiguration, out *LeaderElectionConfiguration, s conversion.Scope) error {
|
||||
return autoConvert_config_LeaderElectionConfiguration_To_v1alpha1_LeaderElectionConfiguration(in, out, s)
|
||||
}
|
||||
|
||||
func Convert_v1alpha1_LoggingConfiguration_To_config_LoggingConfiguration(in *LoggingConfiguration, out *config.LoggingConfiguration, s conversion.Scope) error {
|
||||
return autoConvert_v1alpha1_LoggingConfiguration_To_config_LoggingConfiguration(in, out, s)
|
||||
}
|
||||
|
||||
func Convert_config_LoggingConfiguration_To_v1alpha1_LoggingConfiguration(in *config.LoggingConfiguration, out *LoggingConfiguration, s conversion.Scope) error {
|
||||
return autoConvert_config_LoggingConfiguration_To_v1alpha1_LoggingConfiguration(in, out, s)
|
||||
}
|
||||
113
vendor/k8s.io/component-base/config/v1alpha1/defaults.go
generated
vendored
Normal file
113
vendor/k8s.io/component-base/config/v1alpha1/defaults.go
generated
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
utilpointer "k8s.io/utils/pointer"
|
||||
)
|
||||
|
||||
// RecommendedDefaultLeaderElectionConfiguration defaults a pointer to a
|
||||
// LeaderElectionConfiguration struct. This will set the recommended default
|
||||
// values, but they may be subject to change between API versions. This function
|
||||
// is intentionally not registered in the scheme as a "normal" `SetDefaults_Foo`
|
||||
// function to allow consumers of this type to set whatever defaults for their
|
||||
// embedded configs. Forcing consumers to use these defaults would be problematic
|
||||
// as defaulting in the scheme is done as part of the conversion, and there would
|
||||
// be no easy way to opt-out. Instead, if you want to use this defaulting method
|
||||
// run it in your wrapper struct of this type in its `SetDefaults_` method.
|
||||
func RecommendedDefaultLeaderElectionConfiguration(obj *LeaderElectionConfiguration) {
|
||||
zero := metav1.Duration{}
|
||||
if obj.LeaseDuration == zero {
|
||||
obj.LeaseDuration = metav1.Duration{Duration: 15 * time.Second}
|
||||
}
|
||||
if obj.RenewDeadline == zero {
|
||||
obj.RenewDeadline = metav1.Duration{Duration: 10 * time.Second}
|
||||
}
|
||||
if obj.RetryPeriod == zero {
|
||||
obj.RetryPeriod = metav1.Duration{Duration: 2 * time.Second}
|
||||
}
|
||||
if obj.ResourceLock == "" {
|
||||
// TODO(#80289): Figure out how to migrate to LeaseLock at this point.
|
||||
// This will most probably require going through EndpointsLease first.
|
||||
obj.ResourceLock = EndpointsResourceLock
|
||||
}
|
||||
if obj.LeaderElect == nil {
|
||||
obj.LeaderElect = utilpointer.BoolPtr(true)
|
||||
}
|
||||
}
|
||||
|
||||
// RecommendedDefaultClientConnectionConfiguration defaults a pointer to a
|
||||
// ClientConnectionConfiguration struct. This will set the recommended default
|
||||
// values, but they may be subject to change between API versions. This function
|
||||
// is intentionally not registered in the scheme as a "normal" `SetDefaults_Foo`
|
||||
// function to allow consumers of this type to set whatever defaults for their
|
||||
// embedded configs. Forcing consumers to use these defaults would be problematic
|
||||
// as defaulting in the scheme is done as part of the conversion, and there would
|
||||
// be no easy way to opt-out. Instead, if you want to use this defaulting method
|
||||
// run it in your wrapper struct of this type in its `SetDefaults_` method.
|
||||
func RecommendedDefaultClientConnectionConfiguration(obj *ClientConnectionConfiguration) {
|
||||
if len(obj.ContentType) == 0 {
|
||||
obj.ContentType = "application/vnd.kubernetes.protobuf"
|
||||
}
|
||||
if obj.QPS == 0.0 {
|
||||
obj.QPS = 50.0
|
||||
}
|
||||
if obj.Burst == 0 {
|
||||
obj.Burst = 100
|
||||
}
|
||||
}
|
||||
|
||||
// RecommendedDebuggingConfiguration defaults profiling and debugging configuration.
|
||||
// This will set the recommended default
|
||||
// values, but they may be subject to change between API versions. This function
|
||||
// is intentionally not registered in the scheme as a "normal" `SetDefaults_Foo`
|
||||
// function to allow consumers of this type to set whatever defaults for their
|
||||
// embedded configs. Forcing consumers to use these defaults would be problematic
|
||||
// as defaulting in the scheme is done as part of the conversion, and there would
|
||||
// be no easy way to opt-out. Instead, if you want to use this defaulting method
|
||||
// run it in your wrapper struct of this type in its `SetDefaults_` method.
|
||||
func RecommendedDebuggingConfiguration(obj *DebuggingConfiguration) {
|
||||
if obj.EnableProfiling == nil {
|
||||
obj.EnableProfiling = utilpointer.BoolPtr(true) // profile debugging is cheap to have exposed and standard on kube binaries
|
||||
}
|
||||
}
|
||||
|
||||
// NewRecommendedDebuggingConfiguration returns the current recommended DebuggingConfiguration.
|
||||
// This may change between releases as recommendations shift.
|
||||
func NewRecommendedDebuggingConfiguration() *DebuggingConfiguration {
|
||||
ret := &DebuggingConfiguration{}
|
||||
RecommendedDebuggingConfiguration(ret)
|
||||
return ret
|
||||
}
|
||||
|
||||
// RecommendedLoggingConfiguration defaults logging configuration.
|
||||
// This will set the recommended default
|
||||
// values, but they may be subject to change between API versions. This function
|
||||
// is intentionally not registered in the scheme as a "normal" `SetDefaults_Foo`
|
||||
// function to allow consumers of this type to set whatever defaults for their
|
||||
// embedded configs. Forcing consumers to use these defaults would be problematic
|
||||
// as defaulting in the scheme is done as part of the conversion, and there would
|
||||
// be no easy way to opt-out. Instead, if you want to use this defaulting method
|
||||
// run it in your wrapper struct of this type in its `SetDefaults_` method.
|
||||
func RecommendedLoggingConfiguration(obj *LoggingConfiguration) {
|
||||
if obj.Format == "" {
|
||||
obj.Format = "text"
|
||||
}
|
||||
}
|
||||
20
vendor/k8s.io/component-base/config/v1alpha1/doc.go
generated
vendored
Normal file
20
vendor/k8s.io/component-base/config/v1alpha1/doc.go
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// +k8s:deepcopy-gen=package
|
||||
// +k8s:conversion-gen=k8s.io/component-base/config
|
||||
|
||||
package v1alpha1 // import "k8s.io/component-base/config/v1alpha1"
|
||||
31
vendor/k8s.io/component-base/config/v1alpha1/register.go
generated
vendored
Normal file
31
vendor/k8s.io/component-base/config/v1alpha1/register.go
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
var (
|
||||
// SchemeBuilder is the scheme builder with scheme init functions to run for this API package
|
||||
SchemeBuilder runtime.SchemeBuilder
|
||||
// localSchemeBuilder extends the SchemeBuilder instance with the external types. In this package,
|
||||
// defaulting and conversion init funcs are registered as well.
|
||||
localSchemeBuilder = &SchemeBuilder
|
||||
// AddToScheme is a global function that registers this API group & version to a scheme
|
||||
AddToScheme = localSchemeBuilder.AddToScheme
|
||||
)
|
||||
93
vendor/k8s.io/component-base/config/v1alpha1/types.go
generated
vendored
Normal file
93
vendor/k8s.io/component-base/config/v1alpha1/types.go
generated
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
const EndpointsResourceLock = "endpoints"
|
||||
|
||||
// LeaderElectionConfiguration defines the configuration of leader election
|
||||
// clients for components that can run with leader election enabled.
|
||||
type LeaderElectionConfiguration struct {
|
||||
// leaderElect enables a leader election client to gain leadership
|
||||
// before executing the main loop. Enable this when running replicated
|
||||
// components for high availability.
|
||||
LeaderElect *bool `json:"leaderElect"`
|
||||
// leaseDuration is the duration that non-leader candidates will wait
|
||||
// after observing a leadership renewal until attempting to acquire
|
||||
// leadership of a led but unrenewed leader slot. This is effectively the
|
||||
// maximum duration that a leader can be stopped before it is replaced
|
||||
// by another candidate. This is only applicable if leader election is
|
||||
// enabled.
|
||||
LeaseDuration metav1.Duration `json:"leaseDuration"`
|
||||
// renewDeadline is the interval between attempts by the acting master to
|
||||
// renew a leadership slot before it stops leading. This must be less
|
||||
// than or equal to the lease duration. This is only applicable if leader
|
||||
// election is enabled.
|
||||
RenewDeadline metav1.Duration `json:"renewDeadline"`
|
||||
// retryPeriod is the duration the clients should wait between attempting
|
||||
// acquisition and renewal of a leadership. This is only applicable if
|
||||
// leader election is enabled.
|
||||
RetryPeriod metav1.Duration `json:"retryPeriod"`
|
||||
// resourceLock indicates the resource object type that will be used to lock
|
||||
// during leader election cycles.
|
||||
ResourceLock string `json:"resourceLock"`
|
||||
// resourceName indicates the name of resource object that will be used to lock
|
||||
// during leader election cycles.
|
||||
ResourceName string `json:"resourceName"`
|
||||
// resourceName indicates the namespace of resource object that will be used to lock
|
||||
// during leader election cycles.
|
||||
ResourceNamespace string `json:"resourceNamespace"`
|
||||
}
|
||||
|
||||
// DebuggingConfiguration holds configuration for Debugging related features.
|
||||
type DebuggingConfiguration struct {
|
||||
// enableProfiling enables profiling via web interface host:port/debug/pprof/
|
||||
EnableProfiling *bool `json:"enableProfiling,omitempty"`
|
||||
// enableContentionProfiling enables lock contention profiling, if
|
||||
// enableProfiling is true.
|
||||
EnableContentionProfiling *bool `json:"enableContentionProfiling,omitempty"`
|
||||
}
|
||||
|
||||
// ClientConnectionConfiguration contains details for constructing a client.
|
||||
type ClientConnectionConfiguration struct {
|
||||
// kubeconfig is the path to a KubeConfig file.
|
||||
Kubeconfig string `json:"kubeconfig"`
|
||||
// acceptContentTypes defines the Accept header sent by clients when connecting to a server, overriding the
|
||||
// default value of 'application/json'. This field will control all connections to the server used by a particular
|
||||
// client.
|
||||
AcceptContentTypes string `json:"acceptContentTypes"`
|
||||
// contentType is the content type used when sending data to the server from this client.
|
||||
ContentType string `json:"contentType"`
|
||||
// qps controls the number of queries per second allowed for this connection.
|
||||
QPS float32 `json:"qps"`
|
||||
// burst allows extra queries to accumulate when a client is exceeding its rate.
|
||||
Burst int32 `json:"burst"`
|
||||
}
|
||||
|
||||
// LoggingConfiguration contains logging options
|
||||
// Refer [Logs Options](https://github.com/kubernetes/component-base/blob/master/logs/options.go) for more information.
|
||||
type LoggingConfiguration struct {
|
||||
// Format Flag specifies the structure of log messages.
|
||||
// default value of format is `text`
|
||||
Format string `json:"format,omitempty"`
|
||||
// [Experimental] When enabled prevents logging of fields tagged as sensitive (passwords, keys, tokens).
|
||||
// Runtime log sanitization may introduce significant computation overhead and therefore should not be enabled in production.`)
|
||||
Sanitization bool `json:"sanitization,omitempty"`
|
||||
}
|
||||
154
vendor/k8s.io/component-base/config/v1alpha1/zz_generated.conversion.go
generated
vendored
Normal file
154
vendor/k8s.io/component-base/config/v1alpha1/zz_generated.conversion.go
generated
vendored
Normal file
@@ -0,0 +1,154 @@
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by conversion-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
conversion "k8s.io/apimachinery/pkg/conversion"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
config "k8s.io/component-base/config"
|
||||
)
|
||||
|
||||
func init() {
|
||||
localSchemeBuilder.Register(RegisterConversions)
|
||||
}
|
||||
|
||||
// RegisterConversions adds conversion functions to the given scheme.
|
||||
// Public to allow building arbitrary schemes.
|
||||
func RegisterConversions(s *runtime.Scheme) error {
|
||||
if err := s.AddConversionFunc((*config.ClientConnectionConfiguration)(nil), (*ClientConnectionConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_config_ClientConnectionConfiguration_To_v1alpha1_ClientConnectionConfiguration(a.(*config.ClientConnectionConfiguration), b.(*ClientConnectionConfiguration), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddConversionFunc((*config.DebuggingConfiguration)(nil), (*DebuggingConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_config_DebuggingConfiguration_To_v1alpha1_DebuggingConfiguration(a.(*config.DebuggingConfiguration), b.(*DebuggingConfiguration), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddConversionFunc((*config.LeaderElectionConfiguration)(nil), (*LeaderElectionConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_config_LeaderElectionConfiguration_To_v1alpha1_LeaderElectionConfiguration(a.(*config.LeaderElectionConfiguration), b.(*LeaderElectionConfiguration), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddConversionFunc((*config.LoggingConfiguration)(nil), (*LoggingConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_config_LoggingConfiguration_To_v1alpha1_LoggingConfiguration(a.(*config.LoggingConfiguration), b.(*LoggingConfiguration), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddConversionFunc((*ClientConnectionConfiguration)(nil), (*config.ClientConnectionConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1alpha1_ClientConnectionConfiguration_To_config_ClientConnectionConfiguration(a.(*ClientConnectionConfiguration), b.(*config.ClientConnectionConfiguration), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddConversionFunc((*DebuggingConfiguration)(nil), (*config.DebuggingConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1alpha1_DebuggingConfiguration_To_config_DebuggingConfiguration(a.(*DebuggingConfiguration), b.(*config.DebuggingConfiguration), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddConversionFunc((*LeaderElectionConfiguration)(nil), (*config.LeaderElectionConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1alpha1_LeaderElectionConfiguration_To_config_LeaderElectionConfiguration(a.(*LeaderElectionConfiguration), b.(*config.LeaderElectionConfiguration), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddConversionFunc((*LoggingConfiguration)(nil), (*config.LoggingConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1alpha1_LoggingConfiguration_To_config_LoggingConfiguration(a.(*LoggingConfiguration), b.(*config.LoggingConfiguration), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func autoConvert_v1alpha1_ClientConnectionConfiguration_To_config_ClientConnectionConfiguration(in *ClientConnectionConfiguration, out *config.ClientConnectionConfiguration, s conversion.Scope) error {
|
||||
out.Kubeconfig = in.Kubeconfig
|
||||
out.AcceptContentTypes = in.AcceptContentTypes
|
||||
out.ContentType = in.ContentType
|
||||
out.QPS = in.QPS
|
||||
out.Burst = in.Burst
|
||||
return nil
|
||||
}
|
||||
|
||||
func autoConvert_config_ClientConnectionConfiguration_To_v1alpha1_ClientConnectionConfiguration(in *config.ClientConnectionConfiguration, out *ClientConnectionConfiguration, s conversion.Scope) error {
|
||||
out.Kubeconfig = in.Kubeconfig
|
||||
out.AcceptContentTypes = in.AcceptContentTypes
|
||||
out.ContentType = in.ContentType
|
||||
out.QPS = in.QPS
|
||||
out.Burst = in.Burst
|
||||
return nil
|
||||
}
|
||||
|
||||
func autoConvert_v1alpha1_DebuggingConfiguration_To_config_DebuggingConfiguration(in *DebuggingConfiguration, out *config.DebuggingConfiguration, s conversion.Scope) error {
|
||||
if err := v1.Convert_Pointer_bool_To_bool(&in.EnableProfiling, &out.EnableProfiling, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := v1.Convert_Pointer_bool_To_bool(&in.EnableContentionProfiling, &out.EnableContentionProfiling, s); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func autoConvert_config_DebuggingConfiguration_To_v1alpha1_DebuggingConfiguration(in *config.DebuggingConfiguration, out *DebuggingConfiguration, s conversion.Scope) error {
|
||||
if err := v1.Convert_bool_To_Pointer_bool(&in.EnableProfiling, &out.EnableProfiling, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := v1.Convert_bool_To_Pointer_bool(&in.EnableContentionProfiling, &out.EnableContentionProfiling, s); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func autoConvert_v1alpha1_LeaderElectionConfiguration_To_config_LeaderElectionConfiguration(in *LeaderElectionConfiguration, out *config.LeaderElectionConfiguration, s conversion.Scope) error {
|
||||
if err := v1.Convert_Pointer_bool_To_bool(&in.LeaderElect, &out.LeaderElect, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.LeaseDuration = in.LeaseDuration
|
||||
out.RenewDeadline = in.RenewDeadline
|
||||
out.RetryPeriod = in.RetryPeriod
|
||||
out.ResourceLock = in.ResourceLock
|
||||
out.ResourceName = in.ResourceName
|
||||
out.ResourceNamespace = in.ResourceNamespace
|
||||
return nil
|
||||
}
|
||||
|
||||
func autoConvert_config_LeaderElectionConfiguration_To_v1alpha1_LeaderElectionConfiguration(in *config.LeaderElectionConfiguration, out *LeaderElectionConfiguration, s conversion.Scope) error {
|
||||
if err := v1.Convert_bool_To_Pointer_bool(&in.LeaderElect, &out.LeaderElect, s); err != nil {
|
||||
return err
|
||||
}
|
||||
out.LeaseDuration = in.LeaseDuration
|
||||
out.RenewDeadline = in.RenewDeadline
|
||||
out.RetryPeriod = in.RetryPeriod
|
||||
out.ResourceLock = in.ResourceLock
|
||||
out.ResourceName = in.ResourceName
|
||||
out.ResourceNamespace = in.ResourceNamespace
|
||||
return nil
|
||||
}
|
||||
|
||||
func autoConvert_v1alpha1_LoggingConfiguration_To_config_LoggingConfiguration(in *LoggingConfiguration, out *config.LoggingConfiguration, s conversion.Scope) error {
|
||||
out.Format = in.Format
|
||||
out.Sanitization = in.Sanitization
|
||||
return nil
|
||||
}
|
||||
|
||||
func autoConvert_config_LoggingConfiguration_To_v1alpha1_LoggingConfiguration(in *config.LoggingConfiguration, out *LoggingConfiguration, s conversion.Scope) error {
|
||||
out.Format = in.Format
|
||||
out.Sanitization = in.Sanitization
|
||||
return nil
|
||||
}
|
||||
103
vendor/k8s.io/component-base/config/v1alpha1/zz_generated.deepcopy.go
generated
vendored
Normal file
103
vendor/k8s.io/component-base/config/v1alpha1/zz_generated.deepcopy.go
generated
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by deepcopy-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ClientConnectionConfiguration) DeepCopyInto(out *ClientConnectionConfiguration) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClientConnectionConfiguration.
|
||||
func (in *ClientConnectionConfiguration) DeepCopy() *ClientConnectionConfiguration {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ClientConnectionConfiguration)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DebuggingConfiguration) DeepCopyInto(out *DebuggingConfiguration) {
|
||||
*out = *in
|
||||
if in.EnableProfiling != nil {
|
||||
in, out := &in.EnableProfiling, &out.EnableProfiling
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
if in.EnableContentionProfiling != nil {
|
||||
in, out := &in.EnableContentionProfiling, &out.EnableContentionProfiling
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DebuggingConfiguration.
|
||||
func (in *DebuggingConfiguration) DeepCopy() *DebuggingConfiguration {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(DebuggingConfiguration)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *LeaderElectionConfiguration) DeepCopyInto(out *LeaderElectionConfiguration) {
|
||||
*out = *in
|
||||
if in.LeaderElect != nil {
|
||||
in, out := &in.LeaderElect, &out.LeaderElect
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
out.LeaseDuration = in.LeaseDuration
|
||||
out.RenewDeadline = in.RenewDeadline
|
||||
out.RetryPeriod = in.RetryPeriod
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LeaderElectionConfiguration.
|
||||
func (in *LeaderElectionConfiguration) DeepCopy() *LeaderElectionConfiguration {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(LeaderElectionConfiguration)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *LoggingConfiguration) DeepCopyInto(out *LoggingConfiguration) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LoggingConfiguration.
|
||||
func (in *LoggingConfiguration) DeepCopy() *LoggingConfiguration {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(LoggingConfiguration)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
88
vendor/k8s.io/component-base/config/zz_generated.deepcopy.go
generated
vendored
Normal file
88
vendor/k8s.io/component-base/config/zz_generated.deepcopy.go
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by deepcopy-gen. DO NOT EDIT.
|
||||
|
||||
package config
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ClientConnectionConfiguration) DeepCopyInto(out *ClientConnectionConfiguration) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClientConnectionConfiguration.
|
||||
func (in *ClientConnectionConfiguration) DeepCopy() *ClientConnectionConfiguration {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ClientConnectionConfiguration)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DebuggingConfiguration) DeepCopyInto(out *DebuggingConfiguration) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DebuggingConfiguration.
|
||||
func (in *DebuggingConfiguration) DeepCopy() *DebuggingConfiguration {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(DebuggingConfiguration)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *LeaderElectionConfiguration) DeepCopyInto(out *LeaderElectionConfiguration) {
|
||||
*out = *in
|
||||
out.LeaseDuration = in.LeaseDuration
|
||||
out.RenewDeadline = in.RenewDeadline
|
||||
out.RetryPeriod = in.RetryPeriod
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LeaderElectionConfiguration.
|
||||
func (in *LeaderElectionConfiguration) DeepCopy() *LeaderElectionConfiguration {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(LeaderElectionConfiguration)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *LoggingConfiguration) DeepCopyInto(out *LoggingConfiguration) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LoggingConfiguration.
|
||||
func (in *LoggingConfiguration) DeepCopy() *LoggingConfiguration {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(LoggingConfiguration)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
61
vendor/modules.txt
vendored
61
vendor/modules.txt
vendored
@@ -557,9 +557,23 @@ github.com/prometheus/common/model
|
||||
github.com/prometheus/procfs
|
||||
github.com/prometheus/procfs/internal/fs
|
||||
github.com/prometheus/procfs/internal/util
|
||||
# github.com/redhat-developer/service-binding-operator v0.7.1
|
||||
# github.com/redhat-developer/service-binding-operator v0.9.0
|
||||
## explicit
|
||||
github.com/redhat-developer/service-binding-operator/api/v1alpha1
|
||||
github.com/redhat-developer/service-binding-operator/apis
|
||||
github.com/redhat-developer/service-binding-operator/apis/binding/v1alpha1
|
||||
github.com/redhat-developer/service-binding-operator/apis/spec/v1alpha2
|
||||
github.com/redhat-developer/service-binding-operator/pkg/binding
|
||||
github.com/redhat-developer/service-binding-operator/pkg/client/kubernetes
|
||||
github.com/redhat-developer/service-binding-operator/pkg/converter
|
||||
github.com/redhat-developer/service-binding-operator/pkg/naming
|
||||
github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline
|
||||
github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/builder
|
||||
github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/context
|
||||
github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/handler/collect
|
||||
github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/handler/mapping
|
||||
github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/handler/naming
|
||||
github.com/redhat-developer/service-binding-operator/pkg/reconcile/pipeline/handler/project
|
||||
github.com/redhat-developer/service-binding-operator/pkg/util
|
||||
# github.com/russross/blackfriday v1.5.2
|
||||
github.com/russross/blackfriday
|
||||
# github.com/securego/gosec/v2 v2.8.0
|
||||
@@ -730,6 +744,8 @@ golang.org/x/tools/internal/typesinternal
|
||||
# golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
|
||||
golang.org/x/xerrors
|
||||
golang.org/x/xerrors/internal
|
||||
# gomodules.xyz/jsonpatch/v2 v2.1.0
|
||||
gomodules.xyz/jsonpatch/v2
|
||||
# google.golang.org/appengine v1.6.6
|
||||
google.golang.org/appengine
|
||||
google.golang.org/appengine/internal
|
||||
@@ -847,6 +863,7 @@ k8s.io/api/storage/v1beta1
|
||||
# k8s.io/apiextensions-apiserver v0.20.0
|
||||
k8s.io/apiextensions-apiserver/pkg/apis/apiextensions
|
||||
k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1
|
||||
k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1
|
||||
# k8s.io/apimachinery v0.20.1 => github.com/openshift/kubernetes-apimachinery v0.0.0-20210108114224-194a87c5b03a
|
||||
## explicit
|
||||
k8s.io/apimachinery/pkg/api/equality
|
||||
@@ -892,6 +909,7 @@ k8s.io/apimachinery/pkg/util/remotecommand
|
||||
k8s.io/apimachinery/pkg/util/runtime
|
||||
k8s.io/apimachinery/pkg/util/sets
|
||||
k8s.io/apimachinery/pkg/util/strategicpatch
|
||||
k8s.io/apimachinery/pkg/util/uuid
|
||||
k8s.io/apimachinery/pkg/util/validation
|
||||
k8s.io/apimachinery/pkg/util/validation/field
|
||||
k8s.io/apimachinery/pkg/util/wait
|
||||
@@ -1046,6 +1064,8 @@ k8s.io/client-go/tools/clientcmd
|
||||
k8s.io/client-go/tools/clientcmd/api
|
||||
k8s.io/client-go/tools/clientcmd/api/latest
|
||||
k8s.io/client-go/tools/clientcmd/api/v1
|
||||
k8s.io/client-go/tools/leaderelection
|
||||
k8s.io/client-go/tools/leaderelection/resourcelock
|
||||
k8s.io/client-go/tools/metrics
|
||||
k8s.io/client-go/tools/pager
|
||||
k8s.io/client-go/tools/portforward
|
||||
@@ -1066,6 +1086,8 @@ k8s.io/client-go/util/keyutil
|
||||
k8s.io/client-go/util/retry
|
||||
k8s.io/client-go/util/workqueue
|
||||
# k8s.io/component-base v0.20.1
|
||||
k8s.io/component-base/config
|
||||
k8s.io/component-base/config/v1alpha1
|
||||
k8s.io/component-base/metrics
|
||||
k8s.io/component-base/metrics/legacyregistry
|
||||
k8s.io/component-base/version
|
||||
@@ -1096,9 +1118,44 @@ k8s.io/utils/integer
|
||||
k8s.io/utils/pointer
|
||||
k8s.io/utils/trace
|
||||
# sigs.k8s.io/controller-runtime v0.7.0
|
||||
## explicit
|
||||
sigs.k8s.io/controller-runtime
|
||||
sigs.k8s.io/controller-runtime/pkg/builder
|
||||
sigs.k8s.io/controller-runtime/pkg/cache
|
||||
sigs.k8s.io/controller-runtime/pkg/cache/internal
|
||||
sigs.k8s.io/controller-runtime/pkg/client
|
||||
sigs.k8s.io/controller-runtime/pkg/client/apiutil
|
||||
sigs.k8s.io/controller-runtime/pkg/client/config
|
||||
sigs.k8s.io/controller-runtime/pkg/config
|
||||
sigs.k8s.io/controller-runtime/pkg/config/v1alpha1
|
||||
sigs.k8s.io/controller-runtime/pkg/controller
|
||||
sigs.k8s.io/controller-runtime/pkg/controller/controllerutil
|
||||
sigs.k8s.io/controller-runtime/pkg/conversion
|
||||
sigs.k8s.io/controller-runtime/pkg/event
|
||||
sigs.k8s.io/controller-runtime/pkg/handler
|
||||
sigs.k8s.io/controller-runtime/pkg/healthz
|
||||
sigs.k8s.io/controller-runtime/pkg/internal/controller
|
||||
sigs.k8s.io/controller-runtime/pkg/internal/controller/metrics
|
||||
sigs.k8s.io/controller-runtime/pkg/internal/log
|
||||
sigs.k8s.io/controller-runtime/pkg/internal/recorder
|
||||
sigs.k8s.io/controller-runtime/pkg/leaderelection
|
||||
sigs.k8s.io/controller-runtime/pkg/log
|
||||
sigs.k8s.io/controller-runtime/pkg/manager
|
||||
sigs.k8s.io/controller-runtime/pkg/manager/signals
|
||||
sigs.k8s.io/controller-runtime/pkg/metrics
|
||||
sigs.k8s.io/controller-runtime/pkg/predicate
|
||||
sigs.k8s.io/controller-runtime/pkg/ratelimiter
|
||||
sigs.k8s.io/controller-runtime/pkg/reconcile
|
||||
sigs.k8s.io/controller-runtime/pkg/recorder
|
||||
sigs.k8s.io/controller-runtime/pkg/runtime/inject
|
||||
sigs.k8s.io/controller-runtime/pkg/scheme
|
||||
sigs.k8s.io/controller-runtime/pkg/source
|
||||
sigs.k8s.io/controller-runtime/pkg/source/internal
|
||||
sigs.k8s.io/controller-runtime/pkg/webhook
|
||||
sigs.k8s.io/controller-runtime/pkg/webhook/admission
|
||||
sigs.k8s.io/controller-runtime/pkg/webhook/conversion
|
||||
sigs.k8s.io/controller-runtime/pkg/webhook/internal/certwatcher
|
||||
sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics
|
||||
# sigs.k8s.io/kustomize v2.0.3+incompatible
|
||||
sigs.k8s.io/kustomize/pkg/commands/build
|
||||
sigs.k8s.io/kustomize/pkg/constants
|
||||
|
||||
24
vendor/sigs.k8s.io/controller-runtime/.gitignore
generated
vendored
Normal file
24
vendor/sigs.k8s.io/controller-runtime/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, build with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# editor and IDE paraphernalia
|
||||
.idea
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
|
||||
# Vscode files
|
||||
.vscode
|
||||
|
||||
# Tools binaries.
|
||||
hack/tools/bin
|
||||
35
vendor/sigs.k8s.io/controller-runtime/.golangci.yml
generated
vendored
Normal file
35
vendor/sigs.k8s.io/controller-runtime/.golangci.yml
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
run:
|
||||
deadline: 5m
|
||||
linters-settings:
|
||||
lll:
|
||||
line-length: 170
|
||||
dupl:
|
||||
threshold: 400
|
||||
issues:
|
||||
# don't skip warning about doc comments
|
||||
exclude-use-default: false
|
||||
|
||||
# restore some of the defaults
|
||||
# (fill in the rest as needed)
|
||||
exclude-rules:
|
||||
- linters: [errcheck]
|
||||
text: "Error return value of .((os\\.)?std(out|err)\\..*|.*Close|.*Flush|os\\.Remove(All)?|.*printf?|os\\.(Un)?Setenv). is not checked"
|
||||
linters:
|
||||
disable-all: true
|
||||
enable:
|
||||
- misspell
|
||||
- structcheck
|
||||
- golint
|
||||
- govet
|
||||
- deadcode
|
||||
- errcheck
|
||||
- varcheck
|
||||
- goconst
|
||||
- unparam
|
||||
- ineffassign
|
||||
- nakedret
|
||||
- gocyclo
|
||||
- lll
|
||||
- dupl
|
||||
- goimports
|
||||
- golint
|
||||
19
vendor/sigs.k8s.io/controller-runtime/CONTRIBUTING.md
generated
vendored
Normal file
19
vendor/sigs.k8s.io/controller-runtime/CONTRIBUTING.md
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
# Contributing guidelines
|
||||
|
||||
## Sign the CLA
|
||||
|
||||
Kubernetes projects require that you sign a Contributor License Agreement (CLA) before we can accept your pull requests.
|
||||
|
||||
Please see https://git.k8s.io/community/CLA.md for more info
|
||||
|
||||
## Contributing steps
|
||||
|
||||
1. Submit an issue describing your proposed change to the repo in question.
|
||||
1. The [repo owners](OWNERS) will respond to your issue promptly.
|
||||
1. If your proposed change is accepted, and you haven't already done so, sign a Contributor License Agreement (see details above).
|
||||
1. Fork the desired repo, develop and test your code changes.
|
||||
1. Submit a pull request.
|
||||
|
||||
## Test locally
|
||||
|
||||
Run the command `make test` to test the changes locally.
|
||||
81
vendor/sigs.k8s.io/controller-runtime/FAQ.md
generated
vendored
Normal file
81
vendor/sigs.k8s.io/controller-runtime/FAQ.md
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
# FAQ
|
||||
|
||||
### Q: How do I know which type of object a controller references?
|
||||
|
||||
**A**: Each controller should only reconcile one object type. Other
|
||||
affected objects should be mapped to a single type of root object, using
|
||||
the `EnqueueRequestForOwner` or `EnqueueRequestsFromMapFunc` event
|
||||
handlers, and potentially indices. Then, your Reconcile method should
|
||||
attempt to reconcile *all* state for that given root objects.
|
||||
|
||||
### Q: How do I have different logic in my reconciler for different types of events (e.g. create, update, delete)?
|
||||
|
||||
**A**: You should not. Reconcile functions should be idempotent, and
|
||||
should always reconcile state by reading all the state it needs, then
|
||||
writing updates. This allows your reconciler to correctly respond to
|
||||
generic events, adjust to skipped or coalesced events, and easily deal
|
||||
with application startup. The controller will enqueue reconcile requests
|
||||
for both old and new objects if a mapping changes, but it's your
|
||||
responsibility to make sure you have enough information to be able clean
|
||||
up state that's no longer referenced.
|
||||
|
||||
### Q: My cache might be stale if I read from a cache! How should I deal with that?
|
||||
|
||||
**A**: There are several different approaches that can be taken, depending
|
||||
on your situation.
|
||||
|
||||
- When you can, take advantage of optimistic locking: use deterministic
|
||||
names for objects you create, so that the Kubernetes API server will
|
||||
warn you if the object already exists. Many controllers in Kubernetes
|
||||
take this approach: the StatefulSet controller appends a specific number
|
||||
to each pod that it creates, while the Deployment controller hashes the
|
||||
pod template spec and appends that.
|
||||
|
||||
- In the few cases when you cannot take advantage of deterministic names
|
||||
(e.g. when using generateName), it may be useful in to track which
|
||||
actions you took, and assume that they need to be repeated if they don't
|
||||
occur after a given time (e.g. using a requeue result). This is what
|
||||
the ReplicaSet controller does.
|
||||
|
||||
In general, write your controller with the assumption that information
|
||||
will eventually be correct, but may be slightly out of date. Make sure
|
||||
that your reconcile function enforces the entire state of the world each
|
||||
time it runs. If none of this works for you, you can always construct
|
||||
a client that reads directly from the API server, but this is generally
|
||||
considered to be a last resort, and the two approaches above should
|
||||
generally cover most circumstances.
|
||||
|
||||
### Q: Where's the fake client? How do I use it?
|
||||
|
||||
**A**: The fake client
|
||||
[exists](https://godoc.org/sigs.k8s.io/controller-runtime/pkg/client/fake),
|
||||
but we generally recommend using
|
||||
[envtest.Environment](https://godoc.org/sigs.k8s.io/controller-runtime/pkg/envtest#Environment)
|
||||
to test against a real API server. In our experience, tests using fake
|
||||
clients gradually re-implement poorly-written impressions of a real API
|
||||
server, which leads to hard-to-maintain, complex test code.
|
||||
|
||||
### Q: How should I write tests? Any suggestions for getting started?
|
||||
|
||||
- Use the aforementioned
|
||||
[envtest.Environment](https://godoc.org/sigs.k8s.io/controller-runtime/pkg/envtest#Environment)
|
||||
to spin up a real API server instead of trying to mock one out.
|
||||
|
||||
- Structure your tests to check that the state of the world is as you
|
||||
expect it, *not* that a particular set of API calls were made, when
|
||||
working with Kubernetes APIs. This will allow you to more easily
|
||||
refactor and improve the internals of your controllers without changing
|
||||
your tests.
|
||||
|
||||
- Remember that any time you're interacting with the API server, changes
|
||||
may have some delay between write time and reconcile time.
|
||||
|
||||
### Q: What are these errors about no Kind being registered for a type?
|
||||
|
||||
**A**: You're probably missing a fully-set-up Scheme. Schemes record the
|
||||
mapping between Go types and group-version-kinds in Kubernetes. In
|
||||
general, your application should have its own Scheme containing the types
|
||||
from the API groups that it needs (be they Kubernetes types or your own).
|
||||
See the [scheme builder
|
||||
docs](https://godoc.org/sigs.k8s.io/controller-runtime/pkg/scheme) for
|
||||
more information.
|
||||
110
vendor/sigs.k8s.io/controller-runtime/Makefile
generated
vendored
Normal file
110
vendor/sigs.k8s.io/controller-runtime/Makefile
generated
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright 2020 The Kubernetes Authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# If you update this file, please follow
|
||||
# https://suva.sh/posts/well-documented-makefiles
|
||||
|
||||
## --------------------------------------
|
||||
## General
|
||||
## --------------------------------------
|
||||
|
||||
SHELL:=/usr/bin/env bash
|
||||
.DEFAULT_GOAL:=help
|
||||
|
||||
# Use GOPROXY environment variable if set
|
||||
GOPROXY := $(shell go env GOPROXY)
|
||||
ifeq ($(GOPROXY),)
|
||||
GOPROXY := https://proxy.golang.org
|
||||
endif
|
||||
export GOPROXY
|
||||
|
||||
# Active module mode, as we use go modules to manage dependencies
|
||||
export GO111MODULE=on
|
||||
|
||||
# Tools.
|
||||
TOOLS_DIR := hack/tools
|
||||
TOOLS_BIN_DIR := $(TOOLS_DIR)/bin
|
||||
GOLANGCI_LINT := $(abspath $(TOOLS_BIN_DIR)/golangci-lint)
|
||||
GO_APIDIFF := $(TOOLS_BIN_DIR)/go-apidiff
|
||||
CONTROLLER_GEN := $(TOOLS_BIN_DIR)/controller-gen
|
||||
|
||||
# The help will print out all targets with their descriptions organized bellow their categories. The categories are represented by `##@` and the target descriptions by `##`.
|
||||
# The awk commands is responsible to read the entire set of makefiles included in this invocation, looking for lines of the file as xyz: ## something, and then pretty-format the target and help. Then, if there's a line with ##@ something, that gets pretty-printed as a category.
|
||||
# More info over the usage of ANSI control characters for terminal formatting: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters
|
||||
# More info over awk command: http://linuxcommand.org/lc3_adv_awk.php
|
||||
.PHONY: help
|
||||
help: ## Display this help
|
||||
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
|
||||
|
||||
## --------------------------------------
|
||||
## Testing
|
||||
## --------------------------------------
|
||||
|
||||
.PHONY: test
|
||||
test: ## Run the script check-everything.sh which will check all.
|
||||
TRACE=1 ./hack/check-everything.sh
|
||||
|
||||
## --------------------------------------
|
||||
## Binaries
|
||||
## --------------------------------------
|
||||
|
||||
$(GOLANGCI_LINT): $(TOOLS_DIR)/go.mod # Build golangci-lint from tools folder.
|
||||
cd $(TOOLS_DIR) && go build -tags=tools -o bin/golangci-lint github.com/golangci/golangci-lint/cmd/golangci-lint
|
||||
|
||||
$(GO_APIDIFF): $(TOOLS_DIR)/go.mod # Build go-apidiff from tools folder.
|
||||
cd $(TOOLS_DIR) && go build -tags=tools -o bin/go-apidiff github.com/joelanford/go-apidiff
|
||||
|
||||
$(CONTROLLER_GEN): $(TOOLS_DIR)/go.mod # Build controller-gen from tools folder.
|
||||
cd $(TOOLS_DIR) && go build -tags=tools -o bin/controller-gen sigs.k8s.io/controller-tools/cmd/controller-gen
|
||||
|
||||
## --------------------------------------
|
||||
## Linting
|
||||
## --------------------------------------
|
||||
|
||||
.PHONY: lint
|
||||
lint: $(GOLANGCI_LINT) ## Lint codebase.
|
||||
$(GOLANGCI_LINT) run -v
|
||||
|
||||
## --------------------------------------
|
||||
## Generate
|
||||
## --------------------------------------
|
||||
|
||||
.PHONY: modules
|
||||
modules: ## Runs go mod to ensure modules are up to date.
|
||||
go mod tidy
|
||||
cd $(TOOLS_DIR); go mod tidy
|
||||
|
||||
.PHONY: generate
|
||||
generate: $(CONTROLLER_GEN) ## Runs controller-gen for internal types for config file
|
||||
$(CONTROLLER_GEN) object paths="./pkg/config/v1alpha1/...;./examples/configfile/custom/v1alpha1/..."
|
||||
|
||||
## --------------------------------------
|
||||
## Cleanup / Verification
|
||||
## --------------------------------------
|
||||
|
||||
.PHONY: clean
|
||||
clean: ## Cleanup.
|
||||
$(MAKE) clean-bin
|
||||
|
||||
.PHONY: clean-bin
|
||||
clean-bin: ## Remove all generated binaries.
|
||||
rm -rf hack/tools/bin
|
||||
|
||||
.PHONY: verify-modules
|
||||
verify-modules: modules
|
||||
@if !(git diff --quiet HEAD -- go.sum go.mod); then \
|
||||
echo "go module files are out of date, please run 'make modules'"; exit 1; \
|
||||
fi
|
||||
10
vendor/sigs.k8s.io/controller-runtime/OWNERS
generated
vendored
Normal file
10
vendor/sigs.k8s.io/controller-runtime/OWNERS
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
# See the OWNERS docs: https://git.k8s.io/community/contributors/guide/owners.md
|
||||
|
||||
approvers:
|
||||
- controller-runtime-admins
|
||||
- controller-runtime-maintainers
|
||||
- controller-runtime-approvers
|
||||
reviewers:
|
||||
- controller-runtime-admins
|
||||
- controller-runtime-reviewers
|
||||
- controller-runtime-approvers
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user