Skip to content

Commit

Permalink
[kjobctl] Add job builder. (#2394)
Browse files Browse the repository at this point in the history
  • Loading branch information
mbobrovskyi authored Jun 26, 2024
1 parent 0b4c992 commit 7e37e0c
Show file tree
Hide file tree
Showing 9 changed files with 1,040 additions and 7 deletions.
7 changes: 3 additions & 4 deletions cmd/experimental/kjobctl/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ module sigs.k8s.io/kueue/cmd/experimental/kjobctl
go 1.22.3

require (
github.com/google/go-cmp v0.6.0
github.com/spf13/cobra v1.8.1
k8s.io/api v0.30.2
k8s.io/apimachinery v0.30.2
k8s.io/cli-runtime v0.30.2
k8s.io/client-go v0.30.2
k8s.io/klog/v2 v2.120.1
k8s.io/utils v0.0.0-20240102154912-e7106e64919e
sigs.k8s.io/controller-runtime v0.18.4
sigs.k8s.io/kueue v0.7.0
)

require (
Expand Down Expand Up @@ -41,12 +44,9 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/onsi/ginkgo/v2 v2.19.0 // indirect
github.com/onsi/gomega v1.33.1 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/xlab/treeprint v1.2.0 // indirect
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
golang.org/x/net v0.25.0 // indirect
Expand All @@ -62,7 +62,6 @@ require (
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
k8s.io/utils v0.0.0-20240102154912-e7106e64919e // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 // indirect
sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 // indirect
Expand Down
2 changes: 2 additions & 0 deletions cmd/experimental/kjobctl/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,8 @@ sigs.k8s.io/controller-runtime v0.18.4 h1:87+guW1zhvuPLh1PHybKdYFLU0YJp4FhJRmiHv
sigs.k8s.io/controller-runtime v0.18.4/go.mod h1:TVoGrfdpbA9VRFaRnKgk9P5/atA0pMwq+f+msb9M8Sg=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/kueue v0.7.0 h1:Rwg2Ce/0kjZwdov1XdsAFb11QQtOOHx7HCTwFSMd8wc=
sigs.k8s.io/kueue v0.7.0/go.mod h1:tjzIB8Y1vWwBJRWJsXByRIx89PGUq5/mzeLnYHZoFtk=
sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 h1:XX3Ajgzov2RKUdc5jW3t5jwY7Bo7dcRm+tFxT+NfgY0=
sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3/go.mod h1:9n16EZKMhXBNSiUC5kSdFQJkdH3zbxS/JoO619G1VAY=
sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 h1:W6cLQc5pnqM7vh3b7HvGNfXrJ/xL6BDMS0v1V/HHg5U=
Expand Down
217 changes: 217 additions & 0 deletions cmd/experimental/kjobctl/pkg/builder/builder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
/*
Copyright 2024 The Kubernetes Authors.
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 builder

import (
"context"
"errors"
"slices"

corev1 "k8s.io/api/core/v1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
k8s "k8s.io/client-go/kubernetes"

"sigs.k8s.io/kueue/cmd/experimental/kjobctl/apis/v1alpha1"
"sigs.k8s.io/kueue/cmd/experimental/kjobctl/client-go/clientset/versioned"
"sigs.k8s.io/kueue/cmd/experimental/kjobctl/pkg/cmd/util"
)

var (
noNamespaceSpecifiedErr = errors.New("no namespace specified")
noApplicationProfileSpecifiedErr = errors.New("no application profile specified")
noApplicationProfileModeSpecifiedErr = errors.New("no application profile mode specified")
invalidApplicationProfileModeErr = errors.New("invalid application profile mode")
applicationProfileModeNotConfiguredErr = errors.New("application profile mode not configured")
noCommandSpecifiedErr = errors.New("no command specified")
noParallelismSpecifiedErr = errors.New("no parallelism specified")
noCompletionsSpecifiedErr = errors.New("no completions specified")
noRequestsSpecifiedErr = errors.New("no requests specified")
noLocalQueueSpecifiedErr = errors.New("no local queue specified")
)

type builder interface {
build(ctx context.Context) (runtime.Object, error)
}

type Builder struct {
clientGetter util.ClientGetter
kjobctlClientset versioned.Interface
k8sClientset k8s.Interface

namespace string
profileName string
modeName v1alpha1.ApplicationProfileMode

command []string
parallelism *int32
completions *int32
requests corev1.ResourceList
localQueue string

profile *v1alpha1.ApplicationProfile
mode *v1alpha1.SupportedMode
volumeBundles []v1alpha1.VolumeBundle
}

func NewBuilder(clientGetter util.ClientGetter) *Builder {
return &Builder{clientGetter: clientGetter}
}

func (b *Builder) WithNamespace(namespace string) *Builder {
b.namespace = namespace
return b
}

func (b *Builder) WithProfileName(profileName string) *Builder {
b.profileName = profileName
return b
}

func (b *Builder) WithModeName(modeName v1alpha1.ApplicationProfileMode) *Builder {
b.modeName = modeName
return b
}

func (b *Builder) WithCommand(command []string) *Builder {
b.command = command
return b
}

func (b *Builder) WithParallelism(parallelism *int32) *Builder {
b.parallelism = parallelism
return b
}

func (b *Builder) WithCompletions(completions *int32) *Builder {
b.completions = completions
return b
}

func (b *Builder) WithRequests(requests corev1.ResourceList) *Builder {
b.requests = requests
return b
}

func (b *Builder) WithLocalQueue(localQueue string) *Builder {
b.localQueue = localQueue
return b
}

func (b *Builder) validateGeneral() error {
if b.namespace == "" {
return noNamespaceSpecifiedErr
}

if b.profileName == "" {
return noApplicationProfileSpecifiedErr
}

if b.modeName == "" {
return noApplicationProfileModeSpecifiedErr
}

return nil
}

func (b *Builder) complete(ctx context.Context) error {
var err error

b.kjobctlClientset, err = b.clientGetter.KjobctlClientset()
if err != nil {
return err
}

b.k8sClientset, err = b.clientGetter.K8sClientset()
if err != nil {
return err
}

b.profile, err = b.kjobctlClientset.KjobctlV1alpha1().ApplicationProfiles(b.namespace).Get(ctx, b.profileName, v1.GetOptions{})
if err != nil {
return err
}

for i, mode := range b.profile.Spec.SupportedModes {
if mode.Name == b.modeName {
b.mode = &b.profile.Spec.SupportedModes[i]
}
}

if b.mode == nil {
return applicationProfileModeNotConfiguredErr
}

volumeBundlesList, err := b.kjobctlClientset.KjobctlV1alpha1().VolumeBundles(b.profile.Namespace).List(ctx, v1.ListOptions{})
if err != nil {
return err
}

b.volumeBundles = volumeBundlesList.Items

return nil
}

func (b *Builder) validateFlags() error {
if slices.Contains(b.mode.RequiredFlags, v1alpha1.CmdFlag) && len(b.command) == 0 {
return noCommandSpecifiedErr
}

if slices.Contains(b.mode.RequiredFlags, v1alpha1.ParallelismFlag) && b.parallelism == nil {
return noParallelismSpecifiedErr
}

if slices.Contains(b.mode.RequiredFlags, v1alpha1.CompletionsFlag) && b.completions == nil {
return noCompletionsSpecifiedErr
}

if slices.Contains(b.mode.RequiredFlags, v1alpha1.RequestFlag) && b.requests == nil {
return noRequestsSpecifiedErr
}

if slices.Contains(b.mode.RequiredFlags, v1alpha1.LocalQueueFlag) && b.localQueue == "" {
return noLocalQueueSpecifiedErr
}

return nil
}

func (b *Builder) Do(ctx context.Context) (runtime.Object, error) {
if err := b.validateGeneral(); err != nil {
return nil, err
}

var bImpl builder

if b.modeName == v1alpha1.JobMode {
bImpl = newJobBuilder(b)
}

if bImpl == nil {
return nil, invalidApplicationProfileModeErr
}

if err := b.complete(ctx); err != nil {
return nil, err
}

if err := b.validateFlags(); err != nil {
return nil, err
}

return bImpl.build(ctx)
}
Loading

0 comments on commit 7e37e0c

Please sign in to comment.