mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-22 19:31:44 +00:00
PetSet type, apps apigroup
This commit is contained in:
parent
2599607a64
commit
0ac10c6cc2
110
api/swagger-spec/apps.json
Normal file
110
api/swagger-spec/apps.json
Normal file
@ -0,0 +1,110 @@
|
||||
{
|
||||
"swaggerVersion": "1.2",
|
||||
"apiVersion": "",
|
||||
"basePath": "https://10.10.10.10:443",
|
||||
"resourcePath": "/apis/apps",
|
||||
"apis": [
|
||||
{
|
||||
"path": "/apis/apps",
|
||||
"description": "get information of a group",
|
||||
"operations": [
|
||||
{
|
||||
"type": "unversioned.APIGroup",
|
||||
"method": "GET",
|
||||
"summary": "get information of a group",
|
||||
"nickname": "getAPIGroup",
|
||||
"parameters": [],
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/yaml",
|
||||
"application/vnd.kubernetes.protobuf"
|
||||
],
|
||||
"consumes": [
|
||||
"application/json",
|
||||
"application/yaml",
|
||||
"application/vnd.kubernetes.protobuf"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"models": {
|
||||
"unversioned.APIGroup": {
|
||||
"id": "unversioned.APIGroup",
|
||||
"description": "APIGroup contains the name, the supported versions, and the preferred version of a group.",
|
||||
"required": [
|
||||
"name",
|
||||
"versions",
|
||||
"serverAddressByClientCIDRs"
|
||||
],
|
||||
"properties": {
|
||||
"kind": {
|
||||
"type": "string",
|
||||
"description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds"
|
||||
},
|
||||
"apiVersion": {
|
||||
"type": "string",
|
||||
"description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#resources"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "name is the name of the group."
|
||||
},
|
||||
"versions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "unversioned.GroupVersionForDiscovery"
|
||||
},
|
||||
"description": "versions are the versions supported in this group."
|
||||
},
|
||||
"preferredVersion": {
|
||||
"$ref": "unversioned.GroupVersionForDiscovery",
|
||||
"description": "preferredVersion is the version preferred by the API server, which probably is the storage version."
|
||||
},
|
||||
"serverAddressByClientCIDRs": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "unversioned.ServerAddressByClientCIDR"
|
||||
},
|
||||
"description": "a map of client CIDR to server address that is serving this group. This is to help clients reach servers in the most network-efficient way possible. Clients can use the appropriate server address as per the CIDR that they match. In case of multiple matches, clients should use the longest matching CIDR. The server returns only those CIDRs that it thinks that the client can match. For example: the master will return an internal IP CIDR only, if the client reaches the server using an internal IP. Server looks at X-Forwarded-For header or X-Real-Ip header or request.RemoteAddr (in that order) to get the client IP."
|
||||
}
|
||||
}
|
||||
},
|
||||
"unversioned.GroupVersionForDiscovery": {
|
||||
"id": "unversioned.GroupVersionForDiscovery",
|
||||
"description": "GroupVersion contains the \"group/version\" and \"version\" string of a version. It is made a struct to keep extensiblity.",
|
||||
"required": [
|
||||
"groupVersion",
|
||||
"version"
|
||||
],
|
||||
"properties": {
|
||||
"groupVersion": {
|
||||
"type": "string",
|
||||
"description": "groupVersion specifies the API group and version in the form \"group/version\""
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "version specifies the version in the form of \"version\". This is to save the clients the trouble of splitting the GroupVersion."
|
||||
}
|
||||
}
|
||||
},
|
||||
"unversioned.ServerAddressByClientCIDR": {
|
||||
"id": "unversioned.ServerAddressByClientCIDR",
|
||||
"description": "ServerAddressByClientCIDR helps the client to determine the server address that they should use, depending on the clientCIDR that they match.",
|
||||
"required": [
|
||||
"clientCIDR",
|
||||
"serverAddress"
|
||||
],
|
||||
"properties": {
|
||||
"clientCIDR": {
|
||||
"type": "string",
|
||||
"description": "The CIDR with which clients can match their IP to figure out the server address that they should use."
|
||||
},
|
||||
"serverAddress": {
|
||||
"type": "string",
|
||||
"description": "Address of this server, suitable for a client that matches the above CIDR. This can be a hostname, hostname:port, IP or IP:port."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
2517
api/swagger-spec/apps_v1alpha1.json
Normal file
2517
api/swagger-spec/apps_v1alpha1.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -40,6 +40,14 @@
|
||||
{
|
||||
"path": "/apis/batch",
|
||||
"description": "get information of a group"
|
||||
},
|
||||
{
|
||||
"path": "/apis/apps/v1alpha1",
|
||||
"description": "API at /apis/apps/v1alpha1"
|
||||
},
|
||||
{
|
||||
"path": "/apis/apps",
|
||||
"description": "get information of a group"
|
||||
}
|
||||
],
|
||||
"apiVersion": "",
|
||||
|
@ -38,6 +38,8 @@ import (
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
apiv1 "k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
||||
"k8s.io/kubernetes/pkg/apis/apps"
|
||||
appsapi "k8s.io/kubernetes/pkg/apis/apps/v1alpha1"
|
||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
||||
autoscalingapiv1 "k8s.io/kubernetes/pkg/apis/autoscaling/v1"
|
||||
"k8s.io/kubernetes/pkg/apis/batch"
|
||||
@ -346,6 +348,29 @@ func Run(s *options.APIServer) error {
|
||||
storageDestinations.AddAPIGroup(batch.GroupName, batchEtcdStorage)
|
||||
}
|
||||
|
||||
if apiResourceConfigSource.AnyResourcesForVersionEnabled(appsapi.SchemeGroupVersion) {
|
||||
glog.Infof("Configuring apps/v1alpha1 storage destination")
|
||||
appsGroup, err := registered.Group(apps.GroupName)
|
||||
if err != nil {
|
||||
glog.Fatalf("Apps API is enabled in runtime config, but not enabled in the environment variable KUBE_API_VERSIONS. Error: %v", err)
|
||||
}
|
||||
// Figure out what storage group/version we should use.
|
||||
storageGroupVersion, found := storageVersions[appsGroup.GroupVersion.Group]
|
||||
if !found {
|
||||
glog.Fatalf("Couldn't find the storage version for group: %q in storageVersions: %v", appsGroup.GroupVersion.Group, storageVersions)
|
||||
}
|
||||
|
||||
if storageGroupVersion != "apps/v1alpha1" {
|
||||
glog.Fatalf("The storage version for apps must be apps/v1alpha1")
|
||||
}
|
||||
glog.Infof("Using %v for petset group storage version", storageGroupVersion)
|
||||
appsEtcdStorage, err := newEtcd(api.Codecs, storageGroupVersion, "apps/__internal", s.EtcdConfig)
|
||||
if err != nil {
|
||||
glog.Fatalf("Invalid extensions storage version or misconfigured etcd: %v", err)
|
||||
}
|
||||
storageDestinations.AddAPIGroup(apps.GroupName, appsEtcdStorage)
|
||||
}
|
||||
|
||||
updateEtcdOverrides(s.EtcdServersOverrides, storageVersions, s.EtcdConfig, &storageDestinations, newEtcd)
|
||||
|
||||
// Default to the private server key for service account token signing
|
||||
@ -477,6 +502,7 @@ func parseRuntimeConfig(s *options.APIServer) (genericapiserver.APIResourceConfi
|
||||
extensionsapiv1beta1.SchemeGroupVersion: extensionsGroupVersionString,
|
||||
batchapiv1.SchemeGroupVersion: batchapiv1.SchemeGroupVersion.String(),
|
||||
autoscalingapiv1.SchemeGroupVersion: autoscalingapiv1.SchemeGroupVersion.String(),
|
||||
appsapi.SchemeGroupVersion: appsapi.SchemeGroupVersion.String(),
|
||||
}
|
||||
|
||||
resourceConfig := master.DefaultAPIResourceConfigSource()
|
||||
|
@ -41,6 +41,8 @@ func main() {
|
||||
"k8s.io/kubernetes/pkg/apis/autoscaling/v1",
|
||||
"k8s.io/kubernetes/pkg/apis/batch",
|
||||
"k8s.io/kubernetes/pkg/apis/batch/v1",
|
||||
"k8s.io/kubernetes/pkg/apis/apps",
|
||||
"k8s.io/kubernetes/pkg/apis/apps/v1alpha1",
|
||||
"k8s.io/kubernetes/pkg/apis/componentconfig",
|
||||
"k8s.io/kubernetes/pkg/apis/componentconfig/v1alpha1",
|
||||
"k8s.io/kubernetes/pkg/apis/extensions",
|
||||
|
@ -41,6 +41,8 @@ func main() {
|
||||
"k8s.io/kubernetes/pkg/apis/autoscaling/v1",
|
||||
"k8s.io/kubernetes/pkg/apis/batch",
|
||||
"k8s.io/kubernetes/pkg/apis/batch/v1",
|
||||
"k8s.io/kubernetes/pkg/apis/apps",
|
||||
"k8s.io/kubernetes/pkg/apis/apps/v1alpha1",
|
||||
"k8s.io/kubernetes/pkg/apis/componentconfig",
|
||||
"k8s.io/kubernetes/pkg/apis/componentconfig/v1alpha1",
|
||||
"k8s.io/kubernetes/pkg/apis/extensions",
|
||||
|
@ -69,6 +69,7 @@ func New() *Generator {
|
||||
`k8s.io/kubernetes/pkg/apis/extensions/v1beta1`,
|
||||
`k8s.io/kubernetes/pkg/apis/autoscaling/v1`,
|
||||
`k8s.io/kubernetes/pkg/apis/batch/v1`,
|
||||
`k8s.io/kubernetes/pkg/apis/apps/v1alpha1`,
|
||||
}, ","),
|
||||
DropEmbeddedFields: "k8s.io/kubernetes/pkg/api/unversioned.TypeMeta",
|
||||
}
|
||||
|
@ -421,6 +421,7 @@ _kubectl_get()
|
||||
must_have_one_noun+=("node")
|
||||
must_have_one_noun+=("persistentvolume")
|
||||
must_have_one_noun+=("persistentvolumeclaim")
|
||||
must_have_one_noun+=("petset")
|
||||
must_have_one_noun+=("pod")
|
||||
must_have_one_noun+=("podsecuritypolicy")
|
||||
must_have_one_noun+=("podtemplate")
|
||||
@ -456,6 +457,7 @@ _kubectl_get()
|
||||
noun_aliases+=("ns")
|
||||
noun_aliases+=("persistentvolumeclaims")
|
||||
noun_aliases+=("persistentvolumes")
|
||||
noun_aliases+=("petsets")
|
||||
noun_aliases+=("po")
|
||||
noun_aliases+=("pods")
|
||||
noun_aliases+=("podsecuritypolicies")
|
||||
@ -1170,6 +1172,7 @@ _kubectl_patch()
|
||||
must_have_one_noun+=("node")
|
||||
must_have_one_noun+=("persistentvolume")
|
||||
must_have_one_noun+=("persistentvolumeclaim")
|
||||
must_have_one_noun+=("petset")
|
||||
must_have_one_noun+=("pod")
|
||||
must_have_one_noun+=("podsecuritypolicy")
|
||||
must_have_one_noun+=("podtemplate")
|
||||
@ -1205,6 +1208,7 @@ _kubectl_patch()
|
||||
noun_aliases+=("ns")
|
||||
noun_aliases+=("persistentvolumeclaims")
|
||||
noun_aliases+=("persistentvolumes")
|
||||
noun_aliases+=("petsets")
|
||||
noun_aliases+=("po")
|
||||
noun_aliases+=("pods")
|
||||
noun_aliases+=("podsecuritypolicies")
|
||||
@ -1299,6 +1303,7 @@ _kubectl_delete()
|
||||
must_have_one_noun+=("node")
|
||||
must_have_one_noun+=("persistentvolume")
|
||||
must_have_one_noun+=("persistentvolumeclaim")
|
||||
must_have_one_noun+=("petset")
|
||||
must_have_one_noun+=("pod")
|
||||
must_have_one_noun+=("podsecuritypolicy")
|
||||
must_have_one_noun+=("podtemplate")
|
||||
@ -1334,6 +1339,7 @@ _kubectl_delete()
|
||||
noun_aliases+=("ns")
|
||||
noun_aliases+=("persistentvolumeclaims")
|
||||
noun_aliases+=("persistentvolumes")
|
||||
noun_aliases+=("petsets")
|
||||
noun_aliases+=("po")
|
||||
noun_aliases+=("pods")
|
||||
noun_aliases+=("podsecuritypolicies")
|
||||
@ -1424,6 +1430,7 @@ _kubectl_edit()
|
||||
must_have_one_noun+=("node")
|
||||
must_have_one_noun+=("persistentvolume")
|
||||
must_have_one_noun+=("persistentvolumeclaim")
|
||||
must_have_one_noun+=("petset")
|
||||
must_have_one_noun+=("pod")
|
||||
must_have_one_noun+=("podsecuritypolicy")
|
||||
must_have_one_noun+=("podtemplate")
|
||||
@ -1459,6 +1466,7 @@ _kubectl_edit()
|
||||
noun_aliases+=("ns")
|
||||
noun_aliases+=("persistentvolumeclaims")
|
||||
noun_aliases+=("persistentvolumes")
|
||||
noun_aliases+=("petsets")
|
||||
noun_aliases+=("po")
|
||||
noun_aliases+=("pods")
|
||||
noun_aliases+=("podsecuritypolicies")
|
||||
@ -2708,6 +2716,7 @@ _kubectl_label()
|
||||
must_have_one_noun+=("node")
|
||||
must_have_one_noun+=("persistentvolume")
|
||||
must_have_one_noun+=("persistentvolumeclaim")
|
||||
must_have_one_noun+=("petset")
|
||||
must_have_one_noun+=("pod")
|
||||
must_have_one_noun+=("podsecuritypolicy")
|
||||
must_have_one_noun+=("podtemplate")
|
||||
@ -2743,6 +2752,7 @@ _kubectl_label()
|
||||
noun_aliases+=("ns")
|
||||
noun_aliases+=("persistentvolumeclaims")
|
||||
noun_aliases+=("persistentvolumes")
|
||||
noun_aliases+=("petsets")
|
||||
noun_aliases+=("po")
|
||||
noun_aliases+=("pods")
|
||||
noun_aliases+=("podsecuritypolicies")
|
||||
|
@ -109,7 +109,7 @@ kube-apiserver
|
||||
--service-node-port-range=: A port range to reserve for services with NodePort visibility. Example: '30000-32767'. Inclusive at both ends of the range.
|
||||
--ssh-keyfile="": If non-empty, use secure SSH proxy to the nodes, using this user keyfile
|
||||
--ssh-user="": If non-empty, use secure SSH proxy to the nodes, using this user name
|
||||
--storage-versions="authorization.k8s.io/v1beta1,autoscaling/v1,batch/v1,componentconfig/v1alpha1,extensions/v1beta1,metrics/v1alpha1,v1": The per-group version to store resources in. Specified in the format "group1/version1,group2/version2,...". In the case where objects are moved from one group to the other, you may specify the format "group1=group2/v1beta1,group3/v1beta1,...". You only need to pass the groups you wish to change from the defaults. It defaults to a list of preferred versions of all registered groups, which is derived from the KUBE_API_VERSIONS environment variable.
|
||||
--storage-versions="apps/v1alpha1,authorization.k8s.io/v1beta1,autoscaling/v1,batch/v1,componentconfig/v1alpha1,extensions/v1beta1,metrics/v1alpha1,v1": The per-group version to store resources in. Specified in the format "group1/version1,group2/version2,...". In the case where objects are moved from one group to the other, you may specify the format "group1=group2/v1beta1,group3/v1beta1,...". You only need to pass the groups you wish to change from the defaults. It defaults to a list of preferred versions of all registered groups, which is derived from the KUBE_API_VERSIONS environment variable.
|
||||
--tls-cert-file="": File containing x509 Certificate for HTTPS. (CA cert, if any, concatenated after server cert). If HTTPS serving is enabled, and --tls-cert-file and --tls-private-key-file are not provided, a self-signed certificate and key are generated for the public address and saved to /var/run/kubernetes.
|
||||
--tls-private-key-file="": File containing x509 private key matching --tls-cert-file.
|
||||
--token-auth-file="": If set, the file that will be used to secure the secure port of the API server via token authentication.
|
||||
@ -117,7 +117,7 @@ kube-apiserver
|
||||
--watch-cache-sizes=[]: List of watch cache sizes for every resource (pods, nodes, etc.), comma separated. The individual override format: resource#size, where size is a number. It takes effect when watch-cache is enabled.
|
||||
```
|
||||
|
||||
###### Auto generated by spf13/cobra on 12-Apr-2016
|
||||
###### Auto generated by spf13/cobra on 16-Apr-2016
|
||||
|
||||
|
||||
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
|
||||
|
@ -66,7 +66,7 @@ APISERVER_PID=$!
|
||||
kube::util::wait_for_url "http://127.0.0.1:${API_PORT}/healthz" "apiserver: "
|
||||
|
||||
SWAGGER_API_PATH="http://127.0.0.1:${API_PORT}/swaggerapi/"
|
||||
DEFAULT_GROUP_VERSIONS="v1 autoscaling/v1 batch/v1 extensions/v1beta1"
|
||||
DEFAULT_GROUP_VERSIONS="v1 autoscaling/v1 batch/v1 extensions/v1beta1 apps/v1alpha1"
|
||||
VERSIONS=${VERSIONS:-$DEFAULT_GROUP_VERSIONS}
|
||||
|
||||
kube::log::status "Updating " ${SWAGGER_ROOT_DIR}
|
||||
|
@ -183,7 +183,7 @@ kube::log::status "Starting kube-apiserver"
|
||||
# Admission Controllers to invoke prior to persisting objects in cluster
|
||||
ADMISSION_CONTROL="NamespaceLifecycle,LimitRanger,ResourceQuota"
|
||||
|
||||
KUBE_API_VERSIONS="v1,autoscaling/v1,batch/v1,extensions/v1beta1" "${KUBE_OUTPUT_HOSTBIN}/kube-apiserver" \
|
||||
KUBE_API_VERSIONS="v1,autoscaling/v1,batch/v1,apps/v1alpha1,extensions/v1beta1" "${KUBE_OUTPUT_HOSTBIN}/kube-apiserver" \
|
||||
--address="127.0.0.1" \
|
||||
--public-address-override="127.0.0.1" \
|
||||
--port="${API_PORT}" \
|
||||
@ -529,7 +529,7 @@ runTests() {
|
||||
kubectl create -f hack/testdata/pod-with-precision.json "${kube_flags[@]}"
|
||||
# Post-condition: valid-pod POD is running
|
||||
kube::test::get_object_assert pods "{{range.items}}{{$id_field}}:{{end}}" 'pod-with-precision:'
|
||||
|
||||
|
||||
## Patch preserves precision
|
||||
# Command
|
||||
kubectl patch "${kube_flags[@]}" pod pod-with-precision -p='{"metadata":{"annotations":{"patchkey": "patchvalue"}}}'
|
||||
@ -544,7 +544,7 @@ runTests() {
|
||||
# Post-condition: pod-with-precision POD has annotation
|
||||
kube::test::get_object_assert 'pod pod-with-precision' "{{${annotations_field}.annotatekey}}" 'annotatevalue'
|
||||
# Cleanup
|
||||
kubectl delete pod pod-with-precision "${kube_flags[@]}"
|
||||
kubectl delete pod pod-with-precision "${kube_flags[@]}"
|
||||
|
||||
### Create valid-pod POD
|
||||
# Pre-condition: no POD exists
|
||||
@ -1792,6 +1792,6 @@ __EOF__
|
||||
kube::test::clear_all
|
||||
}
|
||||
|
||||
KUBE_API_VERSIONS="v1,autoscaling/v1,batch/v1,extensions/v1beta1" runTests "v1"
|
||||
KUBE_API_VERSIONS="v1,autoscaling/v1,batch/v1,apps/v1alpha1,extensions/v1beta1" runTests "v1"
|
||||
|
||||
kube::log::status "TEST PASSED"
|
||||
|
@ -58,7 +58,7 @@ KUBE_GOVERALLS_BIN=${KUBE_GOVERALLS_BIN:-}
|
||||
# Lists of API Versions of each groups that should be tested, groups are
|
||||
# separated by comma, lists are separated by semicolon. e.g.,
|
||||
# "v1,compute/v1alpha1,experimental/v1alpha2;v1,compute/v2,experimental/v1alpha3"
|
||||
KUBE_TEST_API_VERSIONS=${KUBE_TEST_API_VERSIONS:-"v1,extensions/v1beta1,metrics/v1alpha1;v1,autoscaling/v1,batch/v1,extensions/v1beta1,metrics/v1alpha1"}
|
||||
KUBE_TEST_API_VERSIONS=${KUBE_TEST_API_VERSIONS:-"v1,extensions/v1beta1,metrics/v1alpha1;v1,autoscaling/v1,batch/v1,extensions/v1beta1,apps/v1alpha1,metrics/v1alpha1"}
|
||||
# once we have multiple group supports
|
||||
# Run tests with the standard (registry) and a custom etcd prefix
|
||||
# (kubernetes.io/registry).
|
||||
@ -326,7 +326,7 @@ for (( i=0, j=0; ; )); do
|
||||
# KUBE_TEST_API sets the version of each group to be tested. KUBE_API_VERSIONS
|
||||
# register the groups/versions as supported by k8s. So KUBE_API_VERSIONS
|
||||
# needs to be the superset of KUBE_TEST_API.
|
||||
KUBE_TEST_API="${apiVersion}" KUBE_API_VERSIONS="v1,autoscaling/v1,batch/v1,extensions/v1beta1,componentconfig/v1alpha1,metrics/v1alpha1,authorization.k8s.io/v1beta1" ETCD_PREFIX=${etcdPrefix} runTests "$@"
|
||||
KUBE_TEST_API="${apiVersion}" KUBE_API_VERSIONS="v1,autoscaling/v1,batch/v1,extensions/v1beta1,componentconfig/v1alpha1,metrics/v1alpha1,apps/v1alpha1,authorization.k8s.io/v1beta1" ETCD_PREFIX=${etcdPrefix} runTests "$@"
|
||||
i=${i}+1
|
||||
j=${j}+1
|
||||
if [[ i -eq ${apiVersionsCount} ]] && [[ j -eq ${etcdPrefixesCount} ]]; then
|
||||
|
@ -29,7 +29,7 @@ source "${KUBE_ROOT}/hack/lib/init.sh"
|
||||
# "v1,compute/v1alpha1,experimental/v1alpha2;v1,compute/v2,experimental/v1alpha3"
|
||||
# TODO: It's going to be:
|
||||
# KUBE_TEST_API_VERSIONS=${KUBE_TEST_API_VERSIONS:-"v1,extensions/v1beta1"}
|
||||
KUBE_TEST_API_VERSIONS=${KUBE_TEST_API_VERSIONS:-"v1,extensions/v1beta1;v1,autoscaling/v1,batch/v1,extensions/v1beta1"}
|
||||
KUBE_TEST_API_VERSIONS=${KUBE_TEST_API_VERSIONS:-"v1,extensions/v1beta1;v1,autoscaling/v1,batch/v1,apps/v1alpha1,extensions/v1beta1"}
|
||||
|
||||
# Give integration tests longer to run
|
||||
KUBE_TIMEOUT=${KUBE_TIMEOUT:--timeout 240s}
|
||||
@ -52,11 +52,11 @@ runTests() {
|
||||
KUBE_RACE="" \
|
||||
KUBE_TIMEOUT="${KUBE_TIMEOUT}" \
|
||||
KUBE_TEST_API_VERSIONS="$1" \
|
||||
KUBE_API_VERSIONS="v1,autoscaling/v1,batch/v1,extensions/v1beta1" \
|
||||
KUBE_API_VERSIONS="v1,autoscaling/v1,batch/v1,apps/v1alpha1,extensions/v1beta1" \
|
||||
"${KUBE_ROOT}/hack/test-go.sh" test/integration
|
||||
|
||||
kube::log::status "Running integration test scenario with watch cache on"
|
||||
KUBE_API_VERSIONS="v1,autoscaling/v1,batch/v1,extensions/v1beta1" KUBE_TEST_API_VERSIONS="$1" "${KUBE_OUTPUT_HOSTBIN}/integration" --v=${LOG_LEVEL} \
|
||||
KUBE_API_VERSIONS="v1,autoscaling/v1,batch/v1,apps/v1alpha1,extensions/v1beta1" KUBE_TEST_API_VERSIONS="$1" "${KUBE_OUTPUT_HOSTBIN}/integration" --v=${LOG_LEVEL} \
|
||||
--max-concurrency="${KUBE_INTEGRATION_TEST_MAX_CONCURRENCY}" --watch-cache=true
|
||||
|
||||
cleanup
|
||||
@ -73,7 +73,7 @@ checkEtcdOnPath() {
|
||||
checkEtcdOnPath
|
||||
|
||||
|
||||
KUBE_API_VERSIONS="v1,autoscaling/v1,batch/v1,extensions/v1beta1" "${KUBE_ROOT}/hack/build-go.sh" "$@" cmd/integration
|
||||
KUBE_API_VERSIONS="v1,autoscaling/v1,batch/v1,apps/v1alpha1,extensions/v1beta1" "${KUBE_ROOT}/hack/build-go.sh" "$@" cmd/integration
|
||||
|
||||
# Run cleanup to stop etcd on interrupt or other kill signal.
|
||||
trap cleanup EXIT
|
||||
|
@ -56,7 +56,7 @@ user_flags="-u $(id -u)"
|
||||
if [[ $(uname) == "Darwin" ]]; then
|
||||
# mapping in a uid from OS X doesn't make any sense
|
||||
user_flags=""
|
||||
fi
|
||||
fi
|
||||
|
||||
for ver in $VERSIONS; do
|
||||
TMP_IN_HOST="${OUTPUT_TMP_IN_HOST}/${ver}"
|
||||
@ -94,7 +94,7 @@ while read file; do
|
||||
generated=$(echo "${generated}" | grep -v "Last updated" || :)
|
||||
|
||||
# By now, the contents should be normalized and stripped of any
|
||||
# auto-managed content.
|
||||
# auto-managed content.
|
||||
if diff -Bw >/dev/null <(echo "${original}") <(echo "${generated}"); then
|
||||
# actual contents same, overwrite generated with original.
|
||||
cp "${OUTPUT}/${file}" "${OUTPUT_TMP}/${file}"
|
||||
|
@ -56,7 +56,7 @@ EOF
|
||||
mv "$TMPFILE" "pkg/$(kube::util::group-version-to-pkg-path "${group_version}")/types_swagger_doc_generated.go"
|
||||
}
|
||||
|
||||
GROUP_VERSIONS=(unversioned v1 authorization/v1beta1 autoscaling/v1 batch/v1 extensions/v1beta1)
|
||||
GROUP_VERSIONS=(unversioned v1 authorization/v1beta1 autoscaling/v1 batch/v1 extensions/v1beta1 apps/v1alpha1)
|
||||
# To avoid compile errors, remove the currently existing files.
|
||||
for group_version in "${GROUP_VERSIONS[@]}"; do
|
||||
rm -f "pkg/$(kube::util::group-version-to-pkg-path "${group_version}")/types_swagger_doc_generated.go"
|
||||
|
@ -27,12 +27,14 @@ import (
|
||||
"k8s.io/kubernetes/pkg/api/meta"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
||||
"k8s.io/kubernetes/pkg/apis/apps"
|
||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
||||
"k8s.io/kubernetes/pkg/apis/batch"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
|
||||
_ "k8s.io/kubernetes/pkg/api/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/apps/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/autoscaling/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/batch/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/componentconfig/install"
|
||||
@ -46,6 +48,7 @@ var (
|
||||
Autoscaling TestGroup
|
||||
Batch TestGroup
|
||||
Extensions TestGroup
|
||||
Apps TestGroup
|
||||
)
|
||||
|
||||
type TestGroup struct {
|
||||
@ -122,10 +125,18 @@ func init() {
|
||||
internalTypes: api.Scheme.KnownTypes(extensions.SchemeGroupVersion),
|
||||
}
|
||||
}
|
||||
if _, ok := Groups[apps.GroupName]; !ok {
|
||||
Groups[apps.GroupName] = TestGroup{
|
||||
externalGroupVersion: unversioned.GroupVersion{Group: apps.GroupName, Version: registered.GroupOrDie(apps.GroupName).GroupVersion.Version},
|
||||
internalGroupVersion: extensions.SchemeGroupVersion,
|
||||
internalTypes: api.Scheme.KnownTypes(extensions.SchemeGroupVersion),
|
||||
}
|
||||
}
|
||||
|
||||
Default = Groups[api.GroupName]
|
||||
Autoscaling = Groups[autoscaling.GroupName]
|
||||
Batch = Groups[batch.GroupName]
|
||||
Apps = Groups[apps.GroupName]
|
||||
Extensions = Groups[extensions.GroupName]
|
||||
}
|
||||
|
||||
|
117
pkg/apis/apps/deep_copy_generated.go
Normal file
117
pkg/apis/apps/deep_copy_generated.go
Normal file
@ -0,0 +1,117 @@
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||
|
||||
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 deepcopy-gen. Do not edit it manually!
|
||||
|
||||
package apps
|
||||
|
||||
import (
|
||||
api "k8s.io/kubernetes/pkg/api"
|
||||
unversioned "k8s.io/kubernetes/pkg/api/unversioned"
|
||||
conversion "k8s.io/kubernetes/pkg/conversion"
|
||||
)
|
||||
|
||||
func init() {
|
||||
if err := api.Scheme.AddGeneratedDeepCopyFuncs(
|
||||
DeepCopy_apps_PetSet,
|
||||
DeepCopy_apps_PetSetList,
|
||||
DeepCopy_apps_PetSetSpec,
|
||||
DeepCopy_apps_PetSetStatus,
|
||||
); err != nil {
|
||||
// if one of the deep copy functions is malformed, detect it immediately.
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_apps_PetSet(in PetSet, out *PetSet, c *conversion.Cloner) error {
|
||||
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := api.DeepCopy_api_ObjectMeta(in.ObjectMeta, &out.ObjectMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := DeepCopy_apps_PetSetSpec(in.Spec, &out.Spec, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := DeepCopy_apps_PetSetStatus(in.Status, &out.Status, c); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_apps_PetSetList(in PetSetList, out *PetSetList, c *conversion.Cloner) error {
|
||||
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := unversioned.DeepCopy_unversioned_ListMeta(in.ListMeta, &out.ListMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Items != nil {
|
||||
in, out := in.Items, &out.Items
|
||||
*out = make([]PetSet, len(in))
|
||||
for i := range in {
|
||||
if err := DeepCopy_apps_PetSet(in[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Items = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_apps_PetSetSpec(in PetSetSpec, out *PetSetSpec, c *conversion.Cloner) error {
|
||||
out.Replicas = in.Replicas
|
||||
if in.Selector != nil {
|
||||
in, out := in.Selector, &out.Selector
|
||||
*out = new(unversioned.LabelSelector)
|
||||
if err := unversioned.DeepCopy_unversioned_LabelSelector(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.Selector = nil
|
||||
}
|
||||
if err := api.DeepCopy_api_PodTemplateSpec(in.Template, &out.Template, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.VolumeClaimTemplates != nil {
|
||||
in, out := in.VolumeClaimTemplates, &out.VolumeClaimTemplates
|
||||
*out = make([]api.PersistentVolumeClaim, len(in))
|
||||
for i := range in {
|
||||
if err := api.DeepCopy_api_PersistentVolumeClaim(in[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.VolumeClaimTemplates = nil
|
||||
}
|
||||
out.ServiceName = in.ServiceName
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_apps_PetSetStatus(in PetSetStatus, out *PetSetStatus, c *conversion.Cloner) error {
|
||||
if in.ObservedGeneration != nil {
|
||||
in, out := in.ObservedGeneration, &out.ObservedGeneration
|
||||
*out = new(int64)
|
||||
**out = *in
|
||||
} else {
|
||||
out.ObservedGeneration = nil
|
||||
}
|
||||
out.Replicas = in.Replicas
|
||||
return nil
|
||||
}
|
125
pkg/apis/apps/install/install.go
Normal file
125
pkg/apis/apps/install/install.go
Normal file
@ -0,0 +1,125 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||
|
||||
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 install installs the apps API group, making it available as
|
||||
// an option to all of the API encoding/decoding machinery.
|
||||
package install
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/meta"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/apimachinery"
|
||||
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
||||
"k8s.io/kubernetes/pkg/apis/apps"
|
||||
"k8s.io/kubernetes/pkg/apis/apps/v1alpha1"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/util/sets"
|
||||
)
|
||||
|
||||
const importPrefix = "k8s.io/kubernetes/pkg/apis/apps"
|
||||
|
||||
var accessor = meta.NewAccessor()
|
||||
|
||||
// availableVersions lists all known external versions for this group from most preferred to least preferred
|
||||
var availableVersions = []unversioned.GroupVersion{v1alpha1.SchemeGroupVersion}
|
||||
|
||||
func init() {
|
||||
registered.RegisterVersions(availableVersions)
|
||||
externalVersions := []unversioned.GroupVersion{}
|
||||
for _, v := range availableVersions {
|
||||
if registered.IsAllowedVersion(v) {
|
||||
externalVersions = append(externalVersions, v)
|
||||
}
|
||||
}
|
||||
if len(externalVersions) == 0 {
|
||||
glog.V(4).Infof("No version is registered for group %v", apps.GroupName)
|
||||
return
|
||||
}
|
||||
|
||||
if err := registered.EnableVersions(externalVersions...); err != nil {
|
||||
glog.V(4).Infof("%v", err)
|
||||
return
|
||||
}
|
||||
if err := enableVersions(externalVersions); err != nil {
|
||||
glog.V(4).Infof("%v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func enableVersions(externalVersions []unversioned.GroupVersion) error {
|
||||
addVersionsToScheme(externalVersions...)
|
||||
preferredExternalVersion := externalVersions[0]
|
||||
|
||||
groupMeta := apimachinery.GroupMeta{
|
||||
GroupVersion: preferredExternalVersion,
|
||||
GroupVersions: externalVersions,
|
||||
RESTMapper: newRESTMapper(externalVersions),
|
||||
SelfLinker: runtime.SelfLinker(accessor),
|
||||
InterfacesFor: interfacesFor,
|
||||
}
|
||||
|
||||
if err := registered.RegisterGroup(groupMeta); err != nil {
|
||||
return err
|
||||
}
|
||||
api.RegisterRESTMapper(groupMeta.RESTMapper)
|
||||
return nil
|
||||
}
|
||||
|
||||
func newRESTMapper(externalVersions []unversioned.GroupVersion) meta.RESTMapper {
|
||||
// the list of kinds that are scoped at the root of the api hierarchy
|
||||
// if a kind is not enumerated here, it is assumed to have a namespace scope
|
||||
rootScoped := sets.NewString()
|
||||
|
||||
ignoredKinds := sets.NewString()
|
||||
|
||||
return api.NewDefaultRESTMapper(externalVersions, interfacesFor, importPrefix, ignoredKinds, rootScoped)
|
||||
}
|
||||
|
||||
// interfacesFor returns the default Codec and ResourceVersioner for a given version
|
||||
// string, or an error if the version is not known.
|
||||
func interfacesFor(version unversioned.GroupVersion) (*meta.VersionInterfaces, error) {
|
||||
switch version {
|
||||
case v1alpha1.SchemeGroupVersion:
|
||||
return &meta.VersionInterfaces{
|
||||
ObjectConvertor: api.Scheme,
|
||||
MetadataAccessor: accessor,
|
||||
}, nil
|
||||
default:
|
||||
g, _ := registered.Group(apps.GroupName)
|
||||
return nil, fmt.Errorf("unsupported storage version: %s (valid: %v)", version, g.GroupVersions)
|
||||
}
|
||||
}
|
||||
|
||||
func addVersionsToScheme(externalVersions ...unversioned.GroupVersion) {
|
||||
// add the internal version to Scheme
|
||||
apps.AddToScheme(api.Scheme)
|
||||
// add the enabled external versions to Scheme
|
||||
for _, v := range externalVersions {
|
||||
if !registered.IsEnabledVersion(v) {
|
||||
glog.Errorf("Version %s is not enabled, so it will not be added to the Scheme.", v)
|
||||
continue
|
||||
}
|
||||
switch v {
|
||||
case v1alpha1.SchemeGroupVersion:
|
||||
v1alpha1.AddToScheme(api.Scheme)
|
||||
}
|
||||
}
|
||||
}
|
57
pkg/apis/apps/register.go
Normal file
57
pkg/apis/apps/register.go
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||
|
||||
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 apps
|
||||
|
||||
import (
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
)
|
||||
|
||||
func AddToScheme(scheme *runtime.Scheme) {
|
||||
// Add the API to Scheme.
|
||||
addKnownTypes(scheme)
|
||||
}
|
||||
|
||||
// GroupName is the group name use in this package
|
||||
const GroupName = "apps"
|
||||
|
||||
// SchemeGroupVersion is group version used to register these objects
|
||||
var SchemeGroupVersion = unversioned.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal}
|
||||
|
||||
// Kind takes an unqualified kind and returns back a Group qualified GroupKind
|
||||
func Kind(kind string) unversioned.GroupKind {
|
||||
return SchemeGroupVersion.WithKind(kind).GroupKind()
|
||||
}
|
||||
|
||||
// Resource takes an unqualified resource and returns back a Group qualified GroupResource
|
||||
func Resource(resource string) unversioned.GroupResource {
|
||||
return SchemeGroupVersion.WithResource(resource).GroupResource()
|
||||
}
|
||||
|
||||
// Adds the list of known types to api.Scheme.
|
||||
func addKnownTypes(scheme *runtime.Scheme) {
|
||||
// TODO this will get cleaned up with the scheme types are fixed
|
||||
scheme.AddKnownTypes(SchemeGroupVersion,
|
||||
&PetSet{},
|
||||
&PetSetList{},
|
||||
&api.ListOptions{},
|
||||
)
|
||||
}
|
||||
|
||||
func (obj *PetSet) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
|
||||
func (obj *PetSetList) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
|
1636
pkg/apis/apps/types.generated.go
Normal file
1636
pkg/apis/apps/types.generated.go
Normal file
File diff suppressed because it is too large
Load Diff
94
pkg/apis/apps/types.go
Normal file
94
pkg/apis/apps/types.go
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||
|
||||
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 apps
|
||||
|
||||
import (
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
)
|
||||
|
||||
// PetSet represents a set of pods with consistent identities.
|
||||
// Identities are defined as:
|
||||
// - Network: A single stable DNS and hostname.
|
||||
// - Storage: As many VolumeClaims as requested.
|
||||
// The PetSet guarantees that a given network identity will always
|
||||
// map to the same storage identity. PetSet is currently in alpha and
|
||||
// and subject to change without notice.
|
||||
type PetSet struct {
|
||||
unversioned.TypeMeta `json:",inline"`
|
||||
api.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
// Spec defines the desired identities of pets in this set.
|
||||
Spec PetSetSpec `json:"spec,omitempty"`
|
||||
|
||||
// Status is the current status of Pets in this PetSet. This data
|
||||
// may be out of date by some window of time.
|
||||
Status PetSetStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// A PetSetSpec is the specification of a PetSet.
|
||||
type PetSetSpec struct {
|
||||
// Replicas is the desired number of replicas of the given Template.
|
||||
// These are replicas in the sense that they are instantiations of the
|
||||
// same Template, but individual replicas also have a consistent identity.
|
||||
// If unspecified, defaults to 1.
|
||||
// TODO: Consider a rename of this field.
|
||||
Replicas int `json:"replicas,omitempty"`
|
||||
|
||||
// Selector is a label query over pods that should match the replica count.
|
||||
// If empty, defaulted to labels on the pod template.
|
||||
// More info: http://releases.k8s.io/HEAD/docs/user-guide/labels.md#label-selectors
|
||||
Selector *unversioned.LabelSelector `json:"selector,omitempty"`
|
||||
|
||||
// Template is the object that describes the pod that will be created if
|
||||
// insufficient replicas are detected. Each pod stamped out by the PetSet
|
||||
// will fulfill this Template, but have a unique identity from the rest
|
||||
// of the PetSet.
|
||||
Template api.PodTemplateSpec `json:"template"`
|
||||
|
||||
// VolumeClaimTemplates is a list of claims that pets are allowed to reference.
|
||||
// The PetSet controller is responsible for mapping network identities to
|
||||
// claims in a way that maintains the identity of a pet. Every claim in
|
||||
// this list must have at least one matching (by name) volumeMount in one
|
||||
// container in the template. A claim in this list takes precedence over
|
||||
// any volumes in the template, with the same name.
|
||||
// TODO: Define the behavior if a claim already exists with the same name.
|
||||
VolumeClaimTemplates []api.PersistentVolumeClaim `json:"volumeClaimTemplates,omitempty"`
|
||||
|
||||
// ServiceName is the name of the service that governs this PetSet.
|
||||
// This service must exist before the PetSet, and is responsible for
|
||||
// the network identity of the set. Pets get DNS/hostnames that follow the
|
||||
// pattern: pet-specific-string.serviceName.default.svc.cluster.local
|
||||
// where "pet-specific-string" is managed by the PetSet controller.
|
||||
ServiceName string `json:"serviceName"`
|
||||
}
|
||||
|
||||
// PetSetStatus represents the current state of a PetSet.
|
||||
type PetSetStatus struct {
|
||||
// most recent generation observed by this autoscaler.
|
||||
ObservedGeneration *int64 `json:"observedGeneration,omitempty"`
|
||||
|
||||
// Replicas is the number of actual replicas.
|
||||
Replicas int `json:"replicas"`
|
||||
}
|
||||
|
||||
// PetSetList is a collection of PetSets.
|
||||
type PetSetList struct {
|
||||
unversioned.TypeMeta `json:",inline"`
|
||||
unversioned.ListMeta `json:"metadata,omitempty"`
|
||||
Items []PetSet `json:"items"`
|
||||
}
|
125
pkg/apis/apps/v1alpha1/conversion.go
Normal file
125
pkg/apis/apps/v1alpha1/conversion.go
Normal file
@ -0,0 +1,125 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||
|
||||
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 (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
v1 "k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/apis/apps"
|
||||
"k8s.io/kubernetes/pkg/conversion"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
)
|
||||
|
||||
func addConversionFuncs(scheme *runtime.Scheme) {
|
||||
// Add non-generated conversion functions to handle the *int32 -> int
|
||||
// conversion. A pointer is useful in the versioned type so we can default
|
||||
// it, but a plain int32 is more convenient in the internal type. These
|
||||
// functions are the same as the autogenerated ones in every other way.
|
||||
err := scheme.AddConversionFuncs(
|
||||
Convert_v1alpha1_PetSetSpec_To_apps_PetSetSpec,
|
||||
Convert_apps_PetSetSpec_To_v1alpha1_PetSetSpec,
|
||||
)
|
||||
if err != nil {
|
||||
// If one of the conversion functions is malformed, detect it immediately.
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = api.Scheme.AddFieldLabelConversionFunc("apps/v1alpha1", "PetSet",
|
||||
func(label, value string) (string, string, error) {
|
||||
switch label {
|
||||
case "metadata.name", "metadata.namespace", "status.successful":
|
||||
return label, value, nil
|
||||
default:
|
||||
return "", "", fmt.Errorf("field label not supported: %s", label)
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
// If one of the conversion functions is malformed, detect it immediately.
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func Convert_v1alpha1_PetSetSpec_To_apps_PetSetSpec(in *PetSetSpec, out *apps.PetSetSpec, s conversion.Scope) error {
|
||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||
defaulting.(func(*PetSetSpec))(in)
|
||||
}
|
||||
if in.Replicas != nil {
|
||||
out.Replicas = int(*in.Replicas)
|
||||
}
|
||||
if in.Selector != nil {
|
||||
in, out := &in.Selector, &out.Selector
|
||||
*out = new(unversioned.LabelSelector)
|
||||
if err := s.Convert(*in, *out, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.Selector = nil
|
||||
}
|
||||
if err := s.Convert(&in.Template, &out.Template, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.VolumeClaimTemplates != nil {
|
||||
in, out := &in.VolumeClaimTemplates, &out.VolumeClaimTemplates
|
||||
*out = make([]api.PersistentVolumeClaim, len(*in))
|
||||
for i := range *in {
|
||||
if err := s.Convert(&(*in)[i], &(*out)[i], 0); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.VolumeClaimTemplates = nil
|
||||
}
|
||||
out.ServiceName = in.ServiceName
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_apps_PetSetSpec_To_v1alpha1_PetSetSpec(in *apps.PetSetSpec, out *PetSetSpec, s conversion.Scope) error {
|
||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||
defaulting.(func(*apps.PetSetSpec))(in)
|
||||
}
|
||||
out.Replicas = new(int32)
|
||||
*out.Replicas = int32(in.Replicas)
|
||||
if in.Selector != nil {
|
||||
in, out := &in.Selector, &out.Selector
|
||||
*out = new(unversioned.LabelSelector)
|
||||
if err := s.Convert(*in, *out, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.Selector = nil
|
||||
}
|
||||
if err := s.Convert(&in.Template, &out.Template, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.VolumeClaimTemplates != nil {
|
||||
in, out := &in.VolumeClaimTemplates, &out.VolumeClaimTemplates
|
||||
*out = make([]v1.PersistentVolumeClaim, len(*in))
|
||||
for i := range *in {
|
||||
if err := s.Convert(&(*in)[i], &(*out)[i], 0); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.VolumeClaimTemplates = nil
|
||||
}
|
||||
out.ServiceName = in.ServiceName
|
||||
return nil
|
||||
}
|
186
pkg/apis/apps/v1alpha1/conversion_generated.go
Normal file
186
pkg/apis/apps/v1alpha1/conversion_generated.go
Normal file
@ -0,0 +1,186 @@
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||
|
||||
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 conversion-gen. Do not edit it manually!
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
api "k8s.io/kubernetes/pkg/api"
|
||||
apps "k8s.io/kubernetes/pkg/apis/apps"
|
||||
conversion "k8s.io/kubernetes/pkg/conversion"
|
||||
reflect "reflect"
|
||||
)
|
||||
|
||||
func init() {
|
||||
if err := api.Scheme.AddGeneratedConversionFuncs(
|
||||
Convert_v1alpha1_PetSet_To_apps_PetSet,
|
||||
Convert_apps_PetSet_To_v1alpha1_PetSet,
|
||||
Convert_v1alpha1_PetSetList_To_apps_PetSetList,
|
||||
Convert_apps_PetSetList_To_v1alpha1_PetSetList,
|
||||
Convert_v1alpha1_PetSetSpec_To_apps_PetSetSpec,
|
||||
Convert_apps_PetSetSpec_To_v1alpha1_PetSetSpec,
|
||||
Convert_v1alpha1_PetSetStatus_To_apps_PetSetStatus,
|
||||
Convert_apps_PetSetStatus_To_v1alpha1_PetSetStatus,
|
||||
); err != nil {
|
||||
// if one of the conversion functions is malformed, detect it immediately.
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func autoConvert_v1alpha1_PetSet_To_apps_PetSet(in *PetSet, out *apps.PetSet, s conversion.Scope) error {
|
||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||
defaulting.(func(*PetSet))(in)
|
||||
}
|
||||
if err := api.Convert_unversioned_TypeMeta_To_unversioned_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO: Inefficient conversion - can we improve it?
|
||||
if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := Convert_v1alpha1_PetSetSpec_To_apps_PetSetSpec(&in.Spec, &out.Spec, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := Convert_v1alpha1_PetSetStatus_To_apps_PetSetStatus(&in.Status, &out.Status, s); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_v1alpha1_PetSet_To_apps_PetSet(in *PetSet, out *apps.PetSet, s conversion.Scope) error {
|
||||
return autoConvert_v1alpha1_PetSet_To_apps_PetSet(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_apps_PetSet_To_v1alpha1_PetSet(in *apps.PetSet, out *PetSet, s conversion.Scope) error {
|
||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||
defaulting.(func(*apps.PetSet))(in)
|
||||
}
|
||||
if err := api.Convert_unversioned_TypeMeta_To_unversioned_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO: Inefficient conversion - can we improve it?
|
||||
if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := Convert_apps_PetSetSpec_To_v1alpha1_PetSetSpec(&in.Spec, &out.Spec, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := Convert_apps_PetSetStatus_To_v1alpha1_PetSetStatus(&in.Status, &out.Status, s); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_apps_PetSet_To_v1alpha1_PetSet(in *apps.PetSet, out *PetSet, s conversion.Scope) error {
|
||||
return autoConvert_apps_PetSet_To_v1alpha1_PetSet(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1alpha1_PetSetList_To_apps_PetSetList(in *PetSetList, out *apps.PetSetList, s conversion.Scope) error {
|
||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||
defaulting.(func(*PetSetList))(in)
|
||||
}
|
||||
if err := api.Convert_unversioned_TypeMeta_To_unversioned_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := api.Convert_unversioned_ListMeta_To_unversioned_ListMeta(&in.ListMeta, &out.ListMeta, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]apps.PetSet, len(*in))
|
||||
for i := range *in {
|
||||
if err := Convert_v1alpha1_PetSet_To_apps_PetSet(&(*in)[i], &(*out)[i], s); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Items = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_v1alpha1_PetSetList_To_apps_PetSetList(in *PetSetList, out *apps.PetSetList, s conversion.Scope) error {
|
||||
return autoConvert_v1alpha1_PetSetList_To_apps_PetSetList(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_apps_PetSetList_To_v1alpha1_PetSetList(in *apps.PetSetList, out *PetSetList, s conversion.Scope) error {
|
||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||
defaulting.(func(*apps.PetSetList))(in)
|
||||
}
|
||||
if err := api.Convert_unversioned_TypeMeta_To_unversioned_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := api.Convert_unversioned_ListMeta_To_unversioned_ListMeta(&in.ListMeta, &out.ListMeta, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]PetSet, len(*in))
|
||||
for i := range *in {
|
||||
if err := Convert_apps_PetSet_To_v1alpha1_PetSet(&(*in)[i], &(*out)[i], s); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Items = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_apps_PetSetList_To_v1alpha1_PetSetList(in *apps.PetSetList, out *PetSetList, s conversion.Scope) error {
|
||||
return autoConvert_apps_PetSetList_To_v1alpha1_PetSetList(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1alpha1_PetSetStatus_To_apps_PetSetStatus(in *PetSetStatus, out *apps.PetSetStatus, s conversion.Scope) error {
|
||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||
defaulting.(func(*PetSetStatus))(in)
|
||||
}
|
||||
if in.ObservedGeneration != nil {
|
||||
in, out := &in.ObservedGeneration, &out.ObservedGeneration
|
||||
*out = new(int64)
|
||||
**out = **in
|
||||
} else {
|
||||
out.ObservedGeneration = nil
|
||||
}
|
||||
out.Replicas = int(in.Replicas)
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_v1alpha1_PetSetStatus_To_apps_PetSetStatus(in *PetSetStatus, out *apps.PetSetStatus, s conversion.Scope) error {
|
||||
return autoConvert_v1alpha1_PetSetStatus_To_apps_PetSetStatus(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_apps_PetSetStatus_To_v1alpha1_PetSetStatus(in *apps.PetSetStatus, out *PetSetStatus, s conversion.Scope) error {
|
||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||
defaulting.(func(*apps.PetSetStatus))(in)
|
||||
}
|
||||
if in.ObservedGeneration != nil {
|
||||
in, out := &in.ObservedGeneration, &out.ObservedGeneration
|
||||
*out = new(int64)
|
||||
**out = **in
|
||||
} else {
|
||||
out.ObservedGeneration = nil
|
||||
}
|
||||
out.Replicas = int32(in.Replicas)
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_apps_PetSetStatus_To_v1alpha1_PetSetStatus(in *apps.PetSetStatus, out *PetSetStatus, s conversion.Scope) error {
|
||||
return autoConvert_apps_PetSetStatus_To_v1alpha1_PetSetStatus(in, out, s)
|
||||
}
|
124
pkg/apis/apps/v1alpha1/deep_copy_generated.go
Normal file
124
pkg/apis/apps/v1alpha1/deep_copy_generated.go
Normal file
@ -0,0 +1,124 @@
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||
|
||||
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 deepcopy-gen. Do not edit it manually!
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
api "k8s.io/kubernetes/pkg/api"
|
||||
unversioned "k8s.io/kubernetes/pkg/api/unversioned"
|
||||
v1 "k8s.io/kubernetes/pkg/api/v1"
|
||||
conversion "k8s.io/kubernetes/pkg/conversion"
|
||||
)
|
||||
|
||||
func init() {
|
||||
if err := api.Scheme.AddGeneratedDeepCopyFuncs(
|
||||
DeepCopy_v1alpha1_PetSet,
|
||||
DeepCopy_v1alpha1_PetSetList,
|
||||
DeepCopy_v1alpha1_PetSetSpec,
|
||||
DeepCopy_v1alpha1_PetSetStatus,
|
||||
); err != nil {
|
||||
// if one of the deep copy functions is malformed, detect it immediately.
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_v1alpha1_PetSet(in PetSet, out *PetSet, c *conversion.Cloner) error {
|
||||
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := v1.DeepCopy_v1_ObjectMeta(in.ObjectMeta, &out.ObjectMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := DeepCopy_v1alpha1_PetSetSpec(in.Spec, &out.Spec, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := DeepCopy_v1alpha1_PetSetStatus(in.Status, &out.Status, c); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_v1alpha1_PetSetList(in PetSetList, out *PetSetList, c *conversion.Cloner) error {
|
||||
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := unversioned.DeepCopy_unversioned_ListMeta(in.ListMeta, &out.ListMeta, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Items != nil {
|
||||
in, out := in.Items, &out.Items
|
||||
*out = make([]PetSet, len(in))
|
||||
for i := range in {
|
||||
if err := DeepCopy_v1alpha1_PetSet(in[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Items = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_v1alpha1_PetSetSpec(in PetSetSpec, out *PetSetSpec, c *conversion.Cloner) error {
|
||||
if in.Replicas != nil {
|
||||
in, out := in.Replicas, &out.Replicas
|
||||
*out = new(int32)
|
||||
**out = *in
|
||||
} else {
|
||||
out.Replicas = nil
|
||||
}
|
||||
if in.Selector != nil {
|
||||
in, out := in.Selector, &out.Selector
|
||||
*out = new(unversioned.LabelSelector)
|
||||
if err := unversioned.DeepCopy_unversioned_LabelSelector(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.Selector = nil
|
||||
}
|
||||
if err := v1.DeepCopy_v1_PodTemplateSpec(in.Template, &out.Template, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.VolumeClaimTemplates != nil {
|
||||
in, out := in.VolumeClaimTemplates, &out.VolumeClaimTemplates
|
||||
*out = make([]v1.PersistentVolumeClaim, len(in))
|
||||
for i := range in {
|
||||
if err := v1.DeepCopy_v1_PersistentVolumeClaim(in[i], &(*out)[i], c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.VolumeClaimTemplates = nil
|
||||
}
|
||||
out.ServiceName = in.ServiceName
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_v1alpha1_PetSetStatus(in PetSetStatus, out *PetSetStatus, c *conversion.Cloner) error {
|
||||
if in.ObservedGeneration != nil {
|
||||
in, out := in.ObservedGeneration, &out.ObservedGeneration
|
||||
*out = new(int64)
|
||||
**out = *in
|
||||
} else {
|
||||
out.ObservedGeneration = nil
|
||||
}
|
||||
out.Replicas = in.Replicas
|
||||
return nil
|
||||
}
|
44
pkg/apis/apps/v1alpha1/defaulting.go
Normal file
44
pkg/apis/apps/v1alpha1/defaulting.go
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||
|
||||
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/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
)
|
||||
|
||||
func addDefaultingFuncs(scheme *runtime.Scheme) {
|
||||
scheme.AddDefaultingFuncs(
|
||||
func(obj *PetSet) {
|
||||
labels := obj.Spec.Template.Labels
|
||||
if labels != nil {
|
||||
if obj.Spec.Selector == nil {
|
||||
obj.Spec.Selector = &unversioned.LabelSelector{
|
||||
MatchLabels: labels,
|
||||
}
|
||||
}
|
||||
if len(obj.Labels) == 0 {
|
||||
obj.Labels = labels
|
||||
}
|
||||
}
|
||||
if obj.Spec.Replicas == nil {
|
||||
obj.Spec.Replicas = new(int32)
|
||||
*obj.Spec.Replicas = 1
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
18
pkg/apis/apps/v1alpha1/doc.go
Normal file
18
pkg/apis/apps/v1alpha1/doc.go
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
// +genconversion=true
|
||||
package v1alpha1
|
49
pkg/apis/apps/v1alpha1/register.go
Normal file
49
pkg/apis/apps/v1alpha1/register.go
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||
|
||||
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/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
versionedwatch "k8s.io/kubernetes/pkg/watch/versioned"
|
||||
)
|
||||
|
||||
// GroupName is the group name use in this package
|
||||
const GroupName = "apps"
|
||||
|
||||
// SchemeGroupVersion is group version used to register these objects
|
||||
var SchemeGroupVersion = unversioned.GroupVersion{Group: GroupName, Version: "v1alpha1"}
|
||||
|
||||
func AddToScheme(scheme *runtime.Scheme) {
|
||||
addKnownTypes(scheme)
|
||||
addDefaultingFuncs(scheme)
|
||||
addConversionFuncs(scheme)
|
||||
}
|
||||
|
||||
// Adds the list of known types to api.Scheme.
|
||||
func addKnownTypes(scheme *runtime.Scheme) {
|
||||
scheme.AddKnownTypes(SchemeGroupVersion,
|
||||
&PetSet{},
|
||||
&PetSetList{},
|
||||
&v1.ListOptions{},
|
||||
)
|
||||
versionedwatch.AddToGroupVersion(scheme, SchemeGroupVersion)
|
||||
}
|
||||
|
||||
func (obj *PetSet) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
|
||||
func (obj *PetSetList) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
|
1666
pkg/apis/apps/v1alpha1/types.generated.go
Normal file
1666
pkg/apis/apps/v1alpha1/types.generated.go
Normal file
File diff suppressed because it is too large
Load Diff
94
pkg/apis/apps/v1alpha1/types.go
Normal file
94
pkg/apis/apps/v1alpha1/types.go
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||
|
||||
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/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
)
|
||||
|
||||
// PetSet represents a set of pods with consistent identities.
|
||||
// Identities are defined as:
|
||||
// - Network: A single stable DNS and hostname.
|
||||
// - Storage: As many VolumeClaims as requested.
|
||||
// The PetSet guarantees that a given network identity will always
|
||||
// map to the same storage identity. PetSet is currently in alpha
|
||||
// and subject to change without notice.
|
||||
type PetSet struct {
|
||||
unversioned.TypeMeta `json:",inline"`
|
||||
v1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
|
||||
// Spec defines the desired identities of pets in this set.
|
||||
Spec PetSetSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`
|
||||
|
||||
// Status is the current status of Pets in this PetSet. This data
|
||||
// may be out of date by some window of time.
|
||||
Status PetSetStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
|
||||
}
|
||||
|
||||
// A PetSetSpec is the specification of a PetSet.
|
||||
type PetSetSpec struct {
|
||||
// Replicas is the desired number of replicas of the given Template.
|
||||
// These are replicas in the sense that they are instantiations of the
|
||||
// same Template, but individual replicas also have a consistent identity.
|
||||
// If unspecified, defaults to 1.
|
||||
// TODO: Consider a rename of this field.
|
||||
Replicas *int32 `json:"replicas,omitempty" protobuf:"varint,1,opt,name=replicas"`
|
||||
|
||||
// Selector is a label query over pods that should match the replica count.
|
||||
// If empty, defaulted to labels on the pod template.
|
||||
// More info: http://releases.k8s.io/HEAD/docs/user-guide/labels.md#label-selectors
|
||||
Selector *unversioned.LabelSelector `json:"selector,omitempty" protobuf:"bytes,2,opt,name=selector"`
|
||||
|
||||
// Template is the object that describes the pod that will be created if
|
||||
// insufficient replicas are detected. Each pod stamped out by the PetSet
|
||||
// will fulfill this Template, but have a unique identity from the rest
|
||||
// of the PetSet.
|
||||
Template v1.PodTemplateSpec `json:"template" protobuf:"bytes,3,opt,name=template"`
|
||||
|
||||
// VolumeClaimTemplates is a list of claims that pets are allowed to reference.
|
||||
// The PetSet controller is responsible for mapping network identities to
|
||||
// claims in a way that maintains the identity of a pet. Every claim in
|
||||
// this list must have at least one matching (by name) volumeMount in one
|
||||
// container in the template. A claim in this list takes precedence over
|
||||
// any volumes in the template, with the same name.
|
||||
// TODO: Define the behavior if a claim already exists with the same name.
|
||||
VolumeClaimTemplates []v1.PersistentVolumeClaim `json:"volumeClaimTemplates,omitempty" protobuf:"bytes,4,rep,name=volumeClaimTemplates"`
|
||||
|
||||
// ServiceName is the name of the service that governs this PetSet.
|
||||
// This service must exist before the PetSet, and is responsible for
|
||||
// the network identity of the set. Pets get DNS/hostnames that follow the
|
||||
// pattern: pet-specific-string.serviceName.default.svc.cluster.local
|
||||
// where "pet-specific-string" is managed by the PetSet controller.
|
||||
ServiceName string `json:"serviceName" protobuf:"bytes,5,opt,name=serviceName"`
|
||||
}
|
||||
|
||||
// PetSetStatus represents the current state of a PetSet.
|
||||
type PetSetStatus struct {
|
||||
// most recent generation observed by this autoscaler.
|
||||
ObservedGeneration *int64 `json:"observedGeneration,omitempty" protobuf:"varint,1,opt,name=observedGeneration"`
|
||||
|
||||
// Replicas is the number of actual replicas.
|
||||
Replicas int32 `json:"replicas" protobuf:"varint,2,opt,name=replicas"`
|
||||
}
|
||||
|
||||
// PetSetList is a collection of PetSets.
|
||||
type PetSetList struct {
|
||||
unversioned.TypeMeta `json:",inline"`
|
||||
unversioned.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
Items []PetSet `json:"items" protobuf:"bytes,2,rep,name=items"`
|
||||
}
|
71
pkg/apis/apps/v1alpha1/types_swagger_doc_generated.go
Normal file
71
pkg/apis/apps/v1alpha1/types_swagger_doc_generated.go
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors All rights reserved.
|
||||
|
||||
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
|
||||
|
||||
// This file contains a collection of methods that can be used from go-restful to
|
||||
// generate Swagger API documentation for its models. Please read this PR for more
|
||||
// information on the implementation: https://github.com/emicklei/go-restful/pull/215
|
||||
//
|
||||
// TODOs are ignored from the parser (e.g. TODO(andronat):... || TODO:...) if and only if
|
||||
// they are on one line! For multiple line or blocks that you want to ignore use ---.
|
||||
// Any context after a --- is ignored.
|
||||
//
|
||||
// Those methods can be generated by using hack/update-generated-swagger-docs.sh
|
||||
|
||||
// AUTO-GENERATED FUNCTIONS START HERE
|
||||
var map_PetSet = map[string]string{
|
||||
"": "PetSet represents a set of pods with consistent identities. Identities are defined as:\n - Network: A single stable DNS and hostname.\n - Storage: As many VolumeClaims as requested.\nThe PetSet guarantees that a given network identity will always map to the same storage identity. PetSet is currently in alpha and subject to change without notice.",
|
||||
"spec": "Spec defines the desired identities of pets in this set.",
|
||||
"status": "Status is the current status of Pets in this PetSet. This data may be out of date by some window of time.",
|
||||
}
|
||||
|
||||
func (PetSet) SwaggerDoc() map[string]string {
|
||||
return map_PetSet
|
||||
}
|
||||
|
||||
var map_PetSetList = map[string]string{
|
||||
"": "PetSetList is a collection of PetSets.",
|
||||
}
|
||||
|
||||
func (PetSetList) SwaggerDoc() map[string]string {
|
||||
return map_PetSetList
|
||||
}
|
||||
|
||||
var map_PetSetSpec = map[string]string{
|
||||
"": "A PetSetSpec is the specification of a PetSet.",
|
||||
"replicas": "Replicas is the desired number of replicas of the given Template. These are replicas in the sense that they are instantiations of the same Template, but individual replicas also have a consistent identity. If unspecified, defaults to 1.",
|
||||
"selector": "Selector is a label query over pods that should match the replica count. If empty, defaulted to labels on the pod template. More info: http://releases.k8s.io/HEAD/docs/user-guide/labels.md#label-selectors",
|
||||
"template": "Template is the object that describes the pod that will be created if insufficient replicas are detected. Each pod stamped out by the PetSet will fulfill this Template, but have a unique identity from the rest of the PetSet.",
|
||||
"volumeClaimTemplates": "VolumeClaimTemplates is a list of claims that pets are allowed to reference. The PetSet controller is responsible for mapping network identities to claims in a way that maintains the identity of a pet. Every claim in this list must have at least one matching (by name) volumeMount in one container in the template. A claim in this list takes precedence over any volumes in the template, with the same name.",
|
||||
"serviceName": "ServiceName is the name of the service that governs this PetSet. This service must exist before the PetSet, and is responsible for the network identity of the set. Pets get DNS/hostnames that follow the pattern: pet-specific-string.serviceName.default.svc.cluster.local where \"pet-specific-string\" is managed by the PetSet controller.",
|
||||
}
|
||||
|
||||
func (PetSetSpec) SwaggerDoc() map[string]string {
|
||||
return map_PetSetSpec
|
||||
}
|
||||
|
||||
var map_PetSetStatus = map[string]string{
|
||||
"": "PetSetStatus represents the current state of a PetSet.",
|
||||
"observedGeneration": "most recent generation observed by this autoscaler.",
|
||||
"replicas": "Replicas is the number of actual replicas.",
|
||||
}
|
||||
|
||||
func (PetSetStatus) SwaggerDoc() map[string]string {
|
||||
return map_PetSetStatus
|
||||
}
|
||||
|
||||
// AUTO-GENERATED FUNCTIONS END HERE
|
110
pkg/apis/apps/validation/validation.go
Normal file
110
pkg/apis/apps/validation/validation.go
Normal file
@ -0,0 +1,110 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||
|
||||
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 validation
|
||||
|
||||
import (
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
unversionedvalidation "k8s.io/kubernetes/pkg/api/unversioned/validation"
|
||||
apivalidation "k8s.io/kubernetes/pkg/api/validation"
|
||||
"k8s.io/kubernetes/pkg/apis/apps"
|
||||
"k8s.io/kubernetes/pkg/labels"
|
||||
"k8s.io/kubernetes/pkg/util/validation/field"
|
||||
)
|
||||
|
||||
// ValidatePetSetName can be used to check whether the given PetSet
|
||||
// name is valid.
|
||||
// Prefix indicates this name will be used as part of generation, in which case
|
||||
// trailing dashes are allowed.
|
||||
func ValidatePetSetName(name string, prefix bool) (bool, string) {
|
||||
return apivalidation.NameIsDNSSubdomain(name, prefix)
|
||||
}
|
||||
|
||||
// Validates the given template and ensures that it is in accordance with the desired selector.
|
||||
func ValidatePodTemplateSpecForPetSet(template *api.PodTemplateSpec, selector labels.Selector, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
if template == nil {
|
||||
allErrs = append(allErrs, field.Required(fldPath, ""))
|
||||
} else {
|
||||
if !selector.Empty() {
|
||||
// Verify that the PetSet selector matches the labels in template.
|
||||
labels := labels.Set(template.Labels)
|
||||
if !selector.Matches(labels) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("metadata", "labels"), template.Labels, "`selector` does not match template `labels`"))
|
||||
}
|
||||
}
|
||||
// TODO: Add validation for PodSpec, currently this will check volumes, which we know will
|
||||
// fail. We should really check that the union of the given volumes and volumeClaims match
|
||||
// volume mounts in the containers.
|
||||
// allErrs = append(allErrs, apivalidation.ValidatePodTemplateSpec(template, fldPath)...)
|
||||
allErrs = append(allErrs, apivalidation.ValidateLabels(template.Labels, fldPath.Child("labels"))...)
|
||||
allErrs = append(allErrs, apivalidation.ValidateAnnotations(template.Annotations, fldPath.Child("annotations"))...)
|
||||
allErrs = append(allErrs, apivalidation.ValidatePodSpecificAnnotations(template.Annotations, fldPath.Child("annotations"))...)
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// ValidatePetSetSpec tests if required fields in the PetSet spec are set.
|
||||
func ValidatePetSetSpec(spec *apps.PetSetSpec, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(spec.Replicas), fldPath.Child("replicas"))...)
|
||||
if spec.Selector == nil {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("selector"), ""))
|
||||
} else {
|
||||
allErrs = append(allErrs, unversionedvalidation.ValidateLabelSelector(spec.Selector, fldPath.Child("selector"))...)
|
||||
if len(spec.Selector.MatchLabels)+len(spec.Selector.MatchExpressions) == 0 {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("selector"), spec.Selector, "empty selector is not valid for petset."))
|
||||
}
|
||||
}
|
||||
|
||||
selector, err := unversioned.LabelSelectorAsSelector(spec.Selector)
|
||||
if err != nil {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("selector"), spec.Selector, ""))
|
||||
} else {
|
||||
allErrs = append(allErrs, ValidatePodTemplateSpecForPetSet(&spec.Template, selector, fldPath.Child("template"))...)
|
||||
}
|
||||
|
||||
if spec.Template.Spec.RestartPolicy != api.RestartPolicyAlways {
|
||||
allErrs = append(allErrs, field.NotSupported(fldPath.Child("template", "spec", "restartPolicy"), spec.Template.Spec.RestartPolicy, []string{string(api.RestartPolicyAlways)}))
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// ValidatePetSet validates a PetSet.
|
||||
func ValidatePetSet(petSet *apps.PetSet) field.ErrorList {
|
||||
allErrs := apivalidation.ValidateObjectMeta(&petSet.ObjectMeta, true, ValidatePetSetName, field.NewPath("metadata"))
|
||||
allErrs = append(allErrs, ValidatePetSetSpec(&petSet.Spec, field.NewPath("spec"))...)
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// ValidatePetSetUpdate tests if required fields in the PetSet are set.
|
||||
func ValidatePetSetUpdate(petSet, oldPetSet *apps.PetSet) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&petSet.ObjectMeta, &oldPetSet.ObjectMeta, field.NewPath("metadata"))...)
|
||||
allErrs = append(allErrs, ValidatePetSetSpec(&petSet.Spec, field.NewPath("spec"))...)
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// ValidatePetSetStatusUpdate tests if required fields in the PetSet are set.
|
||||
func ValidatePetSetStatusUpdate(petSet, oldPetSet *apps.PetSet) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&petSet.ObjectMeta, &oldPetSet.ObjectMeta, field.NewPath("metadata"))...)
|
||||
// TODO: Validate status.
|
||||
return allErrs
|
||||
}
|
379
pkg/apis/apps/validation/validation_test.go
Normal file
379
pkg/apis/apps/validation/validation_test.go
Normal file
@ -0,0 +1,379 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||
|
||||
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 validation
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/apis/apps"
|
||||
)
|
||||
|
||||
func TestValidatePetSet(t *testing.T) {
|
||||
validLabels := map[string]string{"a": "b"}
|
||||
validPodTemplate := api.PodTemplate{
|
||||
Template: api.PodTemplateSpec{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Labels: validLabels,
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
},
|
||||
},
|
||||
}
|
||||
invalidLabels := map[string]string{"NoUppercaseOrSpecialCharsLike=Equals": "b"}
|
||||
invalidPodTemplate := api.PodTemplate{
|
||||
Template: api.PodTemplateSpec{
|
||||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
},
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Labels: invalidLabels,
|
||||
},
|
||||
},
|
||||
}
|
||||
successCases := []apps.PetSet{
|
||||
{
|
||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
||||
Spec: apps.PetSetSpec{
|
||||
Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
|
||||
Template: validPodTemplate.Template,
|
||||
},
|
||||
},
|
||||
{
|
||||
ObjectMeta: api.ObjectMeta{Name: "abc-123", Namespace: api.NamespaceDefault},
|
||||
Spec: apps.PetSetSpec{
|
||||
Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
|
||||
Template: validPodTemplate.Template,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, successCase := range successCases {
|
||||
if errs := ValidatePetSet(&successCase); len(errs) != 0 {
|
||||
t.Errorf("expected success: %v", errs)
|
||||
}
|
||||
}
|
||||
|
||||
errorCases := map[string]apps.PetSet{
|
||||
"zero-length ID": {
|
||||
ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault},
|
||||
Spec: apps.PetSetSpec{
|
||||
Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
|
||||
Template: validPodTemplate.Template,
|
||||
},
|
||||
},
|
||||
"missing-namespace": {
|
||||
ObjectMeta: api.ObjectMeta{Name: "abc-123"},
|
||||
Spec: apps.PetSetSpec{
|
||||
Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
|
||||
Template: validPodTemplate.Template,
|
||||
},
|
||||
},
|
||||
"empty selector": {
|
||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
||||
Spec: apps.PetSetSpec{
|
||||
Template: validPodTemplate.Template,
|
||||
},
|
||||
},
|
||||
"selector_doesnt_match": {
|
||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
||||
Spec: apps.PetSetSpec{
|
||||
Selector: &unversioned.LabelSelector{MatchLabels: map[string]string{"foo": "bar"}},
|
||||
Template: validPodTemplate.Template,
|
||||
},
|
||||
},
|
||||
"invalid manifest": {
|
||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
||||
Spec: apps.PetSetSpec{
|
||||
Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
|
||||
},
|
||||
},
|
||||
"negative_replicas": {
|
||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
||||
Spec: apps.PetSetSpec{
|
||||
Replicas: -1,
|
||||
Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
|
||||
},
|
||||
},
|
||||
"invalid_label": {
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "abc-123",
|
||||
Namespace: api.NamespaceDefault,
|
||||
Labels: map[string]string{
|
||||
"NoUppercaseOrSpecialCharsLike=Equals": "bar",
|
||||
},
|
||||
},
|
||||
Spec: apps.PetSetSpec{
|
||||
Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
|
||||
Template: validPodTemplate.Template,
|
||||
},
|
||||
},
|
||||
"invalid_label 2": {
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "abc-123",
|
||||
Namespace: api.NamespaceDefault,
|
||||
Labels: map[string]string{
|
||||
"NoUppercaseOrSpecialCharsLike=Equals": "bar",
|
||||
},
|
||||
},
|
||||
Spec: apps.PetSetSpec{
|
||||
Template: invalidPodTemplate.Template,
|
||||
},
|
||||
},
|
||||
"invalid_annotation": {
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "abc-123",
|
||||
Namespace: api.NamespaceDefault,
|
||||
Annotations: map[string]string{
|
||||
"NoUppercaseOrSpecialCharsLike=Equals": "bar",
|
||||
},
|
||||
},
|
||||
Spec: apps.PetSetSpec{
|
||||
Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
|
||||
Template: validPodTemplate.Template,
|
||||
},
|
||||
},
|
||||
"invalid restart policy 1": {
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "abc-123",
|
||||
Namespace: api.NamespaceDefault,
|
||||
},
|
||||
Spec: apps.PetSetSpec{
|
||||
Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
|
||||
Template: api.PodTemplateSpec{
|
||||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyOnFailure,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
},
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Labels: validLabels,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"invalid restart policy 2": {
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "abc-123",
|
||||
Namespace: api.NamespaceDefault,
|
||||
},
|
||||
Spec: apps.PetSetSpec{
|
||||
Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
|
||||
Template: api.PodTemplateSpec{
|
||||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyNever,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
},
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Labels: validLabels,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for k, v := range errorCases {
|
||||
errs := ValidatePetSet(&v)
|
||||
if len(errs) == 0 {
|
||||
t.Errorf("expected failure for %s", k)
|
||||
}
|
||||
for i := range errs {
|
||||
field := errs[i].Field
|
||||
if !strings.HasPrefix(field, "spec.template.") &&
|
||||
field != "metadata.name" &&
|
||||
field != "metadata.namespace" &&
|
||||
field != "spec.selector" &&
|
||||
field != "spec.template" &&
|
||||
field != "GCEPersistentDisk.ReadOnly" &&
|
||||
field != "spec.replicas" &&
|
||||
field != "spec.template.labels" &&
|
||||
field != "metadata.annotations" &&
|
||||
field != "metadata.labels" &&
|
||||
field != "status.replicas" {
|
||||
t.Errorf("%s: missing prefix for: %v", k, errs[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidatePetSetUpdate(t *testing.T) {
|
||||
validLabels := map[string]string{"a": "b"}
|
||||
validPodTemplate := api.PodTemplate{
|
||||
Template: api.PodTemplateSpec{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Labels: validLabels,
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
},
|
||||
},
|
||||
}
|
||||
readWriteVolumePodTemplate := api.PodTemplate{
|
||||
Template: api.PodTemplateSpec{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Labels: validLabels,
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
Volumes: []api.Volume{{Name: "gcepd", VolumeSource: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{PDName: "my-PD", FSType: "ext4", Partition: 1, ReadOnly: false}}}},
|
||||
},
|
||||
},
|
||||
}
|
||||
invalidLabels := map[string]string{"NoUppercaseOrSpecialCharsLike=Equals": "b"}
|
||||
invalidPodTemplate := api.PodTemplate{
|
||||
Template: api.PodTemplateSpec{
|
||||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
},
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Labels: invalidLabels,
|
||||
},
|
||||
},
|
||||
}
|
||||
type psUpdateTest struct {
|
||||
old apps.PetSet
|
||||
update apps.PetSet
|
||||
}
|
||||
successCases := []psUpdateTest{
|
||||
{
|
||||
old: apps.PetSet{
|
||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
||||
Spec: apps.PetSetSpec{
|
||||
Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
|
||||
Template: validPodTemplate.Template,
|
||||
},
|
||||
},
|
||||
update: apps.PetSet{
|
||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
||||
Spec: apps.PetSetSpec{
|
||||
Replicas: 3,
|
||||
Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
|
||||
Template: validPodTemplate.Template,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
old: apps.PetSet{
|
||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
||||
Spec: apps.PetSetSpec{
|
||||
Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
|
||||
Template: validPodTemplate.Template,
|
||||
},
|
||||
},
|
||||
update: apps.PetSet{
|
||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
||||
Spec: apps.PetSetSpec{
|
||||
Replicas: 1,
|
||||
Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
|
||||
Template: readWriteVolumePodTemplate.Template,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, successCase := range successCases {
|
||||
successCase.old.ObjectMeta.ResourceVersion = "1"
|
||||
successCase.update.ObjectMeta.ResourceVersion = "1"
|
||||
if errs := ValidatePetSetUpdate(&successCase.update, &successCase.old); len(errs) != 0 {
|
||||
t.Errorf("expected success: %v", errs)
|
||||
}
|
||||
}
|
||||
errorCases := map[string]psUpdateTest{
|
||||
"more than one read/write": {
|
||||
old: apps.PetSet{
|
||||
ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault},
|
||||
Spec: apps.PetSetSpec{
|
||||
Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
|
||||
Template: validPodTemplate.Template,
|
||||
},
|
||||
},
|
||||
update: apps.PetSet{
|
||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
||||
Spec: apps.PetSetSpec{
|
||||
Replicas: 2,
|
||||
Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
|
||||
Template: readWriteVolumePodTemplate.Template,
|
||||
},
|
||||
},
|
||||
},
|
||||
"invalid selector": {
|
||||
old: apps.PetSet{
|
||||
ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault},
|
||||
Spec: apps.PetSetSpec{
|
||||
Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
|
||||
Template: validPodTemplate.Template,
|
||||
},
|
||||
},
|
||||
update: apps.PetSet{
|
||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
||||
Spec: apps.PetSetSpec{
|
||||
Replicas: 2,
|
||||
Selector: &unversioned.LabelSelector{MatchLabels: invalidLabels},
|
||||
Template: validPodTemplate.Template,
|
||||
},
|
||||
},
|
||||
},
|
||||
"invalid pod": {
|
||||
old: apps.PetSet{
|
||||
ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault},
|
||||
Spec: apps.PetSetSpec{
|
||||
Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
|
||||
Template: validPodTemplate.Template,
|
||||
},
|
||||
},
|
||||
update: apps.PetSet{
|
||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
||||
Spec: apps.PetSetSpec{
|
||||
Replicas: 2,
|
||||
Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
|
||||
Template: invalidPodTemplate.Template,
|
||||
},
|
||||
},
|
||||
},
|
||||
"negative replicas": {
|
||||
old: apps.PetSet{
|
||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
||||
Spec: apps.PetSetSpec{
|
||||
Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
|
||||
Template: validPodTemplate.Template,
|
||||
},
|
||||
},
|
||||
update: apps.PetSet{
|
||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
||||
Spec: apps.PetSetSpec{
|
||||
Replicas: -1,
|
||||
Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
|
||||
Template: validPodTemplate.Template,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for testName, errorCase := range errorCases {
|
||||
if errs := ValidatePetSetUpdate(&errorCase.update, &errorCase.old); len(errs) == 0 {
|
||||
t.Errorf("expected failure: %s", testName)
|
||||
}
|
||||
}
|
||||
}
|
@ -22,6 +22,7 @@ import (
|
||||
|
||||
_ "k8s.io/kubernetes/pkg/api/install"
|
||||
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
||||
_ "k8s.io/kubernetes/pkg/apis/apps/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/authorization/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/autoscaling/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/batch/install"
|
||||
|
82
pkg/client/unversioned/apps.go
Normal file
82
pkg/client/unversioned/apps.go
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors All rights reserved.
|
||||
|
||||
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 unversioned
|
||||
|
||||
import (
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
||||
"k8s.io/kubernetes/pkg/apis/apps"
|
||||
"k8s.io/kubernetes/pkg/client/restclient"
|
||||
)
|
||||
|
||||
type AppsInterface interface {
|
||||
PetSetNamespacer
|
||||
}
|
||||
|
||||
// AppsClient is used to interact with Kubernetes batch features.
|
||||
type AppsClient struct {
|
||||
*restclient.RESTClient
|
||||
}
|
||||
|
||||
func (c *AppsClient) PetSet(namespace string) PetSetInterface {
|
||||
return newPetSet(c, namespace)
|
||||
}
|
||||
|
||||
func NewApps(c *restclient.Config) (*AppsClient, error) {
|
||||
config := *c
|
||||
if err := setAppsDefaults(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client, err := restclient.RESTClientFor(&config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &AppsClient{client}, nil
|
||||
}
|
||||
|
||||
func NewAppsOrDie(c *restclient.Config) *AppsClient {
|
||||
client, err := NewApps(c)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return client
|
||||
}
|
||||
|
||||
func setAppsDefaults(config *restclient.Config) error {
|
||||
g, err := registered.Group(apps.GroupName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
config.APIPath = defaultAPIPath
|
||||
if config.UserAgent == "" {
|
||||
config.UserAgent = restclient.DefaultKubernetesUserAgent()
|
||||
}
|
||||
// TODO: Unconditionally set the config.Version, until we fix the config.
|
||||
//if config.Version == "" {
|
||||
copyGroupVersion := g.GroupVersion
|
||||
config.GroupVersion = ©GroupVersion
|
||||
//}
|
||||
|
||||
config.Codec = api.Codecs.LegacyCodec(*config.GroupVersion)
|
||||
if config.QPS == 0 {
|
||||
config.QPS = 5
|
||||
}
|
||||
if config.Burst == 0 {
|
||||
config.Burst = 10
|
||||
}
|
||||
return nil
|
||||
}
|
@ -119,6 +119,7 @@ type Client struct {
|
||||
*AutoscalingClient
|
||||
*BatchClient
|
||||
*ExtensionsClient
|
||||
*AppsClient
|
||||
*discovery.DiscoveryClient
|
||||
}
|
||||
|
||||
@ -156,6 +157,10 @@ func (c *Client) Extensions() ExtensionsInterface {
|
||||
return c.ExtensionsClient
|
||||
}
|
||||
|
||||
func (c *Client) Apps() AppsInterface {
|
||||
return c.AppsClient
|
||||
}
|
||||
|
||||
func (c *Client) Discovery() discovery.DiscoveryInterface {
|
||||
return c.DiscoveryClient
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
||||
"k8s.io/kubernetes/pkg/apis/apps"
|
||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
||||
"k8s.io/kubernetes/pkg/apis/batch"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
@ -82,8 +83,16 @@ func New(c *restclient.Config) (*Client, error) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
var appsClient *AppsClient
|
||||
if registered.IsRegistered(apps.GroupName) {
|
||||
appsConfig := *c
|
||||
appsClient, err = NewApps(&appsConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &Client{RESTClient: client, AutoscalingClient: autoscalingClient, BatchClient: batchClient, ExtensionsClient: extensionsClient, DiscoveryClient: discoveryClient}, nil
|
||||
return &Client{RESTClient: client, AutoscalingClient: autoscalingClient, BatchClient: batchClient, ExtensionsClient: extensionsClient, DiscoveryClient: discoveryClient, AppsClient: appsClient}, nil
|
||||
}
|
||||
|
||||
// MatchesServerVersion queries the server to compares the build version
|
||||
|
@ -22,6 +22,7 @@ import (
|
||||
|
||||
_ "k8s.io/kubernetes/pkg/api/install"
|
||||
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
||||
_ "k8s.io/kubernetes/pkg/apis/apps/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/authorization/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/autoscaling/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/batch/install"
|
||||
|
100
pkg/client/unversioned/pet_sets.go
Normal file
100
pkg/client/unversioned/pet_sets.go
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors All rights reserved.
|
||||
|
||||
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 unversioned
|
||||
|
||||
import (
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/apis/apps"
|
||||
"k8s.io/kubernetes/pkg/watch"
|
||||
)
|
||||
|
||||
// PetSetNamespacer has methods to work with PetSet resources in a namespace
|
||||
type PetSetNamespacer interface {
|
||||
PetSet(namespace string) PetSetInterface
|
||||
}
|
||||
|
||||
// PetSetInterface exposes methods to work on PetSet resources.
|
||||
type PetSetInterface interface {
|
||||
List(opts api.ListOptions) (*apps.PetSetList, error)
|
||||
Get(name string) (*apps.PetSet, error)
|
||||
Create(petSet *apps.PetSet) (*apps.PetSet, error)
|
||||
Update(petSet *apps.PetSet) (*apps.PetSet, error)
|
||||
Delete(name string, options *api.DeleteOptions) error
|
||||
Watch(opts api.ListOptions) (watch.Interface, error)
|
||||
UpdateStatus(petSet *apps.PetSet) (*apps.PetSet, error)
|
||||
}
|
||||
|
||||
// petSet implements PetSetNamespacer interface
|
||||
type petSet struct {
|
||||
r *AppsClient
|
||||
ns string
|
||||
}
|
||||
|
||||
// newPetSet returns a petSet
|
||||
func newPetSet(c *AppsClient, namespace string) *petSet {
|
||||
return &petSet{c, namespace}
|
||||
}
|
||||
|
||||
// List returns a list of petSet that match the label and field selectors.
|
||||
func (c *petSet) List(opts api.ListOptions) (result *apps.PetSetList, err error) {
|
||||
result = &apps.PetSetList{}
|
||||
err = c.r.Get().Namespace(c.ns).Resource("petsets").VersionedParams(&opts, api.ParameterCodec).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Get returns information about a particular petSet.
|
||||
func (c *petSet) Get(name string) (result *apps.PetSet, err error) {
|
||||
result = &apps.PetSet{}
|
||||
err = c.r.Get().Namespace(c.ns).Resource("petsets").Name(name).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Create creates a new petSet.
|
||||
func (c *petSet) Create(petSet *apps.PetSet) (result *apps.PetSet, err error) {
|
||||
result = &apps.PetSet{}
|
||||
err = c.r.Post().Namespace(c.ns).Resource("petsets").Body(petSet).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update updates an existing petSet.
|
||||
func (c *petSet) Update(petSet *apps.PetSet) (result *apps.PetSet, err error) {
|
||||
result = &apps.PetSet{}
|
||||
err = c.r.Put().Namespace(c.ns).Resource("petsets").Name(petSet.Name).Body(petSet).Do().Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete deletes a petSet, returns error if one occurs.
|
||||
func (c *petSet) Delete(name string, options *api.DeleteOptions) (err error) {
|
||||
return c.r.Delete().Namespace(c.ns).Resource("petsets").Name(name).Body(options).Do().Error()
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested petSet.
|
||||
func (c *petSet) Watch(opts api.ListOptions) (watch.Interface, error) {
|
||||
return c.r.Get().
|
||||
Prefix("watch").
|
||||
Namespace(c.ns).
|
||||
Resource("petsets").
|
||||
VersionedParams(&opts, api.ParameterCodec).
|
||||
Watch()
|
||||
}
|
||||
|
||||
// UpdateStatus takes the name of the petSet and the new status. Returns the server's representation of the petSet, and an error, if it occurs.
|
||||
func (c *petSet) UpdateStatus(petSet *apps.PetSet) (result *apps.PetSet, err error) {
|
||||
result = &apps.PetSet{}
|
||||
err = c.r.Put().Namespace(c.ns).Resource("petsets").Name(petSet.Name).SubResource("status").Body(petSet).Do().Into(result)
|
||||
return
|
||||
}
|
165
pkg/client/unversioned/pet_sets_test.go
Normal file
165
pkg/client/unversioned/pet_sets_test.go
Normal file
@ -0,0 +1,165 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||
|
||||
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 unversioned_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
"k8s.io/kubernetes/pkg/apis/apps"
|
||||
"k8s.io/kubernetes/pkg/client/unversioned/testclient/simple"
|
||||
)
|
||||
|
||||
func getPetSetResourceName() string {
|
||||
return "petsets"
|
||||
}
|
||||
|
||||
func TestListPetSets(t *testing.T) {
|
||||
ns := api.NamespaceAll
|
||||
c := &simple.Client{
|
||||
Request: simple.Request{
|
||||
Method: "GET",
|
||||
Path: testapi.Apps.ResourcePath(getPetSetResourceName(), ns, ""),
|
||||
},
|
||||
Response: simple.Response{StatusCode: 200,
|
||||
Body: &apps.PetSetList{
|
||||
Items: []apps.PetSet{
|
||||
{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "foo",
|
||||
Labels: map[string]string{
|
||||
"foo": "bar",
|
||||
"name": "baz",
|
||||
},
|
||||
},
|
||||
Spec: apps.PetSetSpec{
|
||||
Replicas: 2,
|
||||
Template: api.PodTemplateSpec{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
receivedRSList, err := c.Setup(t).Apps().PetSet(ns).List(api.ListOptions{})
|
||||
c.Validate(t, receivedRSList, err)
|
||||
}
|
||||
|
||||
func TestGetPetSet(t *testing.T) {
|
||||
ns := api.NamespaceDefault
|
||||
c := &simple.Client{
|
||||
Request: simple.Request{Method: "GET", Path: testapi.Apps.ResourcePath(getPetSetResourceName(), ns, "foo"), Query: simple.BuildQueryValues(nil)},
|
||||
Response: simple.Response{
|
||||
StatusCode: 200,
|
||||
Body: &apps.PetSet{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "foo",
|
||||
Labels: map[string]string{
|
||||
"foo": "bar",
|
||||
"name": "baz",
|
||||
},
|
||||
},
|
||||
Spec: apps.PetSetSpec{
|
||||
Replicas: 2,
|
||||
Template: api.PodTemplateSpec{},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
receivedRS, err := c.Setup(t).Apps().PetSet(ns).Get("foo")
|
||||
c.Validate(t, receivedRS, err)
|
||||
}
|
||||
|
||||
func TestGetPetSetWithNoName(t *testing.T) {
|
||||
ns := api.NamespaceDefault
|
||||
c := &simple.Client{Error: true}
|
||||
receivedPod, err := c.Setup(t).Apps().PetSet(ns).Get("")
|
||||
if (err != nil) && (err.Error() != simple.NameRequiredError) {
|
||||
t.Errorf("Expected error: %v, but got %v", simple.NameRequiredError, err)
|
||||
}
|
||||
|
||||
c.Validate(t, receivedPod, err)
|
||||
}
|
||||
|
||||
func TestUpdatePetSet(t *testing.T) {
|
||||
ns := api.NamespaceDefault
|
||||
requestRS := &apps.PetSet{
|
||||
ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"},
|
||||
}
|
||||
c := &simple.Client{
|
||||
Request: simple.Request{Method: "PUT", Path: testapi.Apps.ResourcePath(getPetSetResourceName(), ns, "foo"), Query: simple.BuildQueryValues(nil)},
|
||||
Response: simple.Response{
|
||||
StatusCode: 200,
|
||||
Body: &apps.PetSet{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "foo",
|
||||
Labels: map[string]string{
|
||||
"foo": "bar",
|
||||
"name": "baz",
|
||||
},
|
||||
},
|
||||
Spec: apps.PetSetSpec{
|
||||
Replicas: 2,
|
||||
Template: api.PodTemplateSpec{},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
receivedRS, err := c.Setup(t).Apps().PetSet(ns).Update(requestRS)
|
||||
c.Validate(t, receivedRS, err)
|
||||
}
|
||||
|
||||
func TestDeletePetSet(t *testing.T) {
|
||||
ns := api.NamespaceDefault
|
||||
c := &simple.Client{
|
||||
Request: simple.Request{Method: "DELETE", Path: testapi.Apps.ResourcePath(getPetSetResourceName(), ns, "foo"), Query: simple.BuildQueryValues(nil)},
|
||||
Response: simple.Response{StatusCode: 200},
|
||||
}
|
||||
err := c.Setup(t).Apps().PetSet(ns).Delete("foo", nil)
|
||||
c.Validate(t, nil, err)
|
||||
}
|
||||
|
||||
func TestCreatePetSet(t *testing.T) {
|
||||
ns := api.NamespaceDefault
|
||||
requestRS := &apps.PetSet{
|
||||
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
||||
}
|
||||
c := &simple.Client{
|
||||
Request: simple.Request{Method: "POST", Path: testapi.Apps.ResourcePath(getPetSetResourceName(), ns, ""), Body: requestRS, Query: simple.BuildQueryValues(nil)},
|
||||
Response: simple.Response{
|
||||
StatusCode: 200,
|
||||
Body: &apps.PetSet{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "foo",
|
||||
Labels: map[string]string{
|
||||
"foo": "bar",
|
||||
"name": "baz",
|
||||
},
|
||||
},
|
||||
Spec: apps.PetSetSpec{
|
||||
Replicas: 2,
|
||||
Template: api.PodTemplateSpec{},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
receivedRS, err := c.Setup(t).Apps().PetSet(ns).Create(requestRS)
|
||||
c.Validate(t, receivedRS, err)
|
||||
}
|
||||
|
||||
// TODO: Test Status actions.
|
@ -41,6 +41,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/api/validation"
|
||||
"k8s.io/kubernetes/pkg/apimachinery"
|
||||
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
||||
"k8s.io/kubernetes/pkg/apis/apps"
|
||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
||||
"k8s.io/kubernetes/pkg/apis/batch"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
@ -317,6 +318,8 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
|
||||
return c.AutoscalingClient.RESTClient, nil
|
||||
case batch.GroupName:
|
||||
return c.BatchClient.RESTClient, nil
|
||||
case apps.GroupName:
|
||||
return c.AppsClient.RESTClient, nil
|
||||
case extensions.GroupName:
|
||||
return c.ExtensionsClient.RESTClient, nil
|
||||
case api.SchemeGroupVersion.Group:
|
||||
@ -892,6 +895,13 @@ func (c *clientSwaggerSchema) ValidateBytes(data []byte) error {
|
||||
}
|
||||
return getSchemaAndValidate(c.c.AutoscalingClient.RESTClient, data, "apis/", gvk.GroupVersion().String(), c.cacheDir)
|
||||
}
|
||||
if gvk.Group == apps.GroupName {
|
||||
if c.c.AppsClient == nil {
|
||||
return errors.New("unable to validate: no autoscaling client")
|
||||
}
|
||||
return getSchemaAndValidate(c.c.AppsClient.RESTClient, data, "apis/", gvk.GroupVersion().String(), c.cacheDir)
|
||||
}
|
||||
|
||||
if gvk.Group == batch.GroupName {
|
||||
if c.c.BatchClient == nil {
|
||||
return errors.New("unable to validate: no batch client")
|
||||
|
@ -35,6 +35,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/meta"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/apis/apps"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
"k8s.io/kubernetes/pkg/labels"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
@ -417,6 +418,7 @@ var replicaSetColumns = []string{"NAME", "DESIRED", "CURRENT", "AGE"}
|
||||
var jobColumns = []string{"NAME", "DESIRED", "SUCCESSFUL", "AGE"}
|
||||
var serviceColumns = []string{"NAME", "CLUSTER-IP", "EXTERNAL-IP", "PORT(S)", "AGE"}
|
||||
var ingressColumns = []string{"NAME", "RULE", "BACKEND", "ADDRESS", "AGE"}
|
||||
var petSetColumns = []string{"NAME", "DESIRED", "CURRENT", "AGE"}
|
||||
var endpointColumns = []string{"NAME", "ENDPOINTS", "AGE"}
|
||||
var nodeColumns = []string{"NAME", "STATUS", "AGE"}
|
||||
var daemonSetColumns = []string{"NAME", "DESIRED", "CURRENT", "NODE-SELECTOR", "AGE"}
|
||||
@ -457,6 +459,8 @@ func (h *HumanReadablePrinter) addDefaultHandlers() {
|
||||
h.Handler(serviceColumns, printServiceList)
|
||||
h.Handler(ingressColumns, printIngress)
|
||||
h.Handler(ingressColumns, printIngressList)
|
||||
h.Handler(petSetColumns, printPetSet)
|
||||
h.Handler(petSetColumns, printPetSetList)
|
||||
h.Handler(endpointColumns, printEndpoints)
|
||||
h.Handler(endpointColumns, printEndpointsList)
|
||||
h.Handler(nodeColumns, printNode)
|
||||
@ -1015,6 +1019,53 @@ func printIngressList(ingressList *extensions.IngressList, w io.Writer, options
|
||||
return nil
|
||||
}
|
||||
|
||||
func printPetSet(ps *apps.PetSet, w io.Writer, options PrintOptions) error {
|
||||
name := ps.Name
|
||||
namespace := ps.Namespace
|
||||
containers := ps.Spec.Template.Spec.Containers
|
||||
|
||||
if options.WithNamespace {
|
||||
if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
desiredReplicas := ps.Spec.Replicas
|
||||
currentReplicas := ps.Status.Replicas
|
||||
if _, err := fmt.Fprintf(w, "%s\t%d\t%d\t%s",
|
||||
name,
|
||||
desiredReplicas,
|
||||
currentReplicas,
|
||||
translateTimestamp(ps.CreationTimestamp),
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
if options.Wide {
|
||||
if err := layoutContainers(containers, w); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := fmt.Fprintf(w, "\t%s", unversioned.FormatLabelSelector(ps.Spec.Selector)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if _, err := fmt.Fprint(w, appendLabels(ps.Labels, options.ColumnLabels)); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := fmt.Fprint(w, appendAllLabels(options.ShowLabels, ps.Labels)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func printPetSetList(petSetList *apps.PetSetList, w io.Writer, options PrintOptions) error {
|
||||
for _, ps := range petSetList.Items {
|
||||
if err := printPetSet(&ps, w, options); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func printDaemonSet(ds *extensions.DaemonSet, w io.Writer, options PrintOptions) error {
|
||||
name := ds.Name
|
||||
namespace := ds.Namespace
|
||||
|
@ -22,6 +22,7 @@ import (
|
||||
|
||||
_ "k8s.io/kubernetes/pkg/api/install"
|
||||
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
||||
_ "k8s.io/kubernetes/pkg/apis/apps/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/authorization/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/autoscaling/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/batch/install"
|
||||
|
@ -32,6 +32,8 @@ import (
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
apiv1 "k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
||||
"k8s.io/kubernetes/pkg/apis/apps"
|
||||
appsapi "k8s.io/kubernetes/pkg/apis/apps/v1alpha1"
|
||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
||||
autoscalingapiv1 "k8s.io/kubernetes/pkg/apis/autoscaling/v1"
|
||||
"k8s.io/kubernetes/pkg/apis/batch"
|
||||
@ -62,6 +64,7 @@ import (
|
||||
nodeetcd "k8s.io/kubernetes/pkg/registry/node/etcd"
|
||||
pvetcd "k8s.io/kubernetes/pkg/registry/persistentvolume/etcd"
|
||||
pvcetcd "k8s.io/kubernetes/pkg/registry/persistentvolumeclaim/etcd"
|
||||
petsetetcd "k8s.io/kubernetes/pkg/registry/petset/etcd"
|
||||
podetcd "k8s.io/kubernetes/pkg/registry/pod/etcd"
|
||||
pspetcd "k8s.io/kubernetes/pkg/registry/podsecuritypolicy/etcd"
|
||||
podtemplateetcd "k8s.io/kubernetes/pkg/registry/podtemplate/etcd"
|
||||
@ -349,6 +352,38 @@ func (m *Master) InstallAPIs(c *Config) {
|
||||
allGroups = append(allGroups, group)
|
||||
}
|
||||
|
||||
if c.APIResourceConfigSource.AnyResourcesForVersionEnabled(appsapi.SchemeGroupVersion) {
|
||||
appsResources := m.getAppsResources(c)
|
||||
appsGroupMeta := registered.GroupOrDie(apps.GroupName)
|
||||
|
||||
// Hard code preferred group version to apps/v1alpha1
|
||||
appsGroupMeta.GroupVersion = appsapi.SchemeGroupVersion
|
||||
|
||||
apiGroupInfo := genericapiserver.APIGroupInfo{
|
||||
GroupMeta: *appsGroupMeta,
|
||||
VersionedResourcesStorageMap: map[string]map[string]rest.Storage{
|
||||
"v1alpha1": appsResources,
|
||||
},
|
||||
OptionsExternalVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion,
|
||||
Scheme: api.Scheme,
|
||||
ParameterCodec: api.ParameterCodec,
|
||||
NegotiatedSerializer: api.Codecs,
|
||||
NegotiatedStreamSerializer: api.StreamCodecs,
|
||||
}
|
||||
apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo)
|
||||
|
||||
appsGVForDiscovery := unversioned.GroupVersionForDiscovery{
|
||||
GroupVersion: appsGroupMeta.GroupVersion.String(),
|
||||
Version: appsGroupMeta.GroupVersion.Version,
|
||||
}
|
||||
group := unversioned.APIGroup{
|
||||
Name: appsGroupMeta.GroupVersion.Group,
|
||||
Versions: []unversioned.GroupVersionForDiscovery{appsGVForDiscovery},
|
||||
PreferredVersion: appsGVForDiscovery,
|
||||
}
|
||||
allGroups = append(allGroups, group)
|
||||
|
||||
}
|
||||
if err := m.InstallAPIGroups(apiGroupsInfo); err != nil {
|
||||
glog.Fatalf("Error in registering group versions: %v", err)
|
||||
}
|
||||
@ -824,6 +859,27 @@ func (m *Master) getBatchResources(c *Config) map[string]rest.Storage {
|
||||
return storage
|
||||
}
|
||||
|
||||
// getPetSetResources returns the resources for batch api
|
||||
func (m *Master) getAppsResources(c *Config) map[string]rest.Storage {
|
||||
// TODO update when we support more than one version of this group
|
||||
version := appsapi.SchemeGroupVersion
|
||||
|
||||
storage := map[string]rest.Storage{}
|
||||
if c.APIResourceConfigSource.ResourceEnabled(version.WithResource("petsets")) {
|
||||
restOptions := func(resource string) generic.RESTOptions {
|
||||
return generic.RESTOptions{
|
||||
Storage: c.StorageDestinations.Get(apps.GroupName, resource),
|
||||
Decorator: m.StorageDecorator(),
|
||||
DeleteCollectionWorkers: m.deleteCollectionWorkers,
|
||||
}
|
||||
}
|
||||
petsetStorage, petsetStatusStorage := petsetetcd.NewREST(restOptions("petsets"))
|
||||
storage["petsets"] = petsetStorage
|
||||
storage["petsets/status"] = petsetStatusStorage
|
||||
}
|
||||
return storage
|
||||
}
|
||||
|
||||
// findExternalAddress returns ExternalIP of provided node with fallback to LegacyHostIP.
|
||||
func findExternalAddress(node *api.Node) (string, error) {
|
||||
var fallback string
|
||||
@ -876,7 +932,7 @@ func (m *Master) IsTunnelSyncHealthy(req *http.Request) error {
|
||||
|
||||
func DefaultAPIResourceConfigSource() *genericapiserver.ResourceConfig {
|
||||
ret := genericapiserver.NewResourceConfig()
|
||||
ret.EnableVersions(apiv1.SchemeGroupVersion, extensionsapiv1beta1.SchemeGroupVersion, batchapiv1.SchemeGroupVersion, autoscalingapiv1.SchemeGroupVersion)
|
||||
ret.EnableVersions(apiv1.SchemeGroupVersion, extensionsapiv1beta1.SchemeGroupVersion, batchapiv1.SchemeGroupVersion, autoscalingapiv1.SchemeGroupVersion, appsapi.SchemeGroupVersion)
|
||||
|
||||
// all extensions resources except these are disabled by default
|
||||
ret.EnableResources(
|
||||
|
@ -38,6 +38,8 @@ import (
|
||||
|
||||
apiutil "k8s.io/kubernetes/pkg/api/util"
|
||||
apiv1 "k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/apis/apps"
|
||||
appsapi "k8s.io/kubernetes/pkg/apis/apps"
|
||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
||||
autoscalingapiv1 "k8s.io/kubernetes/pkg/apis/autoscaling/v1"
|
||||
"k8s.io/kubernetes/pkg/apis/batch"
|
||||
@ -78,6 +80,8 @@ func setUp(t *testing.T) (*Master, *etcdtesting.EtcdTestServer, Config, *assert.
|
||||
autoscaling.GroupName, etcdstorage.NewEtcdStorage(server.Client, testapi.Autoscaling.Codec(), etcdtest.PathPrefix(), false, etcdtest.DeserializationCacheSize))
|
||||
storageDestinations.AddAPIGroup(
|
||||
batch.GroupName, etcdstorage.NewEtcdStorage(server.Client, testapi.Batch.Codec(), etcdtest.PathPrefix(), false, etcdtest.DeserializationCacheSize))
|
||||
storageDestinations.AddAPIGroup(
|
||||
apps.GroupName, etcdstorage.NewEtcdStorage(server.Client, testapi.Apps.Codec(), etcdtest.PathPrefix(), false, etcdtest.DeserializationCacheSize))
|
||||
storageDestinations.AddAPIGroup(
|
||||
extensions.GroupName, etcdstorage.NewEtcdStorage(server.Client, testapi.Extensions.Codec(), etcdtest.PathPrefix(), false, etcdtest.DeserializationCacheSize))
|
||||
|
||||
@ -85,6 +89,7 @@ func setUp(t *testing.T) (*Master, *etcdtesting.EtcdTestServer, Config, *assert.
|
||||
storageVersions[api.GroupName] = testapi.Default.GroupVersion().String()
|
||||
storageVersions[autoscaling.GroupName] = testapi.Autoscaling.GroupVersion().String()
|
||||
storageVersions[batch.GroupName] = testapi.Batch.GroupVersion().String()
|
||||
storageVersions[apps.GroupName] = testapi.Apps.GroupVersion().String()
|
||||
storageVersions[extensions.GroupName] = testapi.Extensions.GroupVersion().String()
|
||||
config.StorageVersions = storageVersions
|
||||
config.PublicAddress = net.ParseIP("192.168.10.4")
|
||||
@ -123,7 +128,7 @@ func newMaster(t *testing.T) (*Master, *etcdtesting.EtcdTestServer, Config, *ass
|
||||
// limitedAPIResourceConfigSource only enables the core group, the extensions group, the batch group, and the autoscaling group.
|
||||
func limitedAPIResourceConfigSource() *genericapiserver.ResourceConfig {
|
||||
ret := genericapiserver.NewResourceConfig()
|
||||
ret.EnableVersions(apiv1.SchemeGroupVersion, extensionsapiv1beta1.SchemeGroupVersion, batchapiv1.SchemeGroupVersion, autoscalingapiv1.SchemeGroupVersion)
|
||||
ret.EnableVersions(apiv1.SchemeGroupVersion, extensionsapiv1beta1.SchemeGroupVersion, batchapiv1.SchemeGroupVersion, appsapi.SchemeGroupVersion, autoscalingapiv1.SchemeGroupVersion)
|
||||
return ret
|
||||
}
|
||||
|
||||
@ -410,7 +415,7 @@ func TestDiscoveryAtAPIS(t *testing.T) {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
expectGroupNames := sets.NewString(autoscaling.GroupName, batch.GroupName, extensions.GroupName)
|
||||
expectGroupNames := sets.NewString(autoscaling.GroupName, batch.GroupName, apps.GroupName, extensions.GroupName)
|
||||
expectVersions := map[string][]unversioned.GroupVersionForDiscovery{
|
||||
autoscaling.GroupName: {
|
||||
{
|
||||
@ -424,6 +429,12 @@ func TestDiscoveryAtAPIS(t *testing.T) {
|
||||
Version: testapi.Batch.GroupVersion().Version,
|
||||
},
|
||||
},
|
||||
apps.GroupName: {
|
||||
{
|
||||
GroupVersion: testapi.Apps.GroupVersion().String(),
|
||||
Version: testapi.Apps.GroupVersion().Version,
|
||||
},
|
||||
},
|
||||
extensions.GroupName: {
|
||||
{
|
||||
GroupVersion: testapi.Extensions.GroupVersion().String(),
|
||||
@ -440,6 +451,10 @@ func TestDiscoveryAtAPIS(t *testing.T) {
|
||||
GroupVersion: config.StorageVersions[batch.GroupName],
|
||||
Version: apiutil.GetVersion(config.StorageVersions[batch.GroupName]),
|
||||
},
|
||||
apps.GroupName: {
|
||||
GroupVersion: config.StorageVersions[apps.GroupName],
|
||||
Version: apiutil.GetVersion(config.StorageVersions[apps.GroupName]),
|
||||
},
|
||||
extensions.GroupName: {
|
||||
GroupVersion: config.StorageVersions[extensions.GroupName],
|
||||
Version: apiutil.GetVersion(config.StorageVersions[extensions.GroupName]),
|
||||
|
@ -34,6 +34,7 @@ const (
|
||||
Endpoints Resource = "endpoints"
|
||||
HorizontalPodAutoscalers Resource = "horizontalpodautoscalers"
|
||||
Ingress Resource = "ingress"
|
||||
PetSet Resource = "petset"
|
||||
Jobs Resource = "jobs"
|
||||
LimitRanges Resource = "limitranges"
|
||||
Namespaces Resource = "namespaces"
|
||||
@ -59,6 +60,7 @@ func init() {
|
||||
watchCacheSizes[Endpoints] = 1000
|
||||
watchCacheSizes[HorizontalPodAutoscalers] = 100
|
||||
watchCacheSizes[Ingress] = 100
|
||||
watchCacheSizes[PetSet] = 100
|
||||
watchCacheSizes[Jobs] = 100
|
||||
watchCacheSizes[LimitRanges] = 100
|
||||
watchCacheSizes[Namespaces] = 100
|
||||
|
17
pkg/registry/petset/doc.go
Normal file
17
pkg/registry/petset/doc.go
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors All rights reserved.
|
||||
|
||||
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 petset
|
96
pkg/registry/petset/etcd/etcd.go
Normal file
96
pkg/registry/petset/etcd/etcd.go
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors All rights reserved.
|
||||
|
||||
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 etcd
|
||||
|
||||
import (
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
appsapi "k8s.io/kubernetes/pkg/apis/apps"
|
||||
"k8s.io/kubernetes/pkg/fields"
|
||||
"k8s.io/kubernetes/pkg/labels"
|
||||
"k8s.io/kubernetes/pkg/registry/cachesize"
|
||||
"k8s.io/kubernetes/pkg/registry/generic"
|
||||
etcdgeneric "k8s.io/kubernetes/pkg/registry/generic/etcd"
|
||||
"k8s.io/kubernetes/pkg/registry/petset"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
)
|
||||
|
||||
// rest implements a RESTStorage for replication controllers against etcd
|
||||
type REST struct {
|
||||
*etcdgeneric.Etcd
|
||||
}
|
||||
|
||||
// NewREST returns a RESTStorage object that will work against replication controllers.
|
||||
func NewREST(opts generic.RESTOptions) (*REST, *StatusREST) {
|
||||
prefix := "/petsets"
|
||||
|
||||
newListFunc := func() runtime.Object { return &appsapi.PetSetList{} }
|
||||
storageInterface := opts.Decorator(
|
||||
opts.Storage, cachesize.GetWatchCacheSizeByResource(cachesize.PetSet), &appsapi.PetSet{}, prefix, petset.Strategy, newListFunc)
|
||||
|
||||
store := &etcdgeneric.Etcd{
|
||||
NewFunc: func() runtime.Object { return &appsapi.PetSet{} },
|
||||
|
||||
// NewListFunc returns an object capable of storing results of an etcd list.
|
||||
NewListFunc: newListFunc,
|
||||
// Produces a petSet that etcd understands, to the root of the resource
|
||||
// by combining the namespace in the context with the given prefix
|
||||
KeyRootFunc: func(ctx api.Context) string {
|
||||
return etcdgeneric.NamespaceKeyRootFunc(ctx, prefix)
|
||||
},
|
||||
// Produces a petSet that etcd understands, to the resource by combining
|
||||
// the namespace in the context with the given prefix
|
||||
KeyFunc: func(ctx api.Context, name string) (string, error) {
|
||||
return etcdgeneric.NamespaceKeyFunc(ctx, prefix, name)
|
||||
},
|
||||
// Retrieve the name field of a replication controller
|
||||
ObjectNameFunc: func(obj runtime.Object) (string, error) {
|
||||
return obj.(*appsapi.PetSet).Name, nil
|
||||
},
|
||||
// Used to match objects based on labels/fields for list and watch
|
||||
PredicateFunc: func(label labels.Selector, field fields.Selector) generic.Matcher {
|
||||
return petset.MatchPetSet(label, field)
|
||||
},
|
||||
QualifiedResource: appsapi.Resource("petsets"),
|
||||
DeleteCollectionWorkers: opts.DeleteCollectionWorkers,
|
||||
|
||||
// Used to validate controller creation
|
||||
CreateStrategy: petset.Strategy,
|
||||
|
||||
// Used to validate controller updates
|
||||
UpdateStrategy: petset.Strategy,
|
||||
DeleteStrategy: petset.Strategy,
|
||||
|
||||
Storage: storageInterface,
|
||||
}
|
||||
statusStore := *store
|
||||
statusStore.UpdateStrategy = petset.StatusStrategy
|
||||
return &REST{store}, &StatusREST{store: &statusStore}
|
||||
}
|
||||
|
||||
// StatusREST implements the REST endpoint for changing the status of an petSet
|
||||
type StatusREST struct {
|
||||
store *etcdgeneric.Etcd
|
||||
}
|
||||
|
||||
func (r *StatusREST) New() runtime.Object {
|
||||
return &appsapi.PetSet{}
|
||||
}
|
||||
|
||||
// Update alters the status subset of an object.
|
||||
func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
||||
return r.store.Update(ctx, obj)
|
||||
}
|
182
pkg/registry/petset/etcd/etcd_test.go
Normal file
182
pkg/registry/petset/etcd/etcd_test.go
Normal file
@ -0,0 +1,182 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||
|
||||
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 etcd
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/apis/apps"
|
||||
"k8s.io/kubernetes/pkg/fields"
|
||||
"k8s.io/kubernetes/pkg/labels"
|
||||
"k8s.io/kubernetes/pkg/registry/generic"
|
||||
"k8s.io/kubernetes/pkg/registry/registrytest"
|
||||
"k8s.io/kubernetes/pkg/storage/etcd/etcdtest"
|
||||
etcdtesting "k8s.io/kubernetes/pkg/storage/etcd/testing"
|
||||
)
|
||||
|
||||
func newStorage(t *testing.T) (*REST, *StatusREST, *etcdtesting.EtcdTestServer) {
|
||||
etcdStorage, server := registrytest.NewEtcdStorage(t, apps.GroupName)
|
||||
restOptions := generic.RESTOptions{Storage: etcdStorage, Decorator: generic.UndecoratedStorage, DeleteCollectionWorkers: 1}
|
||||
petSetStorage, statusStorage := NewREST(restOptions)
|
||||
return petSetStorage, statusStorage, server
|
||||
}
|
||||
|
||||
// createPetSet is a helper function that returns a PetSet with the updated resource version.
|
||||
func createPetSet(storage *REST, ps apps.PetSet, t *testing.T) (apps.PetSet, error) {
|
||||
ctx := api.WithNamespace(api.NewContext(), ps.Namespace)
|
||||
obj, err := storage.Create(ctx, &ps)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to create PetSet, %v", err)
|
||||
}
|
||||
newPS := obj.(*apps.PetSet)
|
||||
return *newPS, nil
|
||||
}
|
||||
|
||||
func validNewPetSet() *apps.PetSet {
|
||||
return &apps.PetSet{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "foo",
|
||||
Namespace: api.NamespaceDefault,
|
||||
Labels: map[string]string{"a": "b"},
|
||||
},
|
||||
Spec: apps.PetSetSpec{
|
||||
Selector: &unversioned.LabelSelector{MatchLabels: map[string]string{"a": "b"}},
|
||||
Template: api.PodTemplateSpec{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Labels: map[string]string{"a": "b"},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Name: "test",
|
||||
Image: "test_image",
|
||||
ImagePullPolicy: api.PullIfNotPresent,
|
||||
},
|
||||
},
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
},
|
||||
},
|
||||
Replicas: 7,
|
||||
},
|
||||
Status: apps.PetSetStatus{},
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreate(t *testing.T) {
|
||||
storage, _, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
test := registrytest.New(t, storage.Etcd)
|
||||
ps := validNewPetSet()
|
||||
ps.ObjectMeta = api.ObjectMeta{}
|
||||
test.TestCreate(
|
||||
// valid
|
||||
ps,
|
||||
// TODO: Add an invalid case when we have validation.
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: Test updates to spec when we allow them.
|
||||
|
||||
func TestStatusUpdate(t *testing.T) {
|
||||
storage, statusStorage, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
|
||||
ctx := api.WithNamespace(api.NewContext(), api.NamespaceDefault)
|
||||
key := etcdtest.AddPrefix("/petsets/" + api.NamespaceDefault + "/foo")
|
||||
validPetSet := validNewPetSet()
|
||||
if err := storage.Storage.Create(ctx, key, validPetSet, nil, 0); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
update := apps.PetSet{
|
||||
ObjectMeta: validPetSet.ObjectMeta,
|
||||
Spec: apps.PetSetSpec{
|
||||
Replicas: 7,
|
||||
},
|
||||
Status: apps.PetSetStatus{
|
||||
Replicas: 7,
|
||||
},
|
||||
}
|
||||
|
||||
if _, _, err := statusStorage.Update(ctx, &update); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
obj, err := storage.Get(ctx, "foo")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
ps := obj.(*apps.PetSet)
|
||||
if ps.Spec.Replicas != 7 {
|
||||
t.Errorf("we expected .spec.replicas to not be updated but it was updated to %v", ps.Spec.Replicas)
|
||||
}
|
||||
if ps.Status.Replicas != 7 {
|
||||
t.Errorf("we expected .status.replicas to be updated to %d but it was %v", 7, ps.Status.Replicas)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGet(t *testing.T) {
|
||||
storage, _, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
test := registrytest.New(t, storage.Etcd)
|
||||
test.TestGet(validNewPetSet())
|
||||
}
|
||||
|
||||
func TestList(t *testing.T) {
|
||||
storage, _, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
test := registrytest.New(t, storage.Etcd)
|
||||
test.TestList(validNewPetSet())
|
||||
}
|
||||
|
||||
func TestDelete(t *testing.T) {
|
||||
storage, _, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
test := registrytest.New(t, storage.Etcd)
|
||||
test.TestDelete(validNewPetSet())
|
||||
}
|
||||
|
||||
func TestWatch(t *testing.T) {
|
||||
storage, _, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
test := registrytest.New(t, storage.Etcd)
|
||||
test.TestWatch(
|
||||
validNewPetSet(),
|
||||
// matching labels
|
||||
[]labels.Set{
|
||||
{"a": "b"},
|
||||
},
|
||||
// not matching labels
|
||||
[]labels.Set{
|
||||
{"a": "c"},
|
||||
{"foo": "bar"},
|
||||
},
|
||||
|
||||
// matching fields
|
||||
[]fields.Set{
|
||||
{"metadata.name": "foo"},
|
||||
},
|
||||
// not matching fields
|
||||
[]fields.Set{
|
||||
{"metadata.name": "bar"},
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: Test generation number.
|
142
pkg/registry/petset/strategy.go
Normal file
142
pkg/registry/petset/strategy.go
Normal file
@ -0,0 +1,142 @@
|
||||
/*
|
||||
Copyright 2014 The Kubernetes Authors All rights reserved.
|
||||
|
||||
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 petset
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/apis/apps"
|
||||
"k8s.io/kubernetes/pkg/apis/apps/validation"
|
||||
"k8s.io/kubernetes/pkg/fields"
|
||||
"k8s.io/kubernetes/pkg/labels"
|
||||
"k8s.io/kubernetes/pkg/registry/generic"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/util/validation/field"
|
||||
)
|
||||
|
||||
// petSetStrategy implements verification logic for Replication PetSets.
|
||||
type petSetStrategy struct {
|
||||
runtime.ObjectTyper
|
||||
api.NameGenerator
|
||||
}
|
||||
|
||||
// Strategy is the default logic that applies when creating and updating Replication PetSet objects.
|
||||
var Strategy = petSetStrategy{api.Scheme, api.SimpleNameGenerator}
|
||||
|
||||
// NamespaceScoped returns true because all PetSet' need to be within a namespace.
|
||||
func (petSetStrategy) NamespaceScoped() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// PrepareForCreate clears the status of an PetSet before creation.
|
||||
func (petSetStrategy) PrepareForCreate(obj runtime.Object) {
|
||||
petSet := obj.(*apps.PetSet)
|
||||
// create cannot set status
|
||||
petSet.Status = apps.PetSetStatus{}
|
||||
|
||||
petSet.Generation = 1
|
||||
}
|
||||
|
||||
// PrepareForUpdate clears fields that are not allowed to be set by end users on update.
|
||||
func (petSetStrategy) PrepareForUpdate(obj, old runtime.Object) {
|
||||
newPetSet := obj.(*apps.PetSet)
|
||||
oldPetSet := old.(*apps.PetSet)
|
||||
// Update is not allowed to set status
|
||||
newPetSet.Status = oldPetSet.Status
|
||||
|
||||
// Any changes to the spec increment the generation number, any changes to the
|
||||
// status should reflect the generation number of the corresponding object.
|
||||
// See api.ObjectMeta description for more information on Generation.
|
||||
if !reflect.DeepEqual(oldPetSet.Spec, newPetSet.Spec) {
|
||||
newPetSet.Generation = oldPetSet.Generation + 1
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Validate validates a new PetSet.
|
||||
func (petSetStrategy) Validate(ctx api.Context, obj runtime.Object) field.ErrorList {
|
||||
petSet := obj.(*apps.PetSet)
|
||||
return validation.ValidatePetSet(petSet)
|
||||
}
|
||||
|
||||
// Canonicalize normalizes the object after validation.
|
||||
func (petSetStrategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
|
||||
// AllowCreateOnUpdate is false for PetSet; this means POST is needed to create one.
|
||||
func (petSetStrategy) AllowCreateOnUpdate() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// ValidateUpdate is the default update validation for an end user.
|
||||
func (petSetStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList {
|
||||
return field.ErrorList{field.Forbidden(field.NewPath("spec"), "updates to petset spec are forbidden.")}
|
||||
|
||||
// TODO: For now we're taking the safe route and disallowing all updates to spec.
|
||||
// Enable on a case by case basis.
|
||||
//validationErrorList := validation.ValidatePetSet(obj.(*apps.PetSet))
|
||||
//updateErrorList := validation.ValidatePetSetUpdate(obj.(*apps.PetSet), old.(*apps.PetSet))
|
||||
//return append(validationErrorList, updateErrorList...)
|
||||
}
|
||||
|
||||
// AllowUnconditionalUpdate is the default update policy for PetSet objects.
|
||||
func (petSetStrategy) AllowUnconditionalUpdate() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// PetSetToSelectableFields returns a field set that represents the object.
|
||||
func PetSetToSelectableFields(petSet *apps.PetSet) fields.Set {
|
||||
return generic.ObjectMetaFieldsSet(petSet.ObjectMeta, true)
|
||||
}
|
||||
|
||||
// MatchPetSet is the filter used by the generic etcd backend to watch events
|
||||
// from etcd to clients of the apiserver only interested in specific labels/fields.
|
||||
func MatchPetSet(label labels.Selector, field fields.Selector) generic.Matcher {
|
||||
return &generic.SelectionPredicate{
|
||||
Label: label,
|
||||
Field: field,
|
||||
GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) {
|
||||
petSet, ok := obj.(*apps.PetSet)
|
||||
if !ok {
|
||||
return nil, nil, fmt.Errorf("given object is not an PetSet.")
|
||||
}
|
||||
return labels.Set(petSet.ObjectMeta.Labels), PetSetToSelectableFields(petSet), nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type petSetStatusStrategy struct {
|
||||
petSetStrategy
|
||||
}
|
||||
|
||||
var StatusStrategy = petSetStatusStrategy{Strategy}
|
||||
|
||||
// PrepareForUpdate clears fields that are not allowed to be set by end users on update of status
|
||||
func (petSetStatusStrategy) PrepareForUpdate(obj, old runtime.Object) {
|
||||
newPetSet := obj.(*apps.PetSet)
|
||||
oldPetSet := old.(*apps.PetSet)
|
||||
// status changes are not allowed to update spec
|
||||
newPetSet.Spec = oldPetSet.Spec
|
||||
}
|
||||
|
||||
// ValidateUpdate is the default update validation for an end user updating status
|
||||
func (petSetStatusStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList {
|
||||
// TODO: Validate status updates.
|
||||
return validation.ValidatePetSetStatusUpdate(obj.(*apps.PetSet), old.(*apps.PetSet))
|
||||
}
|
136
pkg/registry/petset/strategy_test.go
Normal file
136
pkg/registry/petset/strategy_test.go
Normal file
@ -0,0 +1,136 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||
|
||||
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 petset
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/apis/apps"
|
||||
)
|
||||
|
||||
func TestPetSetStrategy(t *testing.T) {
|
||||
ctx := api.NewDefaultContext()
|
||||
if !Strategy.NamespaceScoped() {
|
||||
t.Errorf("PetSet must be namespace scoped")
|
||||
}
|
||||
if Strategy.AllowCreateOnUpdate() {
|
||||
t.Errorf("PetSet should not allow create on update")
|
||||
}
|
||||
|
||||
validSelector := map[string]string{"a": "b"}
|
||||
validPodTemplate := api.PodTemplate{
|
||||
Template: api.PodTemplateSpec{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Labels: validSelector,
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
},
|
||||
},
|
||||
}
|
||||
ps := &apps.PetSet{
|
||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
||||
Spec: apps.PetSetSpec{
|
||||
Selector: &unversioned.LabelSelector{MatchLabels: validSelector},
|
||||
Template: validPodTemplate.Template,
|
||||
},
|
||||
Status: apps.PetSetStatus{Replicas: 3},
|
||||
}
|
||||
|
||||
Strategy.PrepareForCreate(ps)
|
||||
if ps.Status.Replicas != 0 {
|
||||
t.Error("PetSet should not allow setting status.pets on create")
|
||||
}
|
||||
errs := Strategy.Validate(ctx, ps)
|
||||
if len(errs) != 0 {
|
||||
t.Errorf("Unexpected error validating %v", errs)
|
||||
}
|
||||
|
||||
validPs := &apps.PetSet{
|
||||
ObjectMeta: api.ObjectMeta{Name: ps.Name, Namespace: ps.Namespace},
|
||||
Spec: apps.PetSetSpec{
|
||||
Selector: ps.Spec.Selector,
|
||||
Template: validPodTemplate.Template,
|
||||
},
|
||||
Status: apps.PetSetStatus{Replicas: 4},
|
||||
}
|
||||
Strategy.PrepareForUpdate(validPs, ps)
|
||||
errs = Strategy.ValidateUpdate(ctx, validPs, ps)
|
||||
if len(errs) == 0 {
|
||||
t.Errorf("Expected a validation error since updates are disallowed on petsets.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPetSetStatusStrategy(t *testing.T) {
|
||||
ctx := api.NewDefaultContext()
|
||||
if !StatusStrategy.NamespaceScoped() {
|
||||
t.Errorf("PetSet must be namespace scoped")
|
||||
}
|
||||
if StatusStrategy.AllowCreateOnUpdate() {
|
||||
t.Errorf("PetSet should not allow create on update")
|
||||
}
|
||||
validSelector := map[string]string{"a": "b"}
|
||||
validPodTemplate := api.PodTemplate{
|
||||
Template: api.PodTemplateSpec{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Labels: validSelector,
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
|
||||
},
|
||||
},
|
||||
}
|
||||
oldPS := &apps.PetSet{
|
||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault, ResourceVersion: "10"},
|
||||
Spec: apps.PetSetSpec{
|
||||
Replicas: 3,
|
||||
Selector: &unversioned.LabelSelector{MatchLabels: validSelector},
|
||||
Template: validPodTemplate.Template,
|
||||
},
|
||||
Status: apps.PetSetStatus{
|
||||
Replicas: 1,
|
||||
},
|
||||
}
|
||||
newPS := &apps.PetSet{
|
||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault, ResourceVersion: "9"},
|
||||
Spec: apps.PetSetSpec{
|
||||
Replicas: 1,
|
||||
Selector: &unversioned.LabelSelector{MatchLabels: validSelector},
|
||||
Template: validPodTemplate.Template,
|
||||
},
|
||||
Status: apps.PetSetStatus{
|
||||
Replicas: 2,
|
||||
},
|
||||
}
|
||||
StatusStrategy.PrepareForUpdate(newPS, oldPS)
|
||||
if newPS.Status.Replicas != 2 {
|
||||
t.Errorf("PetSet status updates should allow change of pets: %v", newPS.Status.Replicas)
|
||||
}
|
||||
if newPS.Spec.Replicas != 3 {
|
||||
t.Errorf("PetSet status updates should not clobber spec: %v", newPS.Spec)
|
||||
}
|
||||
errs := StatusStrategy.ValidateUpdate(ctx, newPS, oldPS)
|
||||
if len(errs) != 0 {
|
||||
t.Errorf("Unexpected error %v", errs)
|
||||
}
|
||||
}
|
@ -62,6 +62,13 @@ func NewBatchEtcdStorage(client etcd.Client) storage.Interface {
|
||||
return etcdstorage.NewEtcdStorage(client, testapi.Batch.Codec(), etcdtest.PathPrefix(), false, etcdtest.DeserializationCacheSize)
|
||||
}
|
||||
|
||||
func NewAppsEtcdStorage(client etcd.Client) storage.Interface {
|
||||
if client == nil {
|
||||
client = NewEtcdClient()
|
||||
}
|
||||
return etcdstorage.NewEtcdStorage(client, testapi.Apps.Codec(), etcdtest.PathPrefix(), false, etcdtest.DeserializationCacheSize)
|
||||
}
|
||||
|
||||
func NewExtensionsEtcdStorage(client etcd.Client) storage.Interface {
|
||||
if client == nil {
|
||||
client = NewEtcdClient()
|
||||
|
@ -29,6 +29,7 @@ import (
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
"k8s.io/kubernetes/pkg/apis/apps"
|
||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
||||
"k8s.io/kubernetes/pkg/apis/batch"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
@ -157,6 +158,8 @@ func NewMasterConfig() *master.Config {
|
||||
storageVersions[autoscaling.GroupName] = testapi.Autoscaling.GroupVersion().String()
|
||||
batchEtcdStorage := NewBatchEtcdStorage(etcdClient)
|
||||
storageVersions[batch.GroupName] = testapi.Batch.GroupVersion().String()
|
||||
appsEtcdStorage := NewAppsEtcdStorage(etcdClient)
|
||||
storageVersions[apps.GroupName] = testapi.Apps.GroupVersion().String()
|
||||
expEtcdStorage := NewExtensionsEtcdStorage(etcdClient)
|
||||
storageVersions[extensions.GroupName] = testapi.Extensions.GroupVersion().String()
|
||||
|
||||
@ -164,6 +167,7 @@ func NewMasterConfig() *master.Config {
|
||||
storageDestinations.AddAPIGroup(api.GroupName, etcdStorage)
|
||||
storageDestinations.AddAPIGroup(autoscaling.GroupName, autoscalingEtcdStorage)
|
||||
storageDestinations.AddAPIGroup(batch.GroupName, batchEtcdStorage)
|
||||
storageDestinations.AddAPIGroup(apps.GroupName, appsEtcdStorage)
|
||||
storageDestinations.AddAPIGroup(extensions.GroupName, expEtcdStorage)
|
||||
|
||||
return &master.Config{
|
||||
|
@ -55,6 +55,10 @@ func TestBatchPrefix(t *testing.T) {
|
||||
testPrefix(t, "/apis/batch/")
|
||||
}
|
||||
|
||||
func TestAppsPrefix(t *testing.T) {
|
||||
testPrefix(t, "/apis/apps/")
|
||||
}
|
||||
|
||||
func TestExtensionsPrefix(t *testing.T) {
|
||||
testPrefix(t, "/apis/extensions/")
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user