diff --git a/hack/.linted_packages b/hack/.linted_packages index cf4f5ea9bee..70d0e0bab59 100644 --- a/hack/.linted_packages +++ b/hack/.linted_packages @@ -305,6 +305,8 @@ staging/src/k8s.io/client-go/tools/metrics staging/src/k8s.io/client-go/util/cert staging/src/k8s.io/client-go/util/homedir staging/src/k8s.io/client-go/util/workqueue +staging/src/k8s.io/sample-apiserver +staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/install test/e2e/perftype test/e2e_node/runner/local test/images/clusterapi-tester diff --git a/hack/godep-save.sh b/hack/godep-save.sh index 1bc1f19ff8f..a66cc679bf6 100755 --- a/hack/godep-save.sh +++ b/hack/godep-save.sh @@ -47,6 +47,9 @@ pushd "${KUBE_ROOT}" > /dev/null if [ ! -e "vendor/k8s.io/apimachinery" ]; then ln -s ../../staging/src/k8s.io/apimachinery vendor/k8s.io/apimachinery fi + if [ ! -e "vendor/k8s.io/sample-apiserver" ]; then + ln -s ../../staging/src/k8s.io/sample-apiserver vendor/k8s.io/sample-apiserver + fi popd > /dev/null echo "Don't forget to run hack/update-godep-licenses.sh if you added or removed a dependency!" diff --git a/hack/verify-staging-imports.sh b/hack/verify-staging-imports.sh index 21653a53ce2..b48441079af 100755 --- a/hack/verify-staging-imports.sh +++ b/hack/verify-staging-imports.sh @@ -53,6 +53,7 @@ RC=0 print_forbidden_imports apimachinery k8s.io/ || RC=1 print_forbidden_imports apiserver k8s.io/kubernetes || RC=1 print_forbidden_imports client-go k8s.io/kubernetes k8s.io/apiserver || RC=1 +print_forbidden_imports sample-apiserver k8s.io/kubernetes || RC=1 if [ ${RC} != 0 ]; then exit ${RC} fi diff --git a/staging/src/k8s.io/apiserver/pkg/server/genericapiserver.go b/staging/src/k8s.io/apiserver/pkg/server/genericapiserver.go index 38b5dab5d82..2c19a0d2829 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/genericapiserver.go +++ b/staging/src/k8s.io/apiserver/pkg/server/genericapiserver.go @@ -388,9 +388,10 @@ func NewDefaultAPIGroupInfo(group string, registry *registered.APIRegistrationMa return APIGroupInfo{ GroupMeta: *groupMeta, VersionedResourcesStorageMap: map[string]map[string]rest.Storage{}, - OptionsExternalVersion: ®istry.GroupOrDie("").GroupVersion, - Scheme: scheme, - ParameterCodec: parameterCodec, - NegotiatedSerializer: codecs, + // TODO unhardcode this. It was hardcoded before, but we need to re-evaluate + OptionsExternalVersion: &schema.GroupVersion{Version: "v1"}, + Scheme: scheme, + ParameterCodec: parameterCodec, + NegotiatedSerializer: codecs, } } diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/authentication.go b/staging/src/k8s.io/apiserver/pkg/server/options/authentication.go index aafaa3de809..16378fa145b 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/authentication.go +++ b/staging/src/k8s.io/apiserver/pkg/server/options/authentication.go @@ -60,7 +60,7 @@ func (s *RequestHeaderAuthenticationOptions) AddFlags(fs *pflag.FlagSet) { // ToAuthenticationRequestHeaderConfig returns a RequestHeaderConfig config object for these options // if necessary, nil otherwise. func (s *RequestHeaderAuthenticationOptions) ToAuthenticationRequestHeaderConfig() *authenticatorfactory.RequestHeaderConfig { - if len(s.UsernameHeaders) == 0 { + if len(s.UsernameHeaders) == 0 || (len(s.UsernameHeaders) == 1 && len(s.UsernameHeaders[0]) == 0) { return nil } diff --git a/staging/src/k8s.io/sample-apiserver/artifacts/example/example.yaml b/staging/src/k8s.io/sample-apiserver/artifacts/example/example.yaml new file mode 100644 index 00000000000..078a36d0a21 --- /dev/null +++ b/staging/src/k8s.io/sample-apiserver/artifacts/example/example.yaml @@ -0,0 +1,7 @@ +apiVersion: serviceinjection.k8s.io/v1alpha1 +kind: ServiceInjection +metadata: + name: injector + namespace: kube-system + labels: + sample-label: foo diff --git a/staging/src/k8s.io/sample-apiserver/artifacts/simple-image/Dockerfile b/staging/src/k8s.io/sample-apiserver/artifacts/simple-image/Dockerfile new file mode 100644 index 00000000000..502f6aa9af8 --- /dev/null +++ b/staging/src/k8s.io/sample-apiserver/artifacts/simple-image/Dockerfile @@ -0,0 +1,17 @@ +# Copyright 2017 The Kubernetes Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +FROM fedora +ADD kube-service-injection / +ENTRYPOINT ["/kube-service-injection"] diff --git a/staging/src/k8s.io/sample-apiserver/artifacts/static/static-pod.yaml b/staging/src/k8s.io/sample-apiserver/artifacts/static/static-pod.yaml new file mode 100644 index 00000000000..960e933fc24 --- /dev/null +++ b/staging/src/k8s.io/sample-apiserver/artifacts/static/static-pod.yaml @@ -0,0 +1,33 @@ +apiVersion: v1 +kind: Pod +metadata: + name: kube-service-injection + namespace: kube-system +spec: + hostNetwork: true + containers: + - name: kube-service-injection + image: kube-service-injection + imagePullPolicy: Never + args: + - "--secure-port=9443" + - "--authentication-kubeconfig=/all-certs/admin.kubeconfig" + - "--authorization-kubeconfig=/all-certs/admin.kubeconfig" + - "--tls-ca-file=/all-certs/apiserver.crt" + - "--client-ca-file=/all-certs/client-ca.crt" + - "--requestheader-username-headers=X-Remote-User" + - "--requestheader-group-headers=X-Remote-Group" + - "--requestheader-extra-headers-prefix=X-Remote-Extra-" + - "--requestheader-client-ca-file=/all-certs/request-header-ca.crt" + - "--etcd-servers=http://127.0.0.1:2379" + ports: + - containerPort: 9443 + hostPort: 9443 + volumeMounts: + - name: all-certs + mountPath: /all-certs + readOnly: true + volumes: + - name: all-certs + hostPath: + path: /var/run/kubernetes/ diff --git a/staging/src/k8s.io/sample-apiserver/hack/build-image.sh b/staging/src/k8s.io/sample-apiserver/hack/build-image.sh new file mode 100755 index 00000000000..cc61c7bc6ae --- /dev/null +++ b/staging/src/k8s.io/sample-apiserver/hack/build-image.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +# Copyright 2017 The Kubernetes Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +KUBE_ROOT=$(dirname "${BASH_SOURCE}")/../../.. +source "${KUBE_ROOT}/hack/lib/util.sh" + +# Register function to be called on EXIT to remove generated binary. +function cleanup { + rm "${KUBE_ROOT}/cmd/kube-sample-apiserver/artifacts/simple-image/kube-sample-apiserver" +} +trap cleanup EXIT + +cp -v ${KUBE_ROOT}/_output/local/bin/linux/amd64/kube-sample-apiserver "${KUBE_ROOT}/cmd/kube-sample-apiserver/artifacts/simple-image/kube-sample-apiserver" +docker build -t kube-sample-apiserver:latest ${KUBE_ROOT}/cmd/kube-sample-apiserver/artifacts/simple-image diff --git a/staging/src/k8s.io/sample-apiserver/hack/update-codegen.sh b/staging/src/k8s.io/sample-apiserver/hack/update-codegen.sh new file mode 100755 index 00000000000..0bcf8082efe --- /dev/null +++ b/staging/src/k8s.io/sample-apiserver/hack/update-codegen.sh @@ -0,0 +1,69 @@ +#!/bin/bash + +# Copyright 2017 The Kubernetes Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -o errexit +set -o nounset +set -o pipefail + +KUBE_ROOT=$(dirname "${BASH_SOURCE}")/../../.. +APIFEDERATOR_ROOT=$(dirname "${BASH_SOURCE}")/.. +source "${KUBE_ROOT}/hack/lib/init.sh" + +# Register function to be called on EXIT to remove generated binary. +function cleanup { + rm -f "${CLIENTGEN:-}" + rm -f "${listergen:-}" + rm -f "${informergen:-}" +} +trap cleanup EXIT + +echo "Building client-gen" +CLIENTGEN="${PWD}/client-gen-binary" +go build -o "${CLIENTGEN}" ./cmd/libs/go2idl/client-gen + +PREFIX=k8s.io/sample-apiserver/pkg/apis +INPUT_BASE="--input-base ${PREFIX}" +INPUT_APIS=( +wardle/ +wardle/v1alpha1 +) +INPUT="--input ${INPUT_APIS[@]}" +CLIENTSET_PATH="--clientset-path k8s.io/sample-apiserver/pkg/client/clientset_generated" + +${CLIENTGEN} ${INPUT_BASE} ${INPUT} ${CLIENTSET_PATH} +${CLIENTGEN} --clientset-name="clientset" ${INPUT_BASE} --input wardle/v1alpha1 ${CLIENTSET_PATH} + + +echo "Building lister-gen" +listergen="${PWD}/lister-gen" +go build -o "${listergen}" ./cmd/libs/go2idl/lister-gen + +LISTER_INPUT="--input-dirs k8s.io/sample-apiserver/pkg/apis/wardle --input-dirs k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1" +LISTER_PATH="--output-package k8s.io/sample-apiserver/pkg/client/listers" +${listergen} ${LISTER_INPUT} ${LISTER_PATH} + + +echo "Building informer-gen" +informergen="${PWD}/informer-gen" +go build -o "${informergen}" ./cmd/libs/go2idl/informer-gen + +${informergen} \ + --input-dirs k8s.io/sample-apiserver/pkg/apis/wardle --input-dirs k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1 \ + --versioned-clientset-package k8s.io/sample-apiserver/pkg/client/clientset_generated/clientset \ + --internal-clientset-package k8s.io/sample-apiserver/pkg/client/clientset_generated/internalclientset \ + --listers-package k8s.io/sample-apiserver/pkg/client/listers \ + --output-package k8s.io/sample-apiserver/pkg/client/informers + "$@" diff --git a/staging/src/k8s.io/sample-apiserver/main.go b/staging/src/k8s.io/sample-apiserver/main.go new file mode 100644 index 00000000000..8b9424fa481 --- /dev/null +++ b/staging/src/k8s.io/sample-apiserver/main.go @@ -0,0 +1,43 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "flag" + "os" + "runtime" + + "k8s.io/apimachinery/pkg/util/wait" + // "k8s.io/kubernetes/pkg/util/logs" + "k8s.io/sample-apiserver/pkg/cmd/server" +) + +func main() { + // TODO move package and restore + // logs.InitLogs() + // defer logs.FlushLogs() + + if len(os.Getenv("GOMAXPROCS")) == 0 { + runtime.GOMAXPROCS(runtime.NumCPU()) + } + + cmd := server.NewCommandStartWardleServer(os.Stdout, os.Stderr, wait.NeverStop) + cmd.Flags().AddGoFlagSet(flag.CommandLine) + if err := cmd.Execute(); err != nil { + panic(err) + } +} diff --git a/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/doc.go b/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/doc.go new file mode 100644 index 00000000000..bb99a18fb81 --- /dev/null +++ b/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/doc.go @@ -0,0 +1,21 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +k8s:deepcopy-gen=package,register + +// Package api is the internal version of the API. +// +groupName=wardle.k8s.io +package wardle diff --git a/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/install/install.go b/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/install/install.go new file mode 100644 index 00000000000..74a961939ae --- /dev/null +++ b/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/install/install.go @@ -0,0 +1,44 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package install + +import ( + "k8s.io/apimachinery/pkg/apimachinery/announced" + "k8s.io/apimachinery/pkg/apimachinery/registered" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/sample-apiserver/pkg/apis/wardle" + "k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1" +) + +// Install registers the API group and adds types to a scheme +func Install(groupFactoryRegistry announced.APIGroupFactoryRegistry, registry *registered.APIRegistrationManager, scheme *runtime.Scheme) { + if err := announced.NewGroupMetaFactory( + &announced.GroupMetaFactoryArgs{ + GroupName: wardle.GroupName, + RootScopedKinds: sets.NewString("APIService"), + VersionPreferenceOrder: []string{v1alpha1.SchemeGroupVersion.Version}, + ImportPrefix: "k8s.io/sample-apiserver/pkg/apis/wardle", + AddInternalObjectsToScheme: wardle.AddToScheme, + }, + announced.VersionToSchemeFunc{ + v1alpha1.SchemeGroupVersion.Version: v1alpha1.AddToScheme, + }, + ).Announce(groupFactoryRegistry).RegisterAndEnable(registry, scheme); err != nil { + panic(err) + } +} diff --git a/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/register.go b/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/register.go new file mode 100644 index 00000000000..d7ce354ccf8 --- /dev/null +++ b/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/register.go @@ -0,0 +1,53 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package wardle + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +const GroupName = "wardle.k8s.io" + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal} + +// Kind takes an unqualified kind and returns back a Group qualified GroupKind +func Kind(kind string) schema.GroupKind { + return SchemeGroupVersion.WithKind(kind).GroupKind() +} + +// Resource takes an unqualified resource and returns back a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +var ( + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + AddToScheme = SchemeBuilder.AddToScheme +) + +// Adds the list of known types to api.Scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &Flunder{}, + &FlunderList{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/types.go b/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/types.go new file mode 100644 index 00000000000..270b2f45110 --- /dev/null +++ b/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/types.go @@ -0,0 +1,43 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package wardle + +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +// FlunderList is a list of Flunder objects. +type FlunderList struct { + metav1.TypeMeta + metav1.ListMeta + + Items []Flunder +} + +type FlunderSpec struct { +} + +type FlunderStatus struct { +} + +// +genclient=true + +type Flunder struct { + metav1.TypeMeta + metav1.ObjectMeta + + Spec FlunderSpec + Status FlunderStatus +} diff --git a/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/doc.go b/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/doc.go new file mode 100644 index 00000000000..06c174cf11d --- /dev/null +++ b/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/doc.go @@ -0,0 +1,22 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +k8s:deepcopy-gen=package,register +// +k8s:conversion-gen=k8s.io/sample-apiserver/pkg/apis/wardle + +// Package v1alpha1 is the v1alpha1 version of the API. +// +groupName=wardle.k8s.io +package v1alpha1 diff --git a/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/register.go b/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/register.go new file mode 100644 index 00000000000..5c8a22aae97 --- /dev/null +++ b/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/register.go @@ -0,0 +1,43 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +const GroupName = "wardle.k8s.io" + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha1"} + +var ( + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + AddToScheme = SchemeBuilder.AddToScheme +) + +// Adds the list of known types to api.Scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &Flunder{}, + &FlunderList{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/types.go b/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/types.go new file mode 100644 index 00000000000..8d796a06514 --- /dev/null +++ b/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/types.go @@ -0,0 +1,43 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +// FlunderList is a list of Flunder objects. +type FlunderList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` + + Items []Flunder `json:"items" protobuf:"bytes,2,rep,name=items"` +} + +type FlunderSpec struct { +} + +type FlunderStatus struct { +} + +// +genclient=true + +type Flunder struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` + + Spec FlunderSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"` + Status FlunderStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"` +} diff --git a/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/zz_generated.conversion.go b/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/zz_generated.conversion.go new file mode 100644 index 00000000000..8e9aaa5ba48 --- /dev/null +++ b/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/zz_generated.conversion.go @@ -0,0 +1,129 @@ +// +build !ignore_autogenerated + +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// This file was autogenerated by conversion-gen. Do not edit it manually! + +package v1alpha1 + +import ( + conversion "k8s.io/apimachinery/pkg/conversion" + runtime "k8s.io/apimachinery/pkg/runtime" + wardle "k8s.io/sample-apiserver/pkg/apis/wardle" + unsafe "unsafe" +) + +func init() { + SchemeBuilder.Register(RegisterConversions) +} + +// RegisterConversions adds conversion functions to the given scheme. +// Public to allow building arbitrary schemes. +func RegisterConversions(scheme *runtime.Scheme) error { + return scheme.AddGeneratedConversionFuncs( + Convert_v1alpha1_Flunder_To_wardle_Flunder, + Convert_wardle_Flunder_To_v1alpha1_Flunder, + Convert_v1alpha1_FlunderList_To_wardle_FlunderList, + Convert_wardle_FlunderList_To_v1alpha1_FlunderList, + Convert_v1alpha1_FlunderSpec_To_wardle_FlunderSpec, + Convert_wardle_FlunderSpec_To_v1alpha1_FlunderSpec, + Convert_v1alpha1_FlunderStatus_To_wardle_FlunderStatus, + Convert_wardle_FlunderStatus_To_v1alpha1_FlunderStatus, + ) +} + +func autoConvert_v1alpha1_Flunder_To_wardle_Flunder(in *Flunder, out *wardle.Flunder, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_v1alpha1_FlunderSpec_To_wardle_FlunderSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + if err := Convert_v1alpha1_FlunderStatus_To_wardle_FlunderStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +func Convert_v1alpha1_Flunder_To_wardle_Flunder(in *Flunder, out *wardle.Flunder, s conversion.Scope) error { + return autoConvert_v1alpha1_Flunder_To_wardle_Flunder(in, out, s) +} + +func autoConvert_wardle_Flunder_To_v1alpha1_Flunder(in *wardle.Flunder, out *Flunder, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_wardle_FlunderSpec_To_v1alpha1_FlunderSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + if err := Convert_wardle_FlunderStatus_To_v1alpha1_FlunderStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +func Convert_wardle_Flunder_To_v1alpha1_Flunder(in *wardle.Flunder, out *Flunder, s conversion.Scope) error { + return autoConvert_wardle_Flunder_To_v1alpha1_Flunder(in, out, s) +} + +func autoConvert_v1alpha1_FlunderList_To_wardle_FlunderList(in *FlunderList, out *wardle.FlunderList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]wardle.Flunder)(unsafe.Pointer(&in.Items)) + return nil +} + +func Convert_v1alpha1_FlunderList_To_wardle_FlunderList(in *FlunderList, out *wardle.FlunderList, s conversion.Scope) error { + return autoConvert_v1alpha1_FlunderList_To_wardle_FlunderList(in, out, s) +} + +func autoConvert_wardle_FlunderList_To_v1alpha1_FlunderList(in *wardle.FlunderList, out *FlunderList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]Flunder)(unsafe.Pointer(&in.Items)) + return nil +} + +func Convert_wardle_FlunderList_To_v1alpha1_FlunderList(in *wardle.FlunderList, out *FlunderList, s conversion.Scope) error { + return autoConvert_wardle_FlunderList_To_v1alpha1_FlunderList(in, out, s) +} + +func autoConvert_v1alpha1_FlunderSpec_To_wardle_FlunderSpec(in *FlunderSpec, out *wardle.FlunderSpec, s conversion.Scope) error { + return nil +} + +func Convert_v1alpha1_FlunderSpec_To_wardle_FlunderSpec(in *FlunderSpec, out *wardle.FlunderSpec, s conversion.Scope) error { + return autoConvert_v1alpha1_FlunderSpec_To_wardle_FlunderSpec(in, out, s) +} + +func autoConvert_wardle_FlunderSpec_To_v1alpha1_FlunderSpec(in *wardle.FlunderSpec, out *FlunderSpec, s conversion.Scope) error { + return nil +} + +func Convert_wardle_FlunderSpec_To_v1alpha1_FlunderSpec(in *wardle.FlunderSpec, out *FlunderSpec, s conversion.Scope) error { + return autoConvert_wardle_FlunderSpec_To_v1alpha1_FlunderSpec(in, out, s) +} + +func autoConvert_v1alpha1_FlunderStatus_To_wardle_FlunderStatus(in *FlunderStatus, out *wardle.FlunderStatus, s conversion.Scope) error { + return nil +} + +func Convert_v1alpha1_FlunderStatus_To_wardle_FlunderStatus(in *FlunderStatus, out *wardle.FlunderStatus, s conversion.Scope) error { + return autoConvert_v1alpha1_FlunderStatus_To_wardle_FlunderStatus(in, out, s) +} + +func autoConvert_wardle_FlunderStatus_To_v1alpha1_FlunderStatus(in *wardle.FlunderStatus, out *FlunderStatus, s conversion.Scope) error { + return nil +} + +func Convert_wardle_FlunderStatus_To_v1alpha1_FlunderStatus(in *wardle.FlunderStatus, out *FlunderStatus, s conversion.Scope) error { + return autoConvert_wardle_FlunderStatus_To_v1alpha1_FlunderStatus(in, out, s) +} diff --git a/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/zz_generated.deepcopy.go b/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 00000000000..60d9e324de7 --- /dev/null +++ b/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,93 @@ +// +build !ignore_autogenerated + +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// This file was autogenerated by deepcopy-gen. Do not edit it manually! + +package v1alpha1 + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + conversion "k8s.io/apimachinery/pkg/conversion" + runtime "k8s.io/apimachinery/pkg/runtime" + reflect "reflect" +) + +func init() { + SchemeBuilder.Register(RegisterDeepCopies) +} + +// RegisterDeepCopies adds deep-copy functions to the given scheme. Public +// to allow building arbitrary schemes. +func RegisterDeepCopies(scheme *runtime.Scheme) error { + return scheme.AddGeneratedDeepCopyFuncs( + conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1alpha1_Flunder, InType: reflect.TypeOf(&Flunder{})}, + conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1alpha1_FlunderList, InType: reflect.TypeOf(&FlunderList{})}, + conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1alpha1_FlunderSpec, InType: reflect.TypeOf(&FlunderSpec{})}, + conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1alpha1_FlunderStatus, InType: reflect.TypeOf(&FlunderStatus{})}, + ) +} + +func DeepCopy_v1alpha1_Flunder(in interface{}, out interface{}, c *conversion.Cloner) error { + { + in := in.(*Flunder) + out := out.(*Flunder) + *out = *in + if newVal, err := c.DeepCopy(&in.ObjectMeta); err != nil { + return err + } else { + out.ObjectMeta = *newVal.(*v1.ObjectMeta) + } + return nil + } +} + +func DeepCopy_v1alpha1_FlunderList(in interface{}, out interface{}, c *conversion.Cloner) error { + { + in := in.(*FlunderList) + out := out.(*FlunderList) + *out = *in + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Flunder, len(*in)) + for i := range *in { + if err := DeepCopy_v1alpha1_Flunder(&(*in)[i], &(*out)[i], c); err != nil { + return err + } + } + } + return nil + } +} + +func DeepCopy_v1alpha1_FlunderSpec(in interface{}, out interface{}, c *conversion.Cloner) error { + { + in := in.(*FlunderSpec) + out := out.(*FlunderSpec) + *out = *in + return nil + } +} + +func DeepCopy_v1alpha1_FlunderStatus(in interface{}, out interface{}, c *conversion.Cloner) error { + { + in := in.(*FlunderStatus) + out := out.(*FlunderStatus) + *out = *in + return nil + } +} diff --git a/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/zz_generated.deepcopy.go b/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/zz_generated.deepcopy.go new file mode 100644 index 00000000000..450990303e1 --- /dev/null +++ b/staging/src/k8s.io/sample-apiserver/pkg/apis/wardle/zz_generated.deepcopy.go @@ -0,0 +1,93 @@ +// +build !ignore_autogenerated + +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// This file was autogenerated by deepcopy-gen. Do not edit it manually! + +package wardle + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + conversion "k8s.io/apimachinery/pkg/conversion" + runtime "k8s.io/apimachinery/pkg/runtime" + reflect "reflect" +) + +func init() { + SchemeBuilder.Register(RegisterDeepCopies) +} + +// RegisterDeepCopies adds deep-copy functions to the given scheme. Public +// to allow building arbitrary schemes. +func RegisterDeepCopies(scheme *runtime.Scheme) error { + return scheme.AddGeneratedDeepCopyFuncs( + conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_wardle_Flunder, InType: reflect.TypeOf(&Flunder{})}, + conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_wardle_FlunderList, InType: reflect.TypeOf(&FlunderList{})}, + conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_wardle_FlunderSpec, InType: reflect.TypeOf(&FlunderSpec{})}, + conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_wardle_FlunderStatus, InType: reflect.TypeOf(&FlunderStatus{})}, + ) +} + +func DeepCopy_wardle_Flunder(in interface{}, out interface{}, c *conversion.Cloner) error { + { + in := in.(*Flunder) + out := out.(*Flunder) + *out = *in + if newVal, err := c.DeepCopy(&in.ObjectMeta); err != nil { + return err + } else { + out.ObjectMeta = *newVal.(*v1.ObjectMeta) + } + return nil + } +} + +func DeepCopy_wardle_FlunderList(in interface{}, out interface{}, c *conversion.Cloner) error { + { + in := in.(*FlunderList) + out := out.(*FlunderList) + *out = *in + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Flunder, len(*in)) + for i := range *in { + if err := DeepCopy_wardle_Flunder(&(*in)[i], &(*out)[i], c); err != nil { + return err + } + } + } + return nil + } +} + +func DeepCopy_wardle_FlunderSpec(in interface{}, out interface{}, c *conversion.Cloner) error { + { + in := in.(*FlunderSpec) + out := out.(*FlunderSpec) + *out = *in + return nil + } +} + +func DeepCopy_wardle_FlunderStatus(in interface{}, out interface{}, c *conversion.Cloner) error { + { + in := in.(*FlunderStatus) + out := out.(*FlunderStatus) + *out = *in + return nil + } +} diff --git a/staging/src/k8s.io/sample-apiserver/pkg/apiserver/apiserver.go b/staging/src/k8s.io/sample-apiserver/pkg/apiserver/apiserver.go new file mode 100644 index 00000000000..95ed82fb251 --- /dev/null +++ b/staging/src/k8s.io/sample-apiserver/pkg/apiserver/apiserver.go @@ -0,0 +1,113 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package apiserver + +import ( + "k8s.io/apimachinery/pkg/apimachinery/announced" + "k8s.io/apimachinery/pkg/apimachinery/registered" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/apimachinery/pkg/version" + "k8s.io/apiserver/pkg/registry/rest" + genericapiserver "k8s.io/apiserver/pkg/server" + + "k8s.io/sample-apiserver/pkg/apis/wardle" + "k8s.io/sample-apiserver/pkg/apis/wardle/install" + "k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1" + wardlestorage "k8s.io/sample-apiserver/pkg/registry/wardle" +) + +var ( + groupFactoryRegistry = make(announced.APIGroupFactoryRegistry) + registry = registered.NewOrDie("") + Scheme = runtime.NewScheme() + Codecs = serializer.NewCodecFactory(Scheme) +) + +func init() { + install.Install(groupFactoryRegistry, registry, Scheme) + + // we need to add the options to empty v1 + // TODO fix the server code to avoid this + metav1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) + + // TODO: keep the generic API server from wanting this + unversioned := schema.GroupVersion{Group: "", Version: "v1"} + Scheme.AddUnversionedTypes(unversioned, + &metav1.Status{}, + &metav1.APIVersions{}, + &metav1.APIGroupList{}, + &metav1.APIGroup{}, + &metav1.APIResourceList{}, + ) +} + +type Config struct { + GenericConfig *genericapiserver.Config +} + +// WardleServer contains state for a Kubernetes cluster master/api server. +type WardleServer struct { + GenericAPIServer *genericapiserver.GenericAPIServer +} + +type completedConfig struct { + *Config +} + +// Complete fills in any fields not set that are required to have valid data. It's mutating the receiver. +func (c *Config) Complete() completedConfig { + c.GenericConfig.Complete() + + c.GenericConfig.Version = &version.Info{ + Major: "1", + Minor: "0", + } + + return completedConfig{c} +} + +// SkipComplete provides a way to construct a server instance without config completion. +func (c *Config) SkipComplete() completedConfig { + return completedConfig{c} +} + +// New returns a new instance of WardleServer from the given config. +func (c completedConfig) New() (*WardleServer, error) { + genericServer, err := c.Config.GenericConfig.SkipComplete().New() // completion is done in Complete, no need for a second time + if err != nil { + return nil, err + } + + s := &WardleServer{ + GenericAPIServer: genericServer, + } + + apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(wardle.GroupName, registry, Scheme, metav1.ParameterCodec, Codecs) + apiGroupInfo.GroupMeta.GroupVersion = v1alpha1.SchemeGroupVersion + v1alpha1storage := map[string]rest.Storage{} + v1alpha1storage["flunders"] = wardlestorage.NewREST(Scheme, c.GenericConfig.RESTOptionsGetter) + apiGroupInfo.VersionedResourcesStorageMap["v1alpha1"] = v1alpha1storage + + if err := s.GenericAPIServer.InstallAPIGroup(&apiGroupInfo); err != nil { + return nil, err + } + + return s, nil +} diff --git a/staging/src/k8s.io/sample-apiserver/pkg/cmd/server/start.go b/staging/src/k8s.io/sample-apiserver/pkg/cmd/server/start.go new file mode 100644 index 00000000000..7f087e0fd41 --- /dev/null +++ b/staging/src/k8s.io/sample-apiserver/pkg/cmd/server/start.go @@ -0,0 +1,124 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package server + +import ( + "fmt" + "io" + + "github.com/pborman/uuid" + "github.com/spf13/cobra" + + genericapiserver "k8s.io/apiserver/pkg/server" + genericoptions "k8s.io/apiserver/pkg/server/options" + "k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1" + "k8s.io/sample-apiserver/pkg/apiserver" +) + +const defaultEtcdPathPrefix = "/registry/wardle.kubernetes.io" + +type WardleServerOptions struct { + RecommendedOptions *genericoptions.RecommendedOptions + + StdOut io.Writer + StdErr io.Writer +} + +func NewWardleServerOptions(out, errOut io.Writer) *WardleServerOptions { + o := &WardleServerOptions{ + RecommendedOptions: genericoptions.NewRecommendedOptions(defaultEtcdPathPrefix, apiserver.Scheme, apiserver.Codecs.LegacyCodec(v1alpha1.SchemeGroupVersion)), + + StdOut: out, + StdErr: errOut, + } + o.RecommendedOptions.SecureServing.ServingOptions.BindPort = 443 + + return o +} + +// NewCommandStartMaster provides a CLI handler for 'start master' command +func NewCommandStartWardleServer(out, errOut io.Writer, stopCh <-chan struct{}) *cobra.Command { + o := NewWardleServerOptions(out, errOut) + + cmd := &cobra.Command{ + Short: "Launch a wardle API server", + Long: "Launch a wardle API server", + RunE: func(c *cobra.Command, args []string) error { + if err := o.Complete(); err != nil { + return err + } + if err := o.Validate(args); err != nil { + return err + } + if err := o.RunWardleServer(stopCh); err != nil { + return err + } + return nil + }, + } + + flags := cmd.Flags() + o.RecommendedOptions.AddFlags(flags) + + return cmd +} + +func (o WardleServerOptions) Validate(args []string) error { + return nil +} + +func (o *WardleServerOptions) Complete() error { + return nil +} + +func (o WardleServerOptions) Config() (*apiserver.Config, error) { + // TODO have a "real" external address + if err := o.RecommendedOptions.SecureServing.MaybeDefaultWithSelfSignedCerts("localhost"); err != nil { + return nil, fmt.Errorf("error creating self-signed certificates: %v", err) + } + + serverConfig := genericapiserver.NewConfig().WithSerializer(apiserver.Codecs) + if err := o.RecommendedOptions.ApplyTo(serverConfig); err != nil { + return nil, err + } + + var err error + privilegedLoopbackToken := uuid.NewRandom().String() + if serverConfig.LoopbackClientConfig, err = serverConfig.SecureServingInfo.NewSelfClientConfig(privilegedLoopbackToken); err != nil { + return nil, err + } + + config := &apiserver.Config{ + GenericConfig: serverConfig, + } + return config, nil +} + +func (o WardleServerOptions) RunWardleServer(stopCh <-chan struct{}) error { + config, err := o.Config() + if err != nil { + return err + } + + server, err := config.Complete().New() + if err != nil { + return err + } + server.GenericAPIServer.PrepareRun().Run(stopCh) + + return nil +} diff --git a/staging/src/k8s.io/sample-apiserver/pkg/registry/wardle/etcd.go b/staging/src/k8s.io/sample-apiserver/pkg/registry/wardle/etcd.go new file mode 100644 index 00000000000..f44ffcbf13a --- /dev/null +++ b/staging/src/k8s.io/sample-apiserver/pkg/registry/wardle/etcd.go @@ -0,0 +1,54 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package wardle + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apiserver/pkg/registry/generic" + genericregistry "k8s.io/apiserver/pkg/registry/generic/registry" + "k8s.io/sample-apiserver/pkg/apis/wardle" +) + +// rest implements a RESTStorage for API services against etcd +type REST struct { + *genericregistry.Store +} + +// NewREST returns a RESTStorage object that will work against API services. +func NewREST(scheme *runtime.Scheme, optsGetter generic.RESTOptionsGetter) *REST { + strategy := NewStrategy(scheme) + + store := &genericregistry.Store{ + Copier: scheme, + NewFunc: func() runtime.Object { return &wardle.Flunder{} }, + NewListFunc: func() runtime.Object { return &wardle.FlunderList{} }, + ObjectNameFunc: func(obj runtime.Object) (string, error) { + return obj.(*wardle.Flunder).Name, nil + }, + PredicateFunc: MatchFlunder, + QualifiedResource: wardle.Resource("flunders"), + + CreateStrategy: strategy, + UpdateStrategy: strategy, + DeleteStrategy: strategy, + } + options := &generic.StoreOptions{RESTOptions: optsGetter, AttrFunc: GetAttrs} + if err := store.CompleteWithOptions(options); err != nil { + panic(err) // TODO: Propagate error up + } + return &REST{store} +} diff --git a/staging/src/k8s.io/sample-apiserver/pkg/registry/wardle/strategy.go b/staging/src/k8s.io/sample-apiserver/pkg/registry/wardle/strategy.go new file mode 100644 index 00000000000..12b1a6a8172 --- /dev/null +++ b/staging/src/k8s.io/sample-apiserver/pkg/registry/wardle/strategy.go @@ -0,0 +1,95 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package wardle + +import ( + "fmt" + + "k8s.io/apimachinery/pkg/fields" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/validation/field" + genericapirequest "k8s.io/apiserver/pkg/endpoints/request" + "k8s.io/apiserver/pkg/registry/generic" + "k8s.io/apiserver/pkg/storage" + "k8s.io/apiserver/pkg/storage/names" + + "k8s.io/sample-apiserver/pkg/apis/wardle" +) + +type apiServerStrategy struct { + runtime.ObjectTyper + names.NameGenerator +} + +func NewStrategy(typer runtime.ObjectTyper) apiServerStrategy { + return apiServerStrategy{typer, names.SimpleNameGenerator} +} + +func (apiServerStrategy) NamespaceScoped() bool { + return false +} + +func (apiServerStrategy) PrepareForCreate(ctx genericapirequest.Context, obj runtime.Object) { +} + +func (apiServerStrategy) PrepareForUpdate(ctx genericapirequest.Context, obj, old runtime.Object) { +} + +func (apiServerStrategy) Validate(ctx genericapirequest.Context, obj runtime.Object) field.ErrorList { + return field.ErrorList{} + // return validation.ValidateFlunder(obj.(*wardle.Flunder)) +} + +func (apiServerStrategy) AllowCreateOnUpdate() bool { + return false +} + +func (apiServerStrategy) AllowUnconditionalUpdate() bool { + return false +} + +func (apiServerStrategy) Canonicalize(obj runtime.Object) { +} + +func (apiServerStrategy) ValidateUpdate(ctx genericapirequest.Context, obj, old runtime.Object) field.ErrorList { + return field.ErrorList{} + // return validation.ValidateFlunderUpdate(obj.(*wardle.Flunder), old.(*wardle.Flunder)) +} + +func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, error) { + apiserver, ok := obj.(*wardle.Flunder) + if !ok { + return nil, nil, fmt.Errorf("given object is not a Flunder.") + } + return labels.Set(apiserver.ObjectMeta.Labels), FlunderToSelectableFields(apiserver), nil +} + +// MatchFlunder 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 MatchFlunder(label labels.Selector, field fields.Selector) storage.SelectionPredicate { + return storage.SelectionPredicate{ + Label: label, + Field: field, + GetAttrs: GetAttrs, + } +} + +// FlunderToSelectableFields returns a field set that represents the object. +func FlunderToSelectableFields(obj *wardle.Flunder) fields.Set { + return generic.ObjectMetaFieldsSet(&obj.ObjectMeta, true) +} diff --git a/test/integration/examples/BUILD b/test/integration/examples/BUILD index 133d8002c8b..64e0a428dcf 100644 --- a/test/integration/examples/BUILD +++ b/test/integration/examples/BUILD @@ -12,11 +12,15 @@ go_test( srcs = ["apiserver_test.go"], tags = ["automanaged"], deps = [ - "//cmd/libs/go2idl/client-gen/test_apis/testgroup/v1:go_default_library", - "//examples/apiserver:go_default_library", + "//test/integration/framework:go_default_library", "//vendor:github.com/golang/glog", "//vendor:github.com/stretchr/testify/assert", "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1", + "//vendor:k8s.io/client-go/rest", + "//vendor:k8s.io/client-go/tools/clientcmd", + "//vendor:k8s.io/client-go/tools/clientcmd/api", + "//vendor:k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1", + "//vendor:k8s.io/sample-apiserver/pkg/cmd/server", ], ) diff --git a/test/integration/examples/apiserver_test.go b/test/integration/examples/apiserver_test.go index ff42cdac31e..636f3d370a5 100644 --- a/test/integration/examples/apiserver_test.go +++ b/test/integration/examples/apiserver_test.go @@ -22,18 +22,25 @@ import ( "fmt" "io/ioutil" "net/http" + "os" "testing" "time" - "k8s.io/kubernetes/cmd/libs/go2idl/client-gen/test_apis/testgroup/v1" - "github.com/golang/glog" "github.com/stretchr/testify/assert" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/kubernetes/examples/apiserver" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" + clientcmdapi "k8s.io/client-go/tools/clientcmd/api" + "k8s.io/kubernetes/test/integration/framework" + "k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1" + "k8s.io/sample-apiserver/pkg/cmd/server" ) -var groupVersion = v1.SchemeGroupVersion +const securePort = "6444" + +var groupVersion = v1alpha1.SchemeGroupVersion var groupVersionForDiscovery = metav1.GroupVersionForDiscovery{ GroupVersion: groupVersion.String(), @@ -41,52 +48,85 @@ var groupVersionForDiscovery = metav1.GroupVersionForDiscovery{ } func TestRunServer(t *testing.T) { - serverIP := fmt.Sprintf("http://localhost:%d", apiserver.InsecurePort) + masterConfig := framework.NewIntegrationTestMasterConfig() + _, s := framework.RunAMaster(masterConfig) + defer s.Close() + + adminKubeConfig := createKubeConfig(masterConfig.GenericConfig.LoopbackClientConfig) + kubeconfigFile, _ := ioutil.TempFile("", "") + defer os.Remove(kubeconfigFile.Name()) + clientcmd.WriteToFile(*adminKubeConfig, kubeconfigFile.Name()) + stopCh := make(chan struct{}) - go func() { - if err := apiserver.NewServerRunOptions().Run(stopCh); err != nil { - t.Fatalf("Error in bringing up the server: %v", err) - } - }() defer close(stopCh) - if err := waitForApiserverUp(serverIP); err != nil { + cmd := server.NewCommandStartWardleServer(os.Stdout, os.Stderr, stopCh) + cmd.SetArgs([]string{ + "--secure-port", securePort, + "--requestheader-username-headers", "", + "--authentication-kubeconfig", kubeconfigFile.Name(), + "--authorization-kubeconfig", kubeconfigFile.Name(), + "--etcd-servers", framework.GetEtcdURLFromEnv(), + }) + go cmd.Execute() + + serverLocation := fmt.Sprintf("https://localhost:%s", securePort) + if err := waitForApiserverUp(serverLocation); err != nil { t.Fatalf("%v", err) } - testSwaggerSpec(t, serverIP) - testAPIGroupList(t, serverIP) - testAPIGroup(t, serverIP) - testAPIResourceList(t, serverIP) + + testAPIGroupList(t, serverLocation) + testAPIGroup(t, serverLocation) + testAPIResourceList(t, serverLocation) } -func TestRunSecureServer(t *testing.T) { - serverIP := fmt.Sprintf("https://localhost:%d", apiserver.SecurePort) - stopCh := make(chan struct{}) - go func() { - options := apiserver.NewServerRunOptions() - options.InsecureServing.BindPort = 0 - options.SecureServing.ServingOptions.BindPort = apiserver.SecurePort - if err := options.Run(stopCh); err != nil { - t.Fatalf("Error in bringing up the server: %v", err) - } - }() - defer close(stopCh) - if err := waitForApiserverUp(serverIP); err != nil { - t.Fatalf("%v", err) +func createKubeConfig(clientCfg *rest.Config) *clientcmdapi.Config { + clusterNick := "cluster" + userNick := "user" + contextNick := "context" + + config := clientcmdapi.NewConfig() + + credentials := clientcmdapi.NewAuthInfo() + credentials.Token = clientCfg.BearerToken + credentials.ClientCertificate = clientCfg.TLSClientConfig.CertFile + if len(credentials.ClientCertificate) == 0 { + credentials.ClientCertificateData = clientCfg.TLSClientConfig.CertData } - testSwaggerSpec(t, serverIP) - testAPIGroupList(t, serverIP) - testAPIGroup(t, serverIP) - testAPIResourceList(t, serverIP) + credentials.ClientKey = clientCfg.TLSClientConfig.KeyFile + if len(credentials.ClientKey) == 0 { + credentials.ClientKeyData = clientCfg.TLSClientConfig.KeyData + } + config.AuthInfos[userNick] = credentials + + cluster := clientcmdapi.NewCluster() + cluster.Server = clientCfg.Host + cluster.CertificateAuthority = clientCfg.CAFile + if len(cluster.CertificateAuthority) == 0 { + cluster.CertificateAuthorityData = clientCfg.CAData + } + cluster.InsecureSkipTLSVerify = clientCfg.Insecure + if clientCfg.GroupVersion != nil { + cluster.APIVersion = clientCfg.GroupVersion.String() + } + config.Clusters[clusterNick] = cluster + + context := clientcmdapi.NewContext() + context.Cluster = clusterNick + context.AuthInfo = userNick + config.Contexts[contextNick] = context + config.CurrentContext = contextNick + + return config } -func waitForApiserverUp(serverIP string) error { - for start := time.Now(); time.Since(start) < time.Minute; time.Sleep(5 * time.Second) { - glog.Errorf("Waiting for : %#v", serverIP) +func waitForApiserverUp(serverLocation string) error { + for start := time.Now(); time.Since(start) < 10*time.Second; time.Sleep(5 * time.Second) { + glog.Errorf("Waiting for : %#v", serverLocation) tr := &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, } client := &http.Client{Transport: tr} - _, err := client.Get(serverIP) + _, err := client.Get(serverLocation) if err == nil { return nil } @@ -116,65 +156,58 @@ func readResponse(serverURL string) ([]byte, error) { return contents, nil } -func testSwaggerSpec(t *testing.T, serverIP string) { - serverURL := serverIP + "/swaggerapi" - _, err := readResponse(serverURL) - if err != nil { - t.Fatalf("%v", err) - } -} - -func testAPIGroupList(t *testing.T, serverIP string) { - serverURL := serverIP + "/apis" +func testAPIGroupList(t *testing.T, serverLocation string) { + serverURL := serverLocation + "/apis" contents, err := readResponse(serverURL) if err != nil { t.Fatalf("%v", err) } + t.Log(string(contents)) var apiGroupList metav1.APIGroupList err = json.Unmarshal(contents, &apiGroupList) if err != nil { t.Fatalf("Error in unmarshalling response from server %s: %v", serverURL, err) } assert.Equal(t, 1, len(apiGroupList.Groups)) - assert.Equal(t, apiGroupList.Groups[0].Name, groupVersion.Group) + assert.Equal(t, groupVersion.Group, apiGroupList.Groups[0].Name) assert.Equal(t, 1, len(apiGroupList.Groups[0].Versions)) - assert.Equal(t, apiGroupList.Groups[0].Versions[0], groupVersionForDiscovery) - assert.Equal(t, apiGroupList.Groups[0].PreferredVersion, groupVersionForDiscovery) + assert.Equal(t, groupVersionForDiscovery, apiGroupList.Groups[0].Versions[0]) + assert.Equal(t, groupVersionForDiscovery, apiGroupList.Groups[0].PreferredVersion) } -func testAPIGroup(t *testing.T, serverIP string) { - serverURL := serverIP + "/apis/testgroup.k8s.io" +func testAPIGroup(t *testing.T, serverLocation string) { + serverURL := serverLocation + "/apis/wardle.k8s.io" contents, err := readResponse(serverURL) if err != nil { t.Fatalf("%v", err) } + t.Log(string(contents)) var apiGroup metav1.APIGroup err = json.Unmarshal(contents, &apiGroup) if err != nil { t.Fatalf("Error in unmarshalling response from server %s: %v", serverURL, err) } - assert.Equal(t, apiGroup.APIVersion, groupVersion.Version) - assert.Equal(t, apiGroup.Name, groupVersion.Group) + assert.Equal(t, groupVersion.Group, apiGroup.Name) assert.Equal(t, 1, len(apiGroup.Versions)) - assert.Equal(t, apiGroup.Versions[0].GroupVersion, groupVersion.String()) - assert.Equal(t, apiGroup.Versions[0].Version, groupVersion.Version) - assert.Equal(t, apiGroup.Versions[0], apiGroup.PreferredVersion) + assert.Equal(t, groupVersion.String(), apiGroup.Versions[0].GroupVersion) + assert.Equal(t, groupVersion.Version, apiGroup.Versions[0].Version) + assert.Equal(t, apiGroup.PreferredVersion, apiGroup.Versions[0]) } -func testAPIResourceList(t *testing.T, serverIP string) { - serverURL := serverIP + "/apis/testgroup.k8s.io/v1" +func testAPIResourceList(t *testing.T, serverLocation string) { + serverURL := serverLocation + "/apis/wardle.k8s.io/v1alpha1" contents, err := readResponse(serverURL) if err != nil { t.Fatalf("%v", err) } + t.Log(string(contents)) var apiResourceList metav1.APIResourceList err = json.Unmarshal(contents, &apiResourceList) if err != nil { t.Fatalf("Error in unmarshalling response from server %s: %v", serverURL, err) } - assert.Equal(t, apiResourceList.APIVersion, groupVersion.Version) - assert.Equal(t, apiResourceList.GroupVersion, groupVersion.String()) + assert.Equal(t, groupVersion.String(), apiResourceList.GroupVersion) assert.Equal(t, 1, len(apiResourceList.APIResources)) - assert.Equal(t, apiResourceList.APIResources[0].Name, "testtypes") + assert.Equal(t, "flunders", apiResourceList.APIResources[0].Name) assert.True(t, apiResourceList.APIResources[0].Namespaced) } diff --git a/vendor/BUILD b/vendor/BUILD index dd3fd45ca3c..9202866e0e1 100644 --- a/vendor/BUILD +++ b/vendor/BUILD @@ -15281,3 +15281,125 @@ go_test( "//vendor:k8s.io/client-go/util/cert", ], ) + +go_binary( + name = "k8s.io/sample-apiserver_bin", + library = ":k8s.io/sample-apiserver", + tags = ["automanaged"], +) + +go_library( + name = "k8s.io/sample-apiserver", + srcs = ["k8s.io/sample-apiserver/main.go"], + tags = ["automanaged"], + deps = [ + "//vendor:k8s.io/apimachinery/pkg/util/wait", + "//vendor:k8s.io/sample-apiserver/pkg/cmd/server", + ], +) + +go_library( + name = "k8s.io/sample-apiserver/pkg/apis/wardle", + srcs = [ + "k8s.io/sample-apiserver/pkg/apis/wardle/doc.go", + "k8s.io/sample-apiserver/pkg/apis/wardle/register.go", + "k8s.io/sample-apiserver/pkg/apis/wardle/types.go", + "k8s.io/sample-apiserver/pkg/apis/wardle/zz_generated.deepcopy.go", + ], + tags = ["automanaged"], + deps = [ + "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1", + "//vendor:k8s.io/apimachinery/pkg/conversion", + "//vendor:k8s.io/apimachinery/pkg/runtime", + "//vendor:k8s.io/apimachinery/pkg/runtime/schema", + ], +) + +go_library( + name = "k8s.io/sample-apiserver/pkg/apis/wardle/install", + srcs = ["k8s.io/sample-apiserver/pkg/apis/wardle/install/install.go"], + tags = ["automanaged"], + deps = [ + "//vendor:k8s.io/apimachinery/pkg/apimachinery/announced", + "//vendor:k8s.io/apimachinery/pkg/apimachinery/registered", + "//vendor:k8s.io/apimachinery/pkg/runtime", + "//vendor:k8s.io/apimachinery/pkg/util/sets", + "//vendor:k8s.io/sample-apiserver/pkg/apis/wardle", + "//vendor:k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1", + ], +) + +go_library( + name = "k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1", + srcs = [ + "k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/doc.go", + "k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/register.go", + "k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/types.go", + "k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/zz_generated.conversion.go", + "k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1/zz_generated.deepcopy.go", + ], + tags = ["automanaged"], + deps = [ + "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1", + "//vendor:k8s.io/apimachinery/pkg/conversion", + "//vendor:k8s.io/apimachinery/pkg/runtime", + "//vendor:k8s.io/apimachinery/pkg/runtime/schema", + "//vendor:k8s.io/sample-apiserver/pkg/apis/wardle", + ], +) + +go_library( + name = "k8s.io/sample-apiserver/pkg/apiserver", + srcs = ["k8s.io/sample-apiserver/pkg/apiserver/apiserver.go"], + tags = ["automanaged"], + deps = [ + "//vendor:k8s.io/apimachinery/pkg/apimachinery/announced", + "//vendor:k8s.io/apimachinery/pkg/apimachinery/registered", + "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1", + "//vendor:k8s.io/apimachinery/pkg/runtime", + "//vendor:k8s.io/apimachinery/pkg/runtime/schema", + "//vendor:k8s.io/apimachinery/pkg/runtime/serializer", + "//vendor:k8s.io/apimachinery/pkg/version", + "//vendor:k8s.io/apiserver/pkg/registry/rest", + "//vendor:k8s.io/apiserver/pkg/server", + "//vendor:k8s.io/sample-apiserver/pkg/apis/wardle", + "//vendor:k8s.io/sample-apiserver/pkg/apis/wardle/install", + "//vendor:k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1", + "//vendor:k8s.io/sample-apiserver/pkg/registry/wardle", + ], +) + +go_library( + name = "k8s.io/sample-apiserver/pkg/cmd/server", + srcs = ["k8s.io/sample-apiserver/pkg/cmd/server/start.go"], + tags = ["automanaged"], + deps = [ + "//vendor:github.com/pborman/uuid", + "//vendor:github.com/spf13/cobra", + "//vendor:k8s.io/apiserver/pkg/server", + "//vendor:k8s.io/apiserver/pkg/server/options", + "//vendor:k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1", + "//vendor:k8s.io/sample-apiserver/pkg/apiserver", + ], +) + +go_library( + name = "k8s.io/sample-apiserver/pkg/registry/wardle", + srcs = [ + "k8s.io/sample-apiserver/pkg/registry/wardle/etcd.go", + "k8s.io/sample-apiserver/pkg/registry/wardle/strategy.go", + ], + tags = ["automanaged"], + deps = [ + "//vendor:k8s.io/apimachinery/pkg/fields", + "//vendor:k8s.io/apimachinery/pkg/labels", + "//vendor:k8s.io/apimachinery/pkg/runtime", + "//vendor:k8s.io/apimachinery/pkg/util/validation/field", + "//vendor:k8s.io/apiserver/pkg/endpoints/request", + "//vendor:k8s.io/apiserver/pkg/registry/generic", + "//vendor:k8s.io/apiserver/pkg/registry/generic/registry", + "//vendor:k8s.io/apiserver/pkg/storage", + "//vendor:k8s.io/apiserver/pkg/storage/names", + "//vendor:k8s.io/sample-apiserver/pkg/apis/wardle", + ], +) diff --git a/vendor/k8s.io/sample-apiserver b/vendor/k8s.io/sample-apiserver new file mode 120000 index 00000000000..23b10fee7a1 --- /dev/null +++ b/vendor/k8s.io/sample-apiserver @@ -0,0 +1 @@ +../../staging/src/k8s.io/sample-apiserver \ No newline at end of file