mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-26 21:17:23 +00:00
Add default for protocol and test that it works
This commit is contained in:
parent
de4abee3ef
commit
d3e641e84e
@ -816,6 +816,7 @@ message ContainerPort {
|
|||||||
// Protocol for port. Must be UDP, TCP, or SCTP.
|
// Protocol for port. Must be UDP, TCP, or SCTP.
|
||||||
// Defaults to "TCP".
|
// Defaults to "TCP".
|
||||||
// +optional
|
// +optional
|
||||||
|
// +default="TCP"
|
||||||
optional string protocol = 4;
|
optional string protocol = 4;
|
||||||
|
|
||||||
// What host IP to bind the external port to.
|
// What host IP to bind the external port to.
|
||||||
|
@ -1837,6 +1837,7 @@ type ContainerPort struct {
|
|||||||
// Protocol for port. Must be UDP, TCP, or SCTP.
|
// Protocol for port. Must be UDP, TCP, or SCTP.
|
||||||
// Defaults to "TCP".
|
// Defaults to "TCP".
|
||||||
// +optional
|
// +optional
|
||||||
|
// +default="TCP"
|
||||||
Protocol Protocol `json:"protocol,omitempty" protobuf:"bytes,4,opt,name=protocol,casttype=Protocol"`
|
Protocol Protocol `json:"protocol,omitempty" protobuf:"bytes,4,opt,name=protocol,casttype=Protocol"`
|
||||||
// What host IP to bind the external port to.
|
// What host IP to bind the external port to.
|
||||||
// +optional
|
// +optional
|
||||||
|
@ -18,6 +18,7 @@ go_test(
|
|||||||
"//pkg/controlplane:go_default_library",
|
"//pkg/controlplane:go_default_library",
|
||||||
"//staging/src/k8s.io/api/apps/v1:go_default_library",
|
"//staging/src/k8s.io/api/apps/v1:go_default_library",
|
||||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1:go_default_library",
|
||||||
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1:go_default_library",
|
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1:go_default_library",
|
||||||
"//staging/src/k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset:go_default_library",
|
"//staging/src/k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset:go_default_library",
|
||||||
"//staging/src/k8s.io/apiextensions-apiserver/test/integration/fixtures:go_default_library",
|
"//staging/src/k8s.io/apiextensions-apiserver/test/integration/fixtures:go_default_library",
|
||||||
|
@ -23,6 +23,7 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||||
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
||||||
"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
|
"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
|
||||||
"k8s.io/apiextensions-apiserver/test/integration/fixtures"
|
"k8s.io/apiextensions-apiserver/test/integration/fixtures"
|
||||||
@ -825,3 +826,138 @@ func getManagedFields(rawResponse []byte) ([]metav1.ManagedFieldsEntry, error) {
|
|||||||
}
|
}
|
||||||
return obj.GetManagedFields(), nil
|
return obj.GetManagedFields(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDefaultMissingKeyCRD(t *testing.T) {
|
||||||
|
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, genericfeatures.ServerSideApply, true)()
|
||||||
|
|
||||||
|
server, err := apiservertesting.StartTestServer(t, apiservertesting.NewDefaultTestServerOptions(), nil, framework.SharedEtcd())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer server.TearDownFn()
|
||||||
|
config := server.ClientConfig
|
||||||
|
|
||||||
|
apiExtensionClient, err := clientset.NewForConfig(config)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
dynamicClient, err := dynamic.NewForConfig(config)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
noxuDefinition := fixtures.NewNoxuV1CustomResourceDefinition(apiextensionsv1.ClusterScoped)
|
||||||
|
err = json.Unmarshal([]byte(`{
|
||||||
|
"openAPIV3Schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"spec": {
|
||||||
|
"type": "object",
|
||||||
|
"x-kubernetes-preserve-unknown-fields": true,
|
||||||
|
"properties": {
|
||||||
|
"cronSpec": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^(\\d+|\\*)(/\\d+)?(\\s+(\\d+|\\*)(/\\d+)?){4}$"
|
||||||
|
},
|
||||||
|
"ports": {
|
||||||
|
"type": "array",
|
||||||
|
"x-kubernetes-list-map-keys": [
|
||||||
|
"containerPort",
|
||||||
|
"protocol"
|
||||||
|
],
|
||||||
|
"x-kubernetes-list-type": "map",
|
||||||
|
"items": {
|
||||||
|
"properties": {
|
||||||
|
"containerPort": {
|
||||||
|
"format": "int32",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"hostIP": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"hostPort": {
|
||||||
|
"format": "int32",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"protocol": {
|
||||||
|
"default": "TCP",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"containerPort"
|
||||||
|
],
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`), &noxuDefinition.Spec.Versions[0].Schema)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
kind := noxuDefinition.Spec.Names.Kind
|
||||||
|
apiVersion := noxuDefinition.Spec.Group + "/" + noxuDefinition.Spec.Versions[0].Name
|
||||||
|
name := "mytest"
|
||||||
|
|
||||||
|
rest := apiExtensionClient.Discovery().RESTClient()
|
||||||
|
yamlBody := []byte(fmt.Sprintf(`
|
||||||
|
apiVersion: %s
|
||||||
|
kind: %s
|
||||||
|
metadata:
|
||||||
|
name: %s
|
||||||
|
finalizers:
|
||||||
|
- test-finalizer
|
||||||
|
spec:
|
||||||
|
cronSpec: "* * * * */5"
|
||||||
|
replicas: 1
|
||||||
|
ports:
|
||||||
|
- name: x
|
||||||
|
containerPort: 80`, apiVersion, kind, name))
|
||||||
|
result, err := rest.Patch(types.ApplyPatchType).
|
||||||
|
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).
|
||||||
|
Name(name).
|
||||||
|
Param("fieldManager", "apply_test").
|
||||||
|
Body(yamlBody).
|
||||||
|
DoRaw(context.TODO())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create custom resource with apply: %v:\n%v", err, string(result))
|
||||||
|
}
|
||||||
|
|
||||||
|
// New applier tries to edit an existing list item, we should get conflicts.
|
||||||
|
result, err = rest.Patch(types.ApplyPatchType).
|
||||||
|
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).
|
||||||
|
Name(name).
|
||||||
|
Param("fieldManager", "apply_test_2").
|
||||||
|
Body([]byte(fmt.Sprintf(`
|
||||||
|
apiVersion: %s
|
||||||
|
kind: %s
|
||||||
|
metadata:
|
||||||
|
name: %s
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- name: "y"
|
||||||
|
containerPort: 80
|
||||||
|
protocol: TCP`, apiVersion, kind, name))).
|
||||||
|
DoRaw(context.TODO())
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("Expecting to get conflicts when a different applier updates existing list item, got no error: %s", result)
|
||||||
|
}
|
||||||
|
status, ok := err.(*apierrors.StatusError)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("Expecting to get conflicts as API error")
|
||||||
|
}
|
||||||
|
if len(status.Status().Details.Causes) != 1 {
|
||||||
|
t.Fatalf("Expecting to get one conflict when a different applier updates existing list item, got: %v", status.Status().Details.Causes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -2231,6 +2231,115 @@ func TestApplyCanRemoveMapItemsContributedToByControllers(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestDefaultMissingKeys makes sure that the missing keys default is used when merging.
|
||||||
|
func TestDefaultMissingKeys(t *testing.T) {
|
||||||
|
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, genericfeatures.ServerSideApply, true)()
|
||||||
|
|
||||||
|
_, client, closeFn := setup(t)
|
||||||
|
defer closeFn()
|
||||||
|
|
||||||
|
// Applier creates a deployment with containerPort but no protocol
|
||||||
|
apply := []byte(`{
|
||||||
|
"apiVersion": "apps/v1",
|
||||||
|
"kind": "Deployment",
|
||||||
|
"metadata": {
|
||||||
|
"name": "deployment-shared-map-item-removal",
|
||||||
|
"labels": {"app": "nginx"}
|
||||||
|
},
|
||||||
|
"spec": {
|
||||||
|
"selector": {
|
||||||
|
"matchLabels": {
|
||||||
|
"app": "nginx"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"template": {
|
||||||
|
"metadata": {
|
||||||
|
"labels": {
|
||||||
|
"app": "nginx"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"spec": {
|
||||||
|
"containers": [{
|
||||||
|
"name": "nginx",
|
||||||
|
"image": "nginx:latest",
|
||||||
|
"ports": [{
|
||||||
|
"name": "foo",
|
||||||
|
"containerPort": 80
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
|
||||||
|
_, err := client.CoreV1().RESTClient().Patch(types.ApplyPatchType).
|
||||||
|
AbsPath("/apis/apps/v1").
|
||||||
|
Namespace("default").
|
||||||
|
Resource("deployments").
|
||||||
|
Name("deployment-shared-map-item-removal").
|
||||||
|
Param("fieldManager", "test_applier").
|
||||||
|
Body(apply).
|
||||||
|
Do(context.TODO()).
|
||||||
|
Get()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to create object using Apply patch: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Applier updates the name, and uses the protocol, we should get a conflict.
|
||||||
|
apply = []byte(`{
|
||||||
|
"apiVersion": "apps/v1",
|
||||||
|
"kind": "Deployment",
|
||||||
|
"metadata": {
|
||||||
|
"name": "deployment-shared-map-item-removal",
|
||||||
|
"labels": {"app": "nginx"}
|
||||||
|
},
|
||||||
|
"spec": {
|
||||||
|
"selector": {
|
||||||
|
"matchLabels": {
|
||||||
|
"app": "nginx"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"template": {
|
||||||
|
"metadata": {
|
||||||
|
"labels": {
|
||||||
|
"app": "nginx"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"spec": {
|
||||||
|
"containers": [{
|
||||||
|
"name": "nginx",
|
||||||
|
"image": "nginx:latest",
|
||||||
|
"ports": [{
|
||||||
|
"name": "bar",
|
||||||
|
"containerPort": 80,
|
||||||
|
"protocol": "TCP"
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
patched, err := client.CoreV1().RESTClient().Patch(types.ApplyPatchType).
|
||||||
|
AbsPath("/apis/apps/v1").
|
||||||
|
Namespace("default").
|
||||||
|
Resource("deployments").
|
||||||
|
Name("deployment-shared-map-item-removal").
|
||||||
|
Param("fieldManager", "test_applier_conflict").
|
||||||
|
Body(apply).
|
||||||
|
Do(context.TODO()).
|
||||||
|
Get()
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("Expecting to get conflicts when a different applier updates existing list item, got no error: %s", patched)
|
||||||
|
}
|
||||||
|
status, ok := err.(*apierrors.StatusError)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("Expecting to get conflicts as API error")
|
||||||
|
}
|
||||||
|
if len(status.Status().Details.Causes) != 1 {
|
||||||
|
t.Fatalf("Expecting to get one conflict when a different applier updates existing list item, got: %v", status.Status().Details.Causes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var podBytes = []byte(`
|
var podBytes = []byte(`
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Pod
|
kind: Pod
|
||||||
|
Loading…
Reference in New Issue
Block a user