From c54e174808174065da710d0ebe3c69eba869e75e Mon Sep 17 00:00:00 2001 From: Prashanth Balasubramanian Date: Mon, 28 Sep 2015 16:41:09 -0700 Subject: [PATCH] Ingress Client --- pkg/client/unversioned/experimental.go | 5 + pkg/client/unversioned/ingress.go | 112 +++++++++ pkg/client/unversioned/ingress_test.go | 230 ++++++++++++++++++ .../unversioned/testclient/fake_ingress.go | 86 +++++++ .../unversioned/testclient/testclient.go | 4 + 5 files changed, 437 insertions(+) create mode 100644 pkg/client/unversioned/ingress.go create mode 100644 pkg/client/unversioned/ingress_test.go create mode 100644 pkg/client/unversioned/testclient/fake_ingress.go diff --git a/pkg/client/unversioned/experimental.go b/pkg/client/unversioned/experimental.go index f73ea5c57ac..f93b42f00bd 100644 --- a/pkg/client/unversioned/experimental.go +++ b/pkg/client/unversioned/experimental.go @@ -37,6 +37,7 @@ type ExperimentalInterface interface { DaemonSetsNamespacer DeploymentsNamespacer JobsNamespacer + IngressNamespacer } // ExperimentalClient is used to interact with experimental Kubernetes features. @@ -95,6 +96,10 @@ func (c *ExperimentalClient) Jobs(namespace string) JobInterface { return newJobs(c, namespace) } +func (c *ExperimentalClient) Ingress(namespace string) IngressInterface { + return newIngress(c, namespace) +} + // NewExperimental creates a new ExperimentalClient for the given config. This client // provides access to experimental Kubernetes features. // Experimental features are not supported and may be changed or removed in diff --git a/pkg/client/unversioned/ingress.go b/pkg/client/unversioned/ingress.go new file mode 100644 index 00000000000..b0dd6e61331 --- /dev/null +++ b/pkg/client/unversioned/ingress.go @@ -0,0 +1,112 @@ +/* +Copyright 2015 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package unversioned + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/apis/experimental" + "k8s.io/kubernetes/pkg/fields" + "k8s.io/kubernetes/pkg/labels" + "k8s.io/kubernetes/pkg/watch" +) + +// IngressNamespacer has methods to work with Ingress resources in a namespace +type IngressNamespacer interface { + Ingress(namespace string) IngressInterface +} + +// IngressInterface exposes methods to work on Ingress resources. +type IngressInterface interface { + List(label labels.Selector, field fields.Selector) (*experimental.IngressList, error) + Get(name string) (*experimental.Ingress, error) + Create(ingress *experimental.Ingress) (*experimental.Ingress, error) + Update(ingress *experimental.Ingress) (*experimental.Ingress, error) + Delete(name string, options *api.DeleteOptions) error + Watch(label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) + UpdateStatus(ingress *experimental.Ingress) (*experimental.Ingress, error) +} + +// ingress implements IngressNamespacer interface +type ingress struct { + r *ExperimentalClient + ns string +} + +// newIngress returns a ingress +func newIngress(c *ExperimentalClient, namespace string) *ingress { + return &ingress{c, namespace} +} + +// List returns a list of ingress that match the label and field selectors. +func (c *ingress) List(label labels.Selector, field fields.Selector) (result *experimental.IngressList, err error) { + result = &experimental.IngressList{} + err = c.r.Get().Namespace(c.ns).Resource("ingress").LabelsSelectorParam(label).FieldsSelectorParam(field).Do().Into(result) + return +} + +// Get returns information about a particular ingress. +func (c *ingress) Get(name string) (result *experimental.Ingress, err error) { + result = &experimental.Ingress{} + err = c.r.Get().Namespace(c.ns).Resource("ingress").Name(name).Do().Into(result) + return +} + +// Create creates a new ingress. +func (c *ingress) Create(ingress *experimental.Ingress) (result *experimental.Ingress, err error) { + result = &experimental.Ingress{} + err = c.r.Post().Namespace(c.ns).Resource("ingress").Body(ingress).Do().Into(result) + return +} + +// Update updates an existing ingress. +func (c *ingress) Update(ingress *experimental.Ingress) (result *experimental.Ingress, err error) { + result = &experimental.Ingress{} + err = c.r.Put().Namespace(c.ns).Resource("ingress").Name(ingress.Name).Body(ingress).Do().Into(result) + return +} + +// Delete deletes a ingress, returns error if one occurs. +func (c *ingress) Delete(name string, options *api.DeleteOptions) (err error) { + if options == nil { + return c.r.Delete().Namespace(c.ns).Resource("ingress").Name(name).Do().Error() + } + + body, err := api.Scheme.EncodeToVersion(options, c.r.APIVersion()) + if err != nil { + return err + } + return c.r.Delete().Namespace(c.ns).Resource("ingress").Name(name).Body(body).Do().Error() +} + +// Watch returns a watch.Interface that watches the requested ingress. +func (c *ingress) Watch(label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) { + return c.r.Get(). + Prefix("watch"). + Namespace(c.ns). + Resource("ingress"). + Param("resourceVersion", resourceVersion). + LabelsSelectorParam(label). + FieldsSelectorParam(field). + Watch() +} + +// UpdateStatus takes the name of the ingress and the new status. Returns the server's representation of the ingress, and an error, if it occurs. +func (c *ingress) UpdateStatus(ingress *experimental.Ingress) (result *experimental.Ingress, err error) { + result = &experimental.Ingress{} + err = c.r.Put().Namespace(c.ns).Resource("ingress").Name(ingress.Name).SubResource("status").Body(ingress).Do().Into(result) + return +} diff --git a/pkg/client/unversioned/ingress_test.go b/pkg/client/unversioned/ingress_test.go new file mode 100644 index 00000000000..0fd194baff7 --- /dev/null +++ b/pkg/client/unversioned/ingress_test.go @@ -0,0 +1,230 @@ +/* +Copyright 2015 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package unversioned + +import ( + "testing" + + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/testapi" + "k8s.io/kubernetes/pkg/apis/experimental" + "k8s.io/kubernetes/pkg/fields" + "k8s.io/kubernetes/pkg/labels" +) + +func getIngressResourceName() string { + return "ingress" +} + +func TestListIngress(t *testing.T) { + ns := api.NamespaceAll + c := &testClient{ + Request: testRequest{ + Method: "GET", + Path: testapi.Experimental.ResourcePath(getIngressResourceName(), ns, ""), + }, + Response: Response{StatusCode: 200, + Body: &experimental.IngressList{ + Items: []experimental.Ingress{ + { + ObjectMeta: api.ObjectMeta{ + Name: "foo", + Labels: map[string]string{ + "foo": "bar", + "name": "baz", + }, + }, + Spec: experimental.IngressSpec{ + Rules: []experimental.IngressRule{}, + }, + }, + }, + }, + }, + } + receivedIngressList, err := c.Setup(t).Experimental().Ingress(ns).List(labels.Everything(), fields.Everything()) + c.Validate(t, receivedIngressList, err) +} + +func TestGetIngress(t *testing.T) { + ns := api.NamespaceDefault + c := &testClient{ + Request: testRequest{ + Method: "GET", + Path: testapi.Experimental.ResourcePath(getIngressResourceName(), ns, "foo"), + Query: buildQueryValues(nil), + }, + Response: Response{ + StatusCode: 200, + Body: &experimental.Ingress{ + ObjectMeta: api.ObjectMeta{ + Name: "foo", + Labels: map[string]string{ + "foo": "bar", + "name": "baz", + }, + }, + Spec: experimental.IngressSpec{ + Rules: []experimental.IngressRule{}, + }, + }, + }, + } + receivedIngress, err := c.Setup(t).Experimental().Ingress(ns).Get("foo") + c.Validate(t, receivedIngress, err) +} + +func TestGetIngressWithNoName(t *testing.T) { + ns := api.NamespaceDefault + c := &testClient{Error: true} + receivedIngress, err := c.Setup(t).Experimental().Ingress(ns).Get("") + if (err != nil) && (err.Error() != nameRequiredError) { + t.Errorf("Expected error: %v, but got %v", nameRequiredError, err) + } + + c.Validate(t, receivedIngress, err) +} + +func TestUpdateIngress(t *testing.T) { + ns := api.NamespaceDefault + requestIngress := &experimental.Ingress{ + ObjectMeta: api.ObjectMeta{ + Name: "foo", + Namespace: ns, + ResourceVersion: "1", + }, + } + c := &testClient{ + Request: testRequest{ + Method: "PUT", + Path: testapi.Experimental.ResourcePath(getIngressResourceName(), ns, "foo"), + Query: buildQueryValues(nil), + }, + Response: Response{ + StatusCode: 200, + Body: &experimental.Ingress{ + ObjectMeta: api.ObjectMeta{ + Name: "foo", + Labels: map[string]string{ + "foo": "bar", + "name": "baz", + }, + }, + Spec: experimental.IngressSpec{ + Rules: []experimental.IngressRule{}, + }, + }, + }, + } + receivedIngress, err := c.Setup(t).Experimental().Ingress(ns).Update(requestIngress) + c.Validate(t, receivedIngress, err) +} + +func TestUpdateIngressStatus(t *testing.T) { + ns := api.NamespaceDefault + lbStatus := api.LoadBalancerStatus{ + Ingress: []api.LoadBalancerIngress{ + {IP: "127.0.0.1"}, + }, + } + requestIngress := &experimental.Ingress{ + ObjectMeta: api.ObjectMeta{ + Name: "foo", + Namespace: ns, + ResourceVersion: "1", + }, + Status: experimental.IngressStatus{ + LoadBalancer: lbStatus, + }, + } + c := &testClient{ + Request: testRequest{ + Method: "PUT", + Path: testapi.Experimental.ResourcePath(getIngressResourceName(), ns, "foo") + "/status", + Query: buildQueryValues(nil), + }, + Response: Response{ + StatusCode: 200, + Body: &experimental.Ingress{ + ObjectMeta: api.ObjectMeta{ + Name: "foo", + Labels: map[string]string{ + "foo": "bar", + "name": "baz", + }, + }, + Spec: experimental.IngressSpec{ + Rules: []experimental.IngressRule{}, + }, + Status: experimental.IngressStatus{ + LoadBalancer: lbStatus, + }, + }, + }, + } + receivedIngress, err := c.Setup(t).Experimental().Ingress(ns).UpdateStatus(requestIngress) + c.Validate(t, receivedIngress, err) +} + +func TestDeleteIngress(t *testing.T) { + ns := api.NamespaceDefault + c := &testClient{ + Request: testRequest{ + Method: "DELETE", + Path: testapi.Experimental.ResourcePath(getIngressResourceName(), ns, "foo"), + Query: buildQueryValues(nil), + }, + Response: Response{StatusCode: 200}, + } + err := c.Setup(t).Experimental().Ingress(ns).Delete("foo", nil) + c.Validate(t, nil, err) +} + +func TestCreateIngress(t *testing.T) { + ns := api.NamespaceDefault + requestIngress := &experimental.Ingress{ + ObjectMeta: api.ObjectMeta{ + Name: "foo", + Namespace: ns, + }, + } + c := &testClient{ + Request: testRequest{ + Method: "POST", + Path: testapi.Experimental.ResourcePath(getIngressResourceName(), ns, ""), + Body: requestIngress, + Query: buildQueryValues(nil), + }, + Response: Response{ + StatusCode: 200, + Body: &experimental.Ingress{ + ObjectMeta: api.ObjectMeta{ + Name: "foo", + Labels: map[string]string{ + "foo": "bar", + "name": "baz", + }, + }, + Spec: experimental.IngressSpec{ + Rules: []experimental.IngressRule{}, + }, + }, + }, + } + receivedIngress, err := c.Setup(t).Experimental().Ingress(ns).Create(requestIngress) + c.Validate(t, receivedIngress, err) +} diff --git a/pkg/client/unversioned/testclient/fake_ingress.go b/pkg/client/unversioned/testclient/fake_ingress.go new file mode 100644 index 00000000000..478fb9392d1 --- /dev/null +++ b/pkg/client/unversioned/testclient/fake_ingress.go @@ -0,0 +1,86 @@ +/* +Copyright 2015 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package testclient + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/apis/experimental" + "k8s.io/kubernetes/pkg/fields" + "k8s.io/kubernetes/pkg/labels" + "k8s.io/kubernetes/pkg/watch" +) + +// FakeIngress implements IngressInterface. Meant to be embedded into a struct to get a default +// implementation. This makes faking out just the method you want to test easier. +type FakeIngress struct { + Fake *FakeExperimental + Namespace string +} + +func (c *FakeIngress) Get(name string) (*experimental.Ingress, error) { + obj, err := c.Fake.Invokes(NewGetAction("ingress", c.Namespace, name), &experimental.Ingress{}) + if obj == nil { + return nil, err + } + + return obj.(*experimental.Ingress), err +} + +func (c *FakeIngress) List(label labels.Selector, fields fields.Selector) (*experimental.IngressList, error) { + obj, err := c.Fake.Invokes(NewListAction("ingress", c.Namespace, label, nil), &experimental.IngressList{}) + if obj == nil { + return nil, err + } + + return obj.(*experimental.IngressList), err +} + +func (c *FakeIngress) Create(ingress *experimental.Ingress) (*experimental.Ingress, error) { + obj, err := c.Fake.Invokes(NewCreateAction("ingress", c.Namespace, ingress), ingress) + if obj == nil { + return nil, err + } + + return obj.(*experimental.Ingress), err +} + +func (c *FakeIngress) Update(ingress *experimental.Ingress) (*experimental.Ingress, error) { + obj, err := c.Fake.Invokes(NewUpdateAction("ingress", c.Namespace, ingress), ingress) + if obj == nil { + return nil, err + } + + return obj.(*experimental.Ingress), err +} + +func (c *FakeIngress) Delete(name string, options *api.DeleteOptions) error { + _, err := c.Fake.Invokes(NewDeleteAction("ingress", c.Namespace, name), &experimental.Ingress{}) + return err +} + +func (c *FakeIngress) Watch(label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) { + return c.Fake.InvokesWatch(NewWatchAction("ingress", c.Namespace, label, field, resourceVersion)) +} + +func (c *FakeIngress) UpdateStatus(ingress *experimental.Ingress) (result *experimental.Ingress, err error) { + obj, err := c.Fake.Invokes(NewUpdateSubresourceAction("ingress", "status", c.Namespace, ingress), ingress) + if obj == nil { + return nil, err + } + + return obj.(*experimental.Ingress), err +} diff --git a/pkg/client/unversioned/testclient/testclient.go b/pkg/client/unversioned/testclient/testclient.go index 8a675674e14..07a44a6e0c8 100644 --- a/pkg/client/unversioned/testclient/testclient.go +++ b/pkg/client/unversioned/testclient/testclient.go @@ -305,3 +305,7 @@ func (c *FakeExperimental) Scales(namespace string) client.ScaleInterface { func (c *FakeExperimental) Jobs(namespace string) client.JobInterface { return &FakeJobs{Fake: c, Namespace: namespace} } + +func (c *FakeExperimental) Ingress(namespace string) client.IngressInterface { + return &FakeIngress{Fake: c, Namespace: namespace} +}