Implemented Batch client

This commit is contained in:
Eric Tune 2016-02-17 15:07:38 -08:00
parent d5f303d3d7
commit 175addf2a3
12 changed files with 334 additions and 238 deletions

View File

@ -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"

View File

@ -0,0 +1,82 @@
/*
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
}

View File

@ -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 {
type Client struct { type Client struct {
*RESTClient *RESTClient
*AutoscalingClient *AutoscalingClient
*BatchClient
*ExtensionsClient *ExtensionsClient
*DiscoveryClient *DiscoveryClient
} }
@ -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
} }

View File

@ -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) {
} }
} }
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) {
} }
} }
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

View File

@ -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
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
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
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
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
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
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
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)
} }

View File

@ -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
}

View File

@ -26,19 +26,32 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/apis/batch"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/extensions"
) )
func getJobResourceName() string { func getJobsResourceName() string {
return "jobs" return "jobs"
} }
func TestListJobsViaExtensions(t *testing.T) { func getJobClient(t *testing.T, c *simple.Client, ns, resourceGroup string) JobInterface {
switch resourceGroup {
case batch.GroupName:
return c.Setup(t).Batch().Jobs(ns)
case extensions.GroupName:
return c.Setup(t).Extensions().Jobs(ns)
default:
t.Fatalf("Unknown group %v", resourceGroup)
}
return nil
}
func testListJob(t *testing.T, group testapi.TestGroup, resourceGroup string) {
ns := api.NamespaceAll ns := api.NamespaceAll
c := &simple.Client{ c := &simple.Client{
Request: simple.Request{ Request: simple.Request{
Method: "GET", Method: "GET",
Path: testapi.Extensions.ResourcePath(getJobResourceName(), ns, ""), Path: group.ResourcePath(getJobsResourceName(), ns, ""),
}, },
Response: simple.Response{StatusCode: 200, Response: simple.Response{StatusCode: 200,
Body: &extensions.JobList{ Body: &extensions.JobList{
@ -58,18 +71,24 @@ func TestListJobsViaExtensions(t *testing.T) {
}, },
}, },
}, },
ResourceGroup: resourceGroup,
} }
receivedJobList, err := c.Setup(t).Extensions().Jobs(ns).List(api.ListOptions{}) receivedJobList, err := getJobClient(t, c, ns, resourceGroup).List(api.ListOptions{})
defer c.Close() defer c.Close()
c.Validate(t, receivedJobList, err) c.Validate(t, receivedJobList, err)
} }
func TestGetJobViaExtensions(t *testing.T) { func TestListJob(t *testing.T) {
testListJob(t, testapi.Extensions, extensions.GroupName)
testListJob(t, testapi.Batch, batch.GroupName)
}
func testGetJob(t *testing.T, group testapi.TestGroup, resourceGroup string) {
ns := api.NamespaceDefault ns := api.NamespaceDefault
c := &simple.Client{ c := &simple.Client{
Request: simple.Request{ Request: simple.Request{
Method: "GET", Method: "GET",
Path: testapi.Extensions.ResourcePath(getJobResourceName(), ns, "foo"), Path: group.ResourcePath(getJobsResourceName(), ns, "foo"),
Query: simple.BuildQueryValues(nil), Query: simple.BuildQueryValues(nil),
}, },
Response: simple.Response{ Response: simple.Response{
@ -87,25 +106,19 @@ func TestGetJobViaExtensions(t *testing.T) {
}, },
}, },
}, },
ResourceGroup: resourceGroup,
} }
receivedJob, err := c.Setup(t).Extensions().Jobs(ns).Get("foo") receivedJob, err := getJobClient(t, c, ns, resourceGroup).Get("foo")
defer c.Close() defer c.Close()
c.Validate(t, receivedJob, err) c.Validate(t, receivedJob, err)
} }
func TestGetJobWithNoNameViaExtensions(t *testing.T) { func TestGetJob(t *testing.T) {
ns := api.NamespaceDefault testGetJob(t, testapi.Extensions, extensions.GroupName)
c := &simple.Client{Error: true} testGetJob(t, testapi.Batch, batch.GroupName)
receivedJob, err := c.Setup(t).Extensions().Jobs(ns).Get("")
defer c.Close()
if (err != nil) && (err.Error() != simple.NameRequiredError) {
t.Errorf("Expected error: %v, but got %v", simple.NameRequiredError, err)
}
c.Validate(t, receivedJob, err)
} }
func TestUpdateJobViaExtensions(t *testing.T) { func testUpdateJob(t *testing.T, group testapi.TestGroup, resourceGroup string) {
ns := api.NamespaceDefault ns := api.NamespaceDefault
requestJob := &extensions.Job{ requestJob := &extensions.Job{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
@ -117,7 +130,7 @@ func TestUpdateJobViaExtensions(t *testing.T) {
c := &simple.Client{ c := &simple.Client{
Request: simple.Request{ Request: simple.Request{
Method: "PUT", Method: "PUT",
Path: testapi.Extensions.ResourcePath(getJobResourceName(), ns, "foo"), Path: group.ResourcePath(getJobsResourceName(), ns, "foo"),
Query: simple.BuildQueryValues(nil), Query: simple.BuildQueryValues(nil),
}, },
Response: simple.Response{ Response: simple.Response{
@ -135,13 +148,19 @@ func TestUpdateJobViaExtensions(t *testing.T) {
}, },
}, },
}, },
ResourceGroup: resourceGroup,
} }
receivedJob, err := c.Setup(t).Extensions().Jobs(ns).Update(requestJob) receivedJob, err := getJobClient(t, c, ns, resourceGroup).Update(requestJob)
defer c.Close() defer c.Close()
c.Validate(t, receivedJob, err) c.Validate(t, receivedJob, err)
} }
func TestUpdateJobStatusViaExtensions(t *testing.T) { func TestUpdateJob(t *testing.T) {
testUpdateJob(t, testapi.Extensions, extensions.GroupName)
testUpdateJob(t, testapi.Batch, batch.GroupName)
}
func testUpdateJobStatus(t *testing.T, group testapi.TestGroup, resourceGroup string) {
ns := api.NamespaceDefault ns := api.NamespaceDefault
requestJob := &extensions.Job{ requestJob := &extensions.Job{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
@ -153,7 +172,7 @@ func TestUpdateJobStatusViaExtensions(t *testing.T) {
c := &simple.Client{ c := &simple.Client{
Request: simple.Request{ Request: simple.Request{
Method: "PUT", Method: "PUT",
Path: testapi.Extensions.ResourcePath(getJobResourceName(), ns, "foo") + "/status", Path: group.ResourcePath(getJobsResourceName(), ns, "foo") + "/status",
Query: simple.BuildQueryValues(nil), Query: simple.BuildQueryValues(nil),
}, },
Response: simple.Response{ Response: simple.Response{
@ -174,28 +193,40 @@ func TestUpdateJobStatusViaExtensions(t *testing.T) {
}, },
}, },
}, },
ResourceGroup: resourceGroup,
} }
receivedJob, err := c.Setup(t).Extensions().Jobs(ns).UpdateStatus(requestJob) receivedJob, err := getJobClient(t, c, ns, resourceGroup).UpdateStatus(requestJob)
defer c.Close() defer c.Close()
c.Validate(t, receivedJob, err) c.Validate(t, receivedJob, err)
} }
func TestDeleteJobViaExtensions(t *testing.T) { func TestUpdateJobStatus(t *testing.T) {
testUpdateJobStatus(t, testapi.Extensions, extensions.GroupName)
testUpdateJobStatus(t, testapi.Batch, batch.GroupName)
}
func testDeleteJob(t *testing.T, group testapi.TestGroup, resourceGroup string) {
ns := api.NamespaceDefault ns := api.NamespaceDefault
c := &simple.Client{ c := &simple.Client{
Request: simple.Request{ Request: simple.Request{
Method: "DELETE", Method: "DELETE",
Path: testapi.Extensions.ResourcePath(getJobResourceName(), ns, "foo"), Path: group.ResourcePath(getJobsResourceName(), ns, "foo"),
Query: simple.BuildQueryValues(nil), Query: simple.BuildQueryValues(nil),
}, },
Response: simple.Response{StatusCode: 200}, Response: simple.Response{StatusCode: 200},
ResourceGroup: resourceGroup,
} }
err := c.Setup(t).Extensions().Jobs(ns).Delete("foo", nil) err := getJobClient(t, c, ns, resourceGroup).Delete("foo", nil)
defer c.Close() defer c.Close()
c.Validate(t, nil, err) c.Validate(t, nil, err)
} }
func TestCreateJobViaExtensions(t *testing.T) { func TestDeleteJob(t *testing.T) {
testDeleteJob(t, testapi.Extensions, extensions.GroupName)
testDeleteJob(t, testapi.Batch, batch.GroupName)
}
func testCreateJob(t *testing.T, group testapi.TestGroup, resourceGroup string) {
ns := api.NamespaceDefault ns := api.NamespaceDefault
requestJob := &extensions.Job{ requestJob := &extensions.Job{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
@ -206,7 +237,7 @@ func TestCreateJobViaExtensions(t *testing.T) {
c := &simple.Client{ c := &simple.Client{
Request: simple.Request{ Request: simple.Request{
Method: "POST", Method: "POST",
Path: testapi.Extensions.ResourcePath(getJobResourceName(), ns, ""), Path: group.ResourcePath(getJobsResourceName(), ns, ""),
Body: requestJob, Body: requestJob,
Query: simple.BuildQueryValues(nil), Query: simple.BuildQueryValues(nil),
}, },
@ -225,208 +256,17 @@ func TestCreateJobViaExtensions(t *testing.T) {
}, },
}, },
}, },
ResourceGroup: resourceGroup,
} }
receivedJob, err := c.Setup(t).Extensions().Jobs(ns).Create(requestJob) receivedJob, err := getJobClient(t, c, ns, resourceGroup).Create(requestJob)
defer c.Close() defer c.Close()
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
c.Validate(t, receivedJob, err) c.Validate(t, receivedJob, err)
} }
// Tests below are a copy of the above tests. Once job is removed from extensions, above test cases can be deleted. func TestCreateJob(t *testing.T) {
testCreateJob(t, testapi.Extensions, extensions.GroupName)
func TestListJobsViaBatch(t *testing.T) { testCreateJob(t, testapi.Batch, batch.GroupName)
ns := api.NamespaceAll
c := &simple.Client{
Request: simple.Request{
Method: "GET",
Path: testapi.Batch.ResourcePath(getJobResourceName(), ns, ""),
},
Response: simple.Response{StatusCode: 200,
Body: &extensions.JobList{
Items: []extensions.Job{
{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Labels: map[string]string{
"foo": "bar",
"name": "baz",
},
},
Spec: extensions.JobSpec{
Template: api.PodTemplateSpec{},
},
},
},
},
},
}
receivedJobList, err := c.Setup(t).Batch().Jobs(ns).List(api.ListOptions{})
defer c.Close()
c.Validate(t, receivedJobList, err)
}
func TestGetJobViaBatch(t *testing.T) {
ns := api.NamespaceDefault
c := &simple.Client{
Request: simple.Request{
Method: "GET",
Path: testapi.Batch.ResourcePath(getJobResourceName(), ns, "foo"),
Query: simple.BuildQueryValues(nil),
},
Response: simple.Response{
StatusCode: 200,
Body: &extensions.Job{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Labels: map[string]string{
"foo": "bar",
"name": "baz",
},
},
Spec: extensions.JobSpec{
Template: api.PodTemplateSpec{},
},
},
},
}
receivedJob, err := c.Setup(t).Batch().Jobs(ns).Get("foo")
defer c.Close()
c.Validate(t, receivedJob, err)
}
func TestGetJobWithNoNameViaBatch(t *testing.T) {
ns := api.NamespaceDefault
c := &simple.Client{Error: true}
receivedJob, err := c.Setup(t).Batch().Jobs(ns).Get("")
defer c.Close()
if (err != nil) && (err.Error() != simple.NameRequiredError) {
t.Errorf("Expected error: %v, but got %v", simple.NameRequiredError, err)
}
c.Validate(t, receivedJob, err)
}
func TestUpdateJobViaBatch(t *testing.T) {
ns := api.NamespaceDefault
requestJob := &extensions.Job{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Namespace: ns,
ResourceVersion: "1",
},
}
c := &simple.Client{
Request: simple.Request{
Method: "PUT",
Path: testapi.Batch.ResourcePath(getJobResourceName(), ns, "foo"),
Query: simple.BuildQueryValues(nil),
},
Response: simple.Response{
StatusCode: 200,
Body: &extensions.Job{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Labels: map[string]string{
"foo": "bar",
"name": "baz",
},
},
Spec: extensions.JobSpec{
Template: api.PodTemplateSpec{},
},
},
},
}
receivedJob, err := c.Setup(t).Batch().Jobs(ns).Update(requestJob)
defer c.Close()
c.Validate(t, receivedJob, err)
}
func TestUpdateJobStatusViaBatch(t *testing.T) {
ns := api.NamespaceDefault
requestJob := &extensions.Job{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Namespace: ns,
ResourceVersion: "1",
},
}
c := &simple.Client{
Request: simple.Request{
Method: "PUT",
Path: testapi.Batch.ResourcePath(getJobResourceName(), ns, "foo") + "/status",
Query: simple.BuildQueryValues(nil),
},
Response: simple.Response{
StatusCode: 200,
Body: &extensions.Job{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Labels: map[string]string{
"foo": "bar",
"name": "baz",
},
},
Spec: extensions.JobSpec{
Template: api.PodTemplateSpec{},
},
Status: extensions.JobStatus{
Active: 1,
},
},
},
}
receivedJob, err := c.Setup(t).Batch().Jobs(ns).UpdateStatus(requestJob)
defer c.Close()
c.Validate(t, receivedJob, err)
}
func TestDeleteJobViaBatch(t *testing.T) {
ns := api.NamespaceDefault
c := &simple.Client{
Request: simple.Request{
Method: "DELETE",
Path: testapi.Batch.ResourcePath(getJobResourceName(), ns, "foo"),
Query: simple.BuildQueryValues(nil),
},
Response: simple.Response{StatusCode: 200},
}
err := c.Setup(t).Batch().Jobs(ns).Delete("foo", nil)
defer c.Close()
c.Validate(t, nil, err)
}
func TestCreateJobViaBatch(t *testing.T) {
ns := api.NamespaceDefault
requestJob := &extensions.Job{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Namespace: ns,
},
}
c := &simple.Client{
Request: simple.Request{
Method: "POST",
Path: testapi.Batch.ResourcePath(getJobResourceName(), ns, ""),
Body: requestJob,
Query: simple.BuildQueryValues(nil),
},
Response: simple.Response{
StatusCode: 200,
Body: &extensions.Job{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Labels: map[string]string{
"foo": "bar",
"name": "baz",
},
},
Spec: extensions.JobSpec{
Template: api.PodTemplateSpec{},
},
},
},
}
receivedJob, err := c.Setup(t).Batch().Jobs(ns).Create(requestJob)
defer c.Close()
c.Validate(t, receivedJob, err)
} }

View File

@ -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
}

View File

@ -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()},

View File

@ -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
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...)}

View File

@ -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

View File

@ -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 {
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 {
} }
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")