Auto-update dependencies (#121)

Produced via:
  `dep ensure -update knative.dev/test-infra knative.dev/pkg`
/assign mattmoor
This commit is contained in:
mattmoor-sockpuppet 2019-10-25 13:10:35 -07:00 committed by Knative Prow Robot
parent 9075f22c2a
commit ab9eaf9151
5 changed files with 185 additions and 140 deletions

6
Gopkg.lock generated
View File

@ -933,7 +933,7 @@
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:70af147aaa464fa6248d55e038e1db0d7c70ff6a7a2226c33b5f0d6bf820193b" digest = "1:d91a27f79bca7f71b57bdc3581542d646c90dca75862c38d21ad7b1aca6c22aa"
name = "knative.dev/pkg" name = "knative.dev/pkg"
packages = [ packages = [
"apis", "apis",
@ -952,7 +952,7 @@
"metrics/metricskey", "metrics/metricskey",
] ]
pruneopts = "T" pruneopts = "T"
revision = "f684a1078ac309f4b32e6240d9b622bea092296e" revision = "cad41c40ccb5a40de7a3b65097649703c8d96e0b"
[[projects]] [[projects]]
branch = "master" branch = "master"
@ -963,7 +963,7 @@
"tools/dep-collector", "tools/dep-collector",
] ]
pruneopts = "UT" pruneopts = "UT"
revision = "385c6ecc17489d72a2e0927d4552bcdc1f0d08e0" revision = "75f9d5135b8f823b6a663fe49f00dbc498b6ad33"
[[projects]] [[projects]]
digest = "1:8730e0150dfb2b7e173890c8b9868e7a273082ef8e39f4940e3506a481cf895c" digest = "1:8730e0150dfb2b7e173890c8b9868e7a273082ef8e39f4940e3506a481cf895c"

View File

@ -0,0 +1,95 @@
# Duck Types
Knative leverages duck-typing to interact with resources inside of Kubernetes
without explicit knowlage of the full resource shape. `knative/pkg` defines two
duck types that are used throughout Knative: `Addressable` and `Source`.
For APIs leveraging `ObjectReference`, the context of the resource in question
identifies the duck-type. To enable the case where no `ObjectRefrence` is used,
we have labeled the Custom Resource Definition with the duck-type. Those labels
are as follows:
| Label | Duck-Type |
| ----------------------------------- | ----------------------------------------------------------------------------- |
| `duck.knative.dev/addressable=true` | [Addressable](https://godoc.org/knative.dev/pkg/apis/duck/v1#AddressableType) |
| `duck.knative.dev/source=true` | [Source](https://godoc.org/knative.dev/pkg/apis/duck/v1#Source) |
## Addressable Shape
Addressable is expected to be the following shape:
```yaml
apiVersion: group/version
kind: Kind
status:
address:
url: http://host/path?query
```
## Source Shape
Source is expected to be in the following shape:
(with ref sink)
```yaml
apiVersion: group/version
kind: Kind
spec:
sink:
ref:
apiVersion: group/version
kind: AnAddressableKind
name: a-name
ceOverrides:
extensions:
key: value
status:
observedGeneration: 1
conditions:
- type: Ready
status: "True"
sinkUri: http://host
```
(with uri sink)
```yaml
apiVersion: group/version
kind: Kind
spec:
sink:
uri: http://host/path?query
ceOverrides:
extensions:
key: value
status:
observedGeneration: 1
conditions:
- type: Ready
status: "True"
sinkUri: http://host/path?query
```
(with ref and uri sink)
```yaml
apiVersion: group/version
kind: Kind
spec:
sink:
ref:
apiVersion: group/version
kind: AnAddressableKind
name: a-name
uri: /path?query
ceOverrides:
extensions:
key: value
status:
observedGeneration: 1
conditions:
- type: Ready
status: "True"
sinkUri: http://host/path?query
```

View File

@ -22,13 +22,10 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"reflect" "reflect"
"strings"
"github.com/markbates/inflect"
admissionv1beta1 "k8s.io/api/admission/v1beta1" admissionv1beta1 "k8s.io/api/admission/v1beta1"
admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1" admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes"
@ -36,6 +33,7 @@ import (
"knative.dev/pkg/configmap" "knative.dev/pkg/configmap"
"knative.dev/pkg/kmp" "knative.dev/pkg/kmp"
"knative.dev/pkg/logging" "knative.dev/pkg/logging"
"knative.dev/pkg/ptr"
) )
// ConfigValidationController implements the AdmissionController for ConfigMaps // ConfigValidationController implements the AdmissionController for ConfigMaps
@ -81,84 +79,53 @@ func (ac *ConfigValidationController) Admit(ctx context.Context, request *admiss
func (ac *ConfigValidationController) Register(ctx context.Context, kubeClient kubernetes.Interface, caCert []byte) error { func (ac *ConfigValidationController) Register(ctx context.Context, kubeClient kubernetes.Interface, caCert []byte) error {
client := kubeClient.AdmissionregistrationV1beta1().ValidatingWebhookConfigurations() client := kubeClient.AdmissionregistrationV1beta1().ValidatingWebhookConfigurations()
logger := logging.FromContext(ctx) logger := logging.FromContext(ctx)
failurePolicy := admissionregistrationv1beta1.Fail
resourceGVK := corev1.SchemeGroupVersion.WithKind("ConfigMap")
var rules []admissionregistrationv1beta1.RuleWithOperations
plural := strings.ToLower(inflect.Pluralize(resourceGVK.Kind))
ruleScope := admissionregistrationv1beta1.NamespacedScope ruleScope := admissionregistrationv1beta1.NamespacedScope
rules = append(rules, admissionregistrationv1beta1.RuleWithOperations{ rules := []admissionregistrationv1beta1.RuleWithOperations{{
Operations: []admissionregistrationv1beta1.OperationType{ Operations: []admissionregistrationv1beta1.OperationType{
admissionregistrationv1beta1.Create, admissionregistrationv1beta1.Create,
admissionregistrationv1beta1.Update, admissionregistrationv1beta1.Update,
}, },
Rule: admissionregistrationv1beta1.Rule{ Rule: admissionregistrationv1beta1.Rule{
APIGroups: []string{resourceGVK.Group}, APIGroups: []string{""},
APIVersions: []string{resourceGVK.Version}, APIVersions: []string{"v1"},
Resources: []string{plural + "/*"}, Resources: []string{"configmaps/*"},
Scope: &ruleScope, Scope: &ruleScope,
}, },
}) }}
webhook := &admissionregistrationv1beta1.ValidatingWebhookConfiguration{ configuredWebhook, err := client.Get(ac.options.ConfigValidationWebhookName, metav1.GetOptions{})
ObjectMeta: metav1.ObjectMeta{ if err != nil {
Name: ac.options.ConfigValidationWebhookName, return fmt.Errorf("error retrieving webhook: %v", err)
},
Webhooks: []admissionregistrationv1beta1.ValidatingWebhook{{
Name: ac.options.ConfigValidationWebhookName,
Rules: rules,
ClientConfig: admissionregistrationv1beta1.WebhookClientConfig{
Service: &admissionregistrationv1beta1.ServiceReference{
Namespace: ac.options.Namespace,
Name: ac.options.ServiceName,
Path: &ac.options.ConfigValidationControllerPath,
},
CABundle: caCert,
},
NamespaceSelector: &metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{{
Key: ac.options.ConfigValidationNamespaceLabel,
Operator: metav1.LabelSelectorOpExists,
}},
},
FailurePolicy: &failurePolicy,
}},
} }
// Set the owner to our deployment. webhook := configuredWebhook.DeepCopy()
deployment, err := kubeClient.AppsV1().Deployments(ac.options.Namespace).Get(ac.options.DeploymentName, metav1.GetOptions{})
if err != nil {
return fmt.Errorf("failed to fetch our deployment: %v", err)
}
deploymentRef := metav1.NewControllerRef(deployment, deploymentKind)
webhook.OwnerReferences = append(webhook.OwnerReferences, *deploymentRef)
// Try to create the webhook and if it already exists validate webhook rules. // Clear out any previous (bad) OwnerReferences.
_, err = client.Create(webhook) // See: https://github.com/knative/serving/issues/5845
if err != nil { webhook.OwnerReferences = nil
if !apierrors.IsAlreadyExists(err) {
return fmt.Errorf("failed to create a webhook: %v", err) for i, wh := range webhook.Webhooks {
if wh.Name != webhook.Name {
continue
} }
logger.Info("Webhook already exists") webhook.Webhooks[i].Rules = rules
configuredWebhook, err := client.Get(ac.options.ConfigValidationWebhookName, metav1.GetOptions{}) webhook.Webhooks[i].ClientConfig.CABundle = caCert
if err != nil { if webhook.Webhooks[i].ClientConfig.Service == nil {
return fmt.Errorf("error retrieving webhook: %v", err) return fmt.Errorf("missing service reference for webhook: %s", wh.Name)
} }
if ok, err := kmp.SafeEqual(configuredWebhook.Webhooks, webhook.Webhooks); err != nil { webhook.Webhooks[i].ClientConfig.Service.Path = ptr.String(ac.options.ConfigValidationControllerPath)
return fmt.Errorf("error diffing webhooks: %v", err) }
} else if !ok {
logger.Info("Updating webhook") if ok, err := kmp.SafeEqual(configuredWebhook, webhook); err != nil {
// Set the ResourceVersion as required by update. return fmt.Errorf("error diffing webhooks: %v", err)
webhook.ObjectMeta.ResourceVersion = configuredWebhook.ObjectMeta.ResourceVersion } else if !ok {
if _, err := client.Update(webhook); err != nil { logger.Info("Updating webhook")
return fmt.Errorf("failed to update webhook: %s", err) if _, err := client.Update(webhook); err != nil {
} return fmt.Errorf("failed to update webhook: %v", err)
} else {
logger.Info("Webhook is already valid")
} }
} else { } else {
logger.Info("Created a webhook") logger.Info("Webhook is valid")
} }
return nil return nil

View File

@ -32,7 +32,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes"
@ -40,6 +39,7 @@ import (
"knative.dev/pkg/apis/duck" "knative.dev/pkg/apis/duck"
"knative.dev/pkg/kmp" "knative.dev/pkg/kmp"
"knative.dev/pkg/logging" "knative.dev/pkg/logging"
"knative.dev/pkg/ptr"
) )
// ResourceCallback defines a signature for resource specific (Route, Configuration, etc.) // ResourceCallback defines a signature for resource specific (Route, Configuration, etc.)
@ -108,7 +108,6 @@ func (ac *ResourceAdmissionController) Admit(ctx context.Context, request *admis
func (ac *ResourceAdmissionController) Register(ctx context.Context, kubeClient kubernetes.Interface, caCert []byte) error { func (ac *ResourceAdmissionController) Register(ctx context.Context, kubeClient kubernetes.Interface, caCert []byte) error {
client := kubeClient.AdmissionregistrationV1beta1().MutatingWebhookConfigurations() client := kubeClient.AdmissionregistrationV1beta1().MutatingWebhookConfigurations()
logger := logging.FromContext(ctx) logger := logging.FromContext(ctx)
failurePolicy := admissionregistrationv1beta1.Fail
var rules []admissionregistrationv1beta1.RuleWithOperations var rules []admissionregistrationv1beta1.RuleWithOperations
for gvk := range ac.handlers { for gvk := range ac.handlers {
@ -139,58 +138,39 @@ func (ac *ResourceAdmissionController) Register(ctx context.Context, kubeClient
return lhs.Resources[0] < rhs.Resources[0] return lhs.Resources[0] < rhs.Resources[0]
}) })
webhook := &admissionregistrationv1beta1.MutatingWebhookConfiguration{ configuredWebhook, err := client.Get(ac.options.ResourceMutatingWebhookName, metav1.GetOptions{})
ObjectMeta: metav1.ObjectMeta{ if err != nil {
Name: ac.options.ResourceMutatingWebhookName, return fmt.Errorf("error retrieving webhook: %v", err)
},
Webhooks: []admissionregistrationv1beta1.MutatingWebhook{{
Name: ac.options.ResourceMutatingWebhookName,
Rules: rules,
ClientConfig: admissionregistrationv1beta1.WebhookClientConfig{
Service: &admissionregistrationv1beta1.ServiceReference{
Namespace: ac.options.Namespace,
Name: ac.options.ServiceName,
Path: &ac.options.ResourceAdmissionControllerPath,
},
CABundle: caCert,
},
FailurePolicy: &failurePolicy,
}},
} }
// Set the owner to our deployment. webhook := configuredWebhook.DeepCopy()
deployment, err := kubeClient.AppsV1().Deployments(ac.options.Namespace).Get(ac.options.DeploymentName, metav1.GetOptions{})
if err != nil {
return fmt.Errorf("failed to fetch our deployment: %v", err)
}
deploymentRef := metav1.NewControllerRef(deployment, deploymentKind)
webhook.OwnerReferences = append(webhook.OwnerReferences, *deploymentRef)
// Try to create the webhook and if it already exists validate webhook rules. // Clear out any previous (bad) OwnerReferences.
_, err = client.Create(webhook) // See: https://github.com/knative/serving/issues/5845
if err != nil { webhook.OwnerReferences = nil
if !apierrors.IsAlreadyExists(err) {
return fmt.Errorf("failed to create a webhook: %v", err) for i, wh := range webhook.Webhooks {
if wh.Name != webhook.Name {
continue
} }
logger.Info("Webhook already exists") webhook.Webhooks[i].Rules = rules
configuredWebhook, err := client.Get(ac.options.ResourceMutatingWebhookName, metav1.GetOptions{}) webhook.Webhooks[i].ClientConfig.CABundle = caCert
if err != nil { if webhook.Webhooks[i].ClientConfig.Service == nil {
return fmt.Errorf("error retrieving webhook: %v", err) return fmt.Errorf("missing service reference for webhook: %s", wh.Name)
} }
if ok, err := kmp.SafeEqual(configuredWebhook.Webhooks, webhook.Webhooks); err != nil { webhook.Webhooks[i].ClientConfig.Service.Path = ptr.String(
return fmt.Errorf("error diffing webhooks: %v", err) ac.options.ResourceAdmissionControllerPath)
} else if !ok { }
logger.Info("Updating webhook")
// Set the ResourceVersion as required by update. if ok, err := kmp.SafeEqual(configuredWebhook, webhook); err != nil {
webhook.ObjectMeta.ResourceVersion = configuredWebhook.ObjectMeta.ResourceVersion return fmt.Errorf("error diffing webhooks: %v", err)
if _, err := client.Update(webhook); err != nil { } else if !ok {
return fmt.Errorf("failed to update webhook: %s", err) logger.Info("Updating webhook")
} if _, err := client.Update(webhook); err != nil {
} else { return fmt.Errorf("failed to update webhook: %v", err)
logger.Info("Webhook is already valid")
} }
} else { } else {
logger.Info("Created a webhook") logger.Info("Webhook is valid")
} }
return nil return nil
} }

View File

@ -27,12 +27,11 @@ import (
"time" "time"
"go.uber.org/zap" "go.uber.org/zap"
"golang.org/x/sync/errgroup"
"knative.dev/pkg/logging" "knative.dev/pkg/logging"
"knative.dev/pkg/logging/logkey" "knative.dev/pkg/logging/logkey"
admissionv1beta1 "k8s.io/api/admission/v1beta1" admissionv1beta1 "k8s.io/api/admission/v1beta1"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors" apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -46,7 +45,6 @@ const (
) )
var ( var (
deploymentKind = appsv1.SchemeGroupVersion.WithKind("Deployment")
errMissingNewObject = errors.New("the new object may not be nil") errMissingNewObject = errors.New("the new object may not be nil")
) )
@ -63,9 +61,6 @@ type ControllerOptions struct {
// ServiceName is the service name of the webhook. // ServiceName is the service name of the webhook.
ServiceName string ServiceName string
// DeploymentName is the service name of the webhook.
DeploymentName string
// SecretName is the name of k8s secret that contains the webhook // SecretName is the name of k8s secret that contains the webhook
// server key/cert and corresponding CA cert that signed them. The // server key/cert and corresponding CA cert that signed them. The
// server key/cert are used to serve the webhook and the CA cert // server key/cert are used to serve the webhook and the CA cert
@ -103,9 +98,6 @@ type ControllerOptions struct {
// Service path for ConfigValidationController webhook // Service path for ConfigValidationController webhook
// Default is "/config-validation" and is set by the constructor // Default is "/config-validation" and is set by the constructor
ConfigValidationControllerPath string ConfigValidationControllerPath string
// NamespaceLabel is the label for the Namespace we bind ConfigValidationController to
ConfigValidationNamespaceLabel string
} }
// AdmissionController provides the interface for different admission controllers // AdmissionController provides the interface for different admission controllers
@ -172,32 +164,43 @@ func (ac *Webhook) Run(stop <-chan struct{}) error {
logger.Infof("Delaying admission webhook registration for %v", ac.Options.RegistrationDelay) logger.Infof("Delaying admission webhook registration for %v", ac.Options.RegistrationDelay)
} }
select { eg, ctx := errgroup.WithContext(ctx)
case <-time.After(ac.Options.RegistrationDelay): eg.Go(func() error {
for _, c := range ac.admissionControllers { select {
if err := c.Register(ctx, ac.Client, caCert); err != nil { case <-time.After(ac.Options.RegistrationDelay):
logger.Errorw("failed to register webhook", zap.Error(err)) // Wait an initial delay before registering
return err case <-stop:
return nil
}
// Register the webhook, and then periodically check that it is up to date.
for {
for _, c := range ac.admissionControllers {
if err := c.Register(ctx, ac.Client, caCert); err != nil {
logger.Errorw("failed to register webhook", zap.Error(err))
return err
}
}
logger.Info("Successfully registered webhook")
select {
case <-time.After(10 * time.Minute):
case <-stop:
return nil
} }
} }
logger.Info("Successfully registered webhook") })
case <-stop: eg.Go(func() error {
return nil
}
serverBootstrapErrCh := make(chan struct{})
go func() {
if err := server.ListenAndServeTLS("", ""); err != nil { if err := server.ListenAndServeTLS("", ""); err != nil {
logger.Errorw("ListenAndServeTLS for admission webhook returned error", zap.Error(err)) logger.Errorw("ListenAndServeTLS for admission webhook returned error", zap.Error(err))
close(serverBootstrapErrCh) return err
} }
}() return nil
})
select { select {
case <-stop: case <-stop:
return server.Close() return server.Close()
case <-serverBootstrapErrCh: case <-ctx.Done():
return errors.New("webhook server bootstrap failed") return fmt.Errorf("webhook server bootstrap failed %v", err)
} }
} }