Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add more vkctl command and fix bugs #253

Merged
merged 7 commits into from
Jul 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion cmd/cli/vkctl.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/spf13/pflag"

"k8s.io/apimachinery/pkg/util/wait"

"volcano.sh/volcano/pkg/version"
)

Expand All @@ -45,7 +46,7 @@ func main() {
rootCmd.AddCommand(versionCommand())

if err := rootCmd.Execute(); err != nil {
fmt.Printf("Failed to execute command: %v", err)
fmt.Printf("Failed to execute command: %v\n", err)
}
}

Expand Down
4 changes: 2 additions & 2 deletions pkg/cli/job/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ var deleteJobFlags = &deleteFlags{}
func InitDeleteFlags(cmd *cobra.Command) {
initFlags(cmd, &deleteJobFlags.commonFlags)

cmd.Flags().StringVarP(&deleteJobFlags.Namespace, "namespace", "N", "default", "the namespace of job")
cmd.Flags().StringVarP(&deleteJobFlags.JobName, "name", "n", "", "the name of job")
cmd.Flags().StringVarP(&deleteJobFlags.Namespace, "namespace", "n", "default", "the namespace of job")
cmd.Flags().StringVarP(&deleteJobFlags.JobName, "name", "N", "", "the name of job")
}

// DeleteJob delete the job
Expand Down
14 changes: 12 additions & 2 deletions pkg/cli/job/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"fmt"
"io"
"os"
"strings"

"github.com/spf13/cobra"

Expand All @@ -34,6 +35,8 @@ type listFlags struct {

Namespace string
SchedulerName string
allNamespace bool
selector string
}

const (
Expand Down Expand Up @@ -74,8 +77,10 @@ var listJobFlags = &listFlags{}
func InitListFlags(cmd *cobra.Command) {
initFlags(cmd, &listJobFlags.commonFlags)

cmd.Flags().StringVarP(&listJobFlags.Namespace, "namespace", "N", "default", "the namespace of job")
cmd.Flags().StringVarP(&listJobFlags.Namespace, "namespace", "n", "default", "the namespace of job")
cmd.Flags().StringVarP(&listJobFlags.SchedulerName, "scheduler", "S", "", "list job with specified scheduler name")
cmd.Flags().BoolVarP(&listJobFlags.allNamespace, "all-namespaces", "", false, "list jobs in all namespaces")
cmd.Flags().StringVarP(&listJobFlags.selector, "selector", "", "", "fuzzy matching jobName")
}

// ListJobs lists all jobs details
Expand All @@ -84,7 +89,9 @@ func ListJobs() error {
if err != nil {
return err
}

if listJobFlags.allNamespace {
listJobFlags.Namespace = ""
}
jobClient := versioned.NewForConfigOrDie(config)
jobs, err := jobClient.BatchV1alpha1().Jobs(listJobFlags.Namespace).List(metav1.ListOptions{})
if err != nil {
Expand Down Expand Up @@ -113,6 +120,9 @@ func PrintJobs(jobs *v1alpha1.JobList, writer io.Writer) {
if listJobFlags.SchedulerName != "" && listJobFlags.SchedulerName != job.Spec.SchedulerName {
continue
}
if !strings.Contains(job.Name, listJobFlags.selector) {
continue
}
replicas := int32(0)
for _, ts := range job.Spec.Tasks {
replicas += ts.Replicas
Expand Down
29 changes: 24 additions & 5 deletions pkg/cli/job/list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,20 +42,33 @@ func TestListJob(t *testing.T) {
server := httptest.NewServer(handler)
defer server.Close()

listJobFlags.Master = server.URL
listJobFlags.Namespace = "test"

testCases := []struct {
Name string
ExpectValue error
Name string
ExpectValue error
AllNamespace bool
Selector string
}{
{
Name: "ListJob",
ExpectValue: nil,
},
{
Name: "ListAllNamespaceJob",
ExpectValue: nil,
AllNamespace: true,
},
}

for i, testcase := range testCases {
listJobFlags = &listFlags{
commonFlags: commonFlags{
Master: server.URL,
},
Namespace: "test",
allNamespace: testcase.AllNamespace,
selector: testcase.Selector,
}

err := ListJobs()
if err != nil {
t.Errorf("case %d (%s): expected: %v, got %v ", i, testcase.Name, testcase.ExpectValue, err)
Expand All @@ -74,5 +87,11 @@ func TestInitListFlags(t *testing.T) {
if cmd.Flag("scheduler") == nil {
t.Errorf("Could not find the flag scheduler")
}
if cmd.Flag("all-namespaces") == nil {
t.Errorf("Could not find the flag all-namespaces")
}
if cmd.Flag("selector") == nil {
t.Errorf("Could not find the flag selector")
}

}
4 changes: 2 additions & 2 deletions pkg/cli/job/resume.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ var resumeJobFlags = &resumeFlags{}
func InitResumeFlags(cmd *cobra.Command) {
initFlags(cmd, &resumeJobFlags.commonFlags)

cmd.Flags().StringVarP(&resumeJobFlags.Namespace, "namespace", "N", "default", "the namespace of job")
cmd.Flags().StringVarP(&resumeJobFlags.JobName, "name", "n", "", "the name of job")
cmd.Flags().StringVarP(&resumeJobFlags.Namespace, "namespace", "n", "default", "the namespace of job")
cmd.Flags().StringVarP(&resumeJobFlags.JobName, "name", "N", "", "the name of job")
}

// ResumeJob resumes the job
Expand Down
69 changes: 56 additions & 13 deletions pkg/cli/job/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,15 @@ limitations under the License.
package job

import (
"fmt"
"io/ioutil"
"strings"

"github.com/spf13/cobra"

"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/yaml"

vkapi "volcano.sh/volcano/pkg/apis/batch/v1alpha1"
"volcano.sh/volcano/pkg/client/clientset/versioned"
Expand All @@ -38,6 +43,7 @@ type runFlags struct {
Requests string
Limits string
SchedulerName string
FileName string
}

var launchJobFlags = &runFlags{}
Expand All @@ -47,13 +53,14 @@ func InitRunFlags(cmd *cobra.Command) {
initFlags(cmd, &launchJobFlags.commonFlags)

cmd.Flags().StringVarP(&launchJobFlags.Image, "image", "i", "busybox", "the container image of job")
cmd.Flags().StringVarP(&launchJobFlags.Namespace, "namespace", "N", "default", "the namespace of job")
cmd.Flags().StringVarP(&launchJobFlags.Name, "name", "n", "test", "the name of job")
cmd.Flags().StringVarP(&launchJobFlags.Namespace, "namespace", "n", "default", "the namespace of job")
cmd.Flags().StringVarP(&launchJobFlags.Name, "name", "N", "test", "the name of job")
cmd.Flags().IntVarP(&launchJobFlags.MinAvailable, "min", "m", 1, "the minimal available tasks of job")
cmd.Flags().IntVarP(&launchJobFlags.Replicas, "replicas", "r", 1, "the total tasks of job")
cmd.Flags().StringVarP(&launchJobFlags.Requests, "requests", "R", "cpu=1000m,memory=100Mi", "the resource request of the task")
cmd.Flags().StringVarP(&launchJobFlags.Limits, "limits", "L", "cpu=1000m,memory=100Mi", "the resource limit of the task")
cmd.Flags().StringVarP(&listJobFlags.SchedulerName, "scheduler", "S", "kube-batch", "the scheduler for this job")
cmd.Flags().StringVarP(&launchJobFlags.SchedulerName, "scheduler", "S", "kube-batch", "the scheduler for this job")
cmd.Flags().StringVarP(&launchJobFlags.FileName, "filename", "f", "", "the yaml file of job")
}

var jobName = "job.volcano.sh"
Expand All @@ -75,13 +82,57 @@ func RunJob() error {
return err
}

job := &vkapi.Job{
job, err := readFile(launchJobFlags.FileName)
if err != nil {
return err
}

if job == nil {
job = constructLaunchJobFlagsJob(launchJobFlags, req, limit)
}

jobClient := versioned.NewForConfigOrDie(config)
newJob, err := jobClient.BatchV1alpha1().Jobs(launchJobFlags.Namespace).Create(job)
if err != nil {
return err
}

fmt.Printf("run job %v successfully\n", newJob.Name)

return nil
}

func readFile(filename string) (*vkapi.Job, error) {
if filename == "" {
return nil, nil
}

if !strings.Contains(filename, ".yaml") && !strings.Contains(filename, ".yml") {
return nil, fmt.Errorf("only support yaml file")
}

file, err := ioutil.ReadFile(filename)
if err != nil {
return nil, fmt.Errorf("failed to read file, err: %v", err)
}

var job vkapi.Job
if err := yaml.Unmarshal(file, &job); err != nil {
return nil, fmt.Errorf("Failed to unmarshal file, err: %v", err)
}

return &job, nil
}

func constructLaunchJobFlagsJob(launchJobFlags *runFlags, req, limit v1.ResourceList) *vkapi.Job {
return &vkapi.Job{
ObjectMeta: metav1.ObjectMeta{
Name: launchJobFlags.Name,
Namespace: launchJobFlags.Namespace,
},
Spec: vkapi.JobSpec{
MinAvailable: int32(launchJobFlags.MinAvailable),
MinAvailable: int32(launchJobFlags.MinAvailable),
SchedulerName: launchJobFlags.SchedulerName,
Tasks: []vkapi.TaskSpec{
{
Replicas: int32(launchJobFlags.Replicas),
Expand All @@ -92,7 +143,6 @@ func RunJob() error {
Labels: map[string]string{jobName: launchJobFlags.Name},
},
Spec: v1.PodSpec{
SchedulerName: launchJobFlags.SchedulerName,
RestartPolicy: v1.RestartPolicyNever,
Containers: []v1.Container{
{
Expand All @@ -111,11 +161,4 @@ func RunJob() error {
},
},
}

jobClient := versioned.NewForConfigOrDie(config)
if _, err := jobClient.BatchV1alpha1().Jobs(launchJobFlags.Namespace).Create(job); err != nil {
return err
}

return nil
}
30 changes: 27 additions & 3 deletions pkg/cli/job/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@ package job
import (
"encoding/json"
"github.com/spf13/cobra"
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
"testing"
"time"

v1alpha1 "volcano.sh/volcano/pkg/apis/batch/v1alpha1"
)
Expand All @@ -41,21 +44,42 @@ func TestCreateJob(t *testing.T) {
server := httptest.NewServer(handler)
defer server.Close()

launchJobFlags.Master = server.URL
launchJobFlags.Namespace = "test"
launchJobFlags.Requests = "cpu=1000m,memory=100Mi"
fileName := time.Now().String() + "testCreateJob.yaml"
val, err := json.Marshal(response)
if err != nil {
panic(err)
}
err = ioutil.WriteFile(fileName, val, os.ModePerm)
if err != nil {
panic(err)
}
defer os.Remove(fileName)

testCases := []struct {
Name string
ExpectValue error
FileName string
}{
{
Name: "CreateJob",
ExpectValue: nil,
},
{
Name: "CreateJobWithFile",
FileName: fileName,
ExpectValue: nil,
},
}

for i, testcase := range testCases {
launchJobFlags = &runFlags{
commonFlags: commonFlags{
Master: server.URL,
},
Namespace: "test",
Requests: "cpu=1000m,memory=100Mi",
}

err := RunJob()
if err != nil {
t.Errorf("case %d (%s): expected: %v, got %v ", i, testcase.Name, testcase.ExpectValue, err)
Expand Down
4 changes: 2 additions & 2 deletions pkg/cli/job/suspend.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ var suspendJobFlags = &suspendFlags{}
func InitSuspendFlags(cmd *cobra.Command) {
initFlags(cmd, &suspendJobFlags.commonFlags)

cmd.Flags().StringVarP(&suspendJobFlags.Namespace, "namespace", "N", "default", "the namespace of job")
cmd.Flags().StringVarP(&suspendJobFlags.JobName, "name", "n", "", "the name of job")
cmd.Flags().StringVarP(&suspendJobFlags.Namespace, "namespace", "n", "default", "the namespace of job")
cmd.Flags().StringVarP(&suspendJobFlags.JobName, "name", "N", "", "the name of job")
}

// SuspendJob suspends the job
Expand Down
52 changes: 52 additions & 0 deletions pkg/cli/job/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"fmt"
"os"
"strings"
"time"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

Expand Down Expand Up @@ -97,3 +98,54 @@ func createJobCommand(config *rest.Config, ns, name string, action vkbatchv1.Act

return nil
}

func translateTimestampSince(timestamp metav1.Time) string {
if timestamp.IsZero() {
return "<unknown>"
}
return HumanDuration(time.Since(timestamp.Time))
}

// HumanDuration translate time.Duration to human readable time string
func HumanDuration(d time.Duration) string {
// Allow deviation no more than 2 seconds(excluded) to tolerate machine time
// inconsistence, it can be considered as almost now.
if seconds := int(d.Seconds()); seconds < -1 {
return fmt.Sprintf("<invalid>")
} else if seconds < 0 {
return fmt.Sprintf("0s")
} else if seconds < 60*2 {
return fmt.Sprintf("%ds", seconds)
}
minutes := int(d / time.Minute)
if minutes < 10 {
s := int(d/time.Second) % 60
if s == 0 {
return fmt.Sprintf("%dm", minutes)
}
return fmt.Sprintf("%dm%ds", minutes, s)
} else if minutes < 60*3 {
return fmt.Sprintf("%dm", minutes)
}
hours := int(d / time.Hour)
if hours < 8 {
m := int(d/time.Minute) % 60
if m == 0 {
return fmt.Sprintf("%dh", hours)
}
return fmt.Sprintf("%dh%dm", hours, m)
} else if hours < 48 {
return fmt.Sprintf("%dh", hours)
} else if hours < 24*8 {
h := hours % 24
if h == 0 {
return fmt.Sprintf("%dd", hours/24)
}
return fmt.Sprintf("%dd%dh", hours/24, h)
} else if hours < 24*365*2 {
return fmt.Sprintf("%dd", hours/24)
} else if hours < 24*365*8 {
return fmt.Sprintf("%dy%dd", hours/24/365, (hours/24)%365)
}
return fmt.Sprintf("%dy", int(hours/24/365))
}
Loading