diff --git a/vendor/github.com/alena1108/cluster-controller/.dockerignore b/vendor/github.com/alena1108/cluster-controller/.dockerignore new file mode 100644 index 00000000..6e43c2a9 --- /dev/null +++ b/vendor/github.com/alena1108/cluster-controller/.dockerignore @@ -0,0 +1,4 @@ +./bin +./.dapper +./dist +./.trash-cache diff --git a/vendor/github.com/alena1108/cluster-controller/.drone.yml b/vendor/github.com/alena1108/cluster-controller/.drone.yml new file mode 100644 index 00000000..8f5c37cd --- /dev/null +++ b/vendor/github.com/alena1108/cluster-controller/.drone.yml @@ -0,0 +1,9 @@ +--- +pipeline: + build: + privileged: true + image: rancher/dapper:1.11.2 + volumes: + - /var/run/docker.sock:/var/run/docker.sock + commands: + - dapper ci diff --git a/vendor/github.com/alena1108/cluster-controller/.gitignore b/vendor/github.com/alena1108/cluster-controller/.gitignore new file mode 100644 index 00000000..9e8d97d2 --- /dev/null +++ b/vendor/github.com/alena1108/cluster-controller/.gitignore @@ -0,0 +1,6 @@ +/.dapper +/bin +/dist +*.swp +/.trash-cache +cluster-controller diff --git a/vendor/github.com/alena1108/cluster-controller/Dockerfile.dapper b/vendor/github.com/alena1108/cluster-controller/Dockerfile.dapper new file mode 100644 index 00000000..b7ad8e2b --- /dev/null +++ b/vendor/github.com/alena1108/cluster-controller/Dockerfile.dapper @@ -0,0 +1,31 @@ +FROM ubuntu:16.04 +# FROM arm=armhf/ubuntu:16.04 + +ARG DAPPER_HOST_ARCH +ENV HOST_ARCH=${DAPPER_HOST_ARCH} ARCH=${DAPPER_HOST_ARCH} + +RUN apt-get update && \ + apt-get install -y gcc ca-certificates git wget curl vim less file && \ + rm -f /bin/sh && ln -s /bin/bash /bin/sh + +ENV GOLANG_ARCH_amd64=amd64 GOLANG_ARCH_arm=armv6l GOLANG_ARCH=GOLANG_ARCH_${ARCH} \ + GOPATH=/go PATH=/go/bin:/usr/local/go/bin:${PATH} SHELL=/bin/bash + +RUN wget -O - https://storage.googleapis.com/golang/go1.8.3.linux-${!GOLANG_ARCH}.tar.gz | tar -xzf - -C /usr/local && \ + go get github.com/rancher/trash && go get github.com/golang/lint/golint + +ENV DOCKER_URL_amd64=https://get.docker.com/builds/Linux/x86_64/docker-1.10.3 \ + DOCKER_URL_arm=https://github.com/rancher/docker/releases/download/v1.10.3-ros1/docker-1.10.3_arm \ + DOCKER_URL=DOCKER_URL_${ARCH} + +RUN wget -O - ${!DOCKER_URL} > /usr/bin/docker && chmod +x /usr/bin/docker + +ENV DAPPER_SOURCE /go/src/github.com/rancher/cluster-controller/ +ENV DAPPER_OUTPUT ./bin ./dist +ENV DAPPER_DOCKER_SOCKET true +ENV TRASH_CACHE ${DAPPER_SOURCE}/.trash-cache +ENV HOME ${DAPPER_SOURCE} +WORKDIR ${DAPPER_SOURCE} + +ENTRYPOINT ["./scripts/entry"] +CMD ["ci"] diff --git a/vendor/github.com/alena1108/cluster-controller/LICENSE b/vendor/github.com/alena1108/cluster-controller/LICENSE new file mode 100644 index 00000000..f433b1a5 --- /dev/null +++ b/vendor/github.com/alena1108/cluster-controller/LICENSE @@ -0,0 +1,177 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS diff --git a/vendor/github.com/alena1108/cluster-controller/Makefile b/vendor/github.com/alena1108/cluster-controller/Makefile new file mode 100644 index 00000000..d7d72a16 --- /dev/null +++ b/vendor/github.com/alena1108/cluster-controller/Makefile @@ -0,0 +1,23 @@ +TARGETS := $(shell ls scripts) + +.dapper: + @echo Downloading dapper + @curl -sL https://releases.rancher.com/dapper/latest/dapper-`uname -s`-`uname -m` > .dapper.tmp + @@chmod +x .dapper.tmp + @./.dapper.tmp -v + @mv .dapper.tmp .dapper + +$(TARGETS): .dapper + ./.dapper $@ + +trash: .dapper + ./.dapper -m bind trash + +trash-keep: .dapper + ./.dapper -m bind trash -k + +deps: trash + +.DEFAULT_GOAL := ci + +.PHONY: $(TARGETS) diff --git a/vendor/github.com/alena1108/cluster-controller/README.md b/vendor/github.com/alena1108/cluster-controller/README.md new file mode 100644 index 00000000..acf4aa78 --- /dev/null +++ b/vendor/github.com/alena1108/cluster-controller/README.md @@ -0,0 +1,28 @@ +cluster-controller +======== + +A microservice that does micro things. + +## Building + +`make` + + +## Running + +`./bin/cluster-controller` + +## License +Copyright (c) 2014-2017 [Rancher Labs, Inc.](http://rancher.com) + +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](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. diff --git a/vendor/github.com/alena1108/cluster-controller/client/v1/client.go b/vendor/github.com/alena1108/cluster-controller/client/v1/client.go new file mode 100644 index 00000000..726f5bed --- /dev/null +++ b/vendor/github.com/alena1108/cluster-controller/client/v1/client.go @@ -0,0 +1,63 @@ +package v1 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/pkg/api" + "k8s.io/client-go/rest" +) + +const ( + Group = "rancher.com" +) + +var Version = "v1" + +type ClustersManagerV1Interface interface { + RESTClient() rest.Interface + ClustersGetter +} + +type ClustersManagerV1Client struct { + restClient rest.Interface + dynamicClient *dynamic.Client +} + +func (c *ClustersManagerV1Client) Clusters() ClusterInterface { + return newClusters(c.restClient, c.dynamicClient) +} + +func (c *ClustersManagerV1Client) ClusterNodes() ClusterNodeInterface { + return newClusterNodes(c.restClient, c.dynamicClient) +} + +func (c *ClustersManagerV1Client) RESTClient() rest.Interface { + return c.restClient +} + +func NewForConfig(c *rest.Config) (*ClustersManagerV1Client, error) { + config := *c + SetConfigDefaults(&config) + client, err := rest.RESTClientFor(&config) + if err != nil { + return nil, err + } + + dynamicClient, err := dynamic.NewClient(&config) + if err != nil { + return nil, err + } + + return &ClustersManagerV1Client{client, dynamicClient}, nil +} + +func SetConfigDefaults(config *rest.Config) { + config.GroupVersion = &schema.GroupVersion{ + Group: Group, + Version: Version, + } + config.APIPath = "/apis" + config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: api.Codecs} + return +} diff --git a/vendor/github.com/alena1108/cluster-controller/client/v1/cluster.go b/vendor/github.com/alena1108/cluster-controller/client/v1/cluster.go new file mode 100644 index 00000000..61016611 --- /dev/null +++ b/vendor/github.com/alena1108/cluster-controller/client/v1/cluster.go @@ -0,0 +1,184 @@ +package v1 + +import ( + "encoding/json" + + "github.com/pkg/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/rest" +) + +const ( + ClustersKind = "Cluster" + ClustersName = "clusters" + ClustersSingularName = "cluster" +) + +type ClustersGetter interface { + Clusters(namespace string) ClusterInterface +} + +var _ ClusterInterface = &clusters{} + +type ClusterInterface interface { + Create(*Cluster) (*Cluster, error) + Get(name string, opts metav1.GetOptions) (*Cluster, error) + Update(*Cluster) (*Cluster, error) + Delete(name string, options *metav1.DeleteOptions) error + List(opts metav1.ListOptions) (runtime.Object, error) + Watch(opts metav1.ListOptions) (watch.Interface, error) + DeleteCollection(dopts *metav1.DeleteOptions, lopts metav1.ListOptions) error +} + +type clusters struct { + restClient rest.Interface + client *dynamic.ResourceClient + ns string +} + +func newClusters(r rest.Interface, c *dynamic.Client) *clusters { + return &clusters{ + r, + c.Resource( + &metav1.APIResource{ + Kind: ClustersKind, + Name: ClustersName, + Namespaced: false, + }, + "", + ), + "", + } +} + +func (p *clusters) Create(o *Cluster) (*Cluster, error) { + up, err := UnstructuredFromCluster(o) + if err != nil { + return nil, err + } + + up, err = p.client.Create(up) + if err != nil { + return nil, err + } + + return ClusterFromUnstructured(up) +} + +func (p *clusters) Get(name string, opts metav1.GetOptions) (*Cluster, error) { + obj, err := p.client.Get(name, opts) + if err != nil { + return nil, err + } + return ClusterFromUnstructured(obj) +} + +func (p *clusters) Update(o *Cluster) (*Cluster, error) { + up, err := UnstructuredFromCluster(o) + if err != nil { + return nil, err + } + + curp, err := p.Get(o.Name, metav1.GetOptions{}) + if err != nil { + return nil, errors.Wrap(err, "unable to get current version for update") + } + up.SetResourceVersion(curp.ObjectMeta.ResourceVersion) + + up, err = p.client.Update(up) + if err != nil { + return nil, err + } + + return ClusterFromUnstructured(up) +} + +func (p *clusters) Delete(name string, options *metav1.DeleteOptions) error { + return p.client.Delete(name, options) +} + +func (p *clusters) List(opts metav1.ListOptions) (runtime.Object, error) { + req := p.restClient.Get(). + Namespace(p.ns). + Resource(ClustersName). + FieldsSelectorParam(nil) + + b, err := req.DoRaw() + if err != nil { + return nil, err + } + var prom ClusterList + return &prom, json.Unmarshal(b, &prom) +} + +func (p *clusters) Watch(opts metav1.ListOptions) (watch.Interface, error) { + r, err := p.restClient.Get(). + Prefix("watch"). + Namespace(p.ns). + Resource(ClustersName). + FieldsSelectorParam(nil). + Stream() + if err != nil { + return nil, err + } + return watch.NewStreamWatcher(&clusterDecoder{ + dec: json.NewDecoder(r), + close: r.Close, + }), nil +} + +func (p *clusters) DeleteCollection(dopts *metav1.DeleteOptions, lopts metav1.ListOptions) error { + return p.client.DeleteCollection(dopts, lopts) +} + +func ClusterFromUnstructured(r *unstructured.Unstructured) (*Cluster, error) { + b, err := json.Marshal(r.Object) + if err != nil { + return nil, err + } + var p Cluster + if err := json.Unmarshal(b, &p); err != nil { + return nil, err + } + p.TypeMeta.Kind = ClustersKind + p.TypeMeta.APIVersion = Group + "/" + Version + return &p, nil +} + +func UnstructuredFromCluster(p *Cluster) (*unstructured.Unstructured, error) { + p.TypeMeta.Kind = ClustersKind + p.TypeMeta.APIVersion = Group + "/" + Version + b, err := json.Marshal(p) + if err != nil { + return nil, err + } + var r unstructured.Unstructured + if err := json.Unmarshal(b, &r.Object); err != nil { + return nil, err + } + return &r, nil +} + +type clusterDecoder struct { + dec *json.Decoder + close func() error +} + +func (d *clusterDecoder) Close() { + d.close() +} + +func (d *clusterDecoder) Decode() (action watch.EventType, object runtime.Object, err error) { + var e struct { + Type watch.EventType + Object Cluster + } + if err := d.dec.Decode(&e); err != nil { + return watch.Error, nil, err + } + return e.Type, &e.Object, nil +} diff --git a/vendor/github.com/alena1108/cluster-controller/client/v1/clusternode.go b/vendor/github.com/alena1108/cluster-controller/client/v1/clusternode.go new file mode 100644 index 00000000..5f33cd6e --- /dev/null +++ b/vendor/github.com/alena1108/cluster-controller/client/v1/clusternode.go @@ -0,0 +1,184 @@ +package v1 + +import ( + "encoding/json" + + "github.com/pkg/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/rest" +) + +const ( + ClusterNodesKind = "ClusterNode" + ClusterNodesName = "clusternodes" + ClusterNodesSingularName = "clusternode" +) + +type ClusterNodesGetter interface { + ClusterNodes(namespace string) ClusterNodeInterface +} + +var _ ClusterNodeInterface = &clusternodes{} + +type ClusterNodeInterface interface { + Create(*ClusterNode) (*ClusterNode, error) + Get(name string, opts metav1.GetOptions) (*ClusterNode, error) + Update(*ClusterNode) (*ClusterNode, error) + Delete(name string, options *metav1.DeleteOptions) error + List(opts metav1.ListOptions) (runtime.Object, error) + Watch(opts metav1.ListOptions) (watch.Interface, error) + DeleteCollection(dopts *metav1.DeleteOptions, lopts metav1.ListOptions) error +} + +type clusternodes struct { + restClient rest.Interface + client *dynamic.ResourceClient + ns string +} + +func newClusterNodes(r rest.Interface, c *dynamic.Client) *clusternodes { + return &clusternodes{ + r, + c.Resource( + &metav1.APIResource{ + Kind: ClusterNodesKind, + Name: ClusterNodesName, + Namespaced: false, + }, + "", + ), + "", + } +} + +func (p *clusternodes) Create(o *ClusterNode) (*ClusterNode, error) { + up, err := UnstructuredFromClusterNode(o) + if err != nil { + return nil, err + } + + up, err = p.client.Create(up) + if err != nil { + return nil, err + } + + return ClusterNodeFromUnstructured(up) +} + +func (p *clusternodes) Get(name string, opts metav1.GetOptions) (*ClusterNode, error) { + obj, err := p.client.Get(name, opts) + if err != nil { + return nil, err + } + return ClusterNodeFromUnstructured(obj) +} + +func (p *clusternodes) Update(o *ClusterNode) (*ClusterNode, error) { + up, err := UnstructuredFromClusterNode(o) + if err != nil { + return nil, err + } + + curp, err := p.Get(o.Name, metav1.GetOptions{}) + if err != nil { + return nil, errors.Wrap(err, "unable to get current version for update") + } + up.SetResourceVersion(curp.ObjectMeta.ResourceVersion) + + up, err = p.client.Update(up) + if err != nil { + return nil, err + } + + return ClusterNodeFromUnstructured(up) +} + +func (p *clusternodes) Delete(name string, options *metav1.DeleteOptions) error { + return p.client.Delete(name, options) +} + +func (p *clusternodes) List(opts metav1.ListOptions) (runtime.Object, error) { + req := p.restClient.Get(). + Namespace(p.ns). + Resource(ClusterNodesName). + FieldsSelectorParam(nil) + + b, err := req.DoRaw() + if err != nil { + return nil, err + } + var prom ClusterNodeList + return &prom, json.Unmarshal(b, &prom) +} + +func (p *clusternodes) Watch(opts metav1.ListOptions) (watch.Interface, error) { + r, err := p.restClient.Get(). + Prefix("watch"). + Namespace(p.ns). + Resource(ClusterNodesName). + FieldsSelectorParam(nil). + Stream() + if err != nil { + return nil, err + } + return watch.NewStreamWatcher(&clusterDecoder{ + dec: json.NewDecoder(r), + close: r.Close, + }), nil +} + +func (p *clusternodes) DeleteCollection(dopts *metav1.DeleteOptions, lopts metav1.ListOptions) error { + return p.client.DeleteCollection(dopts, lopts) +} + +func ClusterNodeFromUnstructured(r *unstructured.Unstructured) (*ClusterNode, error) { + b, err := json.Marshal(r.Object) + if err != nil { + return nil, err + } + var p ClusterNode + if err := json.Unmarshal(b, &p); err != nil { + return nil, err + } + p.TypeMeta.Kind = ClusterNodesKind + p.TypeMeta.APIVersion = Group + "/" + Version + return &p, nil +} + +func UnstructuredFromClusterNode(p *ClusterNode) (*unstructured.Unstructured, error) { + p.TypeMeta.Kind = ClusterNodesKind + p.TypeMeta.APIVersion = Group + "/" + Version + b, err := json.Marshal(p) + if err != nil { + return nil, err + } + var r unstructured.Unstructured + if err := json.Unmarshal(b, &r.Object); err != nil { + return nil, err + } + return &r, nil +} + +type clusterNodeDecoder struct { + dec *json.Decoder + close func() error +} + +func (d *clusterNodeDecoder) Close() { + d.close() +} + +func (d *clusterNodeDecoder) Decode() (action watch.EventType, object runtime.Object, err error) { + var e struct { + Type watch.EventType + Object ClusterNode + } + if err := d.dec.Decode(&e); err != nil { + return watch.Error, nil, err + } + return e.Type, &e.Object, nil +} diff --git a/vendor/github.com/alena1108/cluster-controller/client/v1/types.go b/vendor/github.com/alena1108/cluster-controller/client/v1/types.go new file mode 100644 index 00000000..df5e7dd4 --- /dev/null +++ b/vendor/github.com/alena1108/cluster-controller/client/v1/types.go @@ -0,0 +1,216 @@ +package v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/pkg/api/v1" +) + +type ClusterConditionType string + +const ( + // ClusterConditionReady Cluster ready to serve API (healthy when true, unehalthy when false) + ClusterConditionReady = "Ready" + // ClusterConditionProvisioned Cluster is provisioned + ClusterConditionProvisioned = "Provisioned" + // ClusterConditionUpdating Cluster is being updating (upgrading, scaling up) + ClusterConditionUpdating = "Updating" + // More conditions can be added if unredlying controllers request it +) + +type Cluster struct { + metav1.TypeMeta `json:",inline"` + // Standard object’s metadata. More info: + // https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md#metadata + metav1.ObjectMeta `json:"metadata,omitempty"` + // Specification of the desired behavior of the the cluster. More info: + // https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md#spec-and-status + Spec ClusterSpec `json:"spec"` + // Most recent observed status of the cluster. More info: + // https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md#spec-and-status + Status *ClusterStatus `json:"status"` +} + +type ClusterList struct { + metav1.TypeMeta `json:",inline"` + // Standard list metadata + // More info: https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md#metadata + metav1.ListMeta `json:"metadata,omitempty"` + // List of Clusters + Items []*Cluster `json:"items"` +} + +type ClusterSpec struct { + GKEConfig *GKEConfig + AKSConfig *AKSConfig + RKEConfig *RKEConfig +} + +type ClusterStatus struct { + //Conditions represent the latest available observations of an object's current state: + //More info: https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md#typical-status-properties + Conditions []ClusterCondition `json:"conditions,omitempty"` + //Component statuses will represent cluster's components (etcd/controller/scheduler) health + // https://kubernetes.io/docs/api-reference/v1.8/#componentstatus-v1-core + ComponentStatuses v1.ComponentStatusList + APIEndpoint string + ServiceAccountToken string + CACert string +} + +type ClusterCondition struct { + // Type of cluster condition. + Type ClusterConditionType `json:"type"` + // Status of the condition, one of True, False, Unknown. + Status v1.ConditionStatus `json:"status"` + // The last time this condition was updated. + LastUpdateTime string `json:"lastUpdateTime,omitempty"` + // Last time the condition transitioned from one status to another. + LastTransitionTime string `json:"lastTransitionTime,omitempty"` + // The reason for the condition's last transition. + Reason string `json:"reason,omitempty"` +} + +type GKEConfig struct { + // ProjectID is the ID of your project to use when creating a cluster + ProjectID string + // The zone to launch the cluster + Zone string + // The IP address range of the container pods + ClusterIpv4Cidr string + // An optional description of this cluster + Description string + // The number of nodes to create in this cluster + InitialNodeCount int64 + // Size of the disk attached to each node + DiskSizeGb int64 + // The name of a Google Compute Engine + MachineType string + // the initial kubernetes version + InitialClusterVersion string + // The map of Kubernetes labels (key/value pairs) to be applied + // to each node. + Labels map[string]string + // The path to the credential file(key.json) + CredentialPath string + // Enable alpha feature + EnableAlphaFeature bool + // NodePool id + NodePoolID string + + // Update Config + UpdateConfig gkeUpdateConfig +} + +type gkeUpdateConfig struct { + // the number of node + NodeCount int64 + // Master kubernetes version + MasterVersion string + // Node kubernetes version + NodeVersion string +} + +type AKSConfig struct { + //TBD +} + +type RKEConfig struct { + // Kubernetes nodes + Hosts []RKEConfigHost `yaml:"hosts"` + // Kubernetes components + Services RKEConfigServices `yaml:"services"` + // Network plugin used in the kubernetes cluster (flannel, calico) + NetworkPlugin string `yaml:"network_plugin"` + // Authentication type used in the cluster (default: x509) + AuthType string `yaml:"auth_type"` +} + +type RKEConfigHost struct { + // SSH IP address of the host + IP string `yaml:"ip"` + // Advertised address that will be used for components communication + AdvertiseAddress string `yaml:"advertise_address"` + // Host role in kubernetes cluster (controlplane, worker, or etcd) + Role []string `yaml:"role"` + // Hostname of the host + Hostname string `yaml:"hostname"` + // SSH usesr that will be used by RKE + User string `yaml:"user"` + // Docker socket on the host that will be used in tunneling + DockerSocket string `yaml:"docker_socket"` +} + +type RKEConfigServices struct { + // Etcd Service + Etcd ETCDService `yaml:"etcd"` + // KubeAPI Service + KubeAPI KubeAPIService `yaml:"kube-api"` + // KubeController Service + KubeController KubeControllerService `yaml:"kube-controller"` + // Scheduler Service + Scheduler SchedulerService `yaml:"scheduler"` + // Kubelet Service + Kubelet KubeletService `yaml:"kubelet"` + // KubeProxy Service + Kubeproxy KubeproxyService `yaml:"kubeproxy"` +} + +type ETCDService struct { + // Base service properties + baseService `yaml:",inline"` +} + +type KubeAPIService struct { + // Base service properties + baseService `yaml:",inline"` + // Virtual IP range that will be used by Kubernetes services + ServiceClusterIPRange string `yaml:"service_cluster_ip_range"` +} + +type KubeControllerService struct { + // Base service properties + baseService `yaml:",inline"` + // CIDR Range for Pods in cluster + ClusterCIDR string `yaml:"cluster_cidr"` + // Virtual IP range that will be used by Kubernetes services + ServiceClusterIPRange string `yaml:"service_cluster_ip_range"` +} + +type KubeletService struct { + // Base service properties + baseService `yaml:",inline"` + // Domain of the cluster (default: "cluster.local") + ClusterDomain string `yaml:"cluster_domain"` + // The image whose network/ipc namespaces containers in each pod will use + InfraContainerImage string `yaml:"infra_container_image"` + // Cluster DNS service ip + ClusterDNSServer string `yaml:"cluster_dns_server"` +} + +type KubeproxyService struct { + // Base service properties + baseService `yaml:",inline"` +} + +type SchedulerService struct { + // Base service properties + baseService `yaml:",inline"` +} + +type baseService struct { + // Docker image of the service + Image string `yaml:"image"` +} + +type ClusterNode struct { + v1.Node +} + +type ClusterNodeList struct { + metav1.TypeMeta `json:",inline"` + // Standard list metadata + // More info: https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md#metadata + metav1.ListMeta `json:"metadata,omitempty"` + // List of Clusters + Items []*Cluster `json:"items"` +} diff --git a/vendor/github.com/alena1108/cluster-controller/vendor.conf b/vendor/github.com/alena1108/cluster-controller/vendor.conf new file mode 100644 index 00000000..4ef86ebf --- /dev/null +++ b/vendor/github.com/alena1108/cluster-controller/vendor.conf @@ -0,0 +1,10 @@ +# package +github.com/rancher/cluster-controller + +github.com/Sirupsen/logrus v0.10.0 +github.com/urfave/cli v1.18.0 +k8s.io/client-go v4.0.0 transitive=true +github.com/pkg/errors v0.8.0 +github.com/urfave/cli v1.19.1 +golang.org/x/sync/errgroup 450f422ab23cf9881c94e2db30cac0eb1b7cf80c + diff --git a/vendor/k8s.io/client-go/dynamic/BUILD b/vendor/k8s.io/client-go/dynamic/BUILD new file mode 100644 index 00000000..e0320e26 --- /dev/null +++ b/vendor/k8s.io/client-go/dynamic/BUILD @@ -0,0 +1,55 @@ +package(default_visibility = ["//visibility:public"]) + +licenses(["notice"]) + +load( + "@io_bazel_rules_go//go:def.bzl", + "go_library", + "go_test", +) + +go_test( + name = "go_default_test", + srcs = [ + "client_test.go", + "dynamic_util_test.go", + ], + library = ":go_default_library", + tags = ["automanaged"], + deps = [ + "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/runtime/serializer/streaming:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/types:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/watch:go_default_library", + "//vendor/k8s.io/client-go/rest:go_default_library", + "//vendor/k8s.io/client-go/rest/watch:go_default_library", + ], +) + +go_library( + name = "go_default_library", + srcs = [ + "client.go", + "client_pool.go", + "dynamic_util.go", + ], + tags = ["automanaged"], + deps = [ + "//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/conversion/queryparams:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/types:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/watch:go_default_library", + "//vendor/k8s.io/client-go/kubernetes/scheme:go_default_library", + "//vendor/k8s.io/client-go/pkg/api/v1:go_default_library", + "//vendor/k8s.io/client-go/rest:go_default_library", + "//vendor/k8s.io/client-go/util/flowcontrol:go_default_library", + ], +) diff --git a/vendor/k8s.io/client-go/dynamic/client.go b/vendor/k8s.io/client-go/dynamic/client.go new file mode 100644 index 00000000..a0c18209 --- /dev/null +++ b/vendor/k8s.io/client-go/dynamic/client.go @@ -0,0 +1,306 @@ +/* +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 dynamic provides a client interface to arbitrary Kubernetes +// APIs that exposes common high level operations and exposes common +// metadata. +package dynamic + +import ( + "encoding/json" + "errors" + "io" + "net/url" + "strings" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/conversion/queryparams" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/pkg/api/v1" + restclient "k8s.io/client-go/rest" + "k8s.io/client-go/util/flowcontrol" +) + +// Client is a Kubernetes client that allows you to access metadata +// and manipulate metadata of a Kubernetes API group. +type Client struct { + cl *restclient.RESTClient + parameterCodec runtime.ParameterCodec +} + +// NewClient returns a new client based on the passed in config. The +// codec is ignored, as the dynamic client uses it's own codec. +func NewClient(conf *restclient.Config) (*Client, error) { + // avoid changing the original config + confCopy := *conf + conf = &confCopy + + contentConfig := ContentConfig() + contentConfig.GroupVersion = conf.GroupVersion + if conf.NegotiatedSerializer != nil { + contentConfig.NegotiatedSerializer = conf.NegotiatedSerializer + } + conf.ContentConfig = contentConfig + + if conf.APIPath == "" { + conf.APIPath = "/api" + } + + if len(conf.UserAgent) == 0 { + conf.UserAgent = restclient.DefaultKubernetesUserAgent() + } + + cl, err := restclient.RESTClientFor(conf) + if err != nil { + return nil, err + } + + return &Client{cl: cl}, nil +} + +// GetRateLimiter returns rate limier. +func (c *Client) GetRateLimiter() flowcontrol.RateLimiter { + return c.cl.GetRateLimiter() +} + +// Resource returns an API interface to the specified resource for this client's +// group and version. If resource is not a namespaced resource, then namespace +// is ignored. The ResourceClient inherits the parameter codec of c. +func (c *Client) Resource(resource *metav1.APIResource, namespace string) *ResourceClient { + return &ResourceClient{ + cl: c.cl, + resource: resource, + ns: namespace, + parameterCodec: c.parameterCodec, + } +} + +// ParameterCodec returns a client with the provided parameter codec. +func (c *Client) ParameterCodec(parameterCodec runtime.ParameterCodec) *Client { + return &Client{ + cl: c.cl, + parameterCodec: parameterCodec, + } +} + +// ResourceClient is an API interface to a specific resource under a +// dynamic client. +type ResourceClient struct { + cl *restclient.RESTClient + resource *metav1.APIResource + ns string + parameterCodec runtime.ParameterCodec +} + +// List returns a list of objects for this resource. +func (rc *ResourceClient) List(opts metav1.ListOptions) (runtime.Object, error) { + parameterEncoder := rc.parameterCodec + if parameterEncoder == nil { + parameterEncoder = defaultParameterEncoder + } + return rc.cl.Get(). + NamespaceIfScoped(rc.ns, rc.resource.Namespaced). + Resource(rc.resource.Name). + VersionedParams(&opts, parameterEncoder). + Do(). + Get() +} + +// Get gets the resource with the specified name. +func (rc *ResourceClient) Get(name string, opts metav1.GetOptions) (*unstructured.Unstructured, error) { + parameterEncoder := rc.parameterCodec + if parameterEncoder == nil { + parameterEncoder = defaultParameterEncoder + } + result := new(unstructured.Unstructured) + err := rc.cl.Get(). + NamespaceIfScoped(rc.ns, rc.resource.Namespaced). + Resource(rc.resource.Name). + VersionedParams(&opts, parameterEncoder). + Name(name). + Do(). + Into(result) + return result, err +} + +// Delete deletes the resource with the specified name. +func (rc *ResourceClient) Delete(name string, opts *metav1.DeleteOptions) error { + return rc.cl.Delete(). + NamespaceIfScoped(rc.ns, rc.resource.Namespaced). + Resource(rc.resource.Name). + Name(name). + Body(opts). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (rc *ResourceClient) DeleteCollection(deleteOptions *metav1.DeleteOptions, listOptions metav1.ListOptions) error { + parameterEncoder := rc.parameterCodec + if parameterEncoder == nil { + parameterEncoder = defaultParameterEncoder + } + return rc.cl.Delete(). + NamespaceIfScoped(rc.ns, rc.resource.Namespaced). + Resource(rc.resource.Name). + VersionedParams(&listOptions, parameterEncoder). + Body(deleteOptions). + Do(). + Error() +} + +// Create creates the provided resource. +func (rc *ResourceClient) Create(obj *unstructured.Unstructured) (*unstructured.Unstructured, error) { + result := new(unstructured.Unstructured) + err := rc.cl.Post(). + NamespaceIfScoped(rc.ns, rc.resource.Namespaced). + Resource(rc.resource.Name). + Body(obj). + Do(). + Into(result) + return result, err +} + +// Update updates the provided resource. +func (rc *ResourceClient) Update(obj *unstructured.Unstructured) (*unstructured.Unstructured, error) { + result := new(unstructured.Unstructured) + if len(obj.GetName()) == 0 { + return result, errors.New("object missing name") + } + err := rc.cl.Put(). + NamespaceIfScoped(rc.ns, rc.resource.Namespaced). + Resource(rc.resource.Name). + Name(obj.GetName()). + Body(obj). + Do(). + Into(result) + return result, err +} + +// Watch returns a watch.Interface that watches the resource. +func (rc *ResourceClient) Watch(opts metav1.ListOptions) (watch.Interface, error) { + parameterEncoder := rc.parameterCodec + if parameterEncoder == nil { + parameterEncoder = defaultParameterEncoder + } + opts.Watch = true + return rc.cl.Get(). + NamespaceIfScoped(rc.ns, rc.resource.Namespaced). + Resource(rc.resource.Name). + VersionedParams(&opts, parameterEncoder). + Watch() +} + +func (rc *ResourceClient) Patch(name string, pt types.PatchType, data []byte) (*unstructured.Unstructured, error) { + result := new(unstructured.Unstructured) + err := rc.cl.Patch(pt). + NamespaceIfScoped(rc.ns, rc.resource.Namespaced). + Resource(rc.resource.Name). + Name(name). + Body(data). + Do(). + Into(result) + return result, err +} + +// dynamicCodec is a codec that wraps the standard unstructured codec +// with special handling for Status objects. +type dynamicCodec struct{} + +func (dynamicCodec) Decode(data []byte, gvk *schema.GroupVersionKind, obj runtime.Object) (runtime.Object, *schema.GroupVersionKind, error) { + obj, gvk, err := unstructured.UnstructuredJSONScheme.Decode(data, gvk, obj) + if err != nil { + return nil, nil, err + } + + if _, ok := obj.(*metav1.Status); !ok && strings.ToLower(gvk.Kind) == "status" { + obj = &metav1.Status{} + err := json.Unmarshal(data, obj) + if err != nil { + return nil, nil, err + } + } + + return obj, gvk, nil +} + +func (dynamicCodec) Encode(obj runtime.Object, w io.Writer) error { + return unstructured.UnstructuredJSONScheme.Encode(obj, w) +} + +// ContentConfig returns a restclient.ContentConfig for dynamic types. +func ContentConfig() restclient.ContentConfig { + var jsonInfo runtime.SerializerInfo + // TODO: scheme.Codecs here should become "pkg/apis/server/scheme" which is the minimal core you need + // to talk to a kubernetes server + for _, info := range scheme.Codecs.SupportedMediaTypes() { + if info.MediaType == runtime.ContentTypeJSON { + jsonInfo = info + break + } + } + + jsonInfo.Serializer = dynamicCodec{} + jsonInfo.PrettySerializer = nil + return restclient.ContentConfig{ + AcceptContentTypes: runtime.ContentTypeJSON, + ContentType: runtime.ContentTypeJSON, + NegotiatedSerializer: serializer.NegotiatedSerializerWrapper(jsonInfo), + } +} + +// paramaterCodec is a codec converts an API object to query +// parameters without trying to convert to the target version. +type parameterCodec struct{} + +func (parameterCodec) EncodeParameters(obj runtime.Object, to schema.GroupVersion) (url.Values, error) { + return queryparams.Convert(obj) +} + +func (parameterCodec) DecodeParameters(parameters url.Values, from schema.GroupVersion, into runtime.Object) error { + return errors.New("DecodeParameters not implemented on dynamic parameterCodec") +} + +var defaultParameterEncoder runtime.ParameterCodec = parameterCodec{} + +type versionedParameterEncoderWithV1Fallback struct{} + +func (versionedParameterEncoderWithV1Fallback) EncodeParameters(obj runtime.Object, to schema.GroupVersion) (url.Values, error) { + ret, err := scheme.ParameterCodec.EncodeParameters(obj, to) + if err != nil && runtime.IsNotRegisteredError(err) { + // fallback to v1 + return scheme.ParameterCodec.EncodeParameters(obj, v1.SchemeGroupVersion) + } + return ret, err +} + +func (versionedParameterEncoderWithV1Fallback) DecodeParameters(parameters url.Values, from schema.GroupVersion, into runtime.Object) error { + return errors.New("DecodeParameters not implemented on versionedParameterEncoderWithV1Fallback") +} + +// VersionedParameterEncoderWithV1Fallback is useful for encoding query +// parameters for thirdparty resources. It tries to convert object to the +// specified version before converting it to query parameters, and falls back to +// converting to v1 if the object is not registered in the specified version. +// For the record, currently API server always treats query parameters sent to a +// thirdparty resource endpoint as v1. +var VersionedParameterEncoderWithV1Fallback runtime.ParameterCodec = versionedParameterEncoderWithV1Fallback{} diff --git a/vendor/k8s.io/client-go/dynamic/client_pool.go b/vendor/k8s.io/client-go/dynamic/client_pool.go new file mode 100644 index 00000000..f4f2596a --- /dev/null +++ b/vendor/k8s.io/client-go/dynamic/client_pool.go @@ -0,0 +1,122 @@ +/* +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 dynamic + +import ( + "sync" + + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/runtime/schema" + restclient "k8s.io/client-go/rest" +) + +// ClientPool manages a pool of dynamic clients. +type ClientPool interface { + // ClientForGroupVersionKind returns a client configured for the specified groupVersionResource. + // Resource may be empty. + ClientForGroupVersionResource(resource schema.GroupVersionResource) (*Client, error) + // ClientForGroupVersionKind returns a client configured for the specified groupVersionKind. + // Kind may be empty. + ClientForGroupVersionKind(kind schema.GroupVersionKind) (*Client, error) +} + +// APIPathResolverFunc knows how to convert a groupVersion to its API path. The Kind field is +// optional. +type APIPathResolverFunc func(kind schema.GroupVersionKind) string + +// LegacyAPIPathResolverFunc can resolve paths properly with the legacy API. +func LegacyAPIPathResolverFunc(kind schema.GroupVersionKind) string { + if len(kind.Group) == 0 { + return "/api" + } + return "/apis" +} + +// clientPoolImpl implements ClientPool and caches clients for the resource group versions +// is asked to retrieve. This type is thread safe. +type clientPoolImpl struct { + lock sync.RWMutex + config *restclient.Config + clients map[schema.GroupVersion]*Client + apiPathResolverFunc APIPathResolverFunc + mapper meta.RESTMapper +} + +// NewClientPool returns a ClientPool from the specified config. It reuses clients for the the same +// group version. It is expected this type may be wrapped by specific logic that special cases certain +// resources or groups. +func NewClientPool(config *restclient.Config, mapper meta.RESTMapper, apiPathResolverFunc APIPathResolverFunc) ClientPool { + confCopy := *config + + return &clientPoolImpl{ + config: &confCopy, + clients: map[schema.GroupVersion]*Client{}, + apiPathResolverFunc: apiPathResolverFunc, + mapper: mapper, + } +} + +// Instantiates a new dynamic client pool with the given config. +func NewDynamicClientPool(cfg *restclient.Config) ClientPool { + // restMapper is not needed when using LegacyAPIPathResolverFunc + emptyMapper := meta.MultiRESTMapper{} + return NewClientPool(cfg, emptyMapper, LegacyAPIPathResolverFunc) +} + +// ClientForGroupVersionResource uses the provided RESTMapper to identify the appropriate resource. Resource may +// be empty. If no matching kind is found the underlying client for that group is still returned. +func (c *clientPoolImpl) ClientForGroupVersionResource(resource schema.GroupVersionResource) (*Client, error) { + kinds, err := c.mapper.KindsFor(resource) + if err != nil { + if meta.IsNoMatchError(err) { + return c.ClientForGroupVersionKind(schema.GroupVersionKind{Group: resource.Group, Version: resource.Version}) + } + return nil, err + } + return c.ClientForGroupVersionKind(kinds[0]) +} + +// ClientForGroupVersion returns a client for the specified groupVersion, creates one if none exists. Kind +// in the GroupVersionKind may be empty. +func (c *clientPoolImpl) ClientForGroupVersionKind(kind schema.GroupVersionKind) (*Client, error) { + c.lock.Lock() + defer c.lock.Unlock() + + gv := kind.GroupVersion() + + // do we have a client already configured? + if existingClient, found := c.clients[gv]; found { + return existingClient, nil + } + + // avoid changing the original config + confCopy := *c.config + conf := &confCopy + + // we need to set the api path based on group version, if no group, default to legacy path + conf.APIPath = c.apiPathResolverFunc(kind) + + // we need to make a client + conf.GroupVersion = &gv + + dynamicClient, err := NewClient(conf) + if err != nil { + return nil, err + } + c.clients[gv] = dynamicClient + return dynamicClient, nil +} diff --git a/vendor/k8s.io/client-go/dynamic/dynamic_util.go b/vendor/k8s.io/client-go/dynamic/dynamic_util.go new file mode 100644 index 00000000..c834dbb0 --- /dev/null +++ b/vendor/k8s.io/client-go/dynamic/dynamic_util.go @@ -0,0 +1,96 @@ +/* +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 dynamic + +import ( + "fmt" + + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// VersionInterfaces provides an object converter and metadata +// accessor appropriate for use with unstructured objects. +func VersionInterfaces(schema.GroupVersion) (*meta.VersionInterfaces, error) { + return &meta.VersionInterfaces{ + ObjectConvertor: &unstructured.UnstructuredObjectConverter{}, + MetadataAccessor: meta.NewAccessor(), + }, nil +} + +// NewDiscoveryRESTMapper returns a RESTMapper based on discovery information. +func NewDiscoveryRESTMapper(resources []*metav1.APIResourceList, versionFunc meta.VersionInterfacesFunc) (*meta.DefaultRESTMapper, error) { + rm := meta.NewDefaultRESTMapper(nil, versionFunc) + for _, resourceList := range resources { + gv, err := schema.ParseGroupVersion(resourceList.GroupVersion) + if err != nil { + return nil, err + } + + for _, resource := range resourceList.APIResources { + gvk := gv.WithKind(resource.Kind) + scope := meta.RESTScopeRoot + if resource.Namespaced { + scope = meta.RESTScopeNamespace + } + rm.Add(gvk, scope) + } + } + return rm, nil +} + +// ObjectTyper provides an ObjectTyper implementation for +// unstructured.Unstructured object based on discovery information. +type ObjectTyper struct { + registered map[schema.GroupVersionKind]bool +} + +// NewObjectTyper constructs an ObjectTyper from discovery information. +func NewObjectTyper(resources []*metav1.APIResourceList) (runtime.ObjectTyper, error) { + ot := &ObjectTyper{registered: make(map[schema.GroupVersionKind]bool)} + for _, resourceList := range resources { + gv, err := schema.ParseGroupVersion(resourceList.GroupVersion) + if err != nil { + return nil, err + } + + for _, resource := range resourceList.APIResources { + ot.registered[gv.WithKind(resource.Kind)] = true + } + } + return ot, nil +} + +// ObjectKinds returns a slice of one element with the +// group,version,kind of the provided object, or an error if the +// object is not *unstructured.Unstructured or has no group,version,kind +// information. +func (ot *ObjectTyper) ObjectKinds(obj runtime.Object) ([]schema.GroupVersionKind, bool, error) { + if _, ok := obj.(*unstructured.Unstructured); !ok { + return nil, false, fmt.Errorf("type %T is invalid for dynamic object typer", obj) + } + return []schema.GroupVersionKind{obj.GetObjectKind().GroupVersionKind()}, false, nil +} + +// Recognizes returns true if the provided group,version,kind was in +// the discovery information. +func (ot *ObjectTyper) Recognizes(gvk schema.GroupVersionKind) bool { + return ot.registered[gvk] +}