Ability to pre-pull VM images by targeting workers with labels

This commit is contained in:
Nikolay Edigaryev
2025-12-10 20:43:34 +01:00
parent 173a34b083
commit aa36ad4cb6
29 changed files with 1463 additions and 8 deletions
+12
View File
@@ -349,6 +349,18 @@ func (client *Client) ClusterSettings() *ClusterSettingsService {
}
}
func (client *Client) ImagePulls() *ImagePullsService {
return &ImagePullsService{
client: client,
}
}
func (client *Client) ImagePullJobs() *ImagePullJobsService {
return &ImagePullJobsService{
client: client,
}
}
func (client *Client) RPC() *RPCService {
return &RPCService{
client: client,
+82
View File
@@ -0,0 +1,82 @@
package client
import (
"context"
"fmt"
"net/http"
"net/url"
"github.com/cirruslabs/orchard/pkg/resource/v1"
)
const imagePullJobsEndpointPrefix = "imagepulljobs"
type ImagePullJobsService struct {
client *Client
}
func (service *ImagePullJobsService) Create(ctx context.Context, pullJob *v1.ImagePullJob) error {
err := service.client.request(ctx, http.MethodPost, imagePullJobsEndpointPrefix, pullJob, nil, nil)
if err != nil {
return err
}
return nil
}
func (service *ImagePullJobsService) List(ctx context.Context) ([]v1.ImagePullJob, error) {
var pullJobs []v1.ImagePullJob
err := service.client.request(ctx, http.MethodGet, imagePullJobsEndpointPrefix, nil, &pullJobs, nil)
if err != nil {
return nil, err
}
return pullJobs, nil
}
func (service *ImagePullJobsService) Get(ctx context.Context, name string) (*v1.ImagePullJob, error) {
var pullJob v1.ImagePullJob
err := service.client.request(ctx, http.MethodGet, fmt.Sprintf("%s/%s", imagePullJobsEndpointPrefix,
url.PathEscape(name)), nil, &pullJob, nil)
if err != nil {
return nil, err
}
return &pullJob, nil
}
func (service *ImagePullJobsService) Update(ctx context.Context, pull v1.ImagePullJob) (*v1.ImagePullJob, error) {
var updatedPullJob v1.ImagePullJob
err := service.client.request(ctx, http.MethodPut, fmt.Sprintf("%s/%s", imagePullJobsEndpointPrefix,
url.PathEscape(pull.Name)), pull, &updatedPullJob, nil)
if err != nil {
return &updatedPullJob, err
}
return &updatedPullJob, nil
}
func (service *ImagePullJobsService) UpdateState(ctx context.Context, pull v1.ImagePullJob) (*v1.ImagePullJob, error) {
var updatedPullJob v1.ImagePullJob
err := service.client.request(ctx, http.MethodPut, fmt.Sprintf("%s/%s/state", imagePullJobsEndpointPrefix,
url.PathEscape(pull.Name)), pull, &updatedPullJob, nil)
if err != nil {
return &updatedPullJob, err
}
return &updatedPullJob, nil
}
func (service *ImagePullJobsService) Delete(ctx context.Context, name string) error {
err := service.client.request(ctx, http.MethodDelete, fmt.Sprintf("%s/%s", imagePullJobsEndpointPrefix,
url.PathEscape(name)), nil, nil, nil)
if err != nil {
return err
}
return nil
}
+101
View File
@@ -0,0 +1,101 @@
package client
import (
"context"
"fmt"
"net/http"
"net/url"
"github.com/cirruslabs/orchard/pkg/resource/v1"
)
const pullsEndpointPrefix = "imagepulls"
type ImagePullsService struct {
client *Client
}
func (service *ImagePullsService) Create(ctx context.Context, pull *v1.ImagePull) error {
err := service.client.request(ctx, http.MethodPost, pullsEndpointPrefix, pull, nil, nil)
if err != nil {
return err
}
return nil
}
func (service *ImagePullsService) FindForWorker(ctx context.Context, worker string) ([]v1.ImagePull, error) {
allPulls, err := service.List(ctx)
if err != nil {
return nil, err
}
var result []v1.ImagePull
for _, pull := range allPulls {
if pull.Worker != worker {
continue
}
result = append(result, pull)
}
return result, nil
}
func (service *ImagePullsService) List(ctx context.Context) ([]v1.ImagePull, error) {
var pulls []v1.ImagePull
err := service.client.request(ctx, http.MethodGet, pullsEndpointPrefix, nil, &pulls, nil)
if err != nil {
return nil, err
}
return pulls, nil
}
func (service *ImagePullsService) Get(ctx context.Context, name string) (*v1.ImagePull, error) {
var pull v1.ImagePull
err := service.client.request(ctx, http.MethodGet, fmt.Sprintf("%s/%s", pullsEndpointPrefix,
url.PathEscape(name)), nil, &pull, nil)
if err != nil {
return nil, err
}
return &pull, nil
}
func (service *ImagePullsService) Update(ctx context.Context, pull v1.ImagePull) (*v1.ImagePull, error) {
var updatedPull v1.ImagePull
err := service.client.request(ctx, http.MethodPut, fmt.Sprintf("%s/%s", pullsEndpointPrefix,
url.PathEscape(pull.Name)), pull, &updatedPull, nil)
if err != nil {
return &updatedPull, err
}
return &updatedPull, nil
}
func (service *ImagePullsService) UpdateState(ctx context.Context, pull v1.ImagePull) (*v1.ImagePull, error) {
var updatedPull v1.ImagePull
err := service.client.request(ctx, http.MethodPut, fmt.Sprintf("%s/%s/state", pullsEndpointPrefix,
url.PathEscape(pull.Name)), pull, &updatedPull, nil)
if err != nil {
return &updatedPull, err
}
return &updatedPull, nil
}
func (service *ImagePullsService) Delete(ctx context.Context, name string) error {
err := service.client.request(ctx, http.MethodDelete, fmt.Sprintf("%s/%s", pullsEndpointPrefix,
url.PathEscape(name)), nil, nil, nil)
if err != nil {
return err
}
return nil
}
+26
View File
@@ -0,0 +1,26 @@
package v1
type ImagePull struct {
Meta
// UID is a useful field for avoiding data races within a single Name.
//
// It is populated by the Controller when receiving a POST request.
UID string `json:"uid,omitempty"`
OwnerReferences []OwnerReference `json:"ownerReferences,omitempty"`
Image string `json:"image,omitempty"`
Worker string `json:"worker,omitempty"`
PullState
}
func (pull *ImagePull) SetVersion(version uint64) {
pull.Version = version
}
type PullState struct {
Conditions []Condition `json:"conditions,omitempty"`
}
+36
View File
@@ -0,0 +1,36 @@
package v1
type ImagePullJob struct {
Meta
// UID is a useful field for avoiding data races within a single Name.
//
// It is populated by the Controller when receiving a POST request.
UID string `json:"uid,omitempty"`
Image string `json:"image,omitempty"`
Labels Labels `json:"labels,omitempty"`
ImagePullJobState
}
func (imagePullJob *ImagePullJob) SetVersion(version uint64) {
imagePullJob.Version = version
}
func (imagePullJob *ImagePullJob) OwnerReference() OwnerReference {
return OwnerReference{
Kind: KindImagePullJob,
Name: imagePullJob.Name,
UID: imagePullJob.UID,
}
}
type ImagePullJobState struct {
Conditions []Condition `json:"conditions,omitempty"`
Progressing int64 `json:"progressing,omitempty"`
Succeeded int64 `json:"succeeded,omitempty"`
Failed int64 `json:"failed,omitempty"`
Total int64 `json:"total,omitempty"`
}
+7
View File
@@ -0,0 +1,7 @@
package v1
type Kind string
const (
KindImagePullJob Kind = "ImagePullJob"
)
+15
View File
@@ -1,5 +1,10 @@
package v1
import (
"fmt"
"strings"
)
type Labels map[string]string
func (labels Labels) Contains(other Labels) bool {
@@ -11,3 +16,13 @@ func (labels Labels) Contains(other Labels) bool {
return true
}
func (labels Labels) String() string {
var kvs []string
for key, value := range labels {
kvs = append(kvs, fmt.Sprintf("%s: %s", key, value))
}
return strings.Join(kvs, ", ")
}
+15 -3
View File
@@ -21,6 +21,17 @@ type Meta struct {
Version uint64 `json:"version,omitempty"`
}
type OwnerReference struct {
Kind Kind `json:"kind,omitempty"`
Name string `json:"name,omitempty"`
// UID is a useful field for avoiding data races within a single Name.
//
// It is populated by the Controller when receiving a POST request.
UID string `json:"uid,omitempty"`
}
type VM struct {
Image string `json:"image,omitempty"`
ImagePullPolicy ImagePullPolicy `json:"imagePullPolicy,omitempty"`
@@ -195,9 +206,10 @@ const (
type ControllerCapability string
const (
ControllerCapabilityRPCV1 ControllerCapability = "rpc-v1"
ControllerCapabilityRPCV2 ControllerCapability = "rpc-v2"
ControllerCapabilityVMStateEndpoint ControllerCapability = "vm-state-endpoint"
ControllerCapabilityRPCV1 ControllerCapability = "rpc-v1"
ControllerCapabilityRPCV2 ControllerCapability = "rpc-v2"
ControllerCapabilityVMStateEndpoint ControllerCapability = "vm-state-endpoint"
ControllerCapabilityImagePullResource ControllerCapability = "pull-resource"
)
type ControllerCapabilities []ControllerCapability
+7
View File
@@ -13,12 +13,19 @@ type Condition struct {
type ConditionType string
const (
// VM conditions
ConditionTypeScheduled ConditionType = "scheduled"
ConditionTypeRunning ConditionType = "running"
// VM conditions (internal to worker)
ConditionTypeCloning ConditionType = "cloning"
ConditionTypeSuspending ConditionType = "suspending"
ConditionTypeStopping ConditionType = "stopping"
// ImagePull and ImagePullJob conditions
ConditionTypeProgressing ConditionType = "progressing"
ConditionTypeCompleted ConditionType = "completed"
ConditionTypeFailed ConditionType = "failed"
)
type ConditionState string