Commit 175addf2 authored by Eric Tune's avatar Eric Tune

Implemented Batch client

parent d5f303d3
...@@ -33,6 +33,7 @@ import ( ...@@ -33,6 +33,7 @@ import (
_ "k8s.io/kubernetes/pkg/api/install" _ "k8s.io/kubernetes/pkg/api/install"
_ "k8s.io/kubernetes/pkg/apis/autoscaling/install" _ "k8s.io/kubernetes/pkg/apis/autoscaling/install"
_ "k8s.io/kubernetes/pkg/apis/batch/install"
_ "k8s.io/kubernetes/pkg/apis/componentconfig/install" _ "k8s.io/kubernetes/pkg/apis/componentconfig/install"
_ "k8s.io/kubernetes/pkg/apis/extensions/install" _ "k8s.io/kubernetes/pkg/apis/extensions/install"
_ "k8s.io/kubernetes/pkg/apis/metrics/install" _ "k8s.io/kubernetes/pkg/apis/metrics/install"
......
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package unversioned
import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apimachinery/registered"
"k8s.io/kubernetes/pkg/apis/batch"
)
type BatchInterface interface {
JobsNamespacer
}
// BatchClient is used to interact with Kubernetes batch features.
type BatchClient struct {
*RESTClient
}
func (c *BatchClient) Jobs(namespace string) JobInterface {
return newJobsV1(c, namespace)
}
func NewBatch(c *Config) (*BatchClient, error) {
config := *c
if err := setBatchDefaults(&config); err != nil {
return nil, err
}
client, err := RESTClientFor(&config)
if err != nil {
return nil, err
}
return &BatchClient{client}, nil
}
func NewBatchOrDie(c *Config) *BatchClient {
client, err := NewBatch(c)
if err != nil {
panic(err)
}
return client
}
func setBatchDefaults(config *Config) error {
// if batch group is not registered, return an error
g, err := registered.Group(batch.GroupName)
if err != nil {
return err
}
config.APIPath = defaultAPIPath
if config.UserAgent == "" {
config.UserAgent = DefaultKubernetesUserAgent()
}
// TODO: Unconditionally set the config.Version, until we fix the config.
//if config.Version == "" {
copyGroupVersion := g.GroupVersion
config.GroupVersion = &copyGroupVersion
//}
config.Codec = api.Codecs.LegacyCodec(*config.GroupVersion)
if config.QPS == 0 {
config.QPS = 5
}
if config.Burst == 0 {
config.Burst = 10
}
return nil
}
...@@ -42,6 +42,7 @@ type Interface interface { ...@@ -42,6 +42,7 @@ type Interface interface {
ComponentStatusesInterface ComponentStatusesInterface
ConfigMapsNamespacer ConfigMapsNamespacer
Autoscaling() AutoscalingInterface Autoscaling() AutoscalingInterface
Batch() BatchInterface
Extensions() ExtensionsInterface Extensions() ExtensionsInterface
Discovery() DiscoveryInterface Discovery() DiscoveryInterface
} }
...@@ -113,6 +114,7 @@ func (c *Client) ConfigMaps(namespace string) ConfigMapsInterface { ...@@ -113,6 +114,7 @@ func (c *Client) ConfigMaps(namespace string) ConfigMapsInterface {
type Client struct { type Client struct {
*RESTClient *RESTClient
*AutoscalingClient *AutoscalingClient
*BatchClient
*ExtensionsClient *ExtensionsClient
*DiscoveryClient *DiscoveryClient
} }
...@@ -152,6 +154,10 @@ func (c *Client) Autoscaling() AutoscalingInterface { ...@@ -152,6 +154,10 @@ func (c *Client) Autoscaling() AutoscalingInterface {
return c.AutoscalingClient return c.AutoscalingClient
} }
func (c *Client) Batch() BatchInterface {
return c.BatchClient
}
func (c *Client) Extensions() ExtensionsInterface { func (c *Client) Extensions() ExtensionsInterface {
return c.ExtensionsClient return c.ExtensionsClient
} }
......
...@@ -34,6 +34,7 @@ import ( ...@@ -34,6 +34,7 @@ import (
"k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apimachinery/registered" "k8s.io/kubernetes/pkg/apimachinery/registered"
"k8s.io/kubernetes/pkg/apis/autoscaling" "k8s.io/kubernetes/pkg/apis/autoscaling"
"k8s.io/kubernetes/pkg/apis/batch"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util" "k8s.io/kubernetes/pkg/util"
...@@ -165,6 +166,15 @@ func New(c *Config) (*Client, error) { ...@@ -165,6 +166,15 @@ func New(c *Config) (*Client, error) {
} }
} }
var batchClient *BatchClient
if registered.IsRegistered(batch.GroupName) {
batchConfig := *c
batchClient, err = NewBatch(&batchConfig)
if err != nil {
return nil, err
}
}
var extensionsClient *ExtensionsClient var extensionsClient *ExtensionsClient
if registered.IsRegistered(extensions.GroupName) { if registered.IsRegistered(extensions.GroupName) {
extensionsConfig := *c extensionsConfig := *c
...@@ -174,7 +184,7 @@ func New(c *Config) (*Client, error) { ...@@ -174,7 +184,7 @@ func New(c *Config) (*Client, error) {
} }
} }
return &Client{RESTClient: client, AutoscalingClient: autoscalingClient, ExtensionsClient: extensionsClient, DiscoveryClient: discoveryClient}, nil return &Client{RESTClient: client, AutoscalingClient: autoscalingClient, BatchClient: batchClient, ExtensionsClient: extensionsClient, DiscoveryClient: discoveryClient}, nil
} }
// MatchesServerVersion queries the server to compares the build version // MatchesServerVersion queries the server to compares the build version
......
...@@ -35,7 +35,7 @@ func getHorizontalPodAutoscalersResoureName() string { ...@@ -35,7 +35,7 @@ func getHorizontalPodAutoscalersResoureName() string {
return "horizontalpodautoscalers" return "horizontalpodautoscalers"
} }
func getClient(t *testing.T, c *simple.Client, ns, resourceGroup string) HorizontalPodAutoscalerInterface { func getHPAClient(t *testing.T, c *simple.Client, ns, resourceGroup string) HorizontalPodAutoscalerInterface {
switch resourceGroup { switch resourceGroup {
case autoscaling.GroupName: case autoscaling.GroupName:
return c.Setup(t).Autoscaling().HorizontalPodAutoscalers(ns) return c.Setup(t).Autoscaling().HorizontalPodAutoscalers(ns)
...@@ -66,7 +66,7 @@ func testHorizontalPodAutoscalerCreate(t *testing.T, group testapi.TestGroup, re ...@@ -66,7 +66,7 @@ func testHorizontalPodAutoscalerCreate(t *testing.T, group testapi.TestGroup, re
ResourceGroup: resourceGroup, ResourceGroup: resourceGroup,
} }
response, err := getClient(t, c, ns, resourceGroup).Create(&horizontalPodAutoscaler) response, err := getHPAClient(t, c, ns, resourceGroup).Create(&horizontalPodAutoscaler)
defer c.Close() defer c.Close()
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
...@@ -98,7 +98,7 @@ func testHorizontalPodAutoscalerGet(t *testing.T, group testapi.TestGroup, resou ...@@ -98,7 +98,7 @@ func testHorizontalPodAutoscalerGet(t *testing.T, group testapi.TestGroup, resou
ResourceGroup: resourceGroup, ResourceGroup: resourceGroup,
} }
response, err := getClient(t, c, ns, resourceGroup).Get("abc") response, err := getHPAClient(t, c, ns, resourceGroup).Get("abc")
defer c.Close() defer c.Close()
c.Validate(t, response, err) c.Validate(t, response, err)
} }
...@@ -130,7 +130,7 @@ func testHorizontalPodAutoscalerList(t *testing.T, group testapi.TestGroup, reso ...@@ -130,7 +130,7 @@ func testHorizontalPodAutoscalerList(t *testing.T, group testapi.TestGroup, reso
Response: simple.Response{StatusCode: 200, Body: horizontalPodAutoscalerList}, Response: simple.Response{StatusCode: 200, Body: horizontalPodAutoscalerList},
ResourceGroup: resourceGroup, ResourceGroup: resourceGroup,
} }
response, err := getClient(t, c, ns, resourceGroup).List(api.ListOptions{}) response, err := getHPAClient(t, c, ns, resourceGroup).List(api.ListOptions{})
defer c.Close() defer c.Close()
c.Validate(t, response, err) c.Validate(t, response, err)
} }
...@@ -154,7 +154,7 @@ func testHorizontalPodAutoscalerUpdate(t *testing.T, group testapi.TestGroup, re ...@@ -154,7 +154,7 @@ func testHorizontalPodAutoscalerUpdate(t *testing.T, group testapi.TestGroup, re
Response: simple.Response{StatusCode: 200, Body: horizontalPodAutoscaler}, Response: simple.Response{StatusCode: 200, Body: horizontalPodAutoscaler},
ResourceGroup: resourceGroup, ResourceGroup: resourceGroup,
} }
response, err := getClient(t, c, ns, resourceGroup).Update(horizontalPodAutoscaler) response, err := getHPAClient(t, c, ns, resourceGroup).Update(horizontalPodAutoscaler)
defer c.Close() defer c.Close()
c.Validate(t, response, err) c.Validate(t, response, err)
} }
...@@ -178,7 +178,7 @@ func testHorizontalPodAutoscalerUpdateStatus(t *testing.T, group testapi.TestGro ...@@ -178,7 +178,7 @@ func testHorizontalPodAutoscalerUpdateStatus(t *testing.T, group testapi.TestGro
Response: simple.Response{StatusCode: 200, Body: horizontalPodAutoscaler}, Response: simple.Response{StatusCode: 200, Body: horizontalPodAutoscaler},
ResourceGroup: resourceGroup, ResourceGroup: resourceGroup,
} }
response, err := getClient(t, c, ns, resourceGroup).UpdateStatus(horizontalPodAutoscaler) response, err := getHPAClient(t, c, ns, resourceGroup).UpdateStatus(horizontalPodAutoscaler)
defer c.Close() defer c.Close()
c.Validate(t, response, err) c.Validate(t, response, err)
} }
...@@ -195,7 +195,7 @@ func testHorizontalPodAutoscalerDelete(t *testing.T, group testapi.TestGroup, re ...@@ -195,7 +195,7 @@ func testHorizontalPodAutoscalerDelete(t *testing.T, group testapi.TestGroup, re
Response: simple.Response{StatusCode: 200}, Response: simple.Response{StatusCode: 200},
ResourceGroup: resourceGroup, ResourceGroup: resourceGroup,
} }
err := getClient(t, c, ns, resourceGroup).Delete("foo", nil) err := getHPAClient(t, c, ns, resourceGroup).Delete("foo", nil)
defer c.Close() defer c.Close()
c.Validate(t, nil, err) c.Validate(t, nil, err)
} }
...@@ -214,7 +214,7 @@ func testHorizontalPodAutoscalerWatch(t *testing.T, group testapi.TestGroup, res ...@@ -214,7 +214,7 @@ func testHorizontalPodAutoscalerWatch(t *testing.T, group testapi.TestGroup, res
Response: simple.Response{StatusCode: 200}, Response: simple.Response{StatusCode: 200},
ResourceGroup: resourceGroup, ResourceGroup: resourceGroup,
} }
_, err := getClient(t, c, api.NamespaceAll, resourceGroup).Watch(api.ListOptions{}) _, err := getHPAClient(t, c, api.NamespaceAll, resourceGroup).Watch(api.ListOptions{})
defer c.Close() defer c.Close()
c.Validate(t, nil, err) c.Validate(t, nil, err)
} }
......
...@@ -101,3 +101,67 @@ func (c *jobs) UpdateStatus(job *extensions.Job) (result *extensions.Job, err er ...@@ -101,3 +101,67 @@ func (c *jobs) UpdateStatus(job *extensions.Job) (result *extensions.Job, err er
err = c.r.Put().Namespace(c.ns).Resource("jobs").Name(job.Name).SubResource("status").Body(job).Do().Into(result) err = c.r.Put().Namespace(c.ns).Resource("jobs").Name(job.Name).SubResource("status").Body(job).Do().Into(result)
return return
} }
// jobsV1 implements JobsNamespacer interface using BatchClient internally
type jobsV1 struct {
r *BatchClient
ns string
}
// newJobsV1 returns a jobsV1
func newJobsV1(c *BatchClient, namespace string) *jobsV1 {
return &jobsV1{c, namespace}
}
// Ensure statically that jobsV1 implements JobInterface.
var _ JobInterface = &jobsV1{}
// List returns a list of jobs that match the label and field selectors.
func (c *jobsV1) List(opts api.ListOptions) (result *extensions.JobList, err error) {
result = &extensions.JobList{}
err = c.r.Get().Namespace(c.ns).Resource("jobs").VersionedParams(&opts, api.ParameterCodec).Do().Into(result)
return
}
// Get returns information about a particular job.
func (c *jobsV1) Get(name string) (result *extensions.Job, err error) {
result = &extensions.Job{}
err = c.r.Get().Namespace(c.ns).Resource("jobs").Name(name).Do().Into(result)
return
}
// Create creates a new job.
func (c *jobsV1) Create(job *extensions.Job) (result *extensions.Job, err error) {
result = &extensions.Job{}
err = c.r.Post().Namespace(c.ns).Resource("jobs").Body(job).Do().Into(result)
return
}
// Update updates an existing job.
func (c *jobsV1) Update(job *extensions.Job) (result *extensions.Job, err error) {
result = &extensions.Job{}
err = c.r.Put().Namespace(c.ns).Resource("jobs").Name(job.Name).Body(job).Do().Into(result)
return
}
// Delete deletes a job, returns error if one occurs.
func (c *jobsV1) Delete(name string, options *api.DeleteOptions) (err error) {
return c.r.Delete().Namespace(c.ns).Resource("jobs").Name(name).Body(options).Do().Error()
}
// Watch returns a watch.Interface that watches the requested jobs.
func (c *jobsV1) Watch(opts api.ListOptions) (watch.Interface, error) {
return c.r.Get().
Prefix("watch").
Namespace(c.ns).
Resource("jobs").
VersionedParams(&opts, api.ParameterCodec).
Watch()
}
// UpdateStatus takes the name of the job and the new status. Returns the server's representation of the job, and an error, if it occurs.
func (c *jobsV1) UpdateStatus(job *extensions.Job) (result *extensions.Job, err error) {
result = &extensions.Job{}
err = c.r.Put().Namespace(c.ns).Resource("jobs").Name(job.Name).SubResource("status").Body(job).Do().Into(result)
return
}
...@@ -82,3 +82,66 @@ func (c *FakeJobs) UpdateStatus(job *extensions.Job) (result *extensions.Job, er ...@@ -82,3 +82,66 @@ func (c *FakeJobs) UpdateStatus(job *extensions.Job) (result *extensions.Job, er
return obj.(*extensions.Job), err return obj.(*extensions.Job), err
} }
// FakeJobs implements JobInterface. Meant to be embedded into a struct to get a default
// implementation. This makes faking out just the methods you want to test easier.
// This is a test implementation of JobsV1
// TODO(piosz): get back to one client implementation once HPA will be graduated to GA completely
type FakeJobsV1 struct {
Fake *FakeBatch
Namespace string
}
func (c *FakeJobsV1) Get(name string) (*extensions.Job, error) {
obj, err := c.Fake.Invokes(NewGetAction("jobs", c.Namespace, name), &extensions.Job{})
if obj == nil {
return nil, err
}
return obj.(*extensions.Job), err
}
func (c *FakeJobsV1) List(opts api.ListOptions) (*extensions.JobList, error) {
obj, err := c.Fake.Invokes(NewListAction("jobs", c.Namespace, opts), &extensions.JobList{})
if obj == nil {
return nil, err
}
return obj.(*extensions.JobList), err
}
func (c *FakeJobsV1) Create(job *extensions.Job) (*extensions.Job, error) {
obj, err := c.Fake.Invokes(NewCreateAction("jobs", c.Namespace, job), job)
if obj == nil {
return nil, err
}
return obj.(*extensions.Job), err
}
func (c *FakeJobsV1) Update(job *extensions.Job) (*extensions.Job, error) {
obj, err := c.Fake.Invokes(NewUpdateAction("jobs", c.Namespace, job), job)
if obj == nil {
return nil, err
}
return obj.(*extensions.Job), err
}
func (c *FakeJobsV1) Delete(name string, options *api.DeleteOptions) error {
_, err := c.Fake.Invokes(NewDeleteAction("jobs", c.Namespace, name), &extensions.Job{})
return err
}
func (c *FakeJobsV1) Watch(opts api.ListOptions) (watch.Interface, error) {
return c.Fake.InvokesWatch(NewWatchAction("jobs", c.Namespace, opts))
}
func (c *FakeJobsV1) UpdateStatus(job *extensions.Job) (result *extensions.Job, err error) {
obj, err := c.Fake.Invokes(NewUpdateSubresourceAction("jobs", "status", c.Namespace, job), job)
if obj == nil {
return nil, err
}
return obj.(*extensions.Job), err
}
...@@ -92,6 +92,10 @@ func (c *Client) Setup(t *testing.T) *Client { ...@@ -92,6 +92,10 @@ func (c *Client) Setup(t *testing.T) *Client {
Host: c.server.URL, Host: c.server.URL,
ContentConfig: client.ContentConfig{GroupVersion: testapi.Autoscaling.GroupVersion()}, ContentConfig: client.ContentConfig{GroupVersion: testapi.Autoscaling.GroupVersion()},
}) })
c.BatchClient = client.NewBatchOrDie(&client.Config{
Host: c.server.URL,
ContentConfig: client.ContentConfig{GroupVersion: testapi.Batch.GroupVersion()},
})
c.ExtensionsClient = client.NewExtensionsOrDie(&client.Config{ c.ExtensionsClient = client.NewExtensionsOrDie(&client.Config{
Host: c.server.URL, Host: c.server.URL,
ContentConfig: client.ContentConfig{GroupVersion: testapi.Extensions.GroupVersion()}, ContentConfig: client.ContentConfig{GroupVersion: testapi.Extensions.GroupVersion()},
......
...@@ -278,6 +278,10 @@ func (c *Fake) Autoscaling() client.AutoscalingInterface { ...@@ -278,6 +278,10 @@ func (c *Fake) Autoscaling() client.AutoscalingInterface {
return &FakeAutoscaling{c} return &FakeAutoscaling{c}
} }
func (c *Fake) Batch() client.BatchInterface {
return &FakeBatch{c}
}
func (c *Fake) Extensions() client.ExtensionsInterface { func (c *Fake) Extensions() client.ExtensionsInterface {
return &FakeExperimental{c} return &FakeExperimental{c}
} }
...@@ -321,6 +325,19 @@ func (c *FakeAutoscaling) HorizontalPodAutoscalers(namespace string) client.Hori ...@@ -321,6 +325,19 @@ func (c *FakeAutoscaling) HorizontalPodAutoscalers(namespace string) client.Hori
return &FakeHorizontalPodAutoscalersV1{Fake: c, Namespace: namespace} return &FakeHorizontalPodAutoscalersV1{Fake: c, Namespace: namespace}
} }
// NewSimpleFakeBatch returns a client that will respond with the provided objects
func NewSimpleFakeBatch(objects ...runtime.Object) *FakeBatch {
return &FakeBatch{Fake: NewSimpleFake(objects...)}
}
type FakeBatch struct {
*Fake
}
func (c *FakeBatch) Jobs(namespace string) client.JobInterface {
return &FakeJobsV1{Fake: c, Namespace: namespace}
}
// NewSimpleFakeExp returns a client that will respond with the provided objects // NewSimpleFakeExp returns a client that will respond with the provided objects
func NewSimpleFakeExp(objects ...runtime.Object) *FakeExperimental { func NewSimpleFakeExp(objects ...runtime.Object) *FakeExperimental {
return &FakeExperimental{Fake: NewSimpleFake(objects...)} return &FakeExperimental{Fake: NewSimpleFake(objects...)}
......
...@@ -242,7 +242,7 @@ func (o *DrainOptions) getPodsForDeletion() ([]api.Pod, error) { ...@@ -242,7 +242,7 @@ func (o *DrainOptions) getPodsForDeletion() ([]api.Pod, error) {
daemonset_pod = true daemonset_pod = true
} }
} else if sr.Reference.Kind == "Job" { } else if sr.Reference.Kind == "Job" {
job, err := o.client.Jobs(sr.Reference.Namespace).Get(sr.Reference.Name) job, err := o.client.ExtensionsClient.Jobs(sr.Reference.Namespace).Get(sr.Reference.Name)
// Assume the only reason for an error is because the Job is // Assume the only reason for an error is because the Job is
// gone/missing, not for any other cause. TODO(mml): something more // gone/missing, not for any other cause. TODO(mml): something more
......
...@@ -40,6 +40,7 @@ import ( ...@@ -40,6 +40,7 @@ import (
"k8s.io/kubernetes/pkg/api/validation" "k8s.io/kubernetes/pkg/api/validation"
"k8s.io/kubernetes/pkg/apimachinery/registered" "k8s.io/kubernetes/pkg/apimachinery/registered"
"k8s.io/kubernetes/pkg/apis/autoscaling" "k8s.io/kubernetes/pkg/apis/autoscaling"
"k8s.io/kubernetes/pkg/apis/batch"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/extensions"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
client "k8s.io/kubernetes/pkg/client/unversioned" client "k8s.io/kubernetes/pkg/client/unversioned"
...@@ -221,6 +222,8 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory { ...@@ -221,6 +222,8 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
return client.RESTClient, nil return client.RESTClient, nil
case autoscaling.GroupName: case autoscaling.GroupName:
return client.AutoscalingClient.RESTClient, nil return client.AutoscalingClient.RESTClient, nil
case batch.GroupName:
return client.BatchClient.RESTClient, nil
case extensions.GroupName: case extensions.GroupName:
return client.ExtensionsClient.RESTClient, nil return client.ExtensionsClient.RESTClient, nil
} }
...@@ -710,6 +713,12 @@ func (c *clientSwaggerSchema) ValidateBytes(data []byte) error { ...@@ -710,6 +713,12 @@ func (c *clientSwaggerSchema) ValidateBytes(data []byte) error {
} }
return getSchemaAndValidate(c.c.AutoscalingClient.RESTClient, data, "apis/", gvk.GroupVersion().String(), c.cacheDir) return getSchemaAndValidate(c.c.AutoscalingClient.RESTClient, data, "apis/", gvk.GroupVersion().String(), c.cacheDir)
} }
if gvk.Group == batch.GroupName {
if c.c.BatchClient == nil {
return errors.New("unable to validate: no batch client")
}
return getSchemaAndValidate(c.c.BatchClient.RESTClient, data, "apis/", gvk.GroupVersion().String(), c.cacheDir)
}
if gvk.Group == extensions.GroupName { if gvk.Group == extensions.GroupName {
if c.c.ExtensionsClient == nil { if c.c.ExtensionsClient == nil {
return errors.New("unable to validate: no experimental client") return errors.New("unable to validate: no experimental client")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment