mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-03 01:06:27 +00:00
Merge pull request #13254 from soltysh/job_controller_kubectl
Job resource - kubectl part
This commit is contained in:
commit
b2c74a7297
@ -291,6 +291,7 @@ _kubectl_get()
|
|||||||
must_have_one_noun+=("endpoints")
|
must_have_one_noun+=("endpoints")
|
||||||
must_have_one_noun+=("event")
|
must_have_one_noun+=("event")
|
||||||
must_have_one_noun+=("horizontalpodautoscaler")
|
must_have_one_noun+=("horizontalpodautoscaler")
|
||||||
|
must_have_one_noun+=("job")
|
||||||
must_have_one_noun+=("limitrange")
|
must_have_one_noun+=("limitrange")
|
||||||
must_have_one_noun+=("namespace")
|
must_have_one_noun+=("namespace")
|
||||||
must_have_one_noun+=("node")
|
must_have_one_noun+=("node")
|
||||||
@ -459,6 +460,7 @@ _kubectl_delete()
|
|||||||
must_have_one_noun+=("endpoints")
|
must_have_one_noun+=("endpoints")
|
||||||
must_have_one_noun+=("event")
|
must_have_one_noun+=("event")
|
||||||
must_have_one_noun+=("horizontalpodautoscaler")
|
must_have_one_noun+=("horizontalpodautoscaler")
|
||||||
|
must_have_one_noun+=("job")
|
||||||
must_have_one_noun+=("limitrange")
|
must_have_one_noun+=("limitrange")
|
||||||
must_have_one_noun+=("namespace")
|
must_have_one_noun+=("namespace")
|
||||||
must_have_one_noun+=("node")
|
must_have_one_noun+=("node")
|
||||||
@ -829,6 +831,7 @@ _kubectl_label()
|
|||||||
must_have_one_noun+=("endpoints")
|
must_have_one_noun+=("endpoints")
|
||||||
must_have_one_noun+=("event")
|
must_have_one_noun+=("event")
|
||||||
must_have_one_noun+=("horizontalpodautoscaler")
|
must_have_one_noun+=("horizontalpodautoscaler")
|
||||||
|
must_have_one_noun+=("job")
|
||||||
must_have_one_noun+=("limitrange")
|
must_have_one_noun+=("limitrange")
|
||||||
must_have_one_noun+=("namespace")
|
must_have_one_noun+=("namespace")
|
||||||
must_have_one_noun+=("node")
|
must_have_one_noun+=("node")
|
||||||
|
@ -36,6 +36,7 @@ type ExperimentalInterface interface {
|
|||||||
ScaleNamespacer
|
ScaleNamespacer
|
||||||
DaemonSetsNamespacer
|
DaemonSetsNamespacer
|
||||||
DeploymentsNamespacer
|
DeploymentsNamespacer
|
||||||
|
JobsNamespacer
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExperimentalClient is used to interact with experimental Kubernetes features.
|
// ExperimentalClient is used to interact with experimental Kubernetes features.
|
||||||
@ -90,6 +91,10 @@ func (c *ExperimentalClient) Deployments(namespace string) DeploymentInterface {
|
|||||||
return newDeployments(c, namespace)
|
return newDeployments(c, namespace)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *ExperimentalClient) Jobs(namespace string) JobInterface {
|
||||||
|
return newJobs(c, namespace)
|
||||||
|
}
|
||||||
|
|
||||||
// NewExperimental creates a new ExperimentalClient for the given config. This client
|
// NewExperimental creates a new ExperimentalClient for the given config. This client
|
||||||
// provides access to experimental Kubernetes features.
|
// provides access to experimental Kubernetes features.
|
||||||
// Experimental features are not supported and may be changed or removed in
|
// Experimental features are not supported and may be changed or removed in
|
||||||
|
112
pkg/client/unversioned/jobs.go
Normal file
112
pkg/client/unversioned/jobs.go
Normal file
@ -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"
|
||||||
|
)
|
||||||
|
|
||||||
|
// JobsNamespacer has methods to work with Job resources in a namespace
|
||||||
|
type JobsNamespacer interface {
|
||||||
|
Jobs(namespace string) JobInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
// JobInterface exposes methods to work on Job resources.
|
||||||
|
type JobInterface interface {
|
||||||
|
List(label labels.Selector, field fields.Selector) (*experimental.JobList, error)
|
||||||
|
Get(name string) (*experimental.Job, error)
|
||||||
|
Create(job *experimental.Job) (*experimental.Job, error)
|
||||||
|
Update(job *experimental.Job) (*experimental.Job, error)
|
||||||
|
Delete(name string, options *api.DeleteOptions) error
|
||||||
|
Watch(label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error)
|
||||||
|
UpdateStatus(job *experimental.Job) (*experimental.Job, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// jobs implements JobsNamespacer interface
|
||||||
|
type jobs struct {
|
||||||
|
r *ExperimentalClient
|
||||||
|
ns string
|
||||||
|
}
|
||||||
|
|
||||||
|
// newJobs returns a jobs
|
||||||
|
func newJobs(c *ExperimentalClient, namespace string) *jobs {
|
||||||
|
return &jobs{c, namespace}
|
||||||
|
}
|
||||||
|
|
||||||
|
// List returns a list of jobs that match the label and field selectors.
|
||||||
|
func (c *jobs) List(label labels.Selector, field fields.Selector) (result *experimental.JobList, err error) {
|
||||||
|
result = &experimental.JobList{}
|
||||||
|
err = c.r.Get().Namespace(c.ns).Resource("jobs").LabelsSelectorParam(label).FieldsSelectorParam(field).Do().Into(result)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns information about a particular job.
|
||||||
|
func (c *jobs) Get(name string) (result *experimental.Job, err error) {
|
||||||
|
result = &experimental.Job{}
|
||||||
|
err = c.r.Get().Namespace(c.ns).Resource("jobs").Name(name).Do().Into(result)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create creates a new job.
|
||||||
|
func (c *jobs) Create(job *experimental.Job) (result *experimental.Job, err error) {
|
||||||
|
result = &experimental.Job{}
|
||||||
|
err = c.r.Post().Namespace(c.ns).Resource("jobs").Body(job).Do().Into(result)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update updates an existing job.
|
||||||
|
func (c *jobs) Update(job *experimental.Job) (result *experimental.Job, err error) {
|
||||||
|
result = &experimental.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 *jobs) Delete(name string, options *api.DeleteOptions) (err error) {
|
||||||
|
if options == nil {
|
||||||
|
return c.r.Delete().Namespace(c.ns).Resource("jobs").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("jobs").Name(name).Body(body).Do().Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Watch returns a watch.Interface that watches the requested jobs.
|
||||||
|
func (c *jobs) Watch(label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) {
|
||||||
|
return c.r.Get().
|
||||||
|
Prefix("watch").
|
||||||
|
Namespace(c.ns).
|
||||||
|
Resource("jobs").
|
||||||
|
Param("resourceVersion", resourceVersion).
|
||||||
|
LabelsSelectorParam(label).
|
||||||
|
FieldsSelectorParam(field).
|
||||||
|
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 *jobs) UpdateStatus(job *experimental.Job) (result *experimental.Job, err error) {
|
||||||
|
result = &experimental.Job{}
|
||||||
|
err = c.r.Put().Namespace(c.ns).Resource("jobs").Name(job.Name).SubResource("status").Body(job).Do().Into(result)
|
||||||
|
return
|
||||||
|
}
|
222
pkg/client/unversioned/jobs_test.go
Normal file
222
pkg/client/unversioned/jobs_test.go
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
/*
|
||||||
|
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 getJobResourceName() string {
|
||||||
|
return "jobs"
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestListJobs(t *testing.T) {
|
||||||
|
ns := api.NamespaceAll
|
||||||
|
c := &testClient{
|
||||||
|
Request: testRequest{
|
||||||
|
Method: "GET",
|
||||||
|
Path: testapi.Experimental.ResourcePath(getJobResourceName(), ns, ""),
|
||||||
|
},
|
||||||
|
Response: Response{StatusCode: 200,
|
||||||
|
Body: &experimental.JobList{
|
||||||
|
Items: []experimental.Job{
|
||||||
|
{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "foo",
|
||||||
|
Labels: map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
"name": "baz",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: experimental.JobSpec{
|
||||||
|
Template: &api.PodTemplateSpec{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
receivedJobList, err := c.Setup(t).Experimental().Jobs(ns).List(labels.Everything(), fields.Everything())
|
||||||
|
c.Validate(t, receivedJobList, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetJob(t *testing.T) {
|
||||||
|
ns := api.NamespaceDefault
|
||||||
|
c := &testClient{
|
||||||
|
Request: testRequest{
|
||||||
|
Method: "GET",
|
||||||
|
Path: testapi.Experimental.ResourcePath(getJobResourceName(), ns, "foo"),
|
||||||
|
Query: buildQueryValues(nil),
|
||||||
|
},
|
||||||
|
Response: Response{
|
||||||
|
StatusCode: 200,
|
||||||
|
Body: &experimental.Job{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "foo",
|
||||||
|
Labels: map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
"name": "baz",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: experimental.JobSpec{
|
||||||
|
Template: &api.PodTemplateSpec{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
receivedJob, err := c.Setup(t).Experimental().Jobs(ns).Get("foo")
|
||||||
|
c.Validate(t, receivedJob, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetJobWithNoName(t *testing.T) {
|
||||||
|
ns := api.NamespaceDefault
|
||||||
|
c := &testClient{Error: true}
|
||||||
|
receivedJob, err := c.Setup(t).Experimental().Jobs(ns).Get("")
|
||||||
|
if (err != nil) && (err.Error() != nameRequiredError) {
|
||||||
|
t.Errorf("Expected error: %v, but got %v", nameRequiredError, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Validate(t, receivedJob, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdateJob(t *testing.T) {
|
||||||
|
ns := api.NamespaceDefault
|
||||||
|
requestJob := &experimental.Job{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "foo",
|
||||||
|
Namespace: ns,
|
||||||
|
ResourceVersion: "1",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
c := &testClient{
|
||||||
|
Request: testRequest{
|
||||||
|
Method: "PUT",
|
||||||
|
Path: testapi.Experimental.ResourcePath(getJobResourceName(), ns, "foo"),
|
||||||
|
Query: buildQueryValues(nil),
|
||||||
|
},
|
||||||
|
Response: Response{
|
||||||
|
StatusCode: 200,
|
||||||
|
Body: &experimental.Job{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "foo",
|
||||||
|
Labels: map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
"name": "baz",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: experimental.JobSpec{
|
||||||
|
Template: &api.PodTemplateSpec{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
receivedJob, err := c.Setup(t).Experimental().Jobs(ns).Update(requestJob)
|
||||||
|
c.Validate(t, receivedJob, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdateJobStatus(t *testing.T) {
|
||||||
|
ns := api.NamespaceDefault
|
||||||
|
requestJob := &experimental.Job{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "foo",
|
||||||
|
Namespace: ns,
|
||||||
|
ResourceVersion: "1",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
c := &testClient{
|
||||||
|
Request: testRequest{
|
||||||
|
Method: "PUT",
|
||||||
|
Path: testapi.Experimental.ResourcePath(getJobResourceName(), ns, "foo") + "/status",
|
||||||
|
Query: buildQueryValues(nil),
|
||||||
|
},
|
||||||
|
Response: Response{
|
||||||
|
StatusCode: 200,
|
||||||
|
Body: &experimental.Job{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "foo",
|
||||||
|
Labels: map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
"name": "baz",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: experimental.JobSpec{
|
||||||
|
Template: &api.PodTemplateSpec{},
|
||||||
|
},
|
||||||
|
Status: experimental.JobStatus{
|
||||||
|
Active: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
receivedJob, err := c.Setup(t).Experimental().Jobs(ns).UpdateStatus(requestJob)
|
||||||
|
c.Validate(t, receivedJob, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteJob(t *testing.T) {
|
||||||
|
ns := api.NamespaceDefault
|
||||||
|
c := &testClient{
|
||||||
|
Request: testRequest{
|
||||||
|
Method: "DELETE",
|
||||||
|
Path: testapi.Experimental.ResourcePath(getJobResourceName(), ns, "foo"),
|
||||||
|
Query: buildQueryValues(nil),
|
||||||
|
},
|
||||||
|
Response: Response{StatusCode: 200},
|
||||||
|
}
|
||||||
|
err := c.Setup(t).Experimental().Jobs(ns).Delete("foo", nil)
|
||||||
|
c.Validate(t, nil, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateJob(t *testing.T) {
|
||||||
|
ns := api.NamespaceDefault
|
||||||
|
requestJob := &experimental.Job{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "foo",
|
||||||
|
Namespace: ns,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
c := &testClient{
|
||||||
|
Request: testRequest{
|
||||||
|
Method: "POST",
|
||||||
|
Path: testapi.Experimental.ResourcePath(getJobResourceName(), ns, ""),
|
||||||
|
Body: requestJob,
|
||||||
|
Query: buildQueryValues(nil),
|
||||||
|
},
|
||||||
|
Response: Response{
|
||||||
|
StatusCode: 200,
|
||||||
|
Body: &experimental.Job{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "foo",
|
||||||
|
Labels: map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
"name": "baz",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: experimental.JobSpec{
|
||||||
|
Template: &api.PodTemplateSpec{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
receivedJob, err := c.Setup(t).Experimental().Jobs(ns).Create(requestJob)
|
||||||
|
c.Validate(t, receivedJob, err)
|
||||||
|
}
|
@ -261,3 +261,7 @@ func (c *FakeExperimental) Deployments(namespace string) client.DeploymentInterf
|
|||||||
func (c *FakeExperimental) Scales(namespace string) client.ScaleInterface {
|
func (c *FakeExperimental) Scales(namespace string) client.ScaleInterface {
|
||||||
return &FakeScales{Fake: c, Namespace: namespace}
|
return &FakeScales{Fake: c, Namespace: namespace}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *FakeExperimental) Jobs(namespace string) client.JobInterface {
|
||||||
|
panic("unimplemented")
|
||||||
|
}
|
||||||
|
@ -28,6 +28,7 @@ import (
|
|||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/resource"
|
"k8s.io/kubernetes/pkg/api/resource"
|
||||||
|
"k8s.io/kubernetes/pkg/apis/experimental"
|
||||||
client "k8s.io/kubernetes/pkg/client/unversioned"
|
client "k8s.io/kubernetes/pkg/client/unversioned"
|
||||||
"k8s.io/kubernetes/pkg/fieldpath"
|
"k8s.io/kubernetes/pkg/fieldpath"
|
||||||
"k8s.io/kubernetes/pkg/fields"
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
@ -85,6 +86,7 @@ func describerMap(c *client.Client) map[string]Describer {
|
|||||||
func expDescriberMap(c *client.Client) map[string]Describer {
|
func expDescriberMap(c *client.Client) map[string]Describer {
|
||||||
return map[string]Describer{
|
return map[string]Describer{
|
||||||
"HorizontalPodAutoscaler": &HorizontalPodAutoscalerDescriber{c},
|
"HorizontalPodAutoscaler": &HorizontalPodAutoscalerDescriber{c},
|
||||||
|
"Job": &JobDescriber{c},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -854,6 +856,46 @@ func describeReplicationController(controller *api.ReplicationController, events
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// JobDescriber generates information about a job and the pods it has created.
|
||||||
|
type JobDescriber struct {
|
||||||
|
client *client.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *JobDescriber) Describe(namespace, name string) (string, error) {
|
||||||
|
job, err := d.client.Experimental().Jobs(namespace).Get(name)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
events, _ := d.client.Events(namespace).Search(job)
|
||||||
|
|
||||||
|
return describeJob(job, events)
|
||||||
|
}
|
||||||
|
|
||||||
|
func describeJob(job *experimental.Job, events *api.EventList) (string, error) {
|
||||||
|
return tabbedString(func(out io.Writer) error {
|
||||||
|
fmt.Fprintf(out, "Name:\t%s\n", job.Name)
|
||||||
|
fmt.Fprintf(out, "Namespace:\t%s\n", job.Namespace)
|
||||||
|
if job.Spec.Template != nil {
|
||||||
|
fmt.Fprintf(out, "Image(s):\t%s\n", makeImageList(&job.Spec.Template.Spec))
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(out, "Image(s):\t%s\n", "<no template>")
|
||||||
|
}
|
||||||
|
fmt.Fprintf(out, "Selector:\t%s\n", labels.FormatLabels(job.Spec.Selector))
|
||||||
|
fmt.Fprintf(out, "Parallelism:\t%d\n", job.Spec.Parallelism)
|
||||||
|
fmt.Fprintf(out, "Completions:\t%d\n", job.Spec.Completions)
|
||||||
|
fmt.Fprintf(out, "Labels:\t%s\n", labels.FormatLabels(job.Labels))
|
||||||
|
fmt.Fprintf(out, "Pods Statuses:\t%d Running / %d Succeeded / %d Failed\n", job.Status.Active, job.Status.Successful, job.Status.Unsuccessful)
|
||||||
|
if job.Spec.Template != nil {
|
||||||
|
describeVolumes(job.Spec.Template.Spec.Volumes, out)
|
||||||
|
}
|
||||||
|
if events != nil {
|
||||||
|
DescribeEvents(events, out)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// SecretDescriber generates information about a secret
|
// SecretDescriber generates information about a secret
|
||||||
type SecretDescriber struct {
|
type SecretDescriber struct {
|
||||||
client.Interface
|
client.Interface
|
||||||
|
@ -380,6 +380,7 @@ func (h *HumanReadablePrinter) HandledResources() []string {
|
|||||||
var podColumns = []string{"NAME", "READY", "STATUS", "RESTARTS", "AGE"}
|
var podColumns = []string{"NAME", "READY", "STATUS", "RESTARTS", "AGE"}
|
||||||
var podTemplateColumns = []string{"TEMPLATE", "CONTAINER(S)", "IMAGE(S)", "PODLABELS"}
|
var podTemplateColumns = []string{"TEMPLATE", "CONTAINER(S)", "IMAGE(S)", "PODLABELS"}
|
||||||
var replicationControllerColumns = []string{"CONTROLLER", "CONTAINER(S)", "IMAGE(S)", "SELECTOR", "REPLICAS", "AGE"}
|
var replicationControllerColumns = []string{"CONTROLLER", "CONTAINER(S)", "IMAGE(S)", "SELECTOR", "REPLICAS", "AGE"}
|
||||||
|
var jobColumns = []string{"JOB", "CONTAINER(S)", "IMAGE(S)", "SELECTOR", "SUCCESSFUL"}
|
||||||
var serviceColumns = []string{"NAME", "CLUSTER_IP", "EXTERNAL_IP", "PORT(S)", "SELECTOR", "AGE"}
|
var serviceColumns = []string{"NAME", "CLUSTER_IP", "EXTERNAL_IP", "PORT(S)", "SELECTOR", "AGE"}
|
||||||
var endpointColumns = []string{"NAME", "ENDPOINTS", "AGE"}
|
var endpointColumns = []string{"NAME", "ENDPOINTS", "AGE"}
|
||||||
var nodeColumns = []string{"NAME", "LABELS", "STATUS", "AGE"}
|
var nodeColumns = []string{"NAME", "LABELS", "STATUS", "AGE"}
|
||||||
@ -405,6 +406,8 @@ func (h *HumanReadablePrinter) addDefaultHandlers() {
|
|||||||
h.Handler(podTemplateColumns, printPodTemplateList)
|
h.Handler(podTemplateColumns, printPodTemplateList)
|
||||||
h.Handler(replicationControllerColumns, printReplicationController)
|
h.Handler(replicationControllerColumns, printReplicationController)
|
||||||
h.Handler(replicationControllerColumns, printReplicationControllerList)
|
h.Handler(replicationControllerColumns, printReplicationControllerList)
|
||||||
|
h.Handler(jobColumns, printJob)
|
||||||
|
h.Handler(jobColumns, printJobList)
|
||||||
h.Handler(serviceColumns, printService)
|
h.Handler(serviceColumns, printService)
|
||||||
h.Handler(serviceColumns, printServiceList)
|
h.Handler(serviceColumns, printServiceList)
|
||||||
h.Handler(endpointColumns, printEndpoints)
|
h.Handler(endpointColumns, printEndpoints)
|
||||||
@ -655,7 +658,6 @@ func printPodTemplateList(podList *api.PodTemplateList, w io.Writer, withNamespa
|
|||||||
func printReplicationController(controller *api.ReplicationController, w io.Writer, withNamespace bool, wide bool, showAll bool, columnLabels []string) error {
|
func printReplicationController(controller *api.ReplicationController, w io.Writer, withNamespace bool, wide bool, showAll bool, columnLabels []string) error {
|
||||||
name := controller.Name
|
name := controller.Name
|
||||||
namespace := controller.Namespace
|
namespace := controller.Namespace
|
||||||
|
|
||||||
containers := controller.Spec.Template.Spec.Containers
|
containers := controller.Spec.Template.Spec.Containers
|
||||||
var firstContainer api.Container
|
var firstContainer api.Container
|
||||||
if len(containers) > 0 {
|
if len(containers) > 0 {
|
||||||
@ -707,6 +709,33 @@ func printReplicationControllerList(list *api.ReplicationControllerList, w io.Wr
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func printJob(job *experimental.Job, w io.Writer, withNamespace bool, wide bool, showAll bool, columnLabels []string) error {
|
||||||
|
containers := job.Spec.Template.Spec.Containers
|
||||||
|
var firstContainer api.Container
|
||||||
|
if len(containers) > 0 {
|
||||||
|
firstContainer = containers[0]
|
||||||
|
}
|
||||||
|
_, err := fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%d\n",
|
||||||
|
job.Name,
|
||||||
|
firstContainer.Name,
|
||||||
|
firstContainer.Image,
|
||||||
|
labels.FormatLabels(job.Spec.Selector),
|
||||||
|
job.Status.Successful)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func printJobList(list *experimental.JobList, w io.Writer, withNamespace bool, wide bool, showAll bool, columnLabels []string) error {
|
||||||
|
for _, job := range list.Items {
|
||||||
|
if err := printJob(&job, w, withNamespace, wide, showAll, columnLabels); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func getServiceExternalIP(svc *api.Service) string {
|
func getServiceExternalIP(svc *api.Service) string {
|
||||||
switch svc.Spec.Type {
|
switch svc.Spec.Type {
|
||||||
case api.ServiceTypeClusterIP:
|
case api.ServiceTypeClusterIP:
|
||||||
|
@ -14,6 +14,6 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Package controller provides Registry interface and it's RESTStorage
|
// Package job provides Registry interface and it's RESTStorage
|
||||||
// implementation for storing Job api objects.
|
// implementation for storing Job api objects.
|
||||||
package job
|
package job
|
||||||
|
@ -28,7 +28,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/storage"
|
"k8s.io/kubernetes/pkg/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
// rest implements a RESTStorage for jobs against etcd
|
// REST implements a RESTStorage for jobs against etcd
|
||||||
type REST struct {
|
type REST struct {
|
||||||
*etcdgeneric.Etcd
|
*etcdgeneric.Etcd
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user