Skip to content
Draft
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
30 changes: 0 additions & 30 deletions .github/release-drafter.yml

This file was deleted.

26 changes: 6 additions & 20 deletions .github/workflows/docker.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,13 @@ env:
IMAGE_NAME: ${{ github.repository }}

jobs:
test:
runs-on: ubuntu-latest
draft:
uses: metal-stack/actions-common/.github/workflows/release-drafter.yaml@v1

steps:
- name: Checkout code
uses: actions/checkout@v6

- name: Setup Go
uses: actions/setup-go@v6
with:
go-version-file: 'go.mod'
cache: false

- name: Lint
uses: golangci/golangci-lint-action@v9
with:
args: --build-tags integration --timeout=5m

- name: Test
run: |
make test
go-build:
uses: metal-stack/actions-common/.github/workflows/go-build.yaml@v1
with:
build: false

build:
runs-on: ubuntu-latest
Expand Down
15 changes: 0 additions & 15 deletions .github/workflows/release-drafter.yaml

This file was deleted.

6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@ cli:

.PHONY: test
test:
CGO_ENABLED=1 go test ./... -race -coverprofile=coverage.out -covermode=atomic && go tool cover -func=coverage.out
CGO_ENABLED=1 go test ./... -race \
-coverpkg=./... \
-coverprofile=coverage.out \
-covermode=atomic && \
go tool cover -func=coverage.out

.PHONY: golint
golint:
Expand Down
4 changes: 2 additions & 2 deletions cmd/admin/v2/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ func AddCmds(cmd *cobra.Command, c *config.Config) {
adminCmd := &cobra.Command{
Use: "admin",
Short: "admin commands",
Long: "",
Long: "these commands utilize the admin api, which can only be accessed by metal-stack operators.",
SilenceUsage: true,
Hidden: true,
}
Expand All @@ -18,8 +18,8 @@ func AddCmds(cmd *cobra.Command, c *config.Config) {
adminCmd.AddCommand(newComponentCmd(c))
adminCmd.AddCommand(newImageCmd(c))
adminCmd.AddCommand(newProjectCmd(c))
adminCmd.AddCommand(newProjectCmd(c))
adminCmd.AddCommand(newSwitchCmd(c))
adminCmd.AddCommand(newTaskCmd(c))
adminCmd.AddCommand(newTenantCmd(c))
adminCmd.AddCommand(newTokenCmd(c))

Expand Down
105 changes: 77 additions & 28 deletions cmd/admin/v2/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,26 @@ func newImageCmd(c *config.Config) *cobra.Command {
return gcli.DescribeAndPrint("", w.c.DescribePrinter)
}
},
CreateCmdMutateFn: func(cmd *cobra.Command) {
cmd.Flags().String("id", "", "image id")
cmd.Flags().String("url", "", "image url")
cmd.Flags().String("name", "", "image name")
cmd.Flags().String("classification", "", "image classification")
cmd.Flags().String("expires-in", "", "expires-in duration")
cmd.Flags().String("description", "", "image description")
cmd.Flags().StringSlice("features", nil, "image features can be machine and/or firewall")
},
CreateRequestFromCLI: w.createFromCLI,
UpdateCmdMutateFn: func(cmd *cobra.Command) {
cmd.Flags().String("id", "", "image id")
cmd.Flags().String("url", "", "image url")
cmd.Flags().String("name", "", "image name")
cmd.Flags().String("classification", "", "image classification")
cmd.Flags().String("expires-in", "", "expires-in duration")
cmd.Flags().String("description", "", "image description")
cmd.Flags().StringSlice("features", nil, "image features can be machine and/or firewall")
},
UpdateRequestFromCLI: w.updateFromCLI,
}

return genericcli.NewCmds(cmdsConfig)
Expand All @@ -63,30 +83,34 @@ func (c *image) Create(rq *adminv2.ImageServiceCreateRequest) (*apiv2.Image, err
ctx, cancel := c.c.NewRequestContext()
defer cancel()

resp, err := c.c.Client.Adminv2().Image().Create(ctx, rq)
if err != nil {
return nil, fmt.Errorf("failed to create image: %w", err)
}

return resp.Image, nil
}

func (c *image) createFromCLI() (*adminv2.ImageServiceCreateRequest, error) {
var expiresAt *timestamppb.Timestamp
if viper.IsSet("expires-in") {
expiresAt = timestamppb.New(time.Now().Add(viper.GetDuration("expires-in")))
}

req := &adminv2.ImageServiceCreateRequest{
return &adminv2.ImageServiceCreateRequest{
Image: &apiv2.Image{
Id: viper.GetString("id"),
Url: viper.GetString("url"),
Description: pointer.PointerOrNil(viper.GetString("description")),
ExpiresAt: expiresAt,
Features: imageFeaturesFromString(viper.GetStringSlice("features")),
Meta: &apiv2.Meta{
Id: viper.GetString("id"),
Url: viper.GetString("url"),
Classification: imageClassificationFromString(viper.GetString("classification")),
Name: pointer.PointerOrNil(viper.GetString("name")),
Description: pointer.PointerOrNil(viper.GetString("description")),
ExpiresAt: expiresAt,
Features: imageFeaturesFromString(viper.GetStringSlice("features")),
Meta: &apiv2.Meta{
// TODO labels
},
},
}

resp, err := c.c.Client.Adminv2().Image().Create(ctx, req)
if err != nil {
return nil, fmt.Errorf("failed to get image: %w", err)
}

return resp.Image, nil
}, nil
}

func (c *image) Delete(id string) (*apiv2.Image, error) {
Expand Down Expand Up @@ -139,29 +163,41 @@ func (c *image) Update(rq *adminv2.ImageServiceUpdateRequest) (*apiv2.Image, err
ctx, cancel := c.c.NewRequestContext()
defer cancel()

var expiresAt *timestamppb.Timestamp
if viper.IsSet("expires-in") {
expiresAt = timestamppb.New(time.Now().Add(viper.GetDuration("expires-in")))
resp, err := c.c.Client.Adminv2().Image().Update(ctx, rq)
if err != nil {
return nil, fmt.Errorf("failed to update image: %w", err)
}

return resp.Image, nil
}

func (c *image) updateFromCLI(args []string) (*adminv2.ImageServiceUpdateRequest, error) {
id, err := genericcli.GetExactlyOneArg(args)
if err != nil {
return nil, err
}

req := &adminv2.ImageServiceUpdateRequest{
Id: viper.GetString("id"),
Url: new(viper.GetString("url")),
Id: id,
Url: pointer.PointerOrNil(viper.GetString("url")),
Name: pointer.PointerOrNil(viper.GetString("name")),
Description: pointer.PointerOrNil(viper.GetString("description")),
ExpiresAt: expiresAt,
Features: imageFeaturesFromString(viper.GetStringSlice("features")),
UpdateMeta: &apiv2.UpdateMeta{
LockingStrategy: apiv2.OptimisticLockingStrategy_OPTIMISTIC_LOCKING_STRATEGY_CLIENT,
UpdatedAt: rq.UpdateMeta.GetUpdatedAt(),
LockingStrategy: apiv2.OptimisticLockingStrategy_OPTIMISTIC_LOCKING_STRATEGY_SERVER,
},
}

resp, err := c.c.Client.Adminv2().Image().Update(ctx, req)
if err != nil {
return nil, fmt.Errorf("failed to get image: %w", err)
if viper.IsSet("expires-in") {
req.ExpiresAt = timestamppb.New(time.Now().Add(viper.GetDuration("expires-in")))
}
if viper.IsSet("features") {
req.Features = imageFeaturesFromString(viper.GetStringSlice("features"))
}
if viper.IsSet("classification") {
req.Classification = imageClassificationFromString(viper.GetString("classification"))
}

return resp.Image, nil
return req, nil
}

func imageFeaturesFromString(features []string) []apiv2.ImageFeature {
Expand All @@ -180,3 +216,16 @@ func imageFeaturesFromString(features []string) []apiv2.ImageFeature {
}
return result
}

func imageClassificationFromString(classification string) apiv2.ImageClassification {
switch strings.ToLower(strings.TrimSpace(classification)) {
case "preview":
return apiv2.ImageClassification_IMAGE_CLASSIFICATION_PREVIEW
case "supported":
return apiv2.ImageClassification_IMAGE_CLASSIFICATION_SUPPORTED
case "deprecated":
return apiv2.ImageClassification_IMAGE_CLASSIFICATION_DEPRECATED
}

return apiv2.ImageClassification_IMAGE_CLASSIFICATION_UNSPECIFIED
}
125 changes: 125 additions & 0 deletions cmd/admin/v2/task.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package v2

import (
"fmt"

adminv2 "github.com/metal-stack/api/go/metalstack/admin/v2"
"github.com/metal-stack/cli/cmd/config"
"github.com/metal-stack/cli/cmd/sorters"
"github.com/metal-stack/metal-lib/pkg/genericcli"
"github.com/metal-stack/metal-lib/pkg/genericcli/printers"
"github.com/metal-stack/metal-lib/pkg/pointer"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

type task struct {
c *config.Config
}

func newTaskCmd(c *config.Config) *cobra.Command {
w := &task{
c: c,
}

cmdsConfig := &genericcli.CmdsConfig[any, any, *adminv2.TaskInfo]{
BinaryName: config.BinaryName,
GenericCLI: genericcli.NewGenericCLI(w).WithFS(c.Fs),
Singular: "task",
Plural: "tasks",
Description: "get task insights",
DescribePrinter: func() printers.Printer { return c.DescribePrinter },
ListPrinter: func() printers.Printer { return c.ListPrinter },
Sorter: sorters.TaskSorter(),
DescribeCmdMutateFn: func(cmd *cobra.Command) {
cmd.Flags().String("queue", "default", "the queue for which tasks should be described")
},
ListCmdMutateFn: func(cmd *cobra.Command) {
cmd.Flags().String("queue", "", "the queue for which tasks should be listed")
},
DeleteCmdMutateFn: func(cmd *cobra.Command) {
cmd.Flags().String("queue", "default", "the queue of the task which should be delete")
},
OnlyCmds: genericcli.OnlyCmds(genericcli.ListCmd, genericcli.DescribeCmd, genericcli.DeleteCmd),
}

queueCmd := &cobra.Command{
Use: "queues",
Short: "list all queues",
RunE: func(cmd *cobra.Command, args []string) error {
return w.queues()
},
}

return genericcli.NewCmds(cmdsConfig, queueCmd)
}

func (t *task) queues() error {
ctx, cancel := t.c.NewRequestContext()
defer cancel()

req := &adminv2.TaskServiceQueuesRequest{}

resp, err := t.c.Client.Adminv2().Task().Queues(ctx, req)
if err != nil {
return fmt.Errorf("failed to get task queues: %w", err)
}

return t.c.ListPrinter.Print(resp)
}

func (t *task) Get(id string) (*adminv2.TaskInfo, error) {
ctx, cancel := t.c.NewRequestContext()
defer cancel()

req := &adminv2.TaskServiceGetRequest{TaskId: id, Queue: viper.GetString("queue")}

resp, err := t.c.Client.Adminv2().Task().Get(ctx, req)
if err != nil {
return nil, fmt.Errorf("failed to get task: %w", err)
}

return resp.Task, nil
}

func (t *task) List() ([]*adminv2.TaskInfo, error) {
ctx, cancel := t.c.NewRequestContext()
defer cancel()

req := &adminv2.TaskServiceListRequest{
Queue: pointer.PointerOrNil(viper.GetString("queue")),
}

resp, err := t.c.Client.Adminv2().Task().List(ctx, req)
if err != nil {
return nil, fmt.Errorf("failed to list tasks: %w", err)
}

return resp.Tasks, nil
}

func (t *task) Delete(id string) (*adminv2.TaskInfo, error) {
ctx, cancel := t.c.NewRequestContext()
defer cancel()

req := &adminv2.TaskServiceDeleteRequest{TaskId: id, Queue: viper.GetString("queue")}

_, err := t.c.Client.Adminv2().Task().Delete(ctx, req)
if err != nil {
return nil, fmt.Errorf("failed to delete task: %w", err)
}

return nil, nil
}

func (t *task) Create(rq any) (*adminv2.TaskInfo, error) {
panic("unimplemented")
}

func (t *task) Convert(r *adminv2.TaskInfo) (string, any, any, error) {
panic("unimplemented")
}

func (t *task) Update(rq any) (*adminv2.TaskInfo, error) {
panic("unimplemented")
}
Loading