github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/caas/kubernetes/provider/specs/admissionregistration_test.go (about)

     1  // Copyright 2021 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package specs_test
     5  
     6  import (
     7  	"encoding/base64"
     8  	"strings"
     9  
    10  	jc "github.com/juju/testing/checkers"
    11  	gc "gopkg.in/check.v1"
    12  	admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1"
    13  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    14  	"k8s.io/utils/pointer"
    15  
    16  	k8sspecs "github.com/juju/juju/caas/kubernetes/provider/specs"
    17  	"github.com/juju/juju/testing"
    18  )
    19  
    20  type webhooksSuite struct {
    21  	testing.BaseSuite
    22  }
    23  
    24  var _ = gc.Suite(&webhooksSuite{})
    25  
    26  func (s *webhooksSuite) TestK8sMutatingWebhookV1Beta1(c *gc.C) {
    27  	specV1Beta1 := `
    28  name: example-mutatingwebhookconfiguration
    29  labels:
    30    foo: bar
    31  annotations:
    32    juju.io/disable-name-prefix: "true"
    33  webhooks:
    34    - name: "example.mutatingwebhookconfiguration.com"
    35      failurePolicy: Ignore
    36      clientConfig:
    37        service:
    38          name: apple-service
    39          namespace: apples
    40          path: /apple
    41        caBundle: "YXBwbGVz"
    42      namespaceSelector:
    43        matchExpressions:
    44          - key: production
    45            operator: DoesNotExist
    46      rules:
    47        - apiGroups:
    48            - ""
    49          apiVersions:
    50            - v1
    51          operations:
    52            - CREATE
    53            - UPDATE
    54          resources:
    55            - pods
    56  `
    57  	var obj k8sspecs.K8sMutatingWebhook
    58  	err := k8sspecs.NewStrictYAMLOrJSONDecoder(strings.NewReader(specV1Beta1), len(specV1Beta1)).Decode(&obj)
    59  	c.Assert(err, jc.ErrorIsNil)
    60  
    61  	webhookFailurePolicy1 := admissionregistrationv1beta1.Ignore
    62  	CABundle, err := base64.StdEncoding.DecodeString("YXBwbGVz")
    63  	c.Assert(err, jc.ErrorIsNil)
    64  	c.Assert(obj, gc.DeepEquals, k8sspecs.K8sMutatingWebhook{
    65  		Meta: k8sspecs.Meta{
    66  			Name:        "example-mutatingwebhookconfiguration",
    67  			Labels:      map[string]string{"foo": "bar"},
    68  			Annotations: map[string]string{"juju.io/disable-name-prefix": "true"},
    69  		},
    70  		Webhooks: []k8sspecs.K8sMutatingWebhookSpec{
    71  			{
    72  				Version: k8sspecs.K8sWebhookV1Beta1,
    73  				SpecV1Beta1: admissionregistrationv1beta1.MutatingWebhook{
    74  					Name:          "example.mutatingwebhookconfiguration.com",
    75  					FailurePolicy: &webhookFailurePolicy1,
    76  					ClientConfig: admissionregistrationv1beta1.WebhookClientConfig{
    77  						Service: &admissionregistrationv1beta1.ServiceReference{
    78  							Name:      "apple-service",
    79  							Namespace: "apples",
    80  							Path:      pointer.StringPtr("/apple"),
    81  						},
    82  						CABundle: CABundle,
    83  					},
    84  					NamespaceSelector: &metav1.LabelSelector{
    85  						MatchExpressions: []metav1.LabelSelectorRequirement{
    86  							{Key: "production", Operator: metav1.LabelSelectorOpDoesNotExist},
    87  						},
    88  					},
    89  					Rules: []admissionregistrationv1beta1.RuleWithOperations{
    90  						{
    91  							Operations: []admissionregistrationv1beta1.OperationType{
    92  								admissionregistrationv1beta1.Create,
    93  								admissionregistrationv1beta1.Update,
    94  							},
    95  							Rule: admissionregistrationv1beta1.Rule{
    96  								APIGroups:   []string{""},
    97  								APIVersions: []string{"v1"},
    98  								Resources:   []string{"pods"},
    99  							},
   100  						},
   101  					},
   102  				},
   103  			},
   104  		},
   105  	})
   106  }
   107  
   108  func (s *webhooksSuite) TestK8sMutatingWebhookV1(c *gc.C) {
   109  	specV1 := `
   110  name: example-mutatingwebhookconfiguration
   111  labels:
   112    foo: bar
   113  annotations:
   114    juju.io/disable-name-prefix: "true"
   115  webhooks:
   116    - name: "example.mutatingwebhookconfiguration.com"
   117      failurePolicy: Ignore
   118      clientConfig:
   119        service:
   120          name: apple-service
   121          namespace: apples
   122          path: /apple
   123        caBundle: "YXBwbGVz"
   124      namespaceSelector:
   125        matchExpressions:
   126          - key: production
   127            operator: DoesNotExist
   128      rules:
   129        - apiGroups:
   130            - ""
   131          apiVersions:
   132            - v1
   133          operations:
   134            - CREATE
   135            - UPDATE
   136          resources:
   137            - pods
   138  `
   139  	var obj k8sspecs.K8sMutatingWebhook
   140  	err := k8sspecs.NewStrictYAMLOrJSONDecoder(strings.NewReader(specV1), len(specV1)).Decode(&obj)
   141  	c.Assert(err, jc.ErrorIsNil)
   142  
   143  	webhookFailurePolicy1 := admissionregistrationv1beta1.Ignore
   144  	CABundle, err := base64.StdEncoding.DecodeString("YXBwbGVz")
   145  	c.Assert(err, jc.ErrorIsNil)
   146  	c.Assert(obj, gc.DeepEquals, k8sspecs.K8sMutatingWebhook{
   147  		Meta: k8sspecs.Meta{
   148  			Name:        "example-mutatingwebhookconfiguration",
   149  			Labels:      map[string]string{"foo": "bar"},
   150  			Annotations: map[string]string{"juju.io/disable-name-prefix": "true"},
   151  		},
   152  		Webhooks: []k8sspecs.K8sMutatingWebhookSpec{
   153  			{
   154  				Version: k8sspecs.K8sWebhookV1Beta1,
   155  				SpecV1Beta1: admissionregistrationv1beta1.MutatingWebhook{
   156  					Name:          "example.mutatingwebhookconfiguration.com",
   157  					FailurePolicy: &webhookFailurePolicy1,
   158  					ClientConfig: admissionregistrationv1beta1.WebhookClientConfig{
   159  						Service: &admissionregistrationv1beta1.ServiceReference{
   160  							Name:      "apple-service",
   161  							Namespace: "apples",
   162  							Path:      pointer.StringPtr("/apple"),
   163  						},
   164  						CABundle: CABundle,
   165  					},
   166  					NamespaceSelector: &metav1.LabelSelector{
   167  						MatchExpressions: []metav1.LabelSelectorRequirement{
   168  							{Key: "production", Operator: metav1.LabelSelectorOpDoesNotExist},
   169  						},
   170  					},
   171  					Rules: []admissionregistrationv1beta1.RuleWithOperations{
   172  						{
   173  							Operations: []admissionregistrationv1beta1.OperationType{
   174  								admissionregistrationv1beta1.Create,
   175  								admissionregistrationv1beta1.Update,
   176  							},
   177  							Rule: admissionregistrationv1beta1.Rule{
   178  								APIGroups:   []string{""},
   179  								APIVersions: []string{"v1"},
   180  								Resources:   []string{"pods"},
   181  							},
   182  						},
   183  					},
   184  				},
   185  			},
   186  		},
   187  	})
   188  }
   189  
   190  func (s *webhooksSuite) TestK8sMutatingWebhookInvalid(c *gc.C) {
   191  	spec := `
   192  name: example-mutatingwebhookconfiguration
   193  labels:
   194    foo: bar
   195  annotations:
   196    juju.io/disable-name-prefix: "true"
   197  `
   198  	var obj k8sspecs.K8sMutatingWebhook
   199  	err := k8sspecs.NewStrictYAMLOrJSONDecoder(strings.NewReader(spec), len(spec)).Decode(&obj)
   200  	c.Assert(err, jc.ErrorIsNil)
   201  	c.Assert(obj.Validate(), gc.ErrorMatches, `empty webhooks "example-mutatingwebhookconfiguration" not valid`)
   202  }
   203  
   204  func (s *webhooksSuite) TestK8sValidatingWebhookV1Beta1(c *gc.C) {
   205  
   206  	specV1Beta1 := `
   207  name: pod-policy.example.com
   208  labels:
   209    foo: bar
   210  annotations:
   211    juju.io/disable-name-prefix: "true"
   212  webhooks:
   213    - name: "pod-policy.example.com"
   214      rules:
   215        - apiGroups: [""]
   216          apiVersions: ["v1"]
   217          operations: ["CREATE"]
   218          resources: ["pods"]
   219          scope: "Namespaced"
   220      clientConfig:
   221        service:
   222          namespace: "example-namespace"
   223          name: "example-service"
   224        caBundle: "YXBwbGVz"
   225      admissionReviewVersions: ["v1", "v1beta1"]
   226      sideEffects: None
   227      timeoutSeconds: 5
   228  `
   229  	var obj k8sspecs.K8sValidatingWebhook
   230  	err := k8sspecs.NewStrictYAMLOrJSONDecoder(strings.NewReader(specV1Beta1), len(specV1Beta1)).Decode(&obj)
   231  	c.Assert(err, jc.ErrorIsNil)
   232  
   233  	CABundle, err := base64.StdEncoding.DecodeString("YXBwbGVz")
   234  	c.Assert(err, jc.ErrorIsNil)
   235  	scope := admissionregistrationv1beta1.NamespacedScope
   236  	sideEffects := admissionregistrationv1beta1.SideEffectClassNone
   237  	c.Assert(obj, gc.DeepEquals, k8sspecs.K8sValidatingWebhook{
   238  		Meta: k8sspecs.Meta{
   239  			Name:        "pod-policy.example.com",
   240  			Labels:      map[string]string{"foo": "bar"},
   241  			Annotations: map[string]string{"juju.io/disable-name-prefix": "true"},
   242  		},
   243  		Webhooks: []k8sspecs.K8sValidatingWebhookSpec{
   244  			{
   245  				Version: k8sspecs.K8sWebhookV1Beta1,
   246  				SpecV1Beta1: admissionregistrationv1beta1.ValidatingWebhook{
   247  					Name: "pod-policy.example.com",
   248  					Rules: []admissionregistrationv1beta1.RuleWithOperations{
   249  						{
   250  							Operations: []admissionregistrationv1beta1.OperationType{
   251  								admissionregistrationv1beta1.Create,
   252  							},
   253  							Rule: admissionregistrationv1beta1.Rule{
   254  								APIGroups:   []string{""},
   255  								APIVersions: []string{"v1"},
   256  								Resources:   []string{"pods"},
   257  								Scope:       &scope,
   258  							},
   259  						},
   260  					},
   261  					ClientConfig: admissionregistrationv1beta1.WebhookClientConfig{
   262  						Service: &admissionregistrationv1beta1.ServiceReference{
   263  							Name:      "example-service",
   264  							Namespace: "example-namespace",
   265  						},
   266  						CABundle: CABundle,
   267  					},
   268  					AdmissionReviewVersions: []string{"v1", "v1beta1"},
   269  					SideEffects:             &sideEffects,
   270  					TimeoutSeconds:          pointer.Int32Ptr(5),
   271  				},
   272  			},
   273  		},
   274  	})
   275  }
   276  
   277  func (s *webhooksSuite) TestK8sValidatingWebhookV1(c *gc.C) {
   278  
   279  	specV1 := `
   280  name: pod-policy.example.com
   281  labels:
   282    foo: bar
   283  annotations:
   284    juju.io/disable-name-prefix: "true"
   285  webhooks:
   286    - name: "pod-policy.example.com"
   287      rules:
   288        - apiGroups: [""]
   289          apiVersions: ["v1"]
   290          operations: ["CREATE"]
   291          resources: ["pods"]
   292          scope: "Namespaced"
   293      clientConfig:
   294        service:
   295          namespace: "example-namespace"
   296          name: "example-service"
   297        caBundle: "YXBwbGVz"
   298      admissionReviewVersions: ["v1", "v1beta1"]
   299      sideEffects: None
   300      timeoutSeconds: 5
   301  `
   302  	var obj k8sspecs.K8sValidatingWebhook
   303  	err := k8sspecs.NewStrictYAMLOrJSONDecoder(strings.NewReader(specV1), len(specV1)).Decode(&obj)
   304  	c.Assert(err, jc.ErrorIsNil)
   305  
   306  	CABundle, err := base64.StdEncoding.DecodeString("YXBwbGVz")
   307  	c.Assert(err, jc.ErrorIsNil)
   308  	scope := admissionregistrationv1beta1.NamespacedScope
   309  	sideEffects := admissionregistrationv1beta1.SideEffectClassNone
   310  	c.Assert(obj, gc.DeepEquals, k8sspecs.K8sValidatingWebhook{
   311  		Meta: k8sspecs.Meta{
   312  			Name:        "pod-policy.example.com",
   313  			Labels:      map[string]string{"foo": "bar"},
   314  			Annotations: map[string]string{"juju.io/disable-name-prefix": "true"},
   315  		},
   316  		Webhooks: []k8sspecs.K8sValidatingWebhookSpec{
   317  			{
   318  				Version: k8sspecs.K8sWebhookV1Beta1,
   319  				SpecV1Beta1: admissionregistrationv1beta1.ValidatingWebhook{
   320  					Name: "pod-policy.example.com",
   321  					Rules: []admissionregistrationv1beta1.RuleWithOperations{
   322  						{
   323  							Operations: []admissionregistrationv1beta1.OperationType{
   324  								admissionregistrationv1beta1.Create,
   325  							},
   326  							Rule: admissionregistrationv1beta1.Rule{
   327  								APIGroups:   []string{""},
   328  								APIVersions: []string{"v1"},
   329  								Resources:   []string{"pods"},
   330  								Scope:       &scope,
   331  							},
   332  						},
   333  					},
   334  					ClientConfig: admissionregistrationv1beta1.WebhookClientConfig{
   335  						Service: &admissionregistrationv1beta1.ServiceReference{
   336  							Name:      "example-service",
   337  							Namespace: "example-namespace",
   338  						},
   339  						CABundle: CABundle,
   340  					},
   341  					AdmissionReviewVersions: []string{"v1", "v1beta1"},
   342  					SideEffects:             &sideEffects,
   343  					TimeoutSeconds:          pointer.Int32Ptr(5),
   344  				},
   345  			},
   346  		},
   347  	})
   348  }
   349  
   350  func (s *webhooksSuite) TestK8sValidatingWebhookInvalid(c *gc.C) {
   351  
   352  	spec := `
   353  name: pod-policy.example.com
   354  labels:
   355    foo: bar
   356  annotations:
   357    juju.io/disable-name-prefix: "true"
   358  `
   359  	var obj k8sspecs.K8sValidatingWebhook
   360  	err := k8sspecs.NewStrictYAMLOrJSONDecoder(strings.NewReader(spec), len(spec)).Decode(&obj)
   361  	c.Assert(err, jc.ErrorIsNil)
   362  	c.Assert(obj.Validate(), gc.ErrorMatches, `empty webhooks "pod-policy.example.com" not valid`)
   363  }