From afc692f0b8413f0d105393b9d4de18b1c825daf1 Mon Sep 17 00:00:00 2001 From: Benedict Schlueter Date: Tue, 30 May 2023 15:54:52 +0200 Subject: [PATCH 1/3] add initial gcp support Signed-off-by: Benedict Schlueter --- .dockerignore | 3 +- .gitignore | 13 + cli/infrastructure/cloud/cloud.go | 88 +++ cli/infrastructure/cloud/loader.go | 84 +++ cli/infrastructure/cloud/logging.go | 75 +++ cli/infrastructure/cloud/terraform.go | 324 +++++++++++ .../cloud/terraform/gcp/.terraform.lock.hcl | 60 ++ .../cloud/terraform/gcp/main.tf | 210 +++++++ .../gcp/modules/instance_group/main.tf | 136 +++++ .../gcp/modules/instance_group/outputs.tf | 3 + .../gcp/modules/instance_group/variables.tf | 81 +++ .../gcp/modules/loadbalancer/main.tf | 63 +++ .../gcp/modules/loadbalancer/variables.tf | 35 ++ .../cloud/terraform/gcp/variables.tf | 62 +++ cli/infrastructure/cloud/variables.go | 175 ++++++ cli/infrastructure/infrastructure.go | 5 + cli/installer/installer.go | 1 + cli/run.go | 17 +- .../challenges/testing/Dockerfile.archlinux | 4 + images/mkosi.conf | 2 + internal/config/global.go | 2 + internal/config/utils/kubeadm_config.go | 31 +- internal/file/file.go | 234 ++++++++ internal/file/file_test.go | 521 ++++++++++++++++++ internal/main.go | 48 ++ internal/osimage/gcp/gcpupload.go | 237 ++++++++ internal/osimage/osimage.go | 21 + 27 files changed, 2524 insertions(+), 11 deletions(-) create mode 100644 cli/infrastructure/cloud/cloud.go create mode 100644 cli/infrastructure/cloud/loader.go create mode 100644 cli/infrastructure/cloud/logging.go create mode 100644 cli/infrastructure/cloud/terraform.go create mode 100644 cli/infrastructure/cloud/terraform/gcp/.terraform.lock.hcl create mode 100644 cli/infrastructure/cloud/terraform/gcp/main.tf create mode 100644 cli/infrastructure/cloud/terraform/gcp/modules/instance_group/main.tf create mode 100644 cli/infrastructure/cloud/terraform/gcp/modules/instance_group/outputs.tf create mode 100644 cli/infrastructure/cloud/terraform/gcp/modules/instance_group/variables.tf create mode 100644 cli/infrastructure/cloud/terraform/gcp/modules/loadbalancer/main.tf create mode 100644 cli/infrastructure/cloud/terraform/gcp/modules/loadbalancer/variables.tf create mode 100644 cli/infrastructure/cloud/terraform/gcp/variables.tf create mode 100644 cli/infrastructure/cloud/variables.go create mode 100644 internal/file/file.go create mode 100644 internal/file/file_test.go create mode 100644 internal/main.go create mode 100644 internal/osimage/gcp/gcpupload.go create mode 100644 internal/osimage/osimage.go diff --git a/.dockerignore b/.dockerignore index dc6463a..134aa05 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,2 +1,3 @@ /build -/images \ No newline at end of file +/images +/3rdParty \ No newline at end of file diff --git a/.gitignore b/.gitignore index 8c10f05..0996fb0 100644 --- a/.gitignore +++ b/.gitignore @@ -5,12 +5,25 @@ # Unignore all dirs !*/ +*.tfstate + !/images/mkosi.skeleton/** /images/mkosi.skeleton/usr/bin/delegatio-agent !/container/sshd_config /images/*qcow2* /images/*.cmdline +/images/mkosi.cache/** /images/.cache/** /build /3rdParty +/cli/infrastructure/terraform/gcp/delegatio.json + +# Terraform +*.tfstate +*.tfstate.backup +.terraform +.terraform.tfstate.lock.info +*.tfvars +terraform.log +delegatio.json \ No newline at end of file diff --git a/cli/infrastructure/cloud/cloud.go b/cli/infrastructure/cloud/cloud.go new file mode 100644 index 0000000..5ded86c --- /dev/null +++ b/cli/infrastructure/cloud/cloud.go @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: AGPL-3.0-only + * Copyright (c) Edgeless Systems GmbH + * Copyright (c) Benedict Schlueter + */ + +package terraform + +import ( + "context" + "errors" + "fmt" + "path" + + tfjson "github.com/hashicorp/terraform-json" +) + +type terraformClient interface { + PrepareWorkspace(path string, input Variables) error + CreateCluster(ctx context.Context, logLevel LogLevel, targets ...string) (CreateOutput, error) + CreateIAMConfig(ctx context.Context, logLevel LogLevel) (IAMOutput, error) + Destroy(ctx context.Context, logLevel LogLevel) error + CleanUpWorkspace() error + RemoveInstaller() + Show(ctx context.Context) (*tfjson.State, error) +} + +// rollbacker does a rollback. +type rollbacker interface { + rollback(ctx context.Context, logLevel LogLevel) error +} + +// rollbackOnError calls rollback on the rollbacker if the handed error is not nil, +// and writes logs to the writer w. +func rollbackOnError(onErr *error, roll rollbacker, logLevel LogLevel) { + if *onErr == nil { + return + } + fmt.Printf("An error occurred: %s\n", *onErr) + fmt.Println("Attempting to roll back.") + if err := roll.rollback(context.Background(), logLevel); err != nil { + *onErr = errors.Join(*onErr, fmt.Errorf("on rollback: %w", err)) // TODO(katexochen): print the error, or return it? + return + } + fmt.Println("Rollback succeeded.") +} + +type rollbackerTerraform struct { + client terraformClient +} + +func (r *rollbackerTerraform) rollback(ctx context.Context, logLevel LogLevel) error { + if err := r.client.Destroy(ctx, logLevel); err != nil { + return err + } + return r.client.CleanUpWorkspace() +} + +func CreateGCP(ctx context.Context, cl terraformClient) (retErr error) { + tfLogLevel := LogLevelDebug + vars := GCPClusterVariables{ + CommonVariables: CommonVariables{ + Name: "delegatiooooo", + CountControlPlanes: 1, + CountWorkers: 1, + StateDiskSizeGB: 20, + }, + Project: "delegatio", + Region: "europe-west6", + Zone: "europe-west6-a", + CredentialsFile: "/home/bschlueter/University/Github/delegatio/build/delegatio.json", + InstanceType: "g1-small", + StateDiskType: "pd-standard", + ImageID: "https://www.googleapis.com/compute/v1/projects/delegatio/global/images/gcp-0-0-0-test", + Debug: true, + } + + if err := cl.PrepareWorkspace(path.Join("terraform", "gcp"), &vars); err != nil { + return err + } + + defer rollbackOnError(&retErr, &rollbackerTerraform{client: cl}, tfLogLevel) + tfOutput, err := cl.CreateCluster(ctx, tfLogLevel) + if err != nil { + return err + } + fmt.Printf(tfOutput.IP) + return nil +} diff --git a/cli/infrastructure/cloud/loader.go b/cli/infrastructure/cloud/loader.go new file mode 100644 index 0000000..9b89f93 --- /dev/null +++ b/cli/infrastructure/cloud/loader.go @@ -0,0 +1,84 @@ +/* +Copyright (c) Edgeless Systems GmbH + +SPDX-License-Identifier: AGPL-3.0-only +*/ + +package terraform + +import ( + "bytes" + "embed" + "errors" + "io/fs" + slashpath "path" + "path/filepath" + "strings" + + "github.com/benschlueter/delegatio/internal/file" + "github.com/spf13/afero" +) + +// ErrTerraformWorkspaceDifferentFiles is returned when a re-used existing Terraform workspace has different files than the ones to be extracted (e.g. due to a version mix-up or incomplete writes). +var ErrTerraformWorkspaceDifferentFiles = errors.New("creating cluster: trying to overwrite an existing Terraform file with a different version") + +//go:embed terraform/* +//go:embed terraform/*/.terraform.lock.hcl +var terraformFS embed.FS + +// prepareWorkspace loads the embedded Terraform files, +// and writes them into the workspace. +func prepareWorkspace(rootDir string, fileHandler file.Handler, workingDir string) error { + return terraformCopier(fileHandler, rootDir, workingDir) +} + +// terraformCopier copies the embedded Terraform files into the workspace. +func terraformCopier(fileHandler file.Handler, rootDir, workingDir string) error { + goEmbedRootDir := filepath.ToSlash(rootDir) + return fs.WalkDir(terraformFS, goEmbedRootDir, func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + if d.IsDir() { + return nil + } + + goEmbedPath := filepath.ToSlash(path) + content, err := terraformFS.ReadFile(goEmbedPath) + if err != nil { + return err + } + // normalize + fileName := strings.Replace(slashpath.Join(workingDir, path), goEmbedRootDir+"/", "", 1) + if err := fileHandler.Write(fileName, content, file.OptMkdirAll); errors.Is(err, afero.ErrFileExists) { + // If a file already exists, check if it is identical. If yes, continue and don't write anything to disk. + // If no, don't overwrite it and instead throw an error. The affected file could be from a different version, + // provider, corrupted or manually modified in general. + existingFileContent, err := fileHandler.Read(fileName) + if err != nil { + return err + } + + if !bytes.Equal(content, existingFileContent) { + return ErrTerraformWorkspaceDifferentFiles + } + return nil + } else if err != nil { + return err + } + + return nil + }) +} + +func cleanUpWorkspace(fileHandler file.Handler, workingDir string) error { + return ignoreFileNotFoundErr(fileHandler.RemoveAll(workingDir)) +} + +// ignoreFileNotFoundErr ignores the error if it is a file not found error. +func ignoreFileNotFoundErr(err error) error { + if errors.Is(err, afero.ErrFileNotFound) { + return nil + } + return err +} diff --git a/cli/infrastructure/cloud/logging.go b/cli/infrastructure/cloud/logging.go new file mode 100644 index 0000000..6a400fb --- /dev/null +++ b/cli/infrastructure/cloud/logging.go @@ -0,0 +1,75 @@ +/* +Copyright (c) Edgeless Systems GmbH + +SPDX-License-Identifier: AGPL-3.0-only +*/ + +package terraform + +import ( + "fmt" + "strings" +) + +const ( + // LogLevelNone represents a log level that does not produce any output. + LogLevelNone LogLevel = iota + // LogLevelError enables log output at ERROR level. + LogLevelError + // LogLevelWarn enables log output at WARN level. + LogLevelWarn + // LogLevelInfo enables log output at INFO level. + LogLevelInfo + // LogLevelDebug enables log output at DEBUG level. + LogLevelDebug + // LogLevelTrace enables log output at TRACE level. + LogLevelTrace + // LogLevelJSON enables log output at TRACE level in JSON format. + LogLevelJSON +) + +// LogLevel is a Terraform log level. +// As per https://developer.hashicorp.com/terraform/internals/debugging +type LogLevel int + +// ParseLogLevel parses a log level string into a Terraform log level. +func ParseLogLevel(level string) (LogLevel, error) { + switch strings.ToUpper(level) { + case "NONE": + return LogLevelNone, nil + case "ERROR": + return LogLevelError, nil + case "WARN": + return LogLevelWarn, nil + case "INFO": + return LogLevelInfo, nil + case "DEBUG": + return LogLevelDebug, nil + case "TRACE": + return LogLevelTrace, nil + case "JSON": + return LogLevelJSON, nil + default: + return LogLevelNone, fmt.Errorf("invalid log level %s", level) + } +} + +// String returns the string representation of a Terraform log level. +func (l LogLevel) String() string { + switch l { + case LogLevelError: + return "ERROR" + case LogLevelWarn: + return "WARN" + case LogLevelInfo: + return "INFO" + case LogLevelDebug: + return "DEBUG" + case LogLevelTrace: + return "TRACE" + case LogLevelJSON: + return "JSON" + default: + return "" + } +} diff --git a/cli/infrastructure/cloud/terraform.go b/cli/infrastructure/cloud/terraform.go new file mode 100644 index 0000000..adc7295 --- /dev/null +++ b/cli/infrastructure/cloud/terraform.go @@ -0,0 +1,324 @@ +/* +Copyright (c) Edgeless Systems GmbH + +SPDX-License-Identifier: AGPL-3.0-only +*/ + +/* +Package terraform handles creation/destruction of a Constellation cluster using Terraform. + +Since Terraform does not provide a stable Go API, we use the `terraform-exec` package to interact with Terraform. + +The Terraform templates are located in the "terraform" subdirectory. The templates are embedded into the CLI binary using `go:embed`. +On use the relevant template is extracted to the working directory and the user customized variables are written to a `terraform.tfvars` file. +*/ +package terraform + +import ( + "context" + "errors" + "fmt" + "io" + "path/filepath" + + "github.com/benschlueter/delegatio/internal/config" + "github.com/benschlueter/delegatio/internal/file" + "github.com/hashicorp/go-version" + install "github.com/hashicorp/hc-install" + "github.com/hashicorp/hc-install/fs" + "github.com/hashicorp/hc-install/product" + "github.com/hashicorp/hc-install/releases" + "github.com/hashicorp/hc-install/src" + "github.com/hashicorp/terraform-exec/tfexec" + tfjson "github.com/hashicorp/terraform-json" + "github.com/spf13/afero" +) + +const ( + tfVersion = ">= 1.4.6" + terraformVarsFile = "terraform.tfvars" +) + +// ErrTerraformWorkspaceExistsWithDifferentVariables is returned when existing Terraform files differ from the version the CLI wants to extract. +var ErrTerraformWorkspaceExistsWithDifferentVariables = errors.New("creating cluster: a Terraform workspace already exists with different variables") + +// Client manages interaction with Terraform. +type Client struct { + tf tfInterface + + file file.Handler + workingDir string + remove func() +} + +// New sets up a new Client for Terraform. +func New(ctx context.Context, workingDir string) (*Client, error) { + file := file.NewHandler(afero.NewOsFs()) + if err := file.MkdirAll(workingDir); err != nil { + return nil, err + } + tf, remove, err := GetExecutable(ctx, workingDir) + if err != nil { + return nil, err + } + + return &Client{ + tf: tf, + remove: remove, + file: file, + workingDir: workingDir, + }, nil +} + +// Show reads the default state path and outputs the state. +func (c *Client) Show(ctx context.Context) (*tfjson.State, error) { + return c.tf.Show(ctx) +} + +// PrepareWorkspace prepares a Terraform workspace for a Constellation cluster. +func (c *Client) PrepareWorkspace(path string, vars Variables) error { + if err := prepareWorkspace(path, c.file, c.workingDir); err != nil { + return fmt.Errorf("prepare workspace: %w", err) + } + + return c.writeVars(vars) +} + +// CreateCluster creates a Constellation cluster using Terraform. +func (c *Client) CreateCluster(ctx context.Context, logLevel LogLevel, targets ...string) (CreateOutput, error) { + if err := c.setLogLevel(logLevel); err != nil { + return CreateOutput{}, fmt.Errorf("set terraform log level %s: %w", logLevel.String(), err) + } + + if err := c.tf.Init(ctx); err != nil { + return CreateOutput{}, fmt.Errorf("terraform init: %w", err) + } + + opts := []tfexec.ApplyOption{} + for _, target := range targets { + opts = append(opts, tfexec.Target(target)) + } + + if err := c.tf.Apply(ctx, opts...); err != nil { + return CreateOutput{}, fmt.Errorf("terraform apply: %w", err) + } + + tfState, err := c.tf.Show(ctx) + if err != nil { + return CreateOutput{}, fmt.Errorf("terraform show: %w", err) + } + + ipOutput, ok := tfState.Values.Outputs["ip"] + if !ok { + return CreateOutput{}, errors.New("no IP output found") + } + ip, ok := ipOutput.Value.(string) + if !ok { + return CreateOutput{}, errors.New("invalid type in IP output: not a string") + } + + uidOutput, ok := tfState.Values.Outputs["uid"] + if !ok { + return CreateOutput{}, errors.New("no uid output found") + } + uid, ok := uidOutput.Value.(string) + if !ok { + return CreateOutput{}, errors.New("invalid type in uid output: not a string") + } + + return CreateOutput{ + IP: ip, + UID: uid, + }, nil +} + +// CreateOutput contains the Terraform output values of a cluster creation. +type CreateOutput struct { + IP string + Secret string + UID string + // AttestationURL is the URL of the attestation provider. + // It is only set if the cluster is created on Azure. + AttestationURL string +} + +// IAMOutput contains the output information of the Terraform IAM operations. +type IAMOutput struct { + GCP GCPIAMOutput +} + +// GCPIAMOutput contains the output information of the Terraform IAM operation on GCP. +type GCPIAMOutput struct { + SaKey string +} + +// CreateIAMConfig creates an IAM configuration using Terraform. +func (c *Client) CreateIAMConfig(ctx context.Context, logLevel LogLevel) (IAMOutput, error) { + if err := c.setLogLevel(logLevel); err != nil { + return IAMOutput{}, fmt.Errorf("set terraform log level %s: %w", logLevel.String(), err) + } + + if err := c.tf.Init(ctx); err != nil { + return IAMOutput{}, err + } + + if err := c.tf.Apply(ctx); err != nil { + return IAMOutput{}, err + } + + tfState, err := c.tf.Show(ctx) + if err != nil { + return IAMOutput{}, err + } + + saKeyOutputRaw, ok := tfState.Values.Outputs["sa_key"] + if !ok { + return IAMOutput{}, errors.New("no service account key output found") + } + saKeyOutput, ok := saKeyOutputRaw.Value.(string) + if !ok { + return IAMOutput{}, errors.New("invalid type in service account key output: not a string") + } + return IAMOutput{ + GCP: GCPIAMOutput{ + SaKey: saKeyOutput, + }, + }, nil +} + +// Plan determines the diff that will be applied by Terraform. The plan output is written to the planFile. +// If there is a diff, the returned bool is true. Otherwise, it is false. +func (c *Client) Plan(ctx context.Context, logLevel LogLevel, planFile string, targets ...string) (bool, error) { + if err := c.setLogLevel(logLevel); err != nil { + return false, fmt.Errorf("set terraform log level %s: %w", logLevel.String(), err) + } + + if err := c.tf.Init(ctx); err != nil { + return false, fmt.Errorf("terraform init: %w", err) + } + + opts := []tfexec.PlanOption{ + tfexec.Out(planFile), + } + for _, target := range targets { + opts = append(opts, tfexec.Target(target)) + } + return c.tf.Plan(ctx, opts...) +} + +// ShowPlan formats the diff in planFilePath and writes it to the specified output. +func (c *Client) ShowPlan(ctx context.Context, logLevel LogLevel, planFilePath string, output io.Writer) error { + if err := c.setLogLevel(logLevel); err != nil { + return fmt.Errorf("set terraform log level %s: %w", logLevel.String(), err) + } + + planResult, err := c.tf.ShowPlanFileRaw(ctx, planFilePath) + if err != nil { + return fmt.Errorf("terraform show plan: %w", err) + } + + _, err = output.Write([]byte(planResult)) + if err != nil { + return fmt.Errorf("write plan output: %w", err) + } + + return nil +} + +// Destroy destroys Terraform-created cloud resources. +func (c *Client) Destroy(ctx context.Context, logLevel LogLevel) error { + if err := c.setLogLevel(logLevel); err != nil { + return fmt.Errorf("set terraform log level %s: %w", logLevel.String(), err) + } + + if err := c.tf.Init(ctx); err != nil { + return fmt.Errorf("terraform init: %w", err) + } + return c.tf.Destroy(ctx) +} + +// RemoveInstaller removes the Terraform installer, if it was downloaded for this command. +func (c *Client) RemoveInstaller() { + c.remove() +} + +// CleanUpWorkspace removes terraform files from the current directory. +func (c *Client) CleanUpWorkspace() error { + return cleanUpWorkspace(c.file, c.workingDir) +} + +// GetExecutable returns a Terraform executable either from the local filesystem, +// or downloads the latest version fulfilling the version constraint. +func GetExecutable(ctx context.Context, workingDir string) (terraform *tfexec.Terraform, remove func(), err error) { + inst := install.NewInstaller() + + version, err := version.NewConstraint(tfVersion) + if err != nil { + return nil, nil, err + } + + downloadVersion := &releases.LatestVersion{ + Product: product.Terraform, + Constraints: version, + } + localVersion := &fs.Version{ + Product: product.Terraform, + Constraints: version, + } + + execPath, err := inst.Ensure(ctx, []src.Source{localVersion, downloadVersion}) + if err != nil { + return nil, nil, err + } + + tf, err := tfexec.NewTerraform(workingDir, execPath) + + return tf, func() { _ = inst.Remove(context.Background()) }, err +} + +// writeVars tries to write the Terraform variables file or, if it exists, checks if it is the same as we are expecting. +func (c *Client) writeVars(vars Variables) error { + if vars == nil { + return errors.New("creating cluster: vars is nil") + } + + pathToVarsFile := filepath.Join(c.workingDir, terraformVarsFile) + if err := c.file.Write(pathToVarsFile, []byte(vars.String())); errors.Is(err, afero.ErrFileExists) { + // If a variables file already exists, check if it's the same as we're expecting, so we can continue using it. + varsContent, err := c.file.Read(pathToVarsFile) + if err != nil { + return fmt.Errorf("read variables file: %w", err) + } + if vars.String() != string(varsContent) { + return ErrTerraformWorkspaceExistsWithDifferentVariables + } + } else if err != nil { + return fmt.Errorf("write variables file: %w", err) + } + + return nil +} + +// setLogLevel sets the log level for Terraform. +func (c *Client) setLogLevel(logLevel LogLevel) error { + if logLevel.String() != "" { + if err := c.tf.SetLog(logLevel.String()); err != nil { + return fmt.Errorf("set log level %s: %w", logLevel.String(), err) + } + if err := c.tf.SetLogPath(filepath.Join("..", config.TerraformLogFile)); err != nil { + return fmt.Errorf("set log path: %w", err) + } + } + return nil +} + +type tfInterface interface { + Apply(context.Context, ...tfexec.ApplyOption) error + Destroy(context.Context, ...tfexec.DestroyOption) error + Init(context.Context, ...tfexec.InitOption) error + Show(context.Context, ...tfexec.ShowOption) (*tfjson.State, error) + Plan(ctx context.Context, opts ...tfexec.PlanOption) (bool, error) + ShowPlanFileRaw(ctx context.Context, planPath string, opts ...tfexec.ShowOption) (string, error) + SetLog(level string) error + SetLogPath(path string) error +} diff --git a/cli/infrastructure/cloud/terraform/gcp/.terraform.lock.hcl b/cli/infrastructure/cloud/terraform/gcp/.terraform.lock.hcl new file mode 100644 index 0000000..3040fd3 --- /dev/null +++ b/cli/infrastructure/cloud/terraform/gcp/.terraform.lock.hcl @@ -0,0 +1,60 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/google" { + version = "4.65.1" + constraints = "4.65.1" + hashes = [ + "h1:Ro51tXhUEKxzA2aN+xCnX+lvZq1g0xySYxiAWmJ8FD4=", + "zh:159f438520edc356222e0cc302660582d6ba434ea2ed603b790bde1f28206896", + "zh:31750198c7694bbe8e5c94c2604f825e3d0b0e5a280d7ef3493c0981da50f9ed", + "zh:3a9e26800027d9d22bd8390097fc3aee4dbd521f988b1f2d75e4054ffa474fcc", + "zh:3c4d12ef2827676e37688af32f4982844e8ecdd576d5208fc2caaf1047d9d53c", + "zh:84096c55dcce18bf2b238c7df9af7ac22207695f7b3cd30f0caa03a304c81452", + "zh:8586386742458080ba50957dbf03d660d22a9ac5bf13b6f8b3904a93d4a2566c", + "zh:a07ec8f531bb7f202005ffbf1b16e316675a74f31004cd98d29b9a2a2c1a054a", + "zh:a27936fffe7b84fd29429ca7adffe1ff3099089348c85259b4b9846a2d58e3aa", + "zh:beee82487b9e7744614b763b633991abd99894302851194b6481f96989ff14c7", + "zh:d18289e9f85e60fef2782b101fccdc1e092b155d5da7bde3f007f74aaa6a69d7", + "zh:d4531a4f90983fe6b5b115250c0059c48f26657a0ea707579723bfb7cdc380a1", + "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", + ] +} + +provider "registry.terraform.io/hashicorp/google-beta" { + version = "4.68.0" + hashes = [ + "h1:DXqvZLUuT9Z3lqznhqC+XM8zUaulwfOjKEwfcvb9Wrs=", + "zh:1542a09f0e54fd90036e5819abbf49d3225582e6542cd35304dab49791d6bd37", + "zh:1e7f9e9b7e1a19b2d04c1855452d9f9ca78657a22c6dacfcbc7ea3993b7f520d", + "zh:62e97546392b9173ceebb15306fb804099e4d312698b6d2870673d5ae9bc57b5", + "zh:6d829047b8fa9ebd3c476adbda5ec3806e54f5ec8fc1c740c88fa1f6ee5f6dd5", + "zh:7241fa32925205ac4953c4df7078f37ff2d255346fbaa5512a1cbaf1696ce38d", + "zh:95bb72aeef02f6cd296fbbd2cc1758d55167c42a0ab70b2c1530183e85fc7a54", + "zh:ac0a2c4bfa3e2b952dd5c3c4162ec9497444fd88edae1f4543a255f75bdc1b00", + "zh:c7a9a82624f9a15f7ae854a3563f60a39ecd2bc04ac757ee7f87d6b859640c53", + "zh:d147ccf652505a88577428223e21e6e8731161f99f553b2e9300c5ee97d41153", + "zh:df7bef7fe0eb8d89639430a06a64a7c25e811bf53e87d0e80ec9037354e424d1", + "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", + "zh:f7a71410954b3c4639d335bdc3261d340f1c33df8924da3059f3144d575b38b1", + ] +} + +provider "registry.terraform.io/hashicorp/random" { + version = "3.5.1" + hashes = [ + "h1:VSnd9ZIPyfKHOObuQCaKfnjIHRtR7qTw19Rz8tJxm+k=", + "zh:04e3fbd610cb52c1017d282531364b9c53ef72b6bc533acb2a90671957324a64", + "zh:119197103301ebaf7efb91df8f0b6e0dd31e6ff943d231af35ee1831c599188d", + "zh:4d2b219d09abf3b1bb4df93d399ed156cadd61f44ad3baf5cf2954df2fba0831", + "zh:6130bdde527587bbe2dcaa7150363e96dbc5250ea20154176d82bc69df5d4ce3", + "zh:6cc326cd4000f724d3086ee05587e7710f032f94fc9af35e96a386a1c6f2214f", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:b6d88e1d28cf2dfa24e9fdcc3efc77adcdc1c3c3b5c7ce503a423efbdd6de57b", + "zh:ba74c592622ecbcef9dc2a4d81ed321c4e44cddf7da799faa324da9bf52a22b2", + "zh:c7c5cde98fe4ef1143bd1b3ec5dc04baf0d4cc3ca2c5c7d40d17c0e9b2076865", + "zh:dac4bad52c940cd0dfc27893507c1e92393846b024c5a9db159a93c534a3da03", + "zh:de8febe2a2acd9ac454b844a4106ed295ae9520ef54dc8ed2faf29f12716b602", + "zh:eab0d0495e7e711cca367f7d4df6e322e6c562fc52151ec931176115b83ed014", + ] +} diff --git a/cli/infrastructure/cloud/terraform/gcp/main.tf b/cli/infrastructure/cloud/terraform/gcp/main.tf new file mode 100644 index 0000000..f87f365 --- /dev/null +++ b/cli/infrastructure/cloud/terraform/gcp/main.tf @@ -0,0 +1,210 @@ +terraform { + required_providers { + google = { + source = "hashicorp/google" + version = "4.65.1" + } + } +} + +provider "google" { + project = var.project + region = var.region + zone = var.zone +} + +provider "google-beta" { + project = var.project + region = var.region + zone = var.zone +} + +/* +provider "google" { + credentials = file("delegatio.json") + + project = "delegatio" + region = "europe-west6" + zone = "europe-west6-a" +} + + +provider "google-beta" { + credentials = file("delegatio.json") + + project = "delegatio" + region = "europe-west6" + zone = "europe-west6-a" +} */ + +locals { + uid = random_id.uid.hex + name = "${var.name}-${local.uid}" + labels = { delegatio-uid = local.uid } + ports_node_range = "30000-32767" + ports_kubernetes = "6443" + ports_bootstrapper = "9000" + ports_etcd = "2379" + ports_ssh = "22" + cidr_vpc_subnet_nodes = "192.168.178.0/24" + cidr_vpc_subnet_pods = "10.10.0.0/16" + kube_env = "AUTOSCALER_ENV_VARS: kube_reserved=cpu=1060m,memory=1019Mi,ephemeral-storage=41Gi;node_labels=;os=linux;evictionHard=" +} + +resource "random_id" "uid" { + byte_length = 4 +} + +resource "google_compute_network" "vpc_network" { + name = local.name + description = "Delegatio VPC network" + auto_create_subnetworks = false + mtu = 8896 +} + +resource "google_compute_subnetwork" "vpc_subnetwork" { + name = local.name + description = "Delegatio VPC subnetwork" + network = google_compute_network.vpc_network.id + ip_cidr_range = local.cidr_vpc_subnet_nodes + secondary_ip_range = [ + { + range_name = local.name, + ip_cidr_range = local.cidr_vpc_subnet_pods, + } + ] +} + +resource "google_compute_router" "vpc_router" { + name = local.name + description = "Delegatio VPC router" + network = google_compute_network.vpc_network.id +} + +resource "google_compute_router_nat" "vpc_router_nat" { + name = local.name + router = google_compute_router.vpc_router.name + nat_ip_allocate_option = "AUTO_ONLY" + source_subnetwork_ip_ranges_to_nat = "ALL_SUBNETWORKS_ALL_IP_RANGES" +} + +resource "google_compute_firewall" "firewall_external" { + name = local.name + description = "Delegatio VPC firewall" + network = google_compute_network.vpc_network.id + source_ranges = ["0.0.0.0/0"] + direction = "INGRESS" + + allow { + protocol = "tcp" + ports = flatten([ + local.ports_node_range, + local.ports_bootstrapper, + local.ports_kubernetes, + var.debug ? [local.ports_ssh] : [], + ]) + } + +} + +resource "google_compute_firewall" "firewall_internal_nodes" { + name = "${local.name}-nodes" + description = "Constellation VPC firewall" + network = google_compute_network.vpc_network.id + source_ranges = [local.cidr_vpc_subnet_nodes] + direction = "INGRESS" + + allow { protocol = "tcp" } + allow { protocol = "udp" } + allow { protocol = "icmp" } +} + +resource "google_compute_firewall" "firewall_internal_pods" { + name = "${local.name}-pods" + description = "Constellation VPC firewall" + network = google_compute_network.vpc_network.id + source_ranges = [local.cidr_vpc_subnet_pods] + direction = "INGRESS" + + allow { protocol = "tcp" } + allow { protocol = "udp" } + allow { protocol = "icmp" } +} + + +module "instance_group_control_plane" { + source = "./modules/instance_group" + name = local.name + role = "ControlPlane" + uid = local.uid + instance_type = var.instance_type + instance_count = var.control_plane_count + image_id = var.image_id + disk_size = var.state_disk_size + disk_type = var.state_disk_type + network = google_compute_network.vpc_network.id + subnetwork = google_compute_subnetwork.vpc_subnetwork.id + alias_ip_range_name = google_compute_subnetwork.vpc_subnetwork.secondary_ip_range[0].range_name + kube_env = local.kube_env + debug = var.debug + named_ports = flatten([ + { name = "kubernetes", port = local.ports_kubernetes }, + { name = "bootstrapper", port = local.ports_bootstrapper }, + ]) + labels = local.labels +} + +module "instance_group_worker" { + source = "./modules/instance_group" + name = "${local.name}-1" + role = "Worker" + uid = local.uid + instance_type = var.instance_type + instance_count = var.worker_count + image_id = var.image_id + disk_size = var.state_disk_size + disk_type = var.state_disk_type + network = google_compute_network.vpc_network.id + subnetwork = google_compute_subnetwork.vpc_subnetwork.id + alias_ip_range_name = google_compute_subnetwork.vpc_subnetwork.secondary_ip_range[0].range_name + kube_env = local.kube_env + debug = var.debug + labels = local.labels +} + +resource "google_compute_global_address" "loadbalancer_ip" { + name = local.name +} + +module "loadbalancer_kube" { + source = "./modules/loadbalancer" + name = local.name + health_check = "HTTPS" + backend_port_name = "kubernetes" + backend_instance_group = module.instance_group_control_plane.instance_group + ip_address = google_compute_global_address.loadbalancer_ip.self_link + port = local.ports_kubernetes + frontend_labels = merge(local.labels, { delegatio-use = "kubernetes" }) +} + +module "loadbalancer_boot" { + source = "./modules/loadbalancer" + name = local.name + health_check = "TCP" + backend_port_name = "bootstrapper" + backend_instance_group = module.instance_group_control_plane.instance_group + ip_address = google_compute_global_address.loadbalancer_ip.self_link + port = local.ports_bootstrapper + frontend_labels = merge(local.labels, { delegatio-use = "bootstrapper" }) +} + +module "loadbalancer_etcd" { + source = "./modules/loadbalancer" + name = local.name + health_check = "TCP" + backend_port_name = "etcd" + backend_instance_group = module.instance_group_control_plane.instance_group + ip_address = google_compute_global_address.loadbalancer_ip.self_link + port = local.ports_etcd + frontend_labels = merge(local.labels, { delegatio-use = "etcd" }) +} diff --git a/cli/infrastructure/cloud/terraform/gcp/modules/instance_group/main.tf b/cli/infrastructure/cloud/terraform/gcp/modules/instance_group/main.tf new file mode 100644 index 0000000..383d802 --- /dev/null +++ b/cli/infrastructure/cloud/terraform/gcp/modules/instance_group/main.tf @@ -0,0 +1,136 @@ +terraform { + required_providers { + google = { + source = "hashicorp/google" + version = "4.65.1" + } + } +} + +locals { + role_dashed = var.role == "ControlPlane" ? "control-plane" : "worker" + name = "${var.name}-${local.role_dashed}" + state_disk_name = "state-disk" +} + +resource "google_compute_instance_template" "template" { + name = local.name + machine_type = var.instance_type + tags = ["constellation-${var.uid}"] // Note that this is also applied as a label + labels = merge(var.labels, { constellation-role = local.role_dashed }) + + confidential_instance_config { + enable_confidential_compute = false + } + + disk { + disk_size_gb = 30 + source_image = var.image_id + auto_delete = true + boot = true + mode = "READ_WRITE" + } + + disk { + disk_size_gb = var.disk_size + disk_type = var.disk_type + auto_delete = true + device_name = local.state_disk_name // This name is used by disk mapper to find the disk + boot = false + mode = "READ_WRITE" + type = "PERSISTENT" + } + + metadata = { + kube-env = var.kube_env + serial-port-enable = "TRUE" + } + + network_interface { + network = var.network + subnetwork = var.subnetwork + alias_ip_range { + ip_cidr_range = "/24" + subnetwork_range_name = var.alias_ip_range_name + } + } + + scheduling { + on_host_maintenance = "TERMINATE" + } + + service_account { + scopes = [ + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/servicecontrol", + "https://www.googleapis.com/auth/service.management.readonly", + "https://www.googleapis.com/auth/devstorage.read_only", + "https://www.googleapis.com/auth/logging.write", + "https://www.googleapis.com/auth/monitoring.write", + "https://www.googleapis.com/auth/trace.append", + "https://www.googleapis.com/auth/cloud-platform", + ] + } + + shielded_instance_config { + enable_secure_boot = false + enable_vtpm = true + enable_integrity_monitoring = true + } + + lifecycle { + ignore_changes = [ + tags, + labels, + disk, # required. update procedure modifies the instance template externally + metadata, + network_interface, + scheduling, + service_account, + shielded_instance_config, + ] + } +} + +resource "google_compute_instance_group_manager" "instance_group_manager" { + provider = google-beta + name = local.name + description = "Instance group manager for Delegatio" + base_instance_name = local.name + target_size = var.instance_count + + dynamic "stateful_disk" { + for_each = var.role == "ControlPlane" ? [1] : [] + content { + device_name = local.state_disk_name + delete_rule = "ON_PERMANENT_INSTANCE_DELETION" + } + } + + dynamic "stateful_internal_ip" { + for_each = var.role == "ControlPlane" ? [1] : [] + content { + interface_name = "nic0" + delete_rule = "ON_PERMANENT_INSTANCE_DELETION" + } + } + + version { + instance_template = google_compute_instance_template.template.id + } + + dynamic "named_port" { + for_each = toset(var.named_ports) + content { + name = named_port.value.name + port = named_port.value.port + } + } + + lifecycle { + ignore_changes = [ + target_size, # required. autoscaling modifies the instance count externally + version, # required. update procedure modifies the instance template externally + ] + } +} diff --git a/cli/infrastructure/cloud/terraform/gcp/modules/instance_group/outputs.tf b/cli/infrastructure/cloud/terraform/gcp/modules/instance_group/outputs.tf new file mode 100644 index 0000000..66f793f --- /dev/null +++ b/cli/infrastructure/cloud/terraform/gcp/modules/instance_group/outputs.tf @@ -0,0 +1,3 @@ +output "instance_group" { + value = google_compute_instance_group_manager.instance_group_manager.instance_group +} diff --git a/cli/infrastructure/cloud/terraform/gcp/modules/instance_group/variables.tf b/cli/infrastructure/cloud/terraform/gcp/modules/instance_group/variables.tf new file mode 100644 index 0000000..0617933 --- /dev/null +++ b/cli/infrastructure/cloud/terraform/gcp/modules/instance_group/variables.tf @@ -0,0 +1,81 @@ +variable "name" { + type = string + description = "Base name of the instance group." +} + +variable "role" { + type = string + description = "The role of the instance group." + validation { + condition = contains(["ControlPlane", "Worker"], var.role) + error_message = "The role has to be 'ControlPlane' or 'Worker'." + } +} + +variable "uid" { + type = string + description = "UID of the cluster. This is used for tags." +} + +variable "labels" { + type = map(string) + default = {} + description = "Labels to apply to the instance group." +} + +variable "instance_type" { + type = string + description = "Instance type for the nodes." +} + +variable "instance_count" { + type = number + description = "Number of instances in the instance group." +} + +variable "image_id" { + type = string + description = "Image ID for the nodes." +} + +variable "disk_size" { + type = number + description = "Disk size for the nodes, in GB." +} + +variable "disk_type" { + type = string + description = "Disk type for the nodes. Has to be 'pd-standard' or 'pd-ssd'." +} + +variable "network" { + type = string + description = "Name of the network to use." +} + +variable "subnetwork" { + type = string + description = "Name of the subnetwork to use." +} + +variable "kube_env" { + type = string + description = "Kubernetes env." +} + +variable "named_ports" { + type = list(object({ name = string, port = number })) + default = [] + description = "Named ports for the instance group." +} + +variable "debug" { + type = bool + default = false + description = "Enable debug mode. This will enable serial port access on the instances." +} + +variable "alias_ip_range_name" { + type = string + description = "Name of the alias IP range to use." +} diff --git a/cli/infrastructure/cloud/terraform/gcp/modules/loadbalancer/main.tf b/cli/infrastructure/cloud/terraform/gcp/modules/loadbalancer/main.tf new file mode 100644 index 0000000..0d89b1d --- /dev/null +++ b/cli/infrastructure/cloud/terraform/gcp/modules/loadbalancer/main.tf @@ -0,0 +1,63 @@ +terraform { + required_providers { + google = { + source = "hashicorp/google" + version = "4.65.1" + } + } +} + +locals { + name = "${var.name}-${var.backend_port_name}" +} + +resource "google_compute_health_check" "health" { + name = local.name + check_interval_sec = 1 + timeout_sec = 1 + + dynamic "tcp_health_check" { + for_each = var.health_check == "TCP" ? [1] : [] + content { + port = var.port + } + } + + dynamic "https_health_check" { + for_each = var.health_check == "HTTPS" ? [1] : [] + content { + host = "" + port = var.port + request_path = "/readyz" + } + } +} + +resource "google_compute_backend_service" "backend" { + name = local.name + protocol = "TCP" + load_balancing_scheme = "EXTERNAL" + health_checks = [google_compute_health_check.health.self_link] + port_name = var.backend_port_name + timeout_sec = 240 + + backend { + group = var.backend_instance_group + balancing_mode = "UTILIZATION" + } +} + +resource "google_compute_target_tcp_proxy" "proxy" { + name = local.name + backend_service = google_compute_backend_service.backend.self_link +} + +resource "google_compute_global_forwarding_rule" "forwarding" { + name = local.name + ip_address = var.ip_address + ip_protocol = "TCP" + load_balancing_scheme = "EXTERNAL" + port_range = var.port + target = google_compute_target_tcp_proxy.proxy.self_link + labels = var.frontend_labels +} diff --git a/cli/infrastructure/cloud/terraform/gcp/modules/loadbalancer/variables.tf b/cli/infrastructure/cloud/terraform/gcp/modules/loadbalancer/variables.tf new file mode 100644 index 0000000..18c2901 --- /dev/null +++ b/cli/infrastructure/cloud/terraform/gcp/modules/loadbalancer/variables.tf @@ -0,0 +1,35 @@ +variable "name" { + type = string + description = "Base name of the load balancer." +} + +variable "health_check" { + type = string + description = "The type of the health check. 'HTTPS' or 'TCP'." +} + +variable "backend_port_name" { + type = string + description = "Name of backend port. The same name should appear in the instance groups referenced by this service." +} + +variable "backend_instance_group" { + type = string + description = "The URL of the instance group resource from which the load balancer will direct traffic." +} + +variable "ip_address" { + type = string + description = "The IP address that this forwarding rule serves. An address can be specified either by a literal IP address or a reference to an existing Address resource." +} + +variable "port" { + type = number + description = "The port on which to listen for incoming traffic." +} + +variable "frontend_labels" { + type = map(string) + default = {} + description = "Labels to apply to the forwarding rule." +} diff --git a/cli/infrastructure/cloud/terraform/gcp/variables.tf b/cli/infrastructure/cloud/terraform/gcp/variables.tf new file mode 100644 index 0000000..a065b1e --- /dev/null +++ b/cli/infrastructure/cloud/terraform/gcp/variables.tf @@ -0,0 +1,62 @@ +variable "name" { + type = string + default = "delegatioooo" + description = "Base name of the cluster." +} + +variable "debug" { + type = bool + default = true + description = "Enable debug mode. This opens up a debugd port that can be used to deploy a custom bootstrapper." +} + +variable "control_plane_count" { + type = number + default = 2 + description = "The number of control plane nodes to deploy." +} + +variable "worker_count" { + type = number + default = 2 + description = "The number of worker nodes to deploy." +} + +variable "state_disk_size" { + type = number + default = 30 + description = "The size of the state disk in GB." +} + +variable "instance_type" { + type = string + default = "g1-small" + description = "The GCP instance type to deploy." +} + +variable "state_disk_type" { + type = string + default = "pd-ssd" + description = "The type of the state disk." +} + +variable "image_id" { + type = string + default = "https://www.googleapis.com/compute/v1/projects/delegatio/global/images/gcp-0-0-0-test" + description = "The GCP image to use for the cluster nodes." +} + +variable "project" { + type = string + description = "The GCP project to deploy the cluster in." +} + +variable "region" { + type = string + description = "The GCP region to deploy the cluster in." +} + +variable "zone" { + type = string + description = "The GCP zone to deploy the cluster in." +} \ No newline at end of file diff --git a/cli/infrastructure/cloud/variables.go b/cli/infrastructure/cloud/variables.go new file mode 100644 index 0000000..af4b3b2 --- /dev/null +++ b/cli/infrastructure/cloud/variables.go @@ -0,0 +1,175 @@ +/* +Copyright (c) Edgeless Systems GmbH + +SPDX-License-Identifier: AGPL-3.0-only +*/ + +package terraform + +import ( + "fmt" + "strings" +) + +// Variables is a struct that holds all variables that are passed to Terraform. +type Variables interface { + fmt.Stringer +} + +// CommonVariables is user configuration for creating a cluster with Terraform. +type CommonVariables struct { + // Name of the cluster. + Name string + // CountControlPlanes is the number of control-plane nodes to create. + CountControlPlanes int + // CountWorkers is the number of worker nodes to create. + CountWorkers int + // StateDiskSizeGB is the size of the state disk to allocate to each node, in GB. + StateDiskSizeGB int +} + +// String returns a string representation of the variables, formatted as Terraform variables. +func (v *CommonVariables) String() string { + b := &strings.Builder{} + writeLinef(b, "name = %q", v.Name) + writeLinef(b, "control_plane_count = %d", v.CountControlPlanes) + writeLinef(b, "worker_count = %d", v.CountWorkers) + writeLinef(b, "state_disk_size = %d", v.StateDiskSizeGB) + + return b.String() +} + +// GCPClusterVariables is user configuration for creating resources with Terraform on GCP. +type GCPClusterVariables struct { + // CommonVariables contains common variables. + CommonVariables + + // Project is the ID of the GCP project to use. + Project string + // Region is the GCP region to use. + Region string + // Zone is the GCP zone to use. + Zone string + // CredentialsFile is the path to the GCP credentials file. + CredentialsFile string + // InstanceType is the GCP instance type to use. + InstanceType string + // StateDiskType is the GCP disk type to use for the state disk. + StateDiskType string + // ImageID is the ID of the GCP image to use. + ImageID string + // Debug is true if debug mode is enabled. + Debug bool +} + +// String returns a string representation of the variables, formatted as Terraform variables. +func (v *GCPClusterVariables) String() string { + b := &strings.Builder{} + b.WriteString(v.CommonVariables.String()) + writeLinef(b, "project = %q", v.Project) + writeLinef(b, "region = %q", v.Region) + writeLinef(b, "zone = %q", v.Zone) + writeLinef(b, "instance_type = %q", v.InstanceType) + writeLinef(b, "state_disk_type = %q", v.StateDiskType) + writeLinef(b, "image_id = %q", v.ImageID) + writeLinef(b, "debug = %t", v.Debug) + + return b.String() +} + +// GCPIAMVariables is user configuration for creating the IAM confioguration with Terraform on GCP. +type GCPIAMVariables struct { + // Project is the ID of the GCP project to use. + Project string + // Region is the GCP region to use. + Region string + // Zone is the GCP zone to use. + Zone string + // ServiceAccountID is the ID of the service account to use. + ServiceAccountID string +} + +// String returns a string representation of the IAM-specific variables, formatted as Terraform variables. +func (v *GCPIAMVariables) String() string { + b := &strings.Builder{} + writeLinef(b, "project_id = %q", v.Project) + writeLinef(b, "region = %q", v.Region) + writeLinef(b, "zone = %q", v.Zone) + writeLinef(b, "service_account_id = %q", v.ServiceAccountID) + + return b.String() +} + +// QEMUVariables is user configuration for creating a QEMU cluster with Terraform. +type QEMUVariables struct { + // CommonVariables contains common variables. + CommonVariables + + // LibvirtURI is the libvirt connection URI. + LibvirtURI string + // LibvirtSocketPath is the path to the libvirt socket in case of unix socket. + LibvirtSocketPath string + // BootMode is the boot mode to use. + // Can be either "uefi" or "direct-linux-boot". + BootMode string + // CPUCount is the number of CPUs to allocate to each node. + CPUCount int + // MemorySizeMiB is the amount of memory to allocate to each node, in MiB. + MemorySizeMiB int + // IPRangeStart is the first IP address in the IP range to allocate to the cluster. + ImagePath string + // ImageFormat is the format of the image from ImagePath. + ImageFormat string + // MetadataAPIImage is the container image to use for the metadata API. + MetadataAPIImage string + // MetadataLibvirtURI is the libvirt connection URI used by the metadata container. + // In case of unix socket, this should be "qemu:///system". + // Other wise it should be the same as LibvirtURI. + MetadataLibvirtURI string + // NVRAM is the path to the NVRAM template. + NVRAM string + // Firmware is the path to the firmware. + Firmware string + // BzImagePath is the path to the bzImage (kernel). + BzImagePath string + // InitrdPath is the path to the initrd. + InitrdPath string + // KernelCmdline is the kernel command line. + KernelCmdline string +} + +// String returns a string representation of the variables, formatted as Terraform variables. +func (v *QEMUVariables) String() string { + b := &strings.Builder{} + b.WriteString(v.CommonVariables.String()) + writeLinef(b, "libvirt_uri = %q", v.LibvirtURI) + writeLinef(b, "libvirt_socket_path = %q", v.LibvirtSocketPath) + writeLinef(b, "constellation_os_image = %q", v.ImagePath) + writeLinef(b, "image_format = %q", v.ImageFormat) + writeLinef(b, "constellation_boot_mode = %q", v.BootMode) + writeLinef(b, "constellation_kernel = %q", v.BzImagePath) + writeLinef(b, "constellation_initrd = %q", v.InitrdPath) + writeLinef(b, "constellation_cmdline = %q", v.KernelCmdline) + writeLinef(b, "vcpus = %d", v.CPUCount) + writeLinef(b, "memory = %d", v.MemorySizeMiB) + writeLinef(b, "metadata_api_image = %q", v.MetadataAPIImage) + writeLinef(b, "metadata_libvirt_uri = %q", v.MetadataLibvirtURI) + switch v.NVRAM { + case "production": + b.WriteString("nvram = \"/usr/share/OVMF/constellation_vars.production.fd\"\n") + case "testing": + b.WriteString("nvram = \"/usr/share/OVMF/constellation_vars.testing.fd\"\n") + default: + writeLinef(b, "nvram = %q", v.NVRAM) + } + if v.Firmware != "" { + writeLinef(b, "firmware = %q", v.Firmware) + } + + return b.String() +} + +func writeLinef(builder *strings.Builder, format string, a ...any) { + builder.WriteString(fmt.Sprintf(format, a...)) + builder.WriteByte('\n') +} diff --git a/cli/infrastructure/infrastructure.go b/cli/infrastructure/infrastructure.go index e9d205b..1baa486 100644 --- a/cli/infrastructure/infrastructure.go +++ b/cli/infrastructure/infrastructure.go @@ -28,3 +28,8 @@ func NewQemu(log *zap.Logger, imagePath string) (Infrastructure, error) { } return instance, nil } + +// NewCloud creates a new Terraform Infrastructure. +func NewCloud(log *zap.Logger) (Infrastructure, error) { + return nil, nil +} diff --git a/cli/installer/installer.go b/cli/installer/installer.go index fe256be..ba368d2 100644 --- a/cli/installer/installer.go +++ b/cli/installer/installer.go @@ -73,6 +73,7 @@ func (k *installer) connectToEtcd(_ context.Context, creds *config.EtcdCredentia if err != nil { return err } + // get direct loadbalancer IP and place here. k.logger.Info("endpoint", zap.String("api", u.Host)) host, _, err := net.SplitHostPort(u.Host) if err != nil { diff --git a/cli/run.go b/cli/run.go index 32776a3..7711f2d 100644 --- a/cli/run.go +++ b/cli/run.go @@ -6,6 +6,7 @@ package main import ( "context" + "fmt" "github.com/benschlueter/delegatio/cli/bootstrapper" "github.com/benschlueter/delegatio/cli/infrastructure" @@ -37,11 +38,17 @@ func run(ctx context.Context, log *zap.Logger, imageLocation string) error { } }(log, lInstance) // --- infrastructure --- - nodes, err := createInfrastructure(ctx, log, lInstance) - if err != nil { - log.With(zap.Error(err)).DPanic("create infrastructure") - } + /* nodes, err := createInfrastructure(ctx, log, lInstance) + if err != nil { + log.With(zap.Error(err)).DPanic("create infrastructure") + } */ log.Info("finished infrastructure initialization") + nodes := &config.NodeInformation{ + Masters: map[string]string{ + "master1": "34.117.25.173", + }, + } + fmt.Println(nodes) /// --- kubernetes --- creds, err := bootstrapKubernetes(ctx, log, nodes) if err != nil { @@ -59,7 +66,7 @@ func run(ctx context.Context, log *zap.Logger, imageLocation string) error { } func bootstrapKubernetes(ctx context.Context, log *zap.Logger, nodes *config.NodeInformation) (*config.EtcdCredentials, error) { - kubeConf, err := utils.GetKubeInitConfig() + kubeConf, err := utils.GetKubeInitConfig("") if err != nil { log.With(zap.Error(err)).DPanic("failed to get kubeConfig") } diff --git a/container/challenges/testing/Dockerfile.archlinux b/container/challenges/testing/Dockerfile.archlinux index 89db130..d384840 100644 --- a/container/challenges/testing/Dockerfile.archlinux +++ b/container/challenges/testing/Dockerfile.archlinux @@ -17,6 +17,8 @@ RUN go build -o agent-user . FROM archlinux:latest +RUN useradd -d /home/user -s /bin/bash -u 1001 user + COPY --from=0 /delegatio/agent/server/agent / COPY --from=0 /delegatio/grader/user/agent-user / RUN pacman -Syy @@ -24,4 +26,6 @@ RUN pacman -Syy #RUN pacman-key --refresh-keys #RUN pacman -S --noconfirm go git gcc make cmake libvirt +USER user + CMD ["/agent", "--container", "--debug"] \ No newline at end of file diff --git a/images/mkosi.conf b/images/mkosi.conf index 786efac..9a60030 100644 --- a/images/mkosi.conf +++ b/images/mkosi.conf @@ -11,6 +11,8 @@ Output=image Bootable=yes Bootloader=systemd-boot #KernelCommandLine=preempt=full loglevel=8 +#KernelCommandLine=console=ttyS0,38400n8d // GCP + Packages=openssh,vim,curl,python,linux,base,socat,ethtool,conntrack-tools,iptables-nft,runc,cri-o,nfs-utils,bcc-tools,crun RootPassword=1234 diff --git a/internal/config/global.go b/internal/config/global.go index ecd0c85..c7f53ff 100644 --- a/internal/config/global.go +++ b/internal/config/global.go @@ -74,6 +74,8 @@ const ( SandboxPath = "/sandbox" // UUIDEnvVariable is the environment variable name of the uuid of the user. UUIDEnvVariable = "GraderUUID" + // TerraformLogFile is the file name of the Terraform log file. + TerraformLogFile = "terraform.log" ) // GetExampleConfig writes an example config to config.json. diff --git a/internal/config/utils/kubeadm_config.go b/internal/config/utils/kubeadm_config.go index f8340c7..df7244e 100644 --- a/internal/config/utils/kubeadm_config.go +++ b/internal/config/utils/kubeadm_config.go @@ -12,21 +12,25 @@ import ( ) // GetKubeInitConfig returns the init config for kubernetes. -func GetKubeInitConfig() ([]byte, error) { +func GetKubeInitConfig(loadbalancerIP string) ([]byte, error) { k8sConfig := initConfiguration() + if loadbalancerIP != "" { + k8sConfig.SetCertSANs([]string{loadbalancerIP}) + k8sConfig.SetControlPlaneEndpoint(loadbalancerIP + ":6443") + } return marshalK8SResources(&k8sConfig) } -// kubeadmInitYAML groups multiple kubernetes config files into one struct. -type kubeadmInitYAML struct { +// KubeadmInitYAML groups multiple kubernetes config files into one struct. +type KubeadmInitYAML struct { InitConfiguration kubeadm.InitConfiguration ClusterConfiguration kubeadm.ClusterConfiguration KubeletConfiguration kubeletconf.KubeletConfiguration } // initConfiguration sets the pre-defined values for kubernetes. -func initConfiguration() kubeadmInitYAML { - return kubeadmInitYAML{ +func initConfiguration() KubeadmInitYAML { + return KubeadmInitYAML{ InitConfiguration: kubeadm.InitConfiguration{ TypeMeta: v1.TypeMeta{ APIVersion: kubeadm.SchemeGroupVersion.String(), @@ -88,3 +92,20 @@ func initConfiguration() kubeadmInitYAML { }, } } + +// SetCertSANs sets the certSANs for the kubernetes api server. +func (k *KubeadmInitYAML) SetCertSANs(certSANs []string) { + for _, certSAN := range certSANs { + if certSAN == "" { + continue + } + k.ClusterConfiguration.APIServer.CertSANs = append(k.ClusterConfiguration.APIServer.CertSANs, certSAN) + } +} + +// SetControlPlaneEndpoint sets the control plane endpoint if controlPlaneEndpoint is not empty. +func (k *KubeadmInitYAML) SetControlPlaneEndpoint(controlPlaneEndpoint string) { + if controlPlaneEndpoint != "" { + k.ClusterConfiguration.ControlPlaneEndpoint = controlPlaneEndpoint + } +} diff --git a/internal/file/file.go b/internal/file/file.go new file mode 100644 index 0000000..c5bae00 --- /dev/null +++ b/internal/file/file.go @@ -0,0 +1,234 @@ +/* +Copyright (c) Edgeless Systems GmbH + +SPDX-License-Identifier: AGPL-3.0-only +*/ + +/* +Package file provides functions that combine file handling, JSON marshaling +and file system abstraction. +*/ +package file + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io" + "io/fs" + "os" + "path" + "path/filepath" + "strings" + + "github.com/siderolabs/talos/pkg/machinery/config/encoder" + "github.com/spf13/afero" + "gopkg.in/yaml.v3" +) + +// Option is a bitmask of options for file operations. +type Option struct { + uint +} + +// hasOption determines if a set of options contains the given option. +func hasOption(options []Option, op Option) bool { + for _, ops := range options { + if ops == op { + return true + } + } + return false +} + +const ( + // OptNone is a no-op. + optNone uint = iota + // OptOverwrite overwrites an existing file. + optOverwrite + // OptMkdirAll creates the path to the file. + optMkdirAll + // OptAppend appends to the file. + optAppend +) + +var ( + // OptNone is a no-op. + OptNone = Option{optNone} + // OptOverwrite overwrites an existing file. + OptOverwrite = Option{optOverwrite} + // OptMkdirAll creates the path to the file. + OptMkdirAll = Option{optMkdirAll} + // OptAppend appends to the file. + OptAppend = Option{optAppend} +) + +// Handler handles file interaction. +type Handler struct { + fs *afero.Afero +} + +// NewHandler returns a new file handler. +func NewHandler(fs afero.Fs) Handler { + afs := &afero.Afero{Fs: fs} + return Handler{fs: afs} +} + +// Read reads the file given name and returns the bytes read. +func (h *Handler) Read(name string) ([]byte, error) { + file, err := h.fs.OpenFile(name, os.O_RDONLY, 0o600) + if err != nil { + return nil, err + } + defer file.Close() + return io.ReadAll(file) +} + +// Write writes the data bytes into the file with the given name. +func (h *Handler) Write(name string, data []byte, options ...Option) error { + if hasOption(options, OptMkdirAll) { + if err := h.fs.MkdirAll(path.Dir(name), os.ModePerm); err != nil { + return err + } + } + flags := os.O_WRONLY | os.O_CREATE | os.O_EXCL + if hasOption(options, OptOverwrite) { + flags = os.O_WRONLY | os.O_CREATE | os.O_TRUNC + } + if hasOption(options, OptAppend) { + flags = os.O_WRONLY | os.O_CREATE | os.O_APPEND + } + file, err := h.fs.OpenFile(name, flags, 0o600) + if err != nil { + return err + } + _, err = file.Write(data) + if errTmp := file.Close(); errTmp != nil && err == nil { + err = errTmp + } + return err +} + +// ReadJSON reads a JSON file from name and unmarshals it into the content interface. +// The interface content must be a pointer to a JSON marchalable object. +func (h *Handler) ReadJSON(name string, content any) error { + data, err := h.Read(name) + if err != nil { + return err + } + return json.Unmarshal(data, content) +} + +// WriteJSON marshals the content interface to JSON and writes it to the path with the given name. +func (h *Handler) WriteJSON(name string, content any, options ...Option) error { + jsonData, err := json.MarshalIndent(content, "", "\t") + if err != nil { + return err + } + return h.Write(name, jsonData, options...) +} + +// ReadYAML reads a YAML file from name and unmarshals it into the content interface. +// The interface content must be a pointer to a YAML marshalable object. +func (h *Handler) ReadYAML(name string, content any) error { + return h.readYAML(name, content, false) +} + +// ReadYAMLStrict does the same as ReadYAML, but fails if YAML contains fields +// that are not specified in content. +func (h *Handler) ReadYAMLStrict(name string, content any) error { + return h.readYAML(name, content, true) +} + +func (h *Handler) readYAML(name string, content any, strict bool) error { + data, err := h.Read(name) + if err != nil { + return err + } + decoder := yaml.NewDecoder(bytes.NewBuffer(data)) + decoder.KnownFields(strict) + return decoder.Decode(content) +} + +// WriteYAML marshals the content interface to YAML and writes it to the path with the given name. +func (h *Handler) WriteYAML(name string, content any, options ...Option) (err error) { + defer func() { + if r := recover(); r != nil { + err = errors.New("recovered from panic") + } + }() + data, err := encoder.NewEncoder(content).Encode() + if err != nil { + return err + } + return h.Write(name, data, options...) +} + +// Remove deletes the file with the given name. +func (h *Handler) Remove(name string) error { + return h.fs.Remove(name) +} + +// RemoveAll deletes the file or directory with the given name. +func (h *Handler) RemoveAll(name string) error { + return h.fs.RemoveAll(name) +} + +// Stat returns a FileInfo describing the named file, or an error, if any +// happens. +func (h *Handler) Stat(name string) (fs.FileInfo, error) { + return h.fs.Stat(name) +} + +// MkdirAll creates a directory path and all parents that does not exist yet. +func (h *Handler) MkdirAll(name string) error { + return h.fs.MkdirAll(name, 0o700) +} + +// CopyDir copies the src directory recursively into dst with the given options. OptMkdirAll +// is always set. CopyDir does not follow symlinks. +func (h *Handler) CopyDir(src, dst string, opts ...Option) error { + opts = append(opts, OptMkdirAll) + root := filepath.Join(src, string(filepath.Separator)) + + walkFunc := func(path string, info fs.FileInfo, err error) error { + if err != nil { + return err + } + + if info.IsDir() { + return nil + } + + pathWithoutRoot := strings.TrimPrefix(path, root) + return h.CopyFile(path, filepath.Join(dst, pathWithoutRoot), opts...) + } + + return h.fs.Walk(src, walkFunc) +} + +// CopyFile copies the file from src to dst with the given options, respecting file permissions. +func (h *Handler) CopyFile(src, dst string, opts ...Option) error { + srcInfo, err := h.fs.Stat(src) + if err != nil { + return fmt.Errorf("stat source file: %w", err) + } + + content, err := h.fs.ReadFile(src) + if err != nil { + return fmt.Errorf("read source file: %w", err) + } + + err = h.Write(dst, content, opts...) + if err != nil { + return fmt.Errorf("write destination file: %w", err) + } + + err = h.fs.Chmod(dst, srcInfo.Mode()) + if err != nil { + return fmt.Errorf("chmod destination file: %w", err) + } + + return nil +} diff --git a/internal/file/file_test.go b/internal/file/file_test.go new file mode 100644 index 0000000..51cd762 --- /dev/null +++ b/internal/file/file_test.go @@ -0,0 +1,521 @@ +/* +Copyright (c) Edgeless Systems GmbH + +SPDX-License-Identifier: AGPL-3.0-only +*/ + +package file + +import ( + "encoding/json" + "io/fs" + "path/filepath" + "testing" + + "github.com/spf13/afero" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/goleak" + "gopkg.in/yaml.v3" +) + +func TestMain(m *testing.M) { + goleak.VerifyTestMain(m) +} + +func TestWrite(t *testing.T) { + testCases := map[string]struct { + fs afero.Fs + setupFs func(af afero.Afero) error + name string + content string + expectedContent string + options Option + wantErr bool + wantAppend bool + }{ + "successful write": { + fs: afero.NewMemMapFs(), + content: "asdf", + expectedContent: "asdf", + name: "somedir/somefile", + }, + "successful overwrite": { + fs: afero.NewMemMapFs(), + setupFs: func(af afero.Afero) error { return af.WriteFile("somedir/somefile", []byte{}, 0o644) }, + content: "asdf", + expectedContent: "asdf", + name: "somedir/somefile", + options: OptOverwrite, + }, + "successful append": { + fs: afero.NewMemMapFs(), + setupFs: func(af afero.Afero) error { return af.WriteFile("somedir/somefile", []byte("fdsa"), 0o644) }, + content: "asdf", + expectedContent: "fdsaasdf", + name: "somedir/somefile", + options: OptAppend, + }, + "read only fs": { + fs: afero.NewReadOnlyFs(afero.NewMemMapFs()), + name: "somedir/somefile", + wantErr: true, + }, + "file already exists": { + fs: afero.NewMemMapFs(), + setupFs: func(af afero.Afero) error { return af.WriteFile("somedir/somefile", []byte{}, 0o644) }, + name: "somedir/somefile", + wantErr: true, + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + assert := assert.New(t) + require := require.New(t) + + handler := NewHandler(tc.fs) + if tc.setupFs != nil { + require.NoError(tc.setupFs(afero.Afero{Fs: tc.fs})) + } + + if tc.wantErr { + assert.Error(handler.Write(tc.name, []byte(tc.content), tc.options)) + } else { + assert.NoError(handler.Write(tc.name, []byte(tc.content), tc.options)) + content, err := handler.Read(tc.name) + require.NoError(err) + assert.Equal(tc.expectedContent, string(content)) + } + }) + } +} + +func TestReadJSON(t *testing.T) { + type testContent struct { + First string + Second int + } + someContent := testContent{ + First: "first", + Second: 2, + } + jsonContent, err := json.MarshalIndent(someContent, "", "\t") + require.NoError(t, err) + + testCases := map[string]struct { + fs afero.Fs + setupFs func(fs *afero.Afero) error + name string + wantContent any + wantErr bool + }{ + "successful read": { + fs: afero.NewMemMapFs(), + name: "test/statefile", + setupFs: func(fs *afero.Afero) error { return fs.WriteFile("test/statefile", jsonContent, 0o755) }, + wantContent: someContent, + }, + "file not existent": { + fs: afero.NewMemMapFs(), + name: "test/statefile", + wantErr: true, + }, + "file not json": { + fs: afero.NewMemMapFs(), + name: "test/statefile", + setupFs: func(fs *afero.Afero) error { return fs.WriteFile("test/statefile", []byte{0x1}, 0o755) }, + wantErr: true, + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + assert := assert.New(t) + require := require.New(t) + + handler := NewHandler(tc.fs) + if tc.setupFs != nil { + require.NoError(tc.setupFs(handler.fs)) + } + + resultContent := &testContent{} + if tc.wantErr { + assert.Error(handler.ReadJSON(tc.name, resultContent)) + } else { + assert.NoError(handler.ReadJSON(tc.name, resultContent)) + assert.Equal(tc.wantContent, *resultContent) + } + }) + } +} + +func TestWriteJSON(t *testing.T) { + type testContent struct { + First string + Second int + } + someContent := testContent{ + First: "first", + Second: 2, + } + notMarshalableContent := struct{ Foo chan int }{Foo: make(chan int)} + + testCases := map[string]struct { + fs afero.Fs + setupFs func(af afero.Afero) error + name string + content any + options Option + wantErr bool + }{ + "successful write": { + fs: afero.NewMemMapFs(), + name: "test/statefile", + content: someContent, + }, + "successful overwrite": { + fs: afero.NewMemMapFs(), + setupFs: func(af afero.Afero) error { return af.WriteFile("test/statefile", []byte{}, 0o644) }, + name: "test/statefile", + content: someContent, + options: OptOverwrite, + }, + "read only fs": { + fs: afero.NewReadOnlyFs(afero.NewMemMapFs()), + name: "test/statefile", + content: someContent, + wantErr: true, + }, + "file already exists": { + fs: afero.NewMemMapFs(), + setupFs: func(af afero.Afero) error { return af.WriteFile("test/statefile", []byte{}, 0o644) }, + name: "test/statefile", + content: someContent, + wantErr: true, + }, + "marshal error": { + fs: afero.NewMemMapFs(), + name: "test/statefile", + content: notMarshalableContent, + wantErr: true, + }, + "mkdirAll works": { + fs: afero.NewMemMapFs(), + name: "test/statefile", + content: someContent, + options: OptMkdirAll, + }, + // TODO(malt3): add tests for mkdirAll actually creating the necessary folders when https://github.com/spf13/afero/issues/270 is fixed. + // Currently, MemMapFs will create files in nonexistent directories due to a bug in afero, + // making it impossible to test the actual behavior of the mkdirAll parameter. + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + assert := assert.New(t) + require := require.New(t) + + handler := NewHandler(tc.fs) + if tc.setupFs != nil { + require.NoError(tc.setupFs(afero.Afero{Fs: tc.fs})) + } + + if tc.wantErr { + assert.Error(handler.WriteJSON(tc.name, tc.content, tc.options)) + } else { + assert.NoError(handler.WriteJSON(tc.name, tc.content, tc.options)) + resultContent := &testContent{} + assert.NoError(handler.ReadJSON(tc.name, resultContent)) + assert.Equal(tc.content, *resultContent) + } + }) + } +} + +func TestReadYAML(t *testing.T) { + type testContent struct { + First string + Second int + } + someContent := testContent{ + First: "first", + Second: 2, + } + yamlContent, err := yaml.Marshal(someContent) + require.NoError(t, err) + + testCases := map[string]struct { + fs afero.Fs + setupFs func(fs *afero.Afero) error + name string + wantContent any + wantErr bool + }{ + "successful read": { + fs: afero.NewMemMapFs(), + name: "test/config.yaml", + setupFs: func(fs *afero.Afero) error { return fs.WriteFile("test/config.yaml", yamlContent, 0o755) }, + wantContent: someContent, + }, + "file not existent": { + fs: afero.NewMemMapFs(), + name: "test/config.yaml", + wantErr: true, + }, + "file not yaml": { + fs: afero.NewMemMapFs(), + name: "test/config.yaml", + setupFs: func(fs *afero.Afero) error { return fs.WriteFile("test/config.yaml", []byte{0x1}, 0o755) }, + wantErr: true, + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + assert := assert.New(t) + require := require.New(t) + + handler := NewHandler(tc.fs) + if tc.setupFs != nil { + require.NoError(tc.setupFs(handler.fs)) + } + + resultContent := &testContent{} + if tc.wantErr { + assert.Error(handler.ReadYAML(tc.name, resultContent)) + } else { + assert.NoError(handler.ReadYAML(tc.name, resultContent)) + assert.Equal(tc.wantContent, *resultContent) + } + }) + } +} + +func TestWriteYAML(t *testing.T) { + type testContent struct { + First string + Second int + } + someContent := testContent{ + First: "first", + Second: 2, + } + notMarshalableContent := struct{ Foo chan int }{Foo: make(chan int)} + + testCases := map[string]struct { + fs afero.Fs + setupFs func(af afero.Afero) error + name string + content any + options Option + wantErr bool + }{ + "successful write": { + fs: afero.NewMemMapFs(), + name: "test/statefile", + content: someContent, + }, + "successful overwrite": { + fs: afero.NewMemMapFs(), + setupFs: func(af afero.Afero) error { return af.WriteFile("test/statefile", []byte{}, 0o644) }, + name: "test/statefile", + content: someContent, + options: OptOverwrite, + }, + "read only fs": { + fs: afero.NewReadOnlyFs(afero.NewMemMapFs()), + name: "test/statefile", + content: someContent, + wantErr: true, + }, + "file already exists": { + fs: afero.NewMemMapFs(), + setupFs: func(af afero.Afero) error { return af.WriteFile("test/statefile", []byte{}, 0o644) }, + name: "test/statefile", + content: someContent, + wantErr: true, + }, + "marshal error": { + fs: afero.NewMemMapFs(), + name: "test/statefile", + content: notMarshalableContent, + wantErr: true, + }, + "mkdirAll works": { + fs: afero.NewMemMapFs(), + name: "test/statefile", + content: someContent, + options: OptMkdirAll, + }, + // TODO(malt3): add tests for mkdirAll actually creating the necessary folders when https://github.com/spf13/afero/issues/270 is fixed. + // Currently, MemMapFs will create files in nonexistent directories due to a bug in afero, + // making it impossible to test the actual behavior of the mkdirAll parameter. + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + assert := assert.New(t) + require := require.New(t) + + handler := NewHandler(tc.fs) + if tc.setupFs != nil { + require.NoError(tc.setupFs(afero.Afero{Fs: tc.fs})) + } + + if tc.wantErr { + assert.Error(handler.WriteYAML(tc.name, tc.content, tc.options)) + } else { + assert.NoError(handler.WriteYAML(tc.name, tc.content, tc.options)) + resultContent := &testContent{} + assert.NoError(handler.ReadYAML(tc.name, resultContent)) + assert.Equal(tc.content, *resultContent) + } + }) + } +} + +func TestRemove(t *testing.T) { + assert := assert.New(t) + require := require.New(t) + + fs := afero.NewMemMapFs() + handler := NewHandler(fs) + aferoHelper := afero.Afero{Fs: fs} + require.NoError(aferoHelper.WriteFile("a", []byte{0xa}, 0o644)) + require.NoError(aferoHelper.WriteFile("b", []byte{0xb}, 0o644)) + require.NoError(aferoHelper.WriteFile("c", []byte{0xc}, 0o644)) + + assert.NoError(handler.Remove("a")) + assert.NoError(handler.Remove("b")) + assert.NoError(handler.Remove("c")) + + _, err := handler.fs.Stat("a") + assert.ErrorIs(err, afero.ErrFileNotFound) + _, err = handler.fs.Stat("b") + assert.ErrorIs(err, afero.ErrFileNotFound) + _, err = handler.fs.Stat("c") + assert.ErrorIs(err, afero.ErrFileNotFound) + + assert.Error(handler.Remove("d")) +} + +func TestCopyFile(t *testing.T) { + perms := fs.FileMode(0o644) + + setupFs := func(existingFiles ...string) afero.Fs { + fs := afero.NewMemMapFs() + aferoHelper := afero.Afero{Fs: fs} + for _, file := range existingFiles { + require.NoError(t, aferoHelper.WriteFile(file, []byte{}, perms)) + } + return fs + } + + testCases := map[string]struct { + fs afero.Fs + copyFiles [][]string + checkFiles []string + opts []Option + wantErr bool + }{ + "successful copy": { + fs: setupFs("a"), + copyFiles: [][]string{{"a", "b"}}, + checkFiles: []string{"b"}, + }, + "copy to existing file overwrite": { + fs: setupFs("a", "b"), + copyFiles: [][]string{{"a", "b"}}, + checkFiles: []string{"b"}, + opts: []Option{OptOverwrite}, + }, + "copy to existing file no overwrite": { + fs: setupFs("a", "b"), + copyFiles: [][]string{{"a", "b"}}, + checkFiles: []string{"b"}, + wantErr: true, + }, + "file doesn't exist": { + fs: setupFs("a"), + copyFiles: [][]string{{"b", "c"}}, + checkFiles: []string{"a"}, + wantErr: true, + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + assert := assert.New(t) + require := require.New(t) + + handler := NewHandler(tc.fs) + for _, files := range tc.copyFiles { + err := handler.CopyFile(files[0], files[1], tc.opts...) + if tc.wantErr { + assert.Error(err) + } else { + assert.NoError(err) + } + } + + for _, file := range tc.checkFiles { + info, err := handler.fs.Stat(file) + assert.Equal(perms, info.Mode()) + require.NoError(err) + } + }) + } +} + +func TestCopyDir(t *testing.T) { + setupHandler := func(existingFiles ...string) Handler { + fs := afero.NewMemMapFs() + handler := NewHandler(fs) + for _, file := range existingFiles { + err := handler.Write(file, []byte("some content"), OptMkdirAll) + require.NoError(t, err) + } + return handler + } + + testCases := map[string]struct { + handler Handler + copyFiles [][]string + checkFiles []string + opts []Option + }{ + "successful copy": { + handler: setupHandler(filepath.Join("someDir", "someFile"), filepath.Join("someDir", "someOtherDir", "someOtherFile")), + copyFiles: [][]string{{"someDir", "copiedDir"}}, + checkFiles: []string{filepath.Join("copiedDir", "someFile"), filepath.Join("copiedDir", "someOtherDir", "someOtherFile")}, + }, + "copy file": { + handler: setupHandler("someFile"), + copyFiles: [][]string{{"someFile", "copiedFile"}}, + checkFiles: []string{"copiedFile"}, + }, + "copy to existing dir overwrite": { + handler: setupHandler(filepath.Join("someDir", "someFile"), filepath.Join("someDir", "someOtherDir", "someOtherFile"), filepath.Join("copiedDir", "someExistingFile")), + copyFiles: [][]string{{"someDir", "copiedDir"}}, + checkFiles: []string{filepath.Join("copiedDir", "someFile"), filepath.Join("copiedDir", "someOtherDir", "someOtherFile"), filepath.Join("copiedDir", "someExistingFile")}, + opts: []Option{OptOverwrite}, + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + require := require.New(t) + + for _, files := range tc.copyFiles { + err := tc.handler.CopyDir(files[0], files[1], tc.opts...) + require.NoError(err) + } + + for _, file := range tc.checkFiles { + _, err := tc.handler.fs.Stat(file) + require.NoError(err) + } + }) + } +} diff --git a/internal/main.go b/internal/main.go new file mode 100644 index 0000000..91b05bd --- /dev/null +++ b/internal/main.go @@ -0,0 +1,48 @@ +package main + +import ( + "context" + "io" + "os" + + "github.com/benschlueter/delegatio/internal/osimage" + "github.com/benschlueter/delegatio/internal/osimage/gcp" + "go.uber.org/zap" +) + +func main() { + ctx := context.Background() + zapconf := zap.NewDevelopmentConfig() + log, err := zapconf.Build() + if err != nil { + log.With(zap.Error(err)).DPanic("Failed to create logger") + } + defer func() { _ = log.Sync() }() + + uploader, err := gcp.New(ctx, "delegatio", "europe-west3", "delegatio-test-cli", log) + if err != nil { + log.With(zap.Error(err)).DPanic("Failed to create uploader") + } + file, err := os.Open("/tmp/compressed-image.tar.gz") + if err != nil { + log.With(zap.Error(err)).DPanic("Failed to open image file") + } + defer file.Close() + size, err := file.Seek(0, io.SeekEnd) + if err != nil { + log.With(zap.Error(err)).DPanic("Failed to get image file size") + } + if _, err := file.Seek(0, io.SeekStart); err != nil { + log.With(zap.Error(err)).DPanic("Failed to seek to start of image file") + } + _, err = uploader.Upload(ctx, &osimage.UploadRequest{ + Size: size, + Image: file, + Provider: "gcp", + Version: "0-0-0", + Variant: "test", + }) + if err != nil { + log.With(zap.Error(err)).DPanic("Failed to upload image") + } +} diff --git a/internal/osimage/gcp/gcpupload.go b/internal/osimage/gcp/gcpupload.go new file mode 100644 index 0000000..bfb5edb --- /dev/null +++ b/internal/osimage/gcp/gcpupload.go @@ -0,0 +1,237 @@ +/* SPDX-License-Identifier: AGPL-3.0-only + * Copyright (c) Edgeless Systems GmbH + * Copyright (c) Benedict Schlueter + */ + +// package gcp implements uploading os images to gcp. +package gcp + +import ( + "context" + "fmt" + "io" + "net/url" + "path" + "strings" + + compute "cloud.google.com/go/compute/apiv1" + "cloud.google.com/go/compute/apiv1/computepb" + "cloud.google.com/go/storage" + "github.com/benschlueter/delegatio/internal/osimage" + gaxv2 "github.com/googleapis/gax-go/v2" + "go.uber.org/zap" +) + +// Uploader can upload and remove os images on GCP. +type Uploader struct { + project string + location string + bucketName string + image imagesAPI + bucket bucketAPI + + log *zap.Logger +} + +// New creates a new Uploader. +func New(ctx context.Context, project, location, bucketName string, log *zap.Logger) (*Uploader, error) { + image, err := compute.NewImagesRESTClient(ctx) + if err != nil { + return nil, err + } + storage, err := storage.NewClient(ctx) + if err != nil { + return nil, err + } + bucket := storage.Bucket(bucketName) + + return &Uploader{ + project: project, + location: location, + bucketName: bucketName, + image: image, + bucket: bucket, + log: log, + }, nil +} + +// Upload uploads an OS image to GCP. +func (u *Uploader) Upload(ctx context.Context, req *osimage.UploadRequest) (map[string]string, error) { + imageName := req.Provider + "-" + req.Version + "-" + req.Variant + blobName := imageName + ".tar.gz" + if err := u.ensureBucket(ctx); err != nil { + return nil, fmt.Errorf("setup: ensuring bucket exists: %w", err) + } + if err := u.ensureImageDeleted(ctx, imageName); err != nil { + return nil, fmt.Errorf("pre-cleaning: ensuring no image using the same name exists: %w", err) + } + if err := u.ensureBlobDeleted(ctx, blobName); err != nil { + return nil, fmt.Errorf("pre-cleaning: ensuring no blob using the same name exists: %w", err) + } + if err := u.uploadBlob(ctx, blobName, req.Image); err != nil { + return nil, fmt.Errorf("uploading blob: %w", err) + } + defer func() { + // cleanup temporary blob + if err := u.ensureBlobDeleted(ctx, blobName); err != nil { + u.log.Error("post-cleaning: deleting blob", zap.Error(err)) + } + }() + imageRef, err := u.createImage(ctx, imageName, blobName) + if err != nil { + return nil, fmt.Errorf("creating image: %w", err) + } + fmt.Println("imageRef", imageRef) + return map[string]string{ + req.Variant: imageRef, + }, nil +} + +func (u *Uploader) ensureBucket(ctx context.Context) error { + _, err := u.bucket.Attrs(ctx) + if err == nil { + u.log.Debug("bucket exists", zap.String("bucket", u.bucketName)) + return nil + } + if err != storage.ErrBucketNotExist { + return err + } + u.log.Debug("creating bucket %s", zap.String("bucket", u.bucketName)) + return u.bucket.Create(ctx, u.project, &storage.BucketAttrs{ + PublicAccessPrevention: storage.PublicAccessPreventionEnforced, + Location: u.location, + }) +} + +func (u *Uploader) uploadBlob(ctx context.Context, blobName string, img io.Reader) error { + u.log.Debug("uploading os image", zap.String("blob", blobName)) + writer := u.bucket.Object(blobName).NewWriter(ctx) + _, err := io.Copy(writer, img) + if err != nil { + return err + } + return writer.Close() +} + +func (u *Uploader) ensureBlobDeleted(ctx context.Context, blobName string) error { + _, err := u.bucket.Object(blobName).Attrs(ctx) + if err == storage.ErrObjectNotExist { + u.log.Debug("Blob does not exist. Nothing to clean up.", zap.String("blob", blobName), zap.String("bucket", u.bucketName)) + return nil + } + if err != nil { + return err + } + u.log.Debug("Deleting blob", zap.String("blob", blobName)) + return u.bucket.Object(blobName).Delete(ctx) +} + +func (u *Uploader) createImage(ctx context.Context, imageName, blobName string) (string, error) { + u.log.Debug("Creating image", zap.String("image", imageName)) + blobURL := u.blobURL(blobName) + family := u.imageFamily() + req := computepb.InsertImageRequest{ + ImageResource: &computepb.Image{ + Name: &imageName, + RawDisk: &computepb.RawDisk{ + ContainerType: toPtr("TAR"), + Source: &blobURL, + }, + Family: &family, + Architecture: toPtr("X86_64"), + GuestOsFeatures: []*computepb.GuestOsFeature{ + {Type: toPtr("GVNIC")}, + {Type: toPtr("SEV_CAPABLE")}, + {Type: toPtr("VIRTIO_SCSI_MULTIQUEUE")}, + {Type: toPtr("UEFI_COMPATIBLE")}, + }, + }, + Project: u.project, + } + op, err := u.image.Insert(ctx, &req) + if err != nil { + return "", fmt.Errorf("creating image: %w", err) + } + if err := op.Wait(ctx); err != nil { + return "", fmt.Errorf("waiting for image to be created: %w", err) + } + policy := &computepb.Policy{ + Bindings: []*computepb.Binding{ + { + Role: toPtr("roles/compute.imageUser"), + Members: []string{"allAuthenticatedUsers"}, + }, + }, + } + if _, err = u.image.SetIamPolicy(ctx, &computepb.SetIamPolicyImageRequest{ + Resource: imageName, + Project: u.project, + GlobalSetPolicyRequestResource: &computepb.GlobalSetPolicyRequest{ + Policy: policy, + }, + }); err != nil { + return "", fmt.Errorf("setting iam policy: %w", err) + } + image, err := u.image.Get(ctx, &computepb.GetImageRequest{ + Image: imageName, + Project: u.project, + }) + if err != nil { + return "", fmt.Errorf("created image doesn't exist: %w", err) + } + return strings.TrimPrefix(image.GetSelfLink(), "https://www.googleapis.com/compute/v1/"), nil +} + +func (u *Uploader) ensureImageDeleted(ctx context.Context, imageName string) error { + _, err := u.image.Get(ctx, &computepb.GetImageRequest{ + Image: imageName, + Project: u.project, + }) + if err != nil { + u.log.Debug("image does not exist. Nothing to clean up.", zap.String("image", imageName)) + return nil + } + u.log.Debug("deleting image", zap.String("image", imageName)) + op, err := u.image.Delete(ctx, &computepb.DeleteImageRequest{ + Image: imageName, + Project: u.project, + }) + if err != nil { + return err + } + return op.Wait(ctx) +} + +func (u *Uploader) blobURL(blobName string) string { + return (&url.URL{ + Scheme: "https", + Host: "storage.googleapis.com", + Path: path.Join(u.bucketName, blobName), + }).String() +} + +func (u *Uploader) imageFamily() string { + return "delegatio-test" +} + +type imagesAPI interface { + Get(ctx context.Context, req *computepb.GetImageRequest, opts ...gaxv2.CallOption, + ) (*computepb.Image, error) + Insert(ctx context.Context, req *computepb.InsertImageRequest, opts ...gaxv2.CallOption, + ) (*compute.Operation, error) + SetIamPolicy(ctx context.Context, req *computepb.SetIamPolicyImageRequest, opts ...gaxv2.CallOption, + ) (*computepb.Policy, error) + Delete(ctx context.Context, req *computepb.DeleteImageRequest, opts ...gaxv2.CallOption, + ) (*compute.Operation, error) + io.Closer +} + +type bucketAPI interface { + Attrs(ctx context.Context) (attrs *storage.BucketAttrs, err error) + Create(ctx context.Context, projectID string, attrs *storage.BucketAttrs) (err error) + Object(name string) *storage.ObjectHandle +} + +func toPtr[T any](v T) *T { + return &v +} diff --git a/internal/osimage/osimage.go b/internal/osimage/osimage.go new file mode 100644 index 0000000..697270b --- /dev/null +++ b/internal/osimage/osimage.go @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: AGPL-3.0-only + * Copyright (c) Edgeless Systems GmbH + */ + +// package osimage is used to handle osimages in the CI (uploading and maintenance). +package osimage + +import ( + "io" + "time" +) + +// UploadRequest is a request to upload an os image. +type UploadRequest struct { + Provider string + Version string + Variant string + Size int64 + Timestamp time.Time + Image io.ReadSeeker +} From e937b3cd8f0a2f9292cdd9eb80e618358fe001ae Mon Sep 17 00:00:00 2001 From: Benedict Schlueter Date: Fri, 14 Jul 2023 13:11:07 +0200 Subject: [PATCH 2/3] self-join of worker + master nodes Signed-off-by: Benedict Schlueter --- agent/core/core.go | 257 +++++++- agent/core/state/state.go | 59 ++ agent/core/state/state_string.go | 28 + agent/server/main.go | 32 +- agent/server/run.go | 13 +- agent/vmapi/core.go | 16 +- agent/vmapi/kube.go | 85 +++ agent/vmapi/vmproto/Dockerfile.gen-proto | 4 +- agent/vmapi/vmproto/vmapi.pb.go | 577 ++++++++++++++++-- agent/vmapi/vmproto/vmapi.proto | 37 +- agent/vmapi/vmproto/vmapi_grpc.pb.go | 99 +++ build_all.sh | 11 + cli/bootstrapper/kubernetes/exec.go | 2 +- cli/bootstrapper/kubernetes/kubernetes.go | 2 +- cli/infrastructure/cloud/cloud.go | 3 +- .../cloud/terraform/gcp/main.tf | 69 ++- .../gcp/modules/instance_group/main.tf | 9 +- .../gcp/modules/instance_group/variables.tf | 6 + .../gcp/modules/loadbalancer/main.tf | 10 + .../cloud/terraform/gcp/variables.tf | 11 +- cli/installer/installer.go | 4 +- cli/run.go | 17 +- go.mod | 56 +- go.sum | 153 +++-- haproxy.cfg | 76 +++ images/mkosi.postinst | 2 +- images/mkosi.prepare | 2 +- images/mkosi.repart/50-root.conf | 3 +- internal/config/global.go | 4 +- internal/config/utils/kubeadm_config.go | 4 +- ssh/kubernetes/api.go | 3 +- 31 files changed, 1477 insertions(+), 177 deletions(-) create mode 100644 agent/core/state/state.go create mode 100644 agent/core/state/state_string.go create mode 100644 agent/vmapi/kube.go create mode 100755 build_all.sh create mode 100644 haproxy.cfg diff --git a/agent/core/core.go b/agent/core/core.go index 5d86611..10dd6c0 100644 --- a/agent/core/core.go +++ b/agent/core/core.go @@ -1,24 +1,273 @@ /* SPDX-License-Identifier: AGPL-3.0-only * Copyright (c) Benedict Schlueter + * Copyright (c) Edgeless Systems GmbH */ package core import ( + "context" + "errors" + "fmt" + "net" + "os" + "os/exec" + "path/filepath" + "strings" + "sync" + "time" + + "github.com/benschlueter/delegatio/agent/core/state" + "github.com/benschlueter/delegatio/agent/vmapi/vmproto" + "github.com/benschlueter/delegatio/internal/config" "go.uber.org/zap" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + clientset "k8s.io/client-go/kubernetes" + "k8s.io/client-go/tools/clientcmd" + certutil "k8s.io/client-go/util/cert" + bootstraputil "k8s.io/cluster-bootstrap/token/util" + tokenv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/bootstraptoken/v1" + kubeadm "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta4" + kubeconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" + tokenphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/bootstraptoken/node" + "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig" + "k8s.io/kubernetes/cmd/kubeadm/app/util/pubkeypin" ) // Core is responsible for maintaining state information // of the VM-agent. Currently we do not need any state. type Core struct { - zaplogger *zap.Logger + State state.State + zaplogger *zap.Logger + mux sync.Mutex + client clientset.Interface + masterLoadbalancerIP string } // NewCore creates and initializes a new Core object. -func NewCore(zapLogger *zap.Logger) (*Core, error) { +func NewCore(zapLogger *zap.Logger, loadbalancerIP string) (*Core, error) { c := &Core{ - zaplogger: zapLogger, + zaplogger: zapLogger, + masterLoadbalancerIP: loadbalancerIP, + mux: sync.Mutex{}, + client: nil, } - return c, nil } + +// ConnectToKubernetes connects to the Kubernetes API server. +func (c *Core) ConnectToKubernetes() error { + c.zaplogger.Info("Connecting to Kubernetes") + config, err := clientcmd.BuildConfigFromFlags("", "/etc/kubernetes/admin.conf") + if err != nil { + return fmt.Errorf("creating Kubernetes client config: %w", err) + } + client, err := clientset.NewForConfig(config) + if err != nil { + return fmt.Errorf("creating Kubernetes client: %w", err) + } + c.zaplogger.Info("Connected to Kubernetes") + c.client = client + return nil +} + +// GetJoinToken creates a new bootstrap (join) token, which a node can use to join the cluster. +func (c *Core) GetJoinToken(ttl time.Duration) (*kubeadm.BootstrapTokenDiscovery, error) { + // c.log.Infof("Generating new random bootstrap token") + rawToken, err := bootstraputil.GenerateBootstrapToken() + if err != nil { + return nil, fmt.Errorf("couldn't generate random token: %w", err) + } + tokenStr, err := tokenv1.NewBootstrapTokenString(rawToken) + if err != nil { + return nil, fmt.Errorf("invalid token: %w", err) + } + token := tokenv1.BootstrapToken{ + Token: tokenStr, + Description: "Bootstrap token generated by Constellation's Join service", + TTL: &metav1.Duration{Duration: ttl}, + Usages: tokenv1.DefaultTokenUsages, + Groups: tokenv1.DefaultTokenGroups, + } + + // create the token in Kubernetes + // k.log.Infof("Creating bootstrap token in Kubernetes") + if err := tokenphase.CreateNewTokens(c.client, []tokenv1.BootstrapToken{token}); err != nil { + return nil, fmt.Errorf("creating bootstrap token: %w", err) + } + + // parse Kubernetes CA certs + // k.log.Infof("Preparing join token for new node") + rawConfig, err := os.ReadFile("/etc/kubernetes/admin.conf") + if err != nil { + return nil, fmt.Errorf("loading kubeconfig file: %w", err) + } + config, err := clientcmd.Load(rawConfig) + if err != nil { + return nil, fmt.Errorf("loading kubeconfig file: %w", err) + } + _, clusterConfig := kubeconfig.GetClusterFromKubeConfig(config) + if clusterConfig == nil { + return nil, errors.New("couldn't get cluster config from kubeconfig file") + } + caCerts, err := certutil.ParseCertsPEM(clusterConfig.CertificateAuthorityData) + if err != nil { + return nil, fmt.Errorf("parsing CA certs: %w", err) + } + publicKeyPins := make([]string, 0, len(caCerts)) + for _, caCert := range caCerts { + publicKeyPins = append(publicKeyPins, pubkeypin.Hash(caCert)) + } + + // k.log.Infof("Join token creation successful") + return &kubeadm.BootstrapTokenDiscovery{ + Token: tokenStr.String(), + APIServerEndpoint: net.JoinHostPort(c.masterLoadbalancerIP, "6443"), + CACertHashes: publicKeyPins, + }, nil +} + +// JoinCluster joins the Kube Cluster. +// TODO: Authentication checks. +func (c *Core) JoinCluster(ctx context.Context) error { + c.mux.Lock() + defer c.mux.Unlock() + // Advance the state to JoiningCluster + if err := c.State.Require(state.AcceptingInit); err != nil { + return err + } + c.zaplogger.Info("dial master") + conn, err := grpc.DialContext(ctx, net.JoinHostPort(c.masterLoadbalancerIP, config.PublicAPIport), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithBlock()) + if err != nil { + return err + } + defer conn.Close() + client := vmproto.NewAPIClient(conn) + c.zaplogger.Info("grpc call to master") + joinData, err := client.GetJoinDataKube(ctx, &vmproto.GetJoinDataKubeRequest{}) + if err != nil { + return err + } + hostname, err := os.Hostname() + if err != nil { + return err + } + controlPlane := false + if strings.Contains(hostname, "delegatio-master") { + + c.zaplogger.Info("creating directories") + if err := os.MkdirAll(filepath.Join(kubeconstants.KubernetesDir, kubeconstants.DefaultCertificateDir, "etcd"), os.ModePerm); err != nil { + return err + } + c.zaplogger.Info("writing files") + for _, file := range joinData.Files { + err := os.WriteFile(filepath.Join(kubeconstants.KubernetesDir, kubeconstants.DefaultCertificateDir, file.GetName()), file.GetContent(), 0o644) + if err != nil { + return err + } + } + controlPlane = true + } + c.zaplogger.Info("executing kubeadm", zap.String("endpoint", joinData.JoinToken.ApiServerEndpoint), zap.String("token", joinData.JoinToken.Token), zap.String("caCertHash", joinData.JoinToken.CaCertHash), zap.Bool("controlPlane", controlPlane)) + if err := c.executeKubeadm(ctx, joinData.JoinToken.ApiServerEndpoint, joinData.JoinToken.Token, joinData.JoinToken.CaCertHash, controlPlane); err != nil { + c.zaplogger.Error("failed to execute kubeadm", zap.Error(err)) + return err + } + c.State.Advance(state.Initialized) + return nil +} + +func (c *Core) executeKubeadm(ctx context.Context, endpoint, token, caCert string, controlPlane bool) error { + args := []string{ + "join", endpoint, + "--token", token, + "--discovery-token-ca-cert-hash", caCert, + //"--node-name", id, + } + if controlPlane { + args = append(args, "--control-plane") + } + + command := exec.CommandContext(ctx, "/usr/bin/kubeadm", args...) + + fmt.Printf("/usr/bin/kubeadm join %s --token %s --discovery-token-ca-cert-hash %s\n", endpoint, token, caCert) + output, err := command.CombinedOutput() + if err != nil { + return fmt.Errorf("command exited with error code: %w and output: %s", err, output) + } + + return nil +} + +// TryJoinCluster tries to join the cluster every 5 seconds until it succeeds. +func (c *Core) TryJoinCluster(ctx context.Context) { + ticker := time.NewTicker(5 * time.Second) + defer ticker.Stop() + for { + select { + case <-ticker.C: + if c.State.Get() >= state.JoiningCluster { + return + } + if err := c.JoinCluster(ctx); err != nil { + c.zaplogger.Info("Failed to join cluster, retrying in 5 seconds", zap.Error(err)) + } + case <-ctx.Done(): + return + } + } +} + +// IsInReadyState returns true if the Core is in a ready state. +func (c *Core) IsInReadyState() bool { + return c.client != nil +} + +// IsReadyForInit returns true if the Core is in a ready state. +func (c *Core) IsReadyForInit() bool { + return c.State.Get() == state.AcceptingInit +} + +// SetJoiningCluster returns true if the Core is in a ready state. +func (c *Core) SetJoiningCluster() { + // reason later about race conditions / if lock is needed + c.mux.Lock() + c.State.Advance(state.JoiningCluster) + c.mux.Unlock() +} + +func (c *Core) SetInitialized() { + // reason later about race conditions / if lock is needed + c.mux.Lock() + c.State.Advance(state.Initialized) + c.mux.Unlock() +} + +// GetControlPlaneCertificatesAndKeys loads the Kubernetes CA certificates and keys. +func (c *Core) GetControlPlaneCertificatesAndKeys() (map[string][]byte, error) { + c.zaplogger.Info("Loading control plane certificates and keys") + controlPlaneFiles := make(map[string][]byte) + + filenames := []string{ + kubeconstants.CAKeyName, + kubeconstants.ServiceAccountPrivateKeyName, + kubeconstants.FrontProxyCAKeyName, + kubeconstants.EtcdCAKeyName, + kubeconstants.CACertName, + kubeconstants.ServiceAccountPublicKeyName, + kubeconstants.FrontProxyCACertName, + kubeconstants.EtcdCACertName, + } + + for _, filename := range filenames { + key, err := os.ReadFile(filepath.Join(kubeconstants.KubernetesDir, kubeconstants.DefaultCertificateDir, filename)) + if err != nil { + return nil, err + } + controlPlaneFiles[filename] = key + } + + return controlPlaneFiles, nil +} diff --git a/agent/core/state/state.go b/agent/core/state/state.go new file mode 100644 index 0000000..c2f3741 --- /dev/null +++ b/agent/core/state/state.go @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: AGPL-3.0-only + * Copyright (c) Benedict Schlueter + */ + +package state + +import ( + "fmt" + "sync/atomic" +) + +//go:generate stringer -type=State + +// State is a peer's state. +// +// State's methods are thread safe. Get the State's value using the Get method if +// you're accessing it concurrently. Otherwise, you may access it directly. +type State uint32 + +const ( + // Uninitialized is the initial state. + Uninitialized State = iota + // AcceptingInit is the state where the peer is accepting an init message. + AcceptingInit + // JoiningCluster is the state where the peer is about to join the cluster. + JoiningCluster + // Initialized is the state where the peer is initializing. + Initialized + // Failed is the state where the peer has failed. + Failed + maxState +) + +// State's methods should be thread safe. As we only need to protect +// one primitive value, we can use atomic operations. + +// Get gets the state in a thread-safe manner. +func (s *State) Get() State { + return State(atomic.LoadUint32((*uint32)(s))) +} + +// Require checks if the state is one of the desired ones and returns an error otherwise. +func (s *State) Require(states ...State) error { + this := s.Get() + for _, st := range states { + if st == this { + return nil + } + } + return fmt.Errorf("server is not in expected state: require one of %v, but this is %v", states, this) +} + +// Advance advances the state. +func (s *State) Advance(newState State) { + curState := State(atomic.SwapUint32((*uint32)(s), uint32(newState))) + if !(curState < newState && newState < maxState) { + panic(fmt.Errorf("cannot advance from %v to %v", curState, newState)) + } +} diff --git a/agent/core/state/state_string.go b/agent/core/state/state_string.go new file mode 100644 index 0000000..4e6618f --- /dev/null +++ b/agent/core/state/state_string.go @@ -0,0 +1,28 @@ +// Code generated by "stringer -type=State"; DO NOT EDIT. + +package state + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[Uninitialized-0] + _ = x[AcceptingInit-1] + _ = x[JoiningCluster-2] + _ = x[Initialized-3] + _ = x[Failed-4] + _ = x[maxState-5] +} + +const _State_name = "UninitializedAcceptingInitJoiningClusterInitializedFailedmaxState" + +var _State_index = [...]uint8{0, 13, 26, 40, 51, 57, 65} + +func (i State) String() string { + if i >= State(len(_State_index)-1) { + return "State(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _State_name[_State_index[i]:_State_index[i+1]] +} diff --git a/agent/server/main.go b/agent/server/main.go index f7f7525..fdc6628 100644 --- a/agent/server/main.go +++ b/agent/server/main.go @@ -9,7 +9,9 @@ import ( "log" "net" + "cloud.google.com/go/compute/metadata" "github.com/benschlueter/delegatio/internal/config" + "github.com/benschlueter/delegatio/internal/config/definitions" grpc_zap "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap" "go.uber.org/zap" ) @@ -46,5 +48,33 @@ func main() { bindPort = config.PublicAPIport dialer := &net.Dialer{} - run(dialer, bindIP, bindPort, zapLoggerCore, containerMode) + var ipAddr string + if metadata.OnGCE() { + ipAddr, err = metadata.InstanceAttributeValue("loadbalancer") + if err != nil { + zapLoggerCore.Fatal("failed to get loadbalancer ip from metadata | not running in cloud", zap.Error(err)) + } + + localIP, err := metadata.InternalIP() + if err != nil { + zapLoggerCore.Fatal("failed to get local ip from metadata", zap.Error(err)) + } + zapLoggerCore.Info("local ip", zap.String("ip", localIP)) + + attr, err := metadata.ProjectAttributes() + if err != nil { + zapLoggerCore.Fatal("failed to get project attributes from metadata", zap.Error(err)) + } + zapLoggerCore.Info("project attributes", zap.Any("attributes", attr)) + + iattr, err := metadata.InstanceAttributes() + if err != nil { + zapLoggerCore.Fatal("failed to get instance attributes from metadata", zap.Error(err)) + } + zapLoggerCore.Info("instance attributes", zap.Any("attributes", iattr)) + } else { + ipAddr = definitions.NetworkXMLConfig.IPs[0].Address + } + + run(dialer, bindIP, bindPort, zapLoggerCore, containerMode, ipAddr) } diff --git a/agent/server/run.go b/agent/server/run.go index a40795d..365ff8d 100644 --- a/agent/server/run.go +++ b/agent/server/run.go @@ -7,10 +7,12 @@ package main import ( + "context" "net" "sync" "github.com/benschlueter/delegatio/agent/core" + "github.com/benschlueter/delegatio/agent/core/state" "github.com/benschlueter/delegatio/agent/vmapi" "github.com/benschlueter/delegatio/agent/vmapi/vmproto" "github.com/benschlueter/delegatio/internal/config" @@ -24,7 +26,12 @@ import ( var version = "0.0.0" -func run(dialer vmapi.Dialer, bindIP, bindPort string, zapLoggerCore *zap.Logger, containerMode *bool) { +/* + * This will run on the VM's bare matel. We try to contact the control plane + * via the loadbalancerIPAddr to give us the join token. At the same time + * we are waiting for the init-request from a user *only* if we are a control plane. + */ +func run(dialer vmapi.Dialer, bindIP, bindPort string, zapLoggerCore *zap.Logger, containerMode *bool, loadbalancerIPAddr string) { defer func() { _ = zapLoggerCore.Sync() }() zapLoggerCore.Info("starting delegatio agent", zap.String("version", version), zap.String("commit", config.Commit)) @@ -34,7 +41,7 @@ func run(dialer vmapi.Dialer, bindIP, bindPort string, zapLoggerCore *zap.Logger zapLoggerCore.Info("running in qemu mode") } - core, err := core.NewCore(zapLoggerCore) + core, err := core.NewCore(zapLoggerCore, loadbalancerIPAddr) if err != nil { zapLoggerCore.Fatal("failed to create core", zap.Error(err)) } @@ -60,6 +67,8 @@ func run(dialer vmapi.Dialer, bindIP, bindPort string, zapLoggerCore *zap.Logger zapLoggergRPC.Fatal("failed to create listener", zap.Error(err)) } zapLoggergRPC.Info("server listener created", zap.String("address", lis.Addr().String())) + core.State.Advance(state.AcceptingInit) + go core.TryJoinCluster(context.Background()) var wg sync.WaitGroup defer wg.Wait() diff --git a/agent/vmapi/core.go b/agent/vmapi/core.go index 29a1d47..73f3958 100644 --- a/agent/vmapi/core.go +++ b/agent/vmapi/core.go @@ -4,5 +4,19 @@ package vmapi +import ( + "time" + + kubeadm "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta4" +) + // Core interface contains functions to access the state Core data. -type Core interface{} +type Core interface { + ConnectToKubernetes() error + GetJoinToken(time.Duration) (*kubeadm.BootstrapTokenDiscovery, error) + GetControlPlaneCertificatesAndKeys() (map[string][]byte, error) + IsInReadyState() bool + IsReadyForInit() bool + SetJoiningCluster() + SetInitialized() +} diff --git a/agent/vmapi/kube.go b/agent/vmapi/kube.go new file mode 100644 index 0000000..1498b4a --- /dev/null +++ b/agent/vmapi/kube.go @@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: AGPL-3.0-only + * Copyright (c) Benedict Schlueter + */ + +package vmapi + +import ( + "bytes" + "context" + "io" + "os/exec" + "time" + + "github.com/benschlueter/delegatio/agent/vmapi/vmproto" + "go.uber.org/zap" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// GetJoinDataKube returns the join data for the kubernetes cluster. This function will be used by all master nodes except the first one and all worker nodes. +func (a *API) GetJoinDataKube(_ context.Context, _ *vmproto.GetJoinDataKubeRequest) (*vmproto.GetJoinDataKubeResponse, error) { + if !a.core.IsInReadyState() { + return nil, status.Errorf(codes.FailedPrecondition, "cluster is not ready") + } + token, err := a.core.GetJoinToken(5 * time.Minute) + if err != nil { + return nil, status.Errorf(codes.Internal, "get join token %v", err) + } + files, err := a.core.GetControlPlaneCertificatesAndKeys() + if err != nil { + return nil, status.Errorf(codes.Internal, "get certs %v", err) + } + + var controlPlaneFiles []*vmproto.File + for k, v := range files { + controlPlaneFiles = append(controlPlaneFiles, &vmproto.File{ + Name: k, + Content: v, + }) + } + + return &vmproto.GetJoinDataKubeResponse{ + JoinToken: &vmproto.JoinToken{ + Token: token.Token, + CaCertHash: token.CACertHashes[0], + ApiServerEndpoint: token.APIServerEndpoint, + }, + Files: controlPlaneFiles, + }, nil +} + +// InitFirstMaster executes the kubeadm init command on the first master node. The subsequent master nodes will join the cluster automatically. +func (a *API) InitFirstMaster(in *vmproto.InitFirstMasterRequest, srv vmproto.API_InitFirstMasterServer) error { + a.logger.Info("request to execute command", zap.String("command", in.Command), zap.Strings("args", in.Args)) + a.core.SetJoiningCluster() + command := exec.Command(in.Command, in.Args...) + streamer := &streamWriterWrapper{forwardFunc: func(b []byte) error { + return srv.Send(&vmproto.InitFirstMasterResponse{ + Content: &vmproto.InitFirstMasterResponse_Log{ + Log: &vmproto.Log{ + Message: string(b), + }, + }, + }) + }} + var stdoutBuf, stderrBuf bytes.Buffer + + command.Stdout = io.MultiWriter(streamer, &stdoutBuf) + command.Stderr = io.MultiWriter(streamer, &stderrBuf) + + if err := command.Start(); err != nil { + return status.Errorf(codes.Internal, "command exited with error code: %v and output: %s", err, stdoutBuf.Bytes()) + } + + if err := command.Wait(); err != nil { + return status.Errorf(codes.Internal, "command exited with error code: %v and output: %s", err, stdoutBuf.Bytes()) + } + + // So the core has access to the kubernetes client. + if err := a.core.ConnectToKubernetes(); err != nil { + return status.Errorf(codes.Internal, "failed to connect to kubernetes: %v", err) + } + a.core.SetInitialized() + return srv.Send(&vmproto.InitFirstMasterResponse{Content: &vmproto.InitFirstMasterResponse_Output{Output: stdoutBuf.Bytes()}}) +} diff --git a/agent/vmapi/vmproto/Dockerfile.gen-proto b/agent/vmapi/vmproto/Dockerfile.gen-proto index 3edbe74..2cca2ab 100644 --- a/agent/vmapi/vmproto/Dockerfile.gen-proto +++ b/agent/vmapi/vmproto/Dockerfile.gen-proto @@ -24,8 +24,8 @@ RUN go install google.golang.org/protobuf/cmd/protoc-gen-go@v${GEN_GO_VER} && \ # Generate code for every existing proto file WORKDIR /vmapi -COPY vmapi/vmproto/*.proto /vmapi +COPY vmproto/*.proto /vmapi RUN protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative *.proto FROM scratch as export -COPY --from=build /vmapi/*.go vmapi/vmproto/ +COPY --from=build /vmapi/*.go vmproto/ diff --git a/agent/vmapi/vmproto/vmapi.pb.go b/agent/vmapi/vmproto/vmapi.pb.go index 6cbe399..644098d 100644 --- a/agent/vmapi/vmproto/vmapi.pb.go +++ b/agent/vmapi/vmproto/vmapi.pb.go @@ -706,6 +706,361 @@ func (x *Log) GetMessage() string { return "" } +type GetJoinDataKubeRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GetJoinDataKubeRequest) Reset() { + *x = GetJoinDataKubeRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_vmapi_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetJoinDataKubeRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetJoinDataKubeRequest) ProtoMessage() {} + +func (x *GetJoinDataKubeRequest) ProtoReflect() protoreflect.Message { + mi := &file_vmapi_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetJoinDataKubeRequest.ProtoReflect.Descriptor instead. +func (*GetJoinDataKubeRequest) Descriptor() ([]byte, []int) { + return file_vmapi_proto_rawDescGZIP(), []int{11} +} + +type JoinToken struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"` + CaCertHash string `protobuf:"bytes,2,opt,name=caCertHash,proto3" json:"caCertHash,omitempty"` + ApiServerEndpoint string `protobuf:"bytes,3,opt,name=apiServerEndpoint,proto3" json:"apiServerEndpoint,omitempty"` +} + +func (x *JoinToken) Reset() { + *x = JoinToken{} + if protoimpl.UnsafeEnabled { + mi := &file_vmapi_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *JoinToken) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*JoinToken) ProtoMessage() {} + +func (x *JoinToken) ProtoReflect() protoreflect.Message { + mi := &file_vmapi_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use JoinToken.ProtoReflect.Descriptor instead. +func (*JoinToken) Descriptor() ([]byte, []int) { + return file_vmapi_proto_rawDescGZIP(), []int{12} +} + +func (x *JoinToken) GetToken() string { + if x != nil { + return x.Token + } + return "" +} + +func (x *JoinToken) GetCaCertHash() string { + if x != nil { + return x.CaCertHash + } + return "" +} + +func (x *JoinToken) GetApiServerEndpoint() string { + if x != nil { + return x.ApiServerEndpoint + } + return "" +} + +type File struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Content []byte `protobuf:"bytes,2,opt,name=content,proto3" json:"content,omitempty"` +} + +func (x *File) Reset() { + *x = File{} + if protoimpl.UnsafeEnabled { + mi := &file_vmapi_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *File) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*File) ProtoMessage() {} + +func (x *File) ProtoReflect() protoreflect.Message { + mi := &file_vmapi_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use File.ProtoReflect.Descriptor instead. +func (*File) Descriptor() ([]byte, []int) { + return file_vmapi_proto_rawDescGZIP(), []int{13} +} + +func (x *File) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *File) GetContent() []byte { + if x != nil { + return x.Content + } + return nil +} + +type GetJoinDataKubeResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + JoinToken *JoinToken `protobuf:"bytes,1,opt,name=joinToken,proto3" json:"joinToken,omitempty"` + Files []*File `protobuf:"bytes,2,rep,name=files,proto3" json:"files,omitempty"` +} + +func (x *GetJoinDataKubeResponse) Reset() { + *x = GetJoinDataKubeResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_vmapi_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetJoinDataKubeResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetJoinDataKubeResponse) ProtoMessage() {} + +func (x *GetJoinDataKubeResponse) ProtoReflect() protoreflect.Message { + mi := &file_vmapi_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetJoinDataKubeResponse.ProtoReflect.Descriptor instead. +func (*GetJoinDataKubeResponse) Descriptor() ([]byte, []int) { + return file_vmapi_proto_rawDescGZIP(), []int{14} +} + +func (x *GetJoinDataKubeResponse) GetJoinToken() *JoinToken { + if x != nil { + return x.JoinToken + } + return nil +} + +func (x *GetJoinDataKubeResponse) GetFiles() []*File { + if x != nil { + return x.Files + } + return nil +} + +type InitFirstMasterRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Command string `protobuf:"bytes,1,opt,name=command,proto3" json:"command,omitempty"` + Args []string `protobuf:"bytes,2,rep,name=args,proto3" json:"args,omitempty"` + Tty bool `protobuf:"varint,3,opt,name=tty,proto3" json:"tty,omitempty"` +} + +func (x *InitFirstMasterRequest) Reset() { + *x = InitFirstMasterRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_vmapi_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *InitFirstMasterRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InitFirstMasterRequest) ProtoMessage() {} + +func (x *InitFirstMasterRequest) ProtoReflect() protoreflect.Message { + mi := &file_vmapi_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InitFirstMasterRequest.ProtoReflect.Descriptor instead. +func (*InitFirstMasterRequest) Descriptor() ([]byte, []int) { + return file_vmapi_proto_rawDescGZIP(), []int{15} +} + +func (x *InitFirstMasterRequest) GetCommand() string { + if x != nil { + return x.Command + } + return "" +} + +func (x *InitFirstMasterRequest) GetArgs() []string { + if x != nil { + return x.Args + } + return nil +} + +func (x *InitFirstMasterRequest) GetTty() bool { + if x != nil { + return x.Tty + } + return false +} + +type InitFirstMasterResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Content: + // + // *InitFirstMasterResponse_Output + // *InitFirstMasterResponse_Log + Content isInitFirstMasterResponse_Content `protobuf_oneof:"content"` +} + +func (x *InitFirstMasterResponse) Reset() { + *x = InitFirstMasterResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_vmapi_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *InitFirstMasterResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InitFirstMasterResponse) ProtoMessage() {} + +func (x *InitFirstMasterResponse) ProtoReflect() protoreflect.Message { + mi := &file_vmapi_proto_msgTypes[16] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InitFirstMasterResponse.ProtoReflect.Descriptor instead. +func (*InitFirstMasterResponse) Descriptor() ([]byte, []int) { + return file_vmapi_proto_rawDescGZIP(), []int{16} +} + +func (m *InitFirstMasterResponse) GetContent() isInitFirstMasterResponse_Content { + if m != nil { + return m.Content + } + return nil +} + +func (x *InitFirstMasterResponse) GetOutput() []byte { + if x, ok := x.GetContent().(*InitFirstMasterResponse_Output); ok { + return x.Output + } + return nil +} + +func (x *InitFirstMasterResponse) GetLog() *Log { + if x, ok := x.GetContent().(*InitFirstMasterResponse_Log); ok { + return x.Log + } + return nil +} + +type isInitFirstMasterResponse_Content interface { + isInitFirstMasterResponse_Content() +} + +type InitFirstMasterResponse_Output struct { + Output []byte `protobuf:"bytes,1,opt,name=output,proto3,oneof"` +} + +type InitFirstMasterResponse_Log struct { + Log *Log `protobuf:"bytes,2,opt,name=log,proto3,oneof"` +} + +func (*InitFirstMasterResponse_Output) isInitFirstMasterResponse_Content() {} + +func (*InitFirstMasterResponse_Log) isInitFirstMasterResponse_Content() {} + var File_vmapi_proto protoreflect.FileDescriptor var file_vmapi_proto_rawDesc = []byte{ @@ -764,36 +1119,77 @@ var file_vmapi_proto_rawDesc = []byte{ 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x1f, 0x0a, 0x03, 0x4c, 0x6f, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0x84, 0x03, 0x0a, - 0x03, 0x41, 0x50, 0x49, 0x12, 0x5a, 0x0a, 0x11, 0x45, 0x78, 0x65, 0x63, 0x43, 0x6f, 0x6d, 0x6d, - 0x61, 0x6e, 0x64, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x1f, 0x2e, 0x76, 0x6d, 0x61, 0x70, - 0x69, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x53, 0x74, 0x72, - 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x76, 0x6d, 0x61, - 0x70, 0x69, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x53, 0x74, - 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, - 0x12, 0x5e, 0x0a, 0x17, 0x45, 0x78, 0x65, 0x63, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, - 0x65, 0x74, 0x75, 0x72, 0x6e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x19, 0x2e, 0x76, 0x6d, - 0x61, 0x70, 0x69, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x76, 0x6d, 0x61, 0x70, 0x69, 0x2e, 0x45, - 0x78, 0x65, 0x63, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, - 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, - 0x12, 0x44, 0x0a, 0x0b, 0x45, 0x78, 0x65, 0x63, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, - 0x19, 0x2e, 0x76, 0x6d, 0x61, 0x70, 0x69, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x43, 0x6f, 0x6d, 0x6d, - 0x61, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x76, 0x6d, 0x61, - 0x70, 0x69, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x09, 0x57, 0x72, 0x69, 0x74, 0x65, 0x46, - 0x69, 0x6c, 0x65, 0x12, 0x17, 0x2e, 0x76, 0x6d, 0x61, 0x70, 0x69, 0x2e, 0x57, 0x72, 0x69, 0x74, - 0x65, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x76, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x18, 0x0a, 0x16, + 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x69, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x4b, 0x75, 0x62, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x6f, 0x0a, 0x09, 0x4a, 0x6f, 0x69, 0x6e, 0x54, 0x6f, + 0x6b, 0x65, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x61, 0x43, + 0x65, 0x72, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, + 0x61, 0x43, 0x65, 0x72, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x2c, 0x0a, 0x11, 0x61, 0x70, 0x69, + 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x61, 0x70, 0x69, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, + 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x22, 0x34, 0x0a, 0x04, 0x46, 0x69, 0x6c, 0x65, 0x12, + 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x6c, 0x0a, + 0x17, 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x69, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x4b, 0x75, 0x62, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x09, 0x6a, 0x6f, 0x69, 0x6e, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x76, 0x6d, + 0x61, 0x70, 0x69, 0x2e, 0x4a, 0x6f, 0x69, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x09, 0x6a, + 0x6f, 0x69, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x21, 0x0a, 0x05, 0x66, 0x69, 0x6c, 0x65, + 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x76, 0x6d, 0x61, 0x70, 0x69, 0x2e, + 0x46, 0x69, 0x6c, 0x65, 0x52, 0x05, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x22, 0x58, 0x0a, 0x16, 0x49, + 0x6e, 0x69, 0x74, 0x46, 0x69, 0x72, 0x73, 0x74, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, + 0x12, 0x0a, 0x04, 0x61, 0x72, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x61, + 0x72, 0x67, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x03, 0x74, 0x74, 0x79, 0x22, 0x5e, 0x0a, 0x17, 0x49, 0x6e, 0x69, 0x74, 0x46, 0x69, 0x72, + 0x73, 0x74, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x18, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, + 0x48, 0x00, 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x1e, 0x0a, 0x03, 0x6c, 0x6f, + 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x76, 0x6d, 0x61, 0x70, 0x69, 0x2e, + 0x4c, 0x6f, 0x67, 0x48, 0x00, 0x52, 0x03, 0x6c, 0x6f, 0x67, 0x42, 0x09, 0x0a, 0x07, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x32, 0xaa, 0x04, 0x0a, 0x03, 0x41, 0x50, 0x49, 0x12, 0x5a, 0x0a, + 0x11, 0x45, 0x78, 0x65, 0x63, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x53, 0x74, 0x72, 0x65, + 0x61, 0x6d, 0x12, 0x1f, 0x2e, 0x76, 0x6d, 0x61, 0x70, 0x69, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x43, + 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x76, 0x6d, 0x61, 0x70, 0x69, 0x2e, 0x45, 0x78, 0x65, 0x63, + 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, 0x12, 0x5e, 0x0a, 0x17, 0x45, 0x78, 0x65, + 0x63, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x53, 0x74, + 0x72, 0x65, 0x61, 0x6d, 0x12, 0x19, 0x2e, 0x76, 0x6d, 0x61, 0x70, 0x69, 0x2e, 0x45, 0x78, 0x65, + 0x63, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x26, 0x2e, 0x76, 0x6d, 0x61, 0x70, 0x69, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x43, 0x6f, 0x6d, 0x6d, + 0x61, 0x6e, 0x64, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x44, 0x0a, 0x0b, 0x45, 0x78, 0x65, + 0x63, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x19, 0x2e, 0x76, 0x6d, 0x61, 0x70, 0x69, + 0x2e, 0x45, 0x78, 0x65, 0x63, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x76, 0x6d, 0x61, 0x70, 0x69, 0x2e, 0x45, 0x78, 0x65, 0x63, + 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x3e, 0x0a, 0x09, 0x57, 0x72, 0x69, 0x74, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x17, 0x2e, 0x76, 0x6d, 0x61, 0x70, 0x69, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x08, 0x52, 0x65, 0x61, 0x64, 0x46, 0x69, - 0x6c, 0x65, 0x12, 0x16, 0x2e, 0x76, 0x6d, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x46, - 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x76, 0x6d, 0x61, - 0x70, 0x69, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x42, 0x36, 0x5a, 0x34, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x62, 0x65, 0x6e, 0x73, 0x63, 0x68, 0x6c, 0x75, 0x65, 0x74, 0x65, 0x72, 0x2f, 0x64, - 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x76, 0x6d, - 0x61, 0x70, 0x69, 0x2f, 0x76, 0x6d, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x76, 0x6d, 0x61, 0x70, 0x69, 0x2e, 0x57, 0x72, + 0x69, 0x74, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x3b, 0x0a, 0x08, 0x52, 0x65, 0x61, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x16, 0x2e, 0x76, 0x6d, + 0x61, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x76, 0x6d, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x61, 0x64, + 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x0f, + 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x69, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x4b, 0x75, 0x62, 0x65, 0x12, + 0x1d, 0x2e, 0x76, 0x6d, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x69, 0x6e, 0x44, + 0x61, 0x74, 0x61, 0x4b, 0x75, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, + 0x2e, 0x76, 0x6d, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x69, 0x6e, 0x44, 0x61, + 0x74, 0x61, 0x4b, 0x75, 0x62, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x52, + 0x0a, 0x0f, 0x49, 0x6e, 0x69, 0x74, 0x46, 0x69, 0x72, 0x73, 0x74, 0x4d, 0x61, 0x73, 0x74, 0x65, + 0x72, 0x12, 0x1d, 0x2e, 0x76, 0x6d, 0x61, 0x70, 0x69, 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x46, 0x69, + 0x72, 0x73, 0x74, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1e, 0x2e, 0x76, 0x6d, 0x61, 0x70, 0x69, 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x46, 0x69, 0x72, + 0x73, 0x74, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x30, 0x01, 0x42, 0x36, 0x5a, 0x34, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x62, 0x65, 0x6e, 0x73, 0x63, 0x68, 0x6c, 0x75, 0x65, 0x74, 0x65, 0x72, 0x2f, 0x64, 0x65, + 0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x76, 0x6d, 0x61, + 0x70, 0x69, 0x2f, 0x76, 0x6d, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, } var ( @@ -808,7 +1204,7 @@ func file_vmapi_proto_rawDescGZIP() []byte { return file_vmapi_proto_rawDescData } -var file_vmapi_proto_msgTypes = make([]protoimpl.MessageInfo, 11) +var file_vmapi_proto_msgTypes = make([]protoimpl.MessageInfo, 17) var file_vmapi_proto_goTypes = []interface{}{ (*ExecCommandStreamRequest)(nil), // 0: vmapi.ExecCommandStreamRequest (*ExecCommandStreamResponse)(nil), // 1: vmapi.ExecCommandStreamResponse @@ -821,26 +1217,39 @@ var file_vmapi_proto_goTypes = []interface{}{ (*ReadFileRequest)(nil), // 8: vmapi.ReadFileRequest (*ReadFileResponse)(nil), // 9: vmapi.ReadFileResponse (*Log)(nil), // 10: vmapi.Log + (*GetJoinDataKubeRequest)(nil), // 11: vmapi.GetJoinDataKubeRequest + (*JoinToken)(nil), // 12: vmapi.JoinToken + (*File)(nil), // 13: vmapi.File + (*GetJoinDataKubeResponse)(nil), // 14: vmapi.GetJoinDataKubeResponse + (*InitFirstMasterRequest)(nil), // 15: vmapi.InitFirstMasterRequest + (*InitFirstMasterResponse)(nil), // 16: vmapi.InitFirstMasterResponse } var file_vmapi_proto_depIdxs = []int32{ 4, // 0: vmapi.ExecCommandStreamRequest.command:type_name -> vmapi.ExecCommandRequest 3, // 1: vmapi.ExecCommandStreamRequest.termsize:type_name -> vmapi.TerminalSizeRequest 10, // 2: vmapi.ExecCommandReturnStreamResponse.log:type_name -> vmapi.Log - 0, // 3: vmapi.API.ExecCommandStream:input_type -> vmapi.ExecCommandStreamRequest - 4, // 4: vmapi.API.ExecCommandReturnStream:input_type -> vmapi.ExecCommandRequest - 4, // 5: vmapi.API.ExecCommand:input_type -> vmapi.ExecCommandRequest - 6, // 6: vmapi.API.WriteFile:input_type -> vmapi.WriteFileRequest - 8, // 7: vmapi.API.ReadFile:input_type -> vmapi.ReadFileRequest - 1, // 8: vmapi.API.ExecCommandStream:output_type -> vmapi.ExecCommandStreamResponse - 2, // 9: vmapi.API.ExecCommandReturnStream:output_type -> vmapi.ExecCommandReturnStreamResponse - 5, // 10: vmapi.API.ExecCommand:output_type -> vmapi.ExecCommandResponse - 7, // 11: vmapi.API.WriteFile:output_type -> vmapi.WriteFileResponse - 9, // 12: vmapi.API.ReadFile:output_type -> vmapi.ReadFileResponse - 8, // [8:13] is the sub-list for method output_type - 3, // [3:8] is the sub-list for method input_type - 3, // [3:3] is the sub-list for extension type_name - 3, // [3:3] is the sub-list for extension extendee - 0, // [0:3] is the sub-list for field type_name + 12, // 3: vmapi.GetJoinDataKubeResponse.joinToken:type_name -> vmapi.JoinToken + 13, // 4: vmapi.GetJoinDataKubeResponse.files:type_name -> vmapi.File + 10, // 5: vmapi.InitFirstMasterResponse.log:type_name -> vmapi.Log + 0, // 6: vmapi.API.ExecCommandStream:input_type -> vmapi.ExecCommandStreamRequest + 4, // 7: vmapi.API.ExecCommandReturnStream:input_type -> vmapi.ExecCommandRequest + 4, // 8: vmapi.API.ExecCommand:input_type -> vmapi.ExecCommandRequest + 6, // 9: vmapi.API.WriteFile:input_type -> vmapi.WriteFileRequest + 8, // 10: vmapi.API.ReadFile:input_type -> vmapi.ReadFileRequest + 11, // 11: vmapi.API.GetJoinDataKube:input_type -> vmapi.GetJoinDataKubeRequest + 15, // 12: vmapi.API.InitFirstMaster:input_type -> vmapi.InitFirstMasterRequest + 1, // 13: vmapi.API.ExecCommandStream:output_type -> vmapi.ExecCommandStreamResponse + 2, // 14: vmapi.API.ExecCommandReturnStream:output_type -> vmapi.ExecCommandReturnStreamResponse + 5, // 15: vmapi.API.ExecCommand:output_type -> vmapi.ExecCommandResponse + 7, // 16: vmapi.API.WriteFile:output_type -> vmapi.WriteFileResponse + 9, // 17: vmapi.API.ReadFile:output_type -> vmapi.ReadFileResponse + 14, // 18: vmapi.API.GetJoinDataKube:output_type -> vmapi.GetJoinDataKubeResponse + 16, // 19: vmapi.API.InitFirstMaster:output_type -> vmapi.InitFirstMasterResponse + 13, // [13:20] is the sub-list for method output_type + 6, // [6:13] is the sub-list for method input_type + 6, // [6:6] is the sub-list for extension type_name + 6, // [6:6] is the sub-list for extension extendee + 0, // [0:6] is the sub-list for field type_name } func init() { file_vmapi_proto_init() } @@ -981,6 +1390,78 @@ func file_vmapi_proto_init() { return nil } } + file_vmapi_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetJoinDataKubeRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_vmapi_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*JoinToken); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_vmapi_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*File); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_vmapi_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetJoinDataKubeResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_vmapi_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*InitFirstMasterRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_vmapi_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*InitFirstMasterResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } file_vmapi_proto_msgTypes[0].OneofWrappers = []interface{}{ (*ExecCommandStreamRequest_Command)(nil), @@ -996,13 +1477,17 @@ func file_vmapi_proto_init() { (*ExecCommandReturnStreamResponse_Output)(nil), (*ExecCommandReturnStreamResponse_Log)(nil), } + file_vmapi_proto_msgTypes[16].OneofWrappers = []interface{}{ + (*InitFirstMasterResponse_Output)(nil), + (*InitFirstMasterResponse_Log)(nil), + } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_vmapi_proto_rawDesc, NumEnums: 0, - NumMessages: 11, + NumMessages: 17, NumExtensions: 0, NumServices: 1, }, diff --git a/agent/vmapi/vmproto/vmapi.proto b/agent/vmapi/vmproto/vmapi.proto index b26b200..e20ee78 100644 --- a/agent/vmapi/vmproto/vmapi.proto +++ b/agent/vmapi/vmproto/vmapi.proto @@ -11,6 +11,8 @@ service API { rpc ExecCommand(ExecCommandRequest) returns (ExecCommandResponse); rpc WriteFile(WriteFileRequest) returns (WriteFileResponse); rpc ReadFile(ReadFileRequest) returns (ReadFileResponse); + rpc GetJoinDataKube(GetJoinDataKubeRequest) returns (GetJoinDataKubeResponse); + rpc InitFirstMaster(InitFirstMasterRequest) returns (stream InitFirstMasterResponse); } message ExecCommandStreamRequest { @@ -70,8 +72,39 @@ message ReadFileResponse { bytes content = 3; } - - message Log { string message = 1; +} + +message GetJoinDataKubeRequest { +} + +message JoinToken { + string token = 1; + string caCertHash = 2; + string apiServerEndpoint = 3; +} + +message File { + string name = 1; + bytes content = 2; +} + +message GetJoinDataKubeResponse { + JoinToken joinToken = 1; + repeated File files = 2; +} + +message InitFirstMasterRequest { + string command = 1; + repeated string args = 2; + bool tty = 3; +} + + +message InitFirstMasterResponse { + oneof content { + bytes output = 1; + Log log = 2; + } } \ No newline at end of file diff --git a/agent/vmapi/vmproto/vmapi_grpc.pb.go b/agent/vmapi/vmproto/vmapi_grpc.pb.go index 6df448f..2a06e2d 100644 --- a/agent/vmapi/vmproto/vmapi_grpc.pb.go +++ b/agent/vmapi/vmproto/vmapi_grpc.pb.go @@ -27,6 +27,8 @@ type APIClient interface { ExecCommand(ctx context.Context, in *ExecCommandRequest, opts ...grpc.CallOption) (*ExecCommandResponse, error) WriteFile(ctx context.Context, in *WriteFileRequest, opts ...grpc.CallOption) (*WriteFileResponse, error) ReadFile(ctx context.Context, in *ReadFileRequest, opts ...grpc.CallOption) (*ReadFileResponse, error) + GetJoinDataKube(ctx context.Context, in *GetJoinDataKubeRequest, opts ...grpc.CallOption) (*GetJoinDataKubeResponse, error) + InitFirstMaster(ctx context.Context, in *InitFirstMasterRequest, opts ...grpc.CallOption) (API_InitFirstMasterClient, error) } type aPIClient struct { @@ -127,6 +129,47 @@ func (c *aPIClient) ReadFile(ctx context.Context, in *ReadFileRequest, opts ...g return out, nil } +func (c *aPIClient) GetJoinDataKube(ctx context.Context, in *GetJoinDataKubeRequest, opts ...grpc.CallOption) (*GetJoinDataKubeResponse, error) { + out := new(GetJoinDataKubeResponse) + err := c.cc.Invoke(ctx, "/vmapi.API/GetJoinDataKube", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *aPIClient) InitFirstMaster(ctx context.Context, in *InitFirstMasterRequest, opts ...grpc.CallOption) (API_InitFirstMasterClient, error) { + stream, err := c.cc.NewStream(ctx, &API_ServiceDesc.Streams[2], "/vmapi.API/InitFirstMaster", opts...) + if err != nil { + return nil, err + } + x := &aPIInitFirstMasterClient{stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type API_InitFirstMasterClient interface { + Recv() (*InitFirstMasterResponse, error) + grpc.ClientStream +} + +type aPIInitFirstMasterClient struct { + grpc.ClientStream +} + +func (x *aPIInitFirstMasterClient) Recv() (*InitFirstMasterResponse, error) { + m := new(InitFirstMasterResponse) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + // APIServer is the server API for API service. // All implementations must embed UnimplementedAPIServer // for forward compatibility @@ -136,6 +179,8 @@ type APIServer interface { ExecCommand(context.Context, *ExecCommandRequest) (*ExecCommandResponse, error) WriteFile(context.Context, *WriteFileRequest) (*WriteFileResponse, error) ReadFile(context.Context, *ReadFileRequest) (*ReadFileResponse, error) + GetJoinDataKube(context.Context, *GetJoinDataKubeRequest) (*GetJoinDataKubeResponse, error) + InitFirstMaster(*InitFirstMasterRequest, API_InitFirstMasterServer) error mustEmbedUnimplementedAPIServer() } @@ -158,6 +203,12 @@ func (UnimplementedAPIServer) WriteFile(context.Context, *WriteFileRequest) (*Wr func (UnimplementedAPIServer) ReadFile(context.Context, *ReadFileRequest) (*ReadFileResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ReadFile not implemented") } +func (UnimplementedAPIServer) GetJoinDataKube(context.Context, *GetJoinDataKubeRequest) (*GetJoinDataKubeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetJoinDataKube not implemented") +} +func (UnimplementedAPIServer) InitFirstMaster(*InitFirstMasterRequest, API_InitFirstMasterServer) error { + return status.Errorf(codes.Unimplemented, "method InitFirstMaster not implemented") +} func (UnimplementedAPIServer) mustEmbedUnimplementedAPIServer() {} // UnsafeAPIServer may be embedded to opt out of forward compatibility for this service. @@ -272,6 +323,45 @@ func _API_ReadFile_Handler(srv interface{}, ctx context.Context, dec func(interf return interceptor(ctx, in, info, handler) } +func _API_GetJoinDataKube_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetJoinDataKubeRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(APIServer).GetJoinDataKube(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/vmapi.API/GetJoinDataKube", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(APIServer).GetJoinDataKube(ctx, req.(*GetJoinDataKubeRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _API_InitFirstMaster_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(InitFirstMasterRequest) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(APIServer).InitFirstMaster(m, &aPIInitFirstMasterServer{stream}) +} + +type API_InitFirstMasterServer interface { + Send(*InitFirstMasterResponse) error + grpc.ServerStream +} + +type aPIInitFirstMasterServer struct { + grpc.ServerStream +} + +func (x *aPIInitFirstMasterServer) Send(m *InitFirstMasterResponse) error { + return x.ServerStream.SendMsg(m) +} + // API_ServiceDesc is the grpc.ServiceDesc for API service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -291,6 +381,10 @@ var API_ServiceDesc = grpc.ServiceDesc{ MethodName: "ReadFile", Handler: _API_ReadFile_Handler, }, + { + MethodName: "GetJoinDataKube", + Handler: _API_GetJoinDataKube_Handler, + }, }, Streams: []grpc.StreamDesc{ { @@ -304,6 +398,11 @@ var API_ServiceDesc = grpc.ServiceDesc{ Handler: _API_ExecCommandReturnStream_Handler, ServerStreams: true, }, + { + StreamName: "InitFirstMaster", + Handler: _API_InitFirstMaster_Handler, + ServerStreams: true, + }, }, Metadata: "vmapi.proto", } diff --git a/build_all.sh b/build_all.sh new file mode 100755 index 0000000..71d7cbd --- /dev/null +++ b/build_all.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +docker build -f container/challenges/testing/Dockerfile.archlinux -t ghcr.io/benschlueter/delegatio/archimage:0.1 . +docker push ghcr.io/benschlueter/delegatio/archimage:0.1 + + +docker build -f Dockerfile.ssh -t ghcr.io/benschlueter/delegatio/ssh:0.1 . +docker push ghcr.io/benschlueter/delegatio/ssh:0.1 + +docker build -f Dockerfile.grader -t ghcr.io/benschlueter/delegatio/grader:0.1 . +docker push ghcr.io/benschlueter/delegatio/grader:0.1 diff --git a/cli/bootstrapper/kubernetes/exec.go b/cli/bootstrapper/kubernetes/exec.go index c708afe..ae0eb8e 100644 --- a/cli/bootstrapper/kubernetes/exec.go +++ b/cli/bootstrapper/kubernetes/exec.go @@ -95,7 +95,7 @@ func (a *Bootstrapper) joinCluster(ctx context.Context, id, ip string, joinToken func (a *Bootstrapper) executeKubeadm(ctx context.Context, client vmproto.APIClient) (output []byte, err error) { a.log.Info("execute executeKubeadm") - resp, err := client.ExecCommandReturnStream(ctx, &vmproto.ExecCommandRequest{ + resp, err := client.InitFirstMaster(ctx, &vmproto.InitFirstMasterRequest{ Command: "/usr/bin/kubeadm", Args: []string{ "init", diff --git a/cli/bootstrapper/kubernetes/kubernetes.go b/cli/bootstrapper/kubernetes/kubernetes.go index 5c126e4..a265fd1 100644 --- a/cli/bootstrapper/kubernetes/kubernetes.go +++ b/cli/bootstrapper/kubernetes/kubernetes.go @@ -68,7 +68,7 @@ func (a *Bootstrapper) configureKubernetes(ctx context.Context) (*v1beta4.Bootst if err := a.establishClientGoConnection(); err != nil { return nil, err } - a.log.Info("client-go connection establishedw") + a.log.Info("client-go connection established") caFileContentPem, err := a.getKubernetesRootCert(ctx) if err != nil { return nil, fmt.Errorf("loading ca.crt file: %w", err) diff --git a/cli/infrastructure/cloud/cloud.go b/cli/infrastructure/cloud/cloud.go index 5ded86c..cf2f2e6 100644 --- a/cli/infrastructure/cloud/cloud.go +++ b/cli/infrastructure/cloud/cloud.go @@ -55,6 +55,7 @@ func (r *rollbackerTerraform) rollback(ctx context.Context, logLevel LogLevel) e return r.client.CleanUpWorkspace() } +// CreateGCP creates a GCP cluster. func CreateGCP(ctx context.Context, cl terraformClient) (retErr error) { tfLogLevel := LogLevelDebug vars := GCPClusterVariables{ @@ -68,7 +69,7 @@ func CreateGCP(ctx context.Context, cl terraformClient) (retErr error) { Region: "europe-west6", Zone: "europe-west6-a", CredentialsFile: "/home/bschlueter/University/Github/delegatio/build/delegatio.json", - InstanceType: "g1-small", + InstanceType: "e2-standard-2", StateDiskType: "pd-standard", ImageID: "https://www.googleapis.com/compute/v1/projects/delegatio/global/images/gcp-0-0-0-test", Debug: true, diff --git a/cli/infrastructure/cloud/terraform/gcp/main.tf b/cli/infrastructure/cloud/terraform/gcp/main.tf index f87f365..1234fac 100644 --- a/cli/infrastructure/cloud/terraform/gcp/main.tf +++ b/cli/infrastructure/cloud/terraform/gcp/main.tf @@ -131,50 +131,53 @@ resource "google_compute_firewall" "firewall_internal_pods" { allow { protocol = "icmp" } } +resource "google_compute_global_address" "loadbalancer_ip" { + name = local.name +} + module "instance_group_control_plane" { - source = "./modules/instance_group" - name = local.name - role = "ControlPlane" - uid = local.uid - instance_type = var.instance_type - instance_count = var.control_plane_count - image_id = var.image_id - disk_size = var.state_disk_size - disk_type = var.state_disk_type - network = google_compute_network.vpc_network.id - subnetwork = google_compute_subnetwork.vpc_subnetwork.id - alias_ip_range_name = google_compute_subnetwork.vpc_subnetwork.secondary_ip_range[0].range_name - kube_env = local.kube_env - debug = var.debug + source = "./modules/instance_group" + name = local.name + role = "ControlPlane" + uid = local.uid + instance_type = var.instance_type + instance_count = var.control_plane_count + image_id = var.image_id + disk_size = var.state_disk_size + disk_type = var.state_disk_type + network = google_compute_network.vpc_network.id + subnetwork = google_compute_subnetwork.vpc_subnetwork.id + alias_ip_range_name = google_compute_subnetwork.vpc_subnetwork.secondary_ip_range[0].range_name + kube_env = local.kube_env + coordinator_loadbalancer = google_compute_global_address.loadbalancer_ip.address + debug = var.debug named_ports = flatten([ { name = "kubernetes", port = local.ports_kubernetes }, { name = "bootstrapper", port = local.ports_bootstrapper }, ]) - labels = local.labels + labels = local.labels } module "instance_group_worker" { - source = "./modules/instance_group" - name = "${local.name}-1" - role = "Worker" - uid = local.uid - instance_type = var.instance_type - instance_count = var.worker_count - image_id = var.image_id - disk_size = var.state_disk_size - disk_type = var.state_disk_type - network = google_compute_network.vpc_network.id - subnetwork = google_compute_subnetwork.vpc_subnetwork.id - alias_ip_range_name = google_compute_subnetwork.vpc_subnetwork.secondary_ip_range[0].range_name - kube_env = local.kube_env - debug = var.debug - labels = local.labels + source = "./modules/instance_group" + name = "${local.name}-1" + role = "Worker" + uid = local.uid + instance_type = var.instance_type + instance_count = var.worker_count + image_id = var.image_id + disk_size = var.state_disk_size + disk_type = var.state_disk_type + network = google_compute_network.vpc_network.id + subnetwork = google_compute_subnetwork.vpc_subnetwork.id + alias_ip_range_name = google_compute_subnetwork.vpc_subnetwork.secondary_ip_range[0].range_name + kube_env = local.kube_env + coordinator_loadbalancer = google_compute_global_address.loadbalancer_ip.address + debug = var.debug + labels = local.labels } -resource "google_compute_global_address" "loadbalancer_ip" { - name = local.name -} module "loadbalancer_kube" { source = "./modules/loadbalancer" diff --git a/cli/infrastructure/cloud/terraform/gcp/modules/instance_group/main.tf b/cli/infrastructure/cloud/terraform/gcp/modules/instance_group/main.tf index 383d802..70b099f 100644 --- a/cli/infrastructure/cloud/terraform/gcp/modules/instance_group/main.tf +++ b/cli/infrastructure/cloud/terraform/gcp/modules/instance_group/main.tf @@ -42,8 +42,9 @@ resource "google_compute_instance_template" "template" { } metadata = { - kube-env = var.kube_env - serial-port-enable = "TRUE" + kube-env = var.kube_env + loadbalancer = var.coordinator_loadbalancer + serial-port-enable = "TRUE" } network_interface { @@ -55,9 +56,9 @@ resource "google_compute_instance_template" "template" { } } - scheduling { +/* scheduling { on_host_maintenance = "TERMINATE" - } + } */ service_account { scopes = [ diff --git a/cli/infrastructure/cloud/terraform/gcp/modules/instance_group/variables.tf b/cli/infrastructure/cloud/terraform/gcp/modules/instance_group/variables.tf index 0617933..0a16c42 100644 --- a/cli/infrastructure/cloud/terraform/gcp/modules/instance_group/variables.tf +++ b/cli/infrastructure/cloud/terraform/gcp/modules/instance_group/variables.tf @@ -79,3 +79,9 @@ variable "alias_ip_range_name" { type = string description = "Name of the alias IP range to use." } + +variable "coordinator_loadbalancer" { + type = string + default = false + description = "Loadbalancer that balances between the master nodes." +} \ No newline at end of file diff --git a/cli/infrastructure/cloud/terraform/gcp/modules/loadbalancer/main.tf b/cli/infrastructure/cloud/terraform/gcp/modules/loadbalancer/main.tf index 0d89b1d..5ec82c6 100644 --- a/cli/infrastructure/cloud/terraform/gcp/modules/loadbalancer/main.tf +++ b/cli/infrastructure/cloud/terraform/gcp/modules/loadbalancer/main.tf @@ -31,6 +31,16 @@ resource "google_compute_health_check" "health" { request_path = "/readyz" } } + + dynamic "grpc_health_check" { + for_each = var.health_check == "GRPC" ? [1] : [] + + content { + grpc_service_name = "wip" + port = var.port + } + + } } resource "google_compute_backend_service" "backend" { diff --git a/cli/infrastructure/cloud/terraform/gcp/variables.tf b/cli/infrastructure/cloud/terraform/gcp/variables.tf index a065b1e..44eaffd 100644 --- a/cli/infrastructure/cloud/terraform/gcp/variables.tf +++ b/cli/infrastructure/cloud/terraform/gcp/variables.tf @@ -12,13 +12,13 @@ variable "debug" { variable "control_plane_count" { type = number - default = 2 + default = 1 description = "The number of control plane nodes to deploy." } variable "worker_count" { type = number - default = 2 + default = 1 description = "The number of worker nodes to deploy." } @@ -30,7 +30,7 @@ variable "state_disk_size" { variable "instance_type" { type = string - default = "g1-small" + default = "e2-standard-2" description = "The GCP instance type to deploy." } @@ -49,14 +49,17 @@ variable "image_id" { variable "project" { type = string description = "The GCP project to deploy the cluster in." + default = "delegatio" } variable "region" { type = string description = "The GCP region to deploy the cluster in." + default = "europe-west6" } variable "zone" { type = string description = "The GCP zone to deploy the cluster in." -} \ No newline at end of file + default = "europe-west6-a" +} diff --git a/cli/installer/installer.go b/cli/installer/installer.go index ba368d2..3495904 100644 --- a/cli/installer/installer.go +++ b/cli/installer/installer.go @@ -79,7 +79,9 @@ func (k *installer) connectToEtcd(_ context.Context, creds *config.EtcdCredentia if err != nil { return err } - if err := k.client.ConnectToStoreExternal(creds, []string{net.JoinHostPort(host, "2379")}); err != nil { + etcdEndpoint := net.JoinHostPort(host, "2379") + k.logger.Info("etcd endpoint", zap.String("etcd", etcdEndpoint)) + if err := k.client.ConnectToStoreExternal(creds, []string{etcdEndpoint}); err != nil { k.logger.With(zap.Error(err)).Error("failed to connect to store") return err } diff --git a/cli/run.go b/cli/run.go index 7711f2d..9ddcab9 100644 --- a/cli/run.go +++ b/cli/run.go @@ -13,6 +13,7 @@ import ( "github.com/benschlueter/delegatio/cli/installer" "github.com/benschlueter/delegatio/cli/terminate" "github.com/benschlueter/delegatio/internal/config" + "github.com/benschlueter/delegatio/internal/config/definitions" "github.com/benschlueter/delegatio/internal/config/utils" "go.uber.org/zap" @@ -38,17 +39,13 @@ func run(ctx context.Context, log *zap.Logger, imageLocation string) error { } }(log, lInstance) // --- infrastructure --- - /* nodes, err := createInfrastructure(ctx, log, lInstance) - if err != nil { - log.With(zap.Error(err)).DPanic("create infrastructure") - } */ - log.Info("finished infrastructure initialization") - nodes := &config.NodeInformation{ - Masters: map[string]string{ - "master1": "34.117.25.173", - }, + nodes, err := createInfrastructure(ctx, log, lInstance) + if err != nil { + log.With(zap.Error(err)).DPanic("create infrastructure") } + log.Info("finished infrastructure initialization") fmt.Println(nodes) + nodes.Workers = nil /// --- kubernetes --- creds, err := bootstrapKubernetes(ctx, log, nodes) if err != nil { @@ -66,7 +63,7 @@ func run(ctx context.Context, log *zap.Logger, imageLocation string) error { } func bootstrapKubernetes(ctx context.Context, log *zap.Logger, nodes *config.NodeInformation) (*config.EtcdCredentials, error) { - kubeConf, err := utils.GetKubeInitConfig("") + kubeConf, err := utils.GetKubeInitConfig(definitions.NetworkXMLConfig.IPs[0].Address) if err != nil { log.With(zap.Error(err)).DPanic("failed to get kubeConfig") } diff --git a/go.mod b/go.mod index 3b407c5..12a2942 100644 --- a/go.mod +++ b/go.mod @@ -3,21 +3,31 @@ module github.com/benschlueter/delegatio go 1.23 require ( + cloud.google.com/go/compute v1.23.3 + cloud.google.com/go/compute/metadata v0.3.0 + cloud.google.com/go/storage v1.35.1 github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df github.com/creack/pty v1.1.21 github.com/docker/docker v27.1.1+incompatible github.com/go-ldap/ldap/v3 v3.4.8 + github.com/googleapis/gax-go/v2 v2.12.0 github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 + github.com/hashicorp/go-version v1.7.0 + github.com/hashicorp/hc-install v0.9.0 + github.com/hashicorp/terraform-exec v0.21.0 + github.com/hashicorp/terraform-json v0.23.0 + github.com/siderolabs/talos/pkg/machinery v1.8.2 github.com/spf13/afero v1.11.0 github.com/stretchr/testify v1.9.0 go.etcd.io/etcd/client/v3 v3.5.15 go.uber.org/goleak v1.3.0 go.uber.org/zap v1.27.0 - golang.org/x/crypto v0.25.0 - golang.org/x/sync v0.7.0 - golang.org/x/sys v0.22.0 - google.golang.org/grpc v1.65.0 + golang.org/x/crypto v0.26.0 + golang.org/x/sync v0.8.0 + golang.org/x/sys v0.24.0 + google.golang.org/grpc v1.66.3 google.golang.org/protobuf v1.34.2 + gopkg.in/yaml.v3 v3.0.1 helm.sh/helm/v3 v3.15.3 k8s.io/api v0.31.1 k8s.io/apimachinery v0.31.1 @@ -31,6 +41,8 @@ require ( ) require ( + cloud.google.com/go v0.110.10 // indirect + cloud.google.com/go/iam v1.1.5 // indirect github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect @@ -42,11 +54,14 @@ require ( github.com/Masterminds/squirrel v1.5.4 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/Microsoft/hcsshim v0.11.4 // indirect + github.com/ProtonMail/go-crypto v1.1.0-alpha.5.0.20240827111422-b5837fa4476e // indirect + github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chai2010/gettext-go v1.0.2 // indirect + github.com/cloudflare/circl v1.3.9 // indirect github.com/containerd/containerd v1.7.12 // indirect github.com/containerd/log v0.1.0 // indirect github.com/coreos/go-semver v0.3.1 // indirect @@ -61,9 +76,9 @@ require ( github.com/docker/go-metrics v0.0.1 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect - github.com/evanphx/json-patch v5.7.0+incompatible // indirect + github.com/evanphx/json-patch v5.9.0+incompatible // indirect github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect - github.com/fatih/color v1.13.0 // indirect + github.com/fatih/color v1.17.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect @@ -76,21 +91,26 @@ require ( github.com/go-openapi/swag v0.22.4 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/btree v1.0.1 // indirect github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect + github.com/google/s2a-go v0.1.7 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.6.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect github.com/gorilla/mux v1.8.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/gosuri/uitable v0.0.4 // indirect github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-retryablehttp v0.7.7 // indirect github.com/huandu/xstrings v1.4.0 // indirect - github.com/imdario/mergo v0.3.13 // indirect + github.com/imdario/mergo v0.3.15 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jmoiron/sqlx v1.3.5 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -102,7 +122,7 @@ require ( github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect @@ -138,27 +158,31 @@ require ( github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/xlab/treeprint v1.2.0 // indirect + github.com/zclconf/go-cty v1.15.0 // indirect go.etcd.io/etcd/api/v3 v3.5.15 // indirect go.etcd.io/etcd/client/pkg/v3 v3.5.15 // indirect + go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect go.opentelemetry.io/otel v1.28.0 // indirect go.opentelemetry.io/otel/metric v1.28.0 // indirect go.opentelemetry.io/otel/trace v1.28.0 // indirect go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/mod v0.17.0 // indirect - golang.org/x/net v0.26.0 // indirect + golang.org/x/mod v0.21.0 // indirect + golang.org/x/net v0.28.0 // indirect golang.org/x/oauth2 v0.21.0 // indirect - golang.org/x/term v0.22.0 // indirect - golang.org/x/text v0.16.0 // indirect - golang.org/x/time v0.5.0 // indirect + golang.org/x/term v0.23.0 // indirect + golang.org/x/text v0.17.0 // indirect + golang.org/x/time v0.6.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect + golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect + google.golang.org/api v0.152.0 // indirect + google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/apiextensions-apiserver v0.30.0 // indirect k8s.io/apiserver v0.31.1 // indirect k8s.io/cli-runtime v0.31.1 // indirect diff --git a/go.sum b/go.sum index 2a83c09..9ff5ba1 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,16 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.110.10 h1:LXy9GEO+timppncPIAZoOj3l58LIU9k+kn48AN7IO3Y= +cloud.google.com/go v0.110.10/go.mod h1:v1OoFqYxiBkUrruItNM3eT4lLByNjxmJSV/xDKJNnic= +cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk= +cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= +cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= +cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +cloud.google.com/go/iam v1.1.5 h1:1jTsCu4bcsNsE4iiqNT5SHwrDRCfRmIaaaVFhRveTJI= +cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8= +cloud.google.com/go/storage v1.35.1 h1:B59ahL//eDfx2IIKFBeT5Atm9wnNmj3+8xG/W4WB//w= +cloud.google.com/go/storage v1.35.1/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8= +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU= github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= @@ -25,12 +37,16 @@ github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migc github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/Microsoft/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7fz8= github.com/Microsoft/hcsshim v0.11.4/go.mod h1:smjE4dvqPX9Zldna+t5FG3rnoHhaB7QYxPRqGcpAD9w= +github.com/ProtonMail/go-crypto v1.1.0-alpha.5.0.20240827111422-b5837fa4476e h1:O1cSHAcGcbGEO66Qi2AIJeYmXO8iP4L/PNrbdN+RjJA= +github.com/ProtonMail/go-crypto v1.1.0-alpha.5.0.20240827111422-b5837fa4476e/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= +github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY= +github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 h1:4daAzAu0S6Vi7/lbWECcX0j45yZReDZ56BQsrVBOEEY= @@ -63,6 +79,8 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudflare/circl v1.3.9 h1:QFrlgFYf2Qpi8bSpVPK1HBvWpx16v/1TZivyo7pGuBE= +github.com/cloudflare/circl v1.3.9/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= @@ -110,16 +128,18 @@ github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1 h1:ZClxb8laGDf5arX github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/evanphx/json-patch v5.7.0+incompatible h1:vgGkfT/9f8zE6tvSCe74nfpAVDQ2tG6yudJd8LBksgI= -github.com/evanphx/json-patch v5.7.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v5.9.0+incompatible h1:fBXyNpNMuTTDdquAq/uisOr2lShz4oaXpDTX2bLe7ls= +github.com/evanphx/json-patch v5.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= -github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= +github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/foxcpp/go-mockdns v1.0.0 h1:7jBqxd3WDWwi/6WhDvacvH1XsN3rOLXyHM1uhvIx6FI= @@ -132,6 +152,12 @@ github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= +github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= +github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= +github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys= +github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY= github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs= github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= @@ -171,6 +197,7 @@ github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -184,6 +211,7 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/gomodule/redigo v1.8.2 h1:H5XSIre1MB5NbPYFp+i1NBbb5qN1W8Y8YAQoAYbkm8k= @@ -198,19 +226,29 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= +github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af h1:kmjWCqn2qkEml422C2Rrd27c3VGxi6a/6HNq8QmHRKM= github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= +github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= +github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= +github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= +github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= @@ -226,26 +264,42 @@ github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:Fecb github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= +github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= +github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= +github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hc-install v0.9.0 h1:2dIk8LcvANwtv3QZLckxcjyF5w8KVtiMxu6G6eLhghE= +github.com/hashicorp/hc-install v0.9.0/go.mod h1:+6vOP+mf3tuGgMApVYtmsnDoKWMDcFXeTxCACYZ8SFg= +github.com/hashicorp/terraform-exec v0.21.0 h1:uNkLAe95ey5Uux6KJdua6+cv8asgILFVWkd/RG0D2XQ= +github.com/hashicorp/terraform-exec v0.21.0/go.mod h1:1PPeMYou+KDUSSeRE9szMZ/oHf4fYUmB923Wzbq1ICg= +github.com/hashicorp/terraform-json v0.23.0 h1:sniCkExU4iKtTADReHzACkk8fnpQXrdD2xoR+lppBkI= +github.com/hashicorp/terraform-json v0.23.0/go.mod h1:MHdXbBAbSg0GvzuWazEGKAn/cyNfIB7mN6y7KJN6y2c= github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= -github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= +github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM= +github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= @@ -269,6 +323,8 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/karrick/godirwalk v1.17.0 h1:b4kY7nqDdioR/6qnbHQyDvmA17u5G1cZ6J+CZXwSWoI= github.com/karrick/godirwalk v1.17.0/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= +github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= +github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4= @@ -300,14 +356,11 @@ github.com/markbates/oncer v1.0.0 h1:E83IaVAHygyndzPimgUYJjbshhDTALZyXxvk9FOlQRY github.com/markbates/oncer v1.0.0/go.mod h1:Z59JA581E9GP6w96jai+TGqafHPW+cPfRxz2aSZ0mcI= github.com/markbates/safe v1.0.1 h1:yjZkbvRM6IzKj9tlu/zMJLS0n/V351OZWRnF3QfaUxI= github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= -github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= @@ -363,6 +416,8 @@ github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+v github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= +github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= +github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -397,15 +452,19 @@ github.com/rubenv/sql-migrate v1.5.2 h1:bMDqOnrJVV/6JQgQ/MxOpU+AdO8uzYYA/TxFUBzF github.com/rubenv/sql-migrate v1.5.2/go.mod h1:H38GW8Vqf8F0Su5XignRyaRcbXbJunSWxs+kmzlg0Is= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= -github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/siderolabs/talos/pkg/machinery v1.8.2 h1:oBNBIPjOo6SNvVaUb4B4PHGefR6HYgYVl1/GPGppj98= +github.com/siderolabs/talos/pkg/machinery v1.8.2/go.mod h1:cNR2TELu2T9AzYOHAoNr/7ZS3ZVDLzM/KnuOr4XW4s4= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A= +github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= @@ -433,6 +492,8 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= +github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -451,6 +512,8 @@ github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50 h1:hlE8//ciYMzt github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f h1:ERexzlUfuTvpE74urLSbIQW0Z/6hF9t8U4NsJLaioAY= github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= +github.com/zclconf/go-cty v1.15.0 h1:tTCRWxsexYUmtt/wVxgDClUe+uQusuI443uL6e+5sXQ= +github.com/zclconf/go-cty v1.15.0/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= go.etcd.io/etcd/api/v3 v3.5.15 h1:3KpLJir1ZEBrYuV2v+Twaa/e2MdDCEZ/70H+lzEiwsk= go.etcd.io/etcd/api/v3 v3.5.15/go.mod h1:N9EhGzXq58WuMllgH9ZvnEr7SI9pS0k0+DHZezGp7jM= go.etcd.io/etcd/client/pkg/v3 v3.5.15 h1:fo0HpWz/KlHGMCC+YejpiCmyWDEuIpnTDzpJLB5fWlA= @@ -496,8 +559,8 @@ golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4 golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= -golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= +golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= +golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -507,8 +570,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -520,6 +583,7 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= @@ -528,8 +592,8 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= -golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= @@ -541,8 +605,8 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -550,13 +614,10 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -564,11 +625,12 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= -golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= +golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -577,8 +639,8 @@ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= -golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= -golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= +golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= +golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= @@ -586,10 +648,10 @@ golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= +golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -607,29 +669,37 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +google.golang.org/api v0.152.0 h1:t0r1vPnfMc260S2Ci+en7kfCZaLOPs5KI0sVV/6jZrY= +google.golang.org/api v0.152.0/go.mod h1:3qNJX5eOmhiWYc67jRA/3GsDw97UFb5ivv7Y2PrriAY= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 h1:7whR9kGa5LUwFtpLm2ArCEejtnxlGeLbAyjFY8sGNFw= -google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157/go.mod h1:99sLkeliLXfdj2J75X3Ho+rrVCaJze0uwN7zDDkjPVU= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= +google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 h1:wpZ8pe2x1Q3f2KyT5f8oP/fa9rHAKgFPr/HZdNuS+PQ= +google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:J7XzRzVy1+IPwWHZUzoD0IccYZIrXILAQpc+Qy9CMhY= +google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 h1:hjSy6tcFQZ171igDaN5QHOw2n6vx40juYbC/x67CEhc= +google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= -google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.66.3 h1:TWlsh8Mv0QI/1sIbs1W36lqRclxrmF+eFJ4DbI0fuhA= +google.golang.org/grpc v1.66.3/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= @@ -643,6 +713,8 @@ gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSP gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -651,7 +723,6 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= diff --git a/haproxy.cfg b/haproxy.cfg new file mode 100644 index 0000000..b5dac7b --- /dev/null +++ b/haproxy.cfg @@ -0,0 +1,76 @@ +# /etc/haproxy/haproxy.cfg +#--------------------------------------------------------------------- +# Global settings +#--------------------------------------------------------------------- +global + log stdout format raw local0 + daemon + +#--------------------------------------------------------------------- +# common defaults that all the 'listen' and 'backend' sections will +# use if not designated in their block +#--------------------------------------------------------------------- +defaults + mode http + log global + option httplog + option dontlognull + option forwardfor except 127.0.0.0/8 + option redispatch + retries 1 + timeout http-request 10s + timeout queue 20s + timeout connect 5s + timeout client 35s + timeout server 35s + timeout http-keep-alive 10s + timeout check 10s + +#--------------------------------------------------------------------- +# apiserver frontend which proxys to the control plane nodes +#--------------------------------------------------------------------- +frontend apiserver + bind *:6443 + mode tcp + option tcplog + default_backend apiserverbackend + +#--------------------------------------------------------------------- +# round robin balancing for apiserver +#--------------------------------------------------------------------- +backend apiserverbackend + mode tcp + balance roundrobin + server delegatio-master-0 delegatio-master-0:6443 check +#--------------------------------------------------------------------- +# apiserver frontend which proxys to the control plane nodes +#--------------------------------------------------------------------- +frontend delegatioapi + bind *:9000 proto h2 + mode http + + default_backend delegatiobackend + +#--------------------------------------------------------------------- +# round robin balancing for apiserver +#--------------------------------------------------------------------- +backend delegatiobackend + mode http + balance roundrobin + + server delegatio-master-0 delegatio-master-0:9000 check proto h2 + +frontend etcdserver + bind *:2379 + mode tcp + option tcplog + default_backend etcdserverbackend + +#--------------------------------------------------------------------- +# round robin balancing for apiserver +#--------------------------------------------------------------------- +backend etcdserverbackend + mode tcp + balance roundrobin + server delegatio-master-0 delegatio-master-0:2379 check + diff --git a/images/mkosi.postinst b/images/mkosi.postinst index 453d97c..9c817bd 100755 --- a/images/mkosi.postinst +++ b/images/mkosi.postinst @@ -15,4 +15,4 @@ ln -rsf /run/systemd/resolve/stub-resolv.conf ${BUILDROOT}/etc/resolv.conf -ln -sf /usr/share/zoneinfo/Europe/Zurich ${BUILDROOT}/etc/localtime \ No newline at end of file +ln -sf /usr/share/zoneinfo/Europe/Zurich ${BUILDROOT}/etc/localtime diff --git a/images/mkosi.prepare b/images/mkosi.prepare index 6a01067..4dca779 100755 --- a/images/mkosi.prepare +++ b/images/mkosi.prepare @@ -24,4 +24,4 @@ mkdir -p ${BUILDROOT}/etc/systemd/system/kubelet.service.d curl -sSL "https://raw.githubusercontent.com/kubernetes/release/${RELEASE_VERSION}/cmd/kubepkg/templates/latest/deb/kubeadm/10-kubeadm.conf" | tee ${BUILDROOT}/etc/systemd/system/kubelet.service.d/10-kubeadm.conf # Fix cillium error -chown -R root:root ${DEST} \ No newline at end of file +chown -R root:root ${DEST} diff --git a/images/mkosi.repart/50-root.conf b/images/mkosi.repart/50-root.conf index 764d44c..af6a424 100644 --- a/images/mkosi.repart/50-root.conf +++ b/images/mkosi.repart/50-root.conf @@ -2,4 +2,5 @@ Type=root Format=ext4 CopyFiles=/ -SizeMinBytes=20G \ No newline at end of file +SizeMinBytes=20G +SizeMaxBytes=20G \ No newline at end of file diff --git a/internal/config/global.go b/internal/config/global.go index c7f53ff..3752c36 100644 --- a/internal/config/global.go +++ b/internal/config/global.go @@ -14,8 +14,8 @@ import ( // Infrastructure and Kubernetes configdata is stored here. var ( ClusterConfiguration = ClusterConfig{ - NumberOfWorkers: 2, - NumberOfMasters: 1, + NumberOfWorkers: 3, + NumberOfMasters: 3, } // CleanUpTimeout is the timeout after which the save-state function is canceled when ctrl+c is pressed in the cli. CleanUpTimeout = 10 * time.Second diff --git a/internal/config/utils/kubeadm_config.go b/internal/config/utils/kubeadm_config.go index df7244e..1b4c403 100644 --- a/internal/config/utils/kubeadm_config.go +++ b/internal/config/utils/kubeadm_config.go @@ -79,7 +79,8 @@ func initConfiguration() KubeadmInitYAML { }, Etcd: kubeadm.Etcd{ Local: &kubeadm.LocalEtcd{ - ExtraArgs: []kubeadm.Arg{}, + ExtraArgs: []kubeadm.Arg{}, + ServerCertSANs: []string{"127.0.0.1"}, }, }, }, @@ -100,6 +101,7 @@ func (k *KubeadmInitYAML) SetCertSANs(certSANs []string) { continue } k.ClusterConfiguration.APIServer.CertSANs = append(k.ClusterConfiguration.APIServer.CertSANs, certSAN) + k.ClusterConfiguration.Etcd.Local.ServerCertSANs = append(k.ClusterConfiguration.Etcd.Local.ServerCertSANs, certSAN) } } diff --git a/ssh/kubernetes/api.go b/ssh/kubernetes/api.go index 2fa6da8..8ce0cd8 100644 --- a/ssh/kubernetes/api.go +++ b/ssh/kubernetes/api.go @@ -41,7 +41,8 @@ func NewK8sAPIWrapper(logger *zap.Logger) (*K8sAPIWrapper, error) { if err != nil { return nil, err } - core, err := core.NewCore(logger) + // TODO: split core and vmapi into multiple packages / services + core, err := core.NewCore(logger, "") if err != nil { return nil, err } From 414c9f7263690f2eeac704343c0d47b490edec87 Mon Sep 17 00:00:00 2001 From: Benedict Schlueter Date: Sat, 2 Nov 2024 22:51:19 +0100 Subject: [PATCH 3/3] split agent into vm and container Signed-off-by: Benedict Schlueter --- CMakeLists.txt | 2 +- .../containerapi/containerapi.go} | 38 +- agent/container/containerapi/core.go | 8 + agent/container/core/core.go | 27 + agent/{server => container}/main.go | 0 agent/container/run.go | 82 + agent/manageapi/core.go | 8 + agent/{vmapi => manageapi}/exec.go | 34 +- agent/{vmapi => manageapi}/file.go | 12 +- agent/manageapi/manageapi.go | 52 + .../manageproto/Dockerfile.gen-proto | 31 + .../manageproto}/README.md | 0 agent/manageapi/manageproto/managei.pb.go | 865 ++++++++++ .../manageproto/managei.proto} | 39 +- .../manageproto/managei_grpc.pb.go} | 265 +-- agent/{vmapi => manageapi}/size.go | 2 +- agent/{ => vm}/core/core.go | 4 +- agent/{ => vm}/core/state/state.go | 0 agent/{ => vm}/core/state/state_string.go | 0 agent/vm/main.go | 80 + agent/{server => vm}/run.go | 12 +- agent/{ => vm}/vmapi/core.go | 0 agent/{ => vm}/vmapi/kube.go | 17 +- agent/vm/vmapi/vmapi.go | 64 + .../vmapi/vmproto/Dockerfile.gen-proto | 8 +- agent/vm/vmapi/vmproto/README.md | 11 + agent/vm/vmapi/vmproto/vmapi.pb.go | 529 ++++++ agent/vm/vmapi/vmproto/vmapi.proto | 48 + agent/vm/vmapi/vmproto/vmapi_grpc.pb.go | 163 ++ agent/vmapi/vmproto/vmapi.pb.go | 1502 ----------------- cli/bootstrapper/kubernetes/exec.go | 76 +- cli/bootstrapper/kubernetes/get.go | 84 +- cli/bootstrapper/kubernetes/kubernetes.go | 28 +- cli/infrastructure/qemu/block.go | 6 +- .../challenges/testing/Dockerfile.archlinux | 4 +- haproxy.cfg | 4 + ssh/kubernetes/api.go | 10 +- 37 files changed, 2142 insertions(+), 1973 deletions(-) rename agent/{vmapi/vmapi.go => container/containerapi/containerapi.go} (83%) create mode 100644 agent/container/containerapi/core.go create mode 100644 agent/container/core/core.go rename agent/{server => container}/main.go (100%) create mode 100644 agent/container/run.go create mode 100644 agent/manageapi/core.go rename agent/{vmapi => manageapi}/exec.go (81%) rename agent/{vmapi => manageapi}/file.go (79%) create mode 100644 agent/manageapi/manageapi.go create mode 100644 agent/manageapi/manageproto/Dockerfile.gen-proto rename agent/{vmapi/vmproto => manageapi/manageproto}/README.md (100%) create mode 100644 agent/manageapi/manageproto/managei.pb.go rename agent/{vmapi/vmproto/vmapi.proto => manageapi/manageproto/managei.proto} (64%) rename agent/{vmapi/vmproto/vmapi_grpc.pb.go => manageapi/manageproto/managei_grpc.pb.go} (50%) rename agent/{vmapi => manageapi}/size.go (98%) rename agent/{ => vm}/core/core.go (98%) rename agent/{ => vm}/core/state/state.go (100%) rename agent/{ => vm}/core/state/state_string.go (100%) create mode 100644 agent/vm/main.go rename agent/{server => vm}/run.go (84%) rename agent/{ => vm}/vmapi/core.go (100%) rename agent/{ => vm}/vmapi/kube.go (89%) create mode 100644 agent/vm/vmapi/vmapi.go rename agent/{ => vm}/vmapi/vmproto/Dockerfile.gen-proto (93%) create mode 100644 agent/vm/vmapi/vmproto/README.md create mode 100644 agent/vm/vmapi/vmproto/vmapi.pb.go create mode 100644 agent/vm/vmapi/vmproto/vmapi.proto create mode 100644 agent/vm/vmapi/vmproto/vmapi_grpc.pb.go delete mode 100644 agent/vmapi/vmproto/vmapi.pb.go diff --git a/CMakeLists.txt b/CMakeLists.txt index 82dada2..5a1f1a8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,7 +33,7 @@ add_custom_target(images ALL # add_custom_target(delegatio-agent ALL go build -o ${CMAKE_BINARY_DIR}/delegatio-agent - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/agent/server + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/agent/vm BYPRODUCTS delegatio-agent ) diff --git a/agent/vmapi/vmapi.go b/agent/container/containerapi/containerapi.go similarity index 83% rename from agent/vmapi/vmapi.go rename to agent/container/containerapi/containerapi.go index 7f429e2..cbe6924 100644 --- a/agent/vmapi/vmapi.go +++ b/agent/container/containerapi/containerapi.go @@ -2,7 +2,7 @@ * Copyright (c) Benedict Schlueter */ -package vmapi +package containerapi import ( "context" @@ -13,7 +13,7 @@ import ( "strconv" "syscall" - "github.com/benschlueter/delegatio/agent/vmapi/vmproto" + "github.com/benschlueter/delegatio/agent/manageapi/manageproto" "github.com/benschlueter/delegatio/internal/config" "go.uber.org/zap" "golang.org/x/sync/errgroup" @@ -22,8 +22,8 @@ import ( "k8s.io/client-go/tools/remotecommand" ) -// VMAPI interface contains functions to access the agent. -type VMAPI interface { +// ContainerAPI interface contains functions to access the container agent. +type ContainerAPI interface { CreateExecInPodgRPC(context.Context, string, *config.KubeExecConfig) error WriteFileInPodgRPC(context.Context, string, *config.KubeFileWriteConfig) error } @@ -33,7 +33,7 @@ type API struct { logger *zap.Logger core Core dialer Dialer - vmproto.UnimplementedAPIServer + manageproto.UnimplementedAPIServer } // New creates a new API. @@ -74,9 +74,9 @@ func (a *API) WriteFileInPodgRPC(ctx context.Context, endpoint string, conf *con return err } defer conn.Close() - client := vmproto.NewAPIClient(conn) + client := manageproto.NewAPIClient(conn) _, err = client.WriteFile(ctx, - &vmproto.WriteFileRequest{ + &manageproto.WriteFileRequest{ Filepath: conf.FilePath, Filename: conf.FileName, Content: conf.FileData, @@ -98,14 +98,14 @@ func (a *API) CreateExecInPodgRPC(ctx context.Context, endpoint string, conf *co return err } defer conn.Close() - client := vmproto.NewAPIClient(conn) + client := manageproto.NewAPIClient(conn) resp, err := client.ExecCommandStream(ctx) if err != nil { return err } - err = resp.Send(&vmproto.ExecCommandStreamRequest{ - Content: &vmproto.ExecCommandStreamRequest_Command{ - Command: &vmproto.ExecCommandRequest{ + err = resp.Send(&manageproto.ExecCommandStreamRequest{ + Content: &manageproto.ExecCommandStreamRequest_Command{ + Command: &manageproto.ExecCommandRequest{ Command: conf.Command, Tty: conf.Tty, }, @@ -132,7 +132,7 @@ func (a *API) CreateExecInPodgRPC(ctx context.Context, endpoint string, conf *co return err } -func (a *API) termSizeHandler(ctx context.Context, resp vmproto.API_ExecCommandStreamClient, resizeData remotecommand.TerminalSizeQueue) error { +func (a *API) termSizeHandler(ctx context.Context, resp manageproto.API_ExecCommandStreamClient, resizeData remotecommand.TerminalSizeQueue) error { queue := make(chan *remotecommand.TerminalSize, 1) go func() { for { @@ -155,9 +155,9 @@ func (a *API) termSizeHandler(ctx context.Context, resp vmproto.API_ExecCommandS a.logger.Debug("terminalSizeHandler queue closed") return errors.New("window size queue closed") } - err := resp.Send(&vmproto.ExecCommandStreamRequest{ - Content: &vmproto.ExecCommandStreamRequest_Termsize{ - Termsize: &vmproto.TerminalSizeRequest{ + err := resp.Send(&manageproto.ExecCommandStreamRequest{ + Content: &manageproto.ExecCommandStreamRequest_Termsize{ + Termsize: &manageproto.TerminalSizeRequest{ Width: int32(item.Width), Height: int32(item.Height), }, @@ -173,7 +173,7 @@ func (a *API) termSizeHandler(ctx context.Context, resp vmproto.API_ExecCommandS // receiver is called from the agent. // It receives data from the agent and writes it to the SSH Client (end-user). -func (a *API) receiver(ctx context.Context, cancel context.CancelFunc, resp vmproto.API_ExecCommandStreamClient, stdout io.Writer, stderr io.Writer) error { +func (a *API) receiver(ctx context.Context, cancel context.CancelFunc, resp manageproto.API_ExecCommandStreamClient, stdout io.Writer, stderr io.Writer) error { for { select { case <-ctx.Done(): @@ -207,7 +207,7 @@ func (a *API) receiver(ctx context.Context, cancel context.CancelFunc, resp vmpr // we don't need to cancel the context. If we fail to send something receiving will either return EOF or an error. // Thus the receiver will stop and cancel the context. -func (a *API) sender(ctx context.Context, resp vmproto.API_ExecCommandStreamClient, stdin io.Reader) error { +func (a *API) sender(ctx context.Context, resp manageproto.API_ExecCommandStreamClient, stdin io.Reader) error { // g, _ := errgroup.WithContext(ctx) errChan := make(chan error, 1) @@ -227,8 +227,8 @@ func (a *API) sender(ctx context.Context, resp vmproto.API_ExecCommandStreamClie errChan <- err return } - err = resp.Send(&vmproto.ExecCommandStreamRequest{ - Content: &vmproto.ExecCommandStreamRequest_Stdin{ + err = resp.Send(&manageproto.ExecCommandStreamRequest{ + Content: &manageproto.ExecCommandStreamRequest_Stdin{ Stdin: copier[:n], }, }) diff --git a/agent/container/containerapi/core.go b/agent/container/containerapi/core.go new file mode 100644 index 0000000..b380c79 --- /dev/null +++ b/agent/container/containerapi/core.go @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: AGPL-3.0-only + * Copyright (c) Benedict Schlueter + */ + +package containerapi + +// Core interface contains functions to access the state Core data. +type Core interface{} diff --git a/agent/container/core/core.go b/agent/container/core/core.go new file mode 100644 index 0000000..5364170 --- /dev/null +++ b/agent/container/core/core.go @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: AGPL-3.0-only + * Copyright (c) Benedict Schlueter + * Copyright (c) Edgeless Systems GmbH + */ + +package core + +import ( + "sync" + + "go.uber.org/zap" +) + +// Core is responsible for maintaining state information of the container-agent. +type Core struct { + zaplogger *zap.Logger + mux sync.Mutex +} + +// NewCore creates and initializes a new Core object. +func NewCore(zapLogger *zap.Logger) (*Core, error) { + c := &Core{ + zaplogger: zapLogger, + mux: sync.Mutex{}, + } + return c, nil +} diff --git a/agent/server/main.go b/agent/container/main.go similarity index 100% rename from agent/server/main.go rename to agent/container/main.go diff --git a/agent/container/run.go b/agent/container/run.go new file mode 100644 index 0000000..e437eef --- /dev/null +++ b/agent/container/run.go @@ -0,0 +1,82 @@ +/* SPDX-License-Identifier: AGPL-3.0-only + * Copyright (c) Edgeless Systems GmbH + * Copyright (c) Benedict Schlueter + * Copyright (c) Leonard Cohnen + */ + +package main + +import ( + "context" + "net" + "sync" + + "github.com/benschlueter/delegatio/agent/manageapi" + "github.com/benschlueter/delegatio/agent/manageapi/manageproto" + "github.com/benschlueter/delegatio/agent/vm/core" + "github.com/benschlueter/delegatio/agent/vm/core/state" + "github.com/benschlueter/delegatio/internal/config" + grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware" + grpc_zap "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap" + grpc_ctxtags "github.com/grpc-ecosystem/go-grpc-middleware/tags" + "go.uber.org/zap" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +var version = "0.0.0" + +/* + * This will run on the VM's bare matel. We try to contact the control plane + * via the loadbalancerIPAddr to give us the join token. At the same time + * we are waiting for the init-request from a user *only* if we are a control plane. + */ +func run(dialer manageapi.Dialer, bindIP, bindPort string, zapLoggerCore *zap.Logger, containerMode *bool, loadbalancerIPAddr string) { + defer func() { _ = zapLoggerCore.Sync() }() + zapLoggerCore.Info("starting delegatio agent", zap.String("version", version), zap.String("commit", config.Commit)) + + if *containerMode { + zapLoggerCore.Info("running in container mode") + } else { + zapLoggerCore.Info("running in qemu mode") + } + + core, err := core.NewCore(zapLoggerCore, loadbalancerIPAddr) + if err != nil { + zapLoggerCore.Fatal("failed to create core", zap.Error(err)) + } + + vapi := manageapi.New(zapLoggerCore.Named("vmapi"), core, dialer) + zapLoggergRPC := zapLoggerCore.Named("gRPC") + + grpcServer := grpc.NewServer( + grpc.Creds(insecure.NewCredentials()), + grpc.StreamInterceptor(grpc_middleware.ChainStreamServer( + grpc_ctxtags.StreamServerInterceptor(), + grpc_zap.StreamServerInterceptor(zapLoggergRPC), + )), + grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer( + grpc_ctxtags.UnaryServerInterceptor(), + grpc_zap.UnaryServerInterceptor(zapLoggergRPC), + )), + ) + manageproto.RegisterAPIServer(grpcServer, vapi) + + lis, err := net.Listen("tcp", net.JoinHostPort(bindIP, bindPort)) + if err != nil { + zapLoggergRPC.Fatal("failed to create listener", zap.Error(err)) + } + zapLoggergRPC.Info("server listener created", zap.String("address", lis.Addr().String())) + core.State.Advance(state.AcceptingInit) + go core.TryJoinCluster(context.Background()) + + var wg sync.WaitGroup + defer wg.Wait() + wg.Add(1) + go func() { + defer wg.Done() + if err := grpcServer.Serve(lis); err != nil { + zapLoggergRPC.Fatal("failed to serve gRPC", zap.Error(err)) + } + }() +} diff --git a/agent/manageapi/core.go b/agent/manageapi/core.go new file mode 100644 index 0000000..f64da4a --- /dev/null +++ b/agent/manageapi/core.go @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: AGPL-3.0-only + * Copyright (c) Benedict Schlueter + */ + +package manageapi + +// Core interface contains functions to access the state Core data. +type Core interface{} diff --git a/agent/vmapi/exec.go b/agent/manageapi/exec.go similarity index 81% rename from agent/vmapi/exec.go rename to agent/manageapi/exec.go index 730b8b7..6383b29 100644 --- a/agent/vmapi/exec.go +++ b/agent/manageapi/exec.go @@ -2,7 +2,7 @@ * Copyright (c) Benedict Schlueter */ -package vmapi +package manageapi import ( "bytes" @@ -12,7 +12,7 @@ import ( "io" "os/exec" - "github.com/benschlueter/delegatio/agent/vmapi/vmproto" + "github.com/benschlueter/delegatio/agent/manageapi/manageproto" "github.com/creack/pty" "go.uber.org/zap" "golang.org/x/sys/unix" @@ -25,7 +25,7 @@ func setSize(fd uintptr, size *TerminalSize) error { return unix.IoctlSetWinsize(int(fd), unix.TIOCSWINSZ, winsize) } -func (a *API) ttyCmd(execCmd *exec.Cmd, stdin io.Reader, stdout io.WriteCloser, handler *TerminalSizeHandler) error { +func (a *ManageAPI) ttyCmd(execCmd *exec.Cmd, stdin io.Reader, stdout io.WriteCloser, handler *TerminalSizeHandler) error { p, err := pty.Start(execCmd) if err != nil { return err @@ -67,7 +67,7 @@ func (a *API) ttyCmd(execCmd *exec.Cmd, stdin io.Reader, stdout io.WriteCloser, // ExecCommandStream executes a command in the VM and streams the output to the caller. // This is useful if the command needs much time to run and we want to log the current state, i.e. kubeadm. -func (a *API) ExecCommandStream(srv vmproto.API_ExecCommandStreamServer) error { +func (a *ManageAPI) ExecCommandStream(srv manageproto.API_ExecCommandStreamServer) error { a.logger.Info("ExecCommandStream") in, err := srv.Recv() if err != nil { @@ -84,8 +84,8 @@ func (a *API) ExecCommandStream(srv vmproto.API_ExecCommandStreamServer) error { errorStreamWriter := &streamWriterWrapper{ forwardFunc: func(b []byte) error { - return srv.Send(&vmproto.ExecCommandStreamResponse{ - Content: &vmproto.ExecCommandStreamResponse_Stderr{ + return srv.Send(&manageproto.ExecCommandStreamResponse{ + Content: &manageproto.ExecCommandStreamResponse_Stderr{ Stderr: b, }, }) @@ -93,8 +93,8 @@ func (a *API) ExecCommandStream(srv vmproto.API_ExecCommandStreamServer) error { } stdoutStreamWrtier := &streamWriterWrapper{ forwardFunc: func(b []byte) error { - return srv.Send(&vmproto.ExecCommandStreamResponse{ - Content: &vmproto.ExecCommandStreamResponse_Stdout{ + return srv.Send(&manageproto.ExecCommandStreamResponse{ + Content: &manageproto.ExecCommandStreamResponse_Stdout{ Stdout: b, }, }) @@ -161,8 +161,8 @@ func (a *API) ExecCommandStream(srv vmproto.API_ExecCommandStreamServer) error { exitCode = -1 } // Instead of done we should return the exit code of the command. - if err := srv.Send(&vmproto.ExecCommandStreamResponse{ - Content: &vmproto.ExecCommandStreamResponse_Err{ + if err := srv.Send(&manageproto.ExecCommandStreamResponse{ + Content: &manageproto.ExecCommandStreamResponse_Err{ Err: fmt.Sprint(exitCode), }, }); err != nil { @@ -174,13 +174,13 @@ func (a *API) ExecCommandStream(srv vmproto.API_ExecCommandStreamServer) error { // ExecCommandReturnStream executes a command in the VM and streams the output to the caller. // This is useful if the command needs much time to run and we want to log the current state, i.e. kubeadm. -func (a *API) ExecCommandReturnStream(in *vmproto.ExecCommandRequest, srv vmproto.API_ExecCommandReturnStreamServer) error { +func (a *ManageAPI) ExecCommandReturnStream(in *manageproto.ExecCommandRequest, srv manageproto.API_ExecCommandReturnStreamServer) error { a.logger.Info("request to execute command", zap.String("command", in.Command), zap.Strings("args", in.Args)) command := exec.Command(in.Command, in.Args...) streamer := &streamWriterWrapper{forwardFunc: func(b []byte) error { - return srv.Send(&vmproto.ExecCommandReturnStreamResponse{ - Content: &vmproto.ExecCommandReturnStreamResponse_Log{ - Log: &vmproto.Log{ + return srv.Send(&manageproto.ExecCommandReturnStreamResponse{ + Content: &manageproto.ExecCommandReturnStreamResponse_Log{ + Log: &manageproto.Log{ Message: string(b), }, }, @@ -198,18 +198,18 @@ func (a *API) ExecCommandReturnStream(in *vmproto.ExecCommandRequest, srv vmprot if err := command.Wait(); err != nil { return status.Errorf(codes.Internal, "command exited with error code: %v and output: %s", err, stdoutBuf.Bytes()) } - return srv.Send(&vmproto.ExecCommandReturnStreamResponse{Content: &vmproto.ExecCommandReturnStreamResponse_Output{Output: stdoutBuf.Bytes()}}) + return srv.Send(&manageproto.ExecCommandReturnStreamResponse{Content: &manageproto.ExecCommandReturnStreamResponse_Output{Output: stdoutBuf.Bytes()}}) } // ExecCommand executes a command in the VM. -func (a *API) ExecCommand(_ context.Context, in *vmproto.ExecCommandRequest) (*vmproto.ExecCommandResponse, error) { +func (a *ManageAPI) ExecCommand(_ context.Context, in *manageproto.ExecCommandRequest) (*manageproto.ExecCommandResponse, error) { a.logger.Info("request to execute command", zap.String("command", in.Command), zap.Strings("args", in.Args)) command := exec.Command(in.Command, in.Args...) output, err := command.Output() if err != nil { return nil, status.Errorf(codes.Internal, "command exited with error code: %v and output: %s", err, string(output)) } - return &vmproto.ExecCommandResponse{Output: output}, nil + return &manageproto.ExecCommandResponse{Output: output}, nil } type streamWriterWrapper struct { diff --git a/agent/vmapi/file.go b/agent/manageapi/file.go similarity index 79% rename from agent/vmapi/file.go rename to agent/manageapi/file.go index 0c05ad8..43dd8cf 100644 --- a/agent/vmapi/file.go +++ b/agent/manageapi/file.go @@ -2,21 +2,21 @@ * Copyright (c) Benedict Schlueter */ -package vmapi +package manageapi import ( "context" "os" "path/filepath" - "github.com/benschlueter/delegatio/agent/vmapi/vmproto" + "github.com/benschlueter/delegatio/agent/manageapi/manageproto" "go.uber.org/zap" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) // WriteFile creates a file and writes output to it. -func (a *API) WriteFile(_ context.Context, in *vmproto.WriteFileRequest) (*vmproto.WriteFileResponse, error) { +func (a *ManageAPI) WriteFile(_ context.Context, in *manageproto.WriteFileRequest) (*manageproto.WriteFileResponse, error) { a.logger.Info("request to write file", zap.String("path", in.Filepath), zap.String("name", in.Filename)) if _, err := os.Stat(in.Filepath); os.IsNotExist(err) { if err := os.MkdirAll(in.Filepath, 0o700); err != nil { @@ -30,16 +30,16 @@ func (a *API) WriteFile(_ context.Context, in *vmproto.WriteFileRequest) (*vmpro return nil, status.Errorf(codes.Internal, "file write failed exited with error code: %v", err) } a.logger.Debug("wrote content to disk", zap.String("path", in.Filepath), zap.String("name", in.Filename)) - return &vmproto.WriteFileResponse{}, nil + return &manageproto.WriteFileResponse{}, nil } // ReadFile reads a file and returns its content. -func (a *API) ReadFile(_ context.Context, in *vmproto.ReadFileRequest) (*vmproto.ReadFileResponse, error) { +func (a *ManageAPI) ReadFile(_ context.Context, in *manageproto.ReadFileRequest) (*manageproto.ReadFileResponse, error) { a.logger.Info("request to read file", zap.String("path", in.Filepath), zap.String("name", in.Filename)) content, err := os.ReadFile(filepath.Join(in.Filepath, in.Filename)) if err != nil { a.logger.Error("failed to read file", zap.String("path", in.Filepath), zap.String("name", in.Filename), zap.Error(err)) return nil, status.Errorf(codes.Internal, "file read failed exited with error code: %v", err) } - return &vmproto.ReadFileResponse{Content: content}, nil + return &manageproto.ReadFileResponse{Content: content}, nil } diff --git a/agent/manageapi/manageapi.go b/agent/manageapi/manageapi.go new file mode 100644 index 0000000..658d107 --- /dev/null +++ b/agent/manageapi/manageapi.go @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: AGPL-3.0-only + * Copyright (c) Benedict Schlueter + */ + +package manageapi + +import ( + "context" + "net" + + "github.com/benschlueter/delegatio/agent/manageapi/manageproto" + "go.uber.org/zap" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +// ManageAPI is the ManageAPI. +type ManageAPI struct { + logger *zap.Logger + core Core + dialer Dialer + manageproto.UnimplementedAPIServer +} + +// New creates a new API. +func New(logger *zap.Logger, core Core, dialer Dialer) *ManageAPI { + return &ManageAPI{ + logger: logger, + core: core, + dialer: dialer, + } +} + +func (a *ManageAPI) dialInsecure(ctx context.Context, target string) (*grpc.ClientConn, error) { + return grpc.DialContext(ctx, target, + a.grpcWithDialer(), + grpc.WithTransportCredentials(insecure.NewCredentials()), + grpc.WithBlock(), + ) +} + +func (a *ManageAPI) grpcWithDialer() grpc.DialOption { + return grpc.WithContextDialer(func(ctx context.Context, addr string) (net.Conn, error) { + return a.dialer.DialContext(ctx, "tcp", addr) + }) +} + +// Dialer is the dial interface. Necessary to stub network connections for local testing +// with bufconns. +type Dialer interface { + DialContext(ctx context.Context, network, address string) (net.Conn, error) +} diff --git a/agent/manageapi/manageproto/Dockerfile.gen-proto b/agent/manageapi/manageproto/Dockerfile.gen-proto new file mode 100644 index 0000000..9dd6841 --- /dev/null +++ b/agent/manageapi/manageproto/Dockerfile.gen-proto @@ -0,0 +1,31 @@ +FROM ubuntu@sha256:7cc0576c7c0ec2384de5cbf245f41567e922aab1b075f3e8ad565f508032df17 as build + +ARG GO_VER=1.23.1 +ARG GEN_GO_VER=1.35.1 +ARG GEN_GO_GRPC_VER=1.5.1 +ARG PB_VER=28.3 + +ENV DEBIAN_FRONTEND="noninteractive" +RUN apt-get update && apt-get install -y wget tar unzip + +# Install Go +RUN wget https://go.dev/dl/go${GO_VER}.linux-amd64.tar.gz && \ + tar -C /usr/local -xzf go${GO_VER}.linux-amd64.tar.gz && rm go${GO_VER}.linux-amd64.tar.gz +ENV PATH ${PATH}:/usr/local/go/bin:/root/go/bin + + +RUN wget https://github.com/protocolbuffers/protobuf/releases/download/v${PB_VER}/protoc-${PB_VER}-linux-x86_64.zip && \ + unzip protoc-${PB_VER}-linux-x86_64.zip -d /root/.local && \ + cp /root/.local/bin/protoc /usr/local/bin/protoc +ENV PATH="$PATH:/root/.local/bin" + +RUN go install google.golang.org/protobuf/cmd/protoc-gen-go@v${GEN_GO_VER} && \ + go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v${GEN_GO_GRPC_VER} + +# Generate code for every existing proto file +WORKDIR /manageapi +COPY manageproto/*.proto /manageapi +RUN protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative *.proto + +FROM scratch as export +COPY --from=build /manageapi/*.go manageproto/ diff --git a/agent/vmapi/vmproto/README.md b/agent/manageapi/manageproto/README.md similarity index 100% rename from agent/vmapi/vmproto/README.md rename to agent/manageapi/manageproto/README.md diff --git a/agent/manageapi/manageproto/managei.pb.go b/agent/manageapi/manageproto/managei.pb.go new file mode 100644 index 0000000..741481e --- /dev/null +++ b/agent/manageapi/manageproto/managei.pb.go @@ -0,0 +1,865 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.35.1 +// protoc v5.28.3 +// source: managei.proto + +package manageproto + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type ExecCommandStreamRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Content: + // + // *ExecCommandStreamRequest_Command + // *ExecCommandStreamRequest_Stdin + // *ExecCommandStreamRequest_Termsize + Content isExecCommandStreamRequest_Content `protobuf_oneof:"content"` +} + +func (x *ExecCommandStreamRequest) Reset() { + *x = ExecCommandStreamRequest{} + mi := &file_managei_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ExecCommandStreamRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExecCommandStreamRequest) ProtoMessage() {} + +func (x *ExecCommandStreamRequest) ProtoReflect() protoreflect.Message { + mi := &file_managei_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExecCommandStreamRequest.ProtoReflect.Descriptor instead. +func (*ExecCommandStreamRequest) Descriptor() ([]byte, []int) { + return file_managei_proto_rawDescGZIP(), []int{0} +} + +func (m *ExecCommandStreamRequest) GetContent() isExecCommandStreamRequest_Content { + if m != nil { + return m.Content + } + return nil +} + +func (x *ExecCommandStreamRequest) GetCommand() *ExecCommandRequest { + if x, ok := x.GetContent().(*ExecCommandStreamRequest_Command); ok { + return x.Command + } + return nil +} + +func (x *ExecCommandStreamRequest) GetStdin() []byte { + if x, ok := x.GetContent().(*ExecCommandStreamRequest_Stdin); ok { + return x.Stdin + } + return nil +} + +func (x *ExecCommandStreamRequest) GetTermsize() *TerminalSizeRequest { + if x, ok := x.GetContent().(*ExecCommandStreamRequest_Termsize); ok { + return x.Termsize + } + return nil +} + +type isExecCommandStreamRequest_Content interface { + isExecCommandStreamRequest_Content() +} + +type ExecCommandStreamRequest_Command struct { + Command *ExecCommandRequest `protobuf:"bytes,1,opt,name=command,proto3,oneof"` +} + +type ExecCommandStreamRequest_Stdin struct { + Stdin []byte `protobuf:"bytes,2,opt,name=stdin,proto3,oneof"` +} + +type ExecCommandStreamRequest_Termsize struct { + Termsize *TerminalSizeRequest `protobuf:"bytes,3,opt,name=termsize,proto3,oneof"` +} + +func (*ExecCommandStreamRequest_Command) isExecCommandStreamRequest_Content() {} + +func (*ExecCommandStreamRequest_Stdin) isExecCommandStreamRequest_Content() {} + +func (*ExecCommandStreamRequest_Termsize) isExecCommandStreamRequest_Content() {} + +type ExecCommandStreamResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Content: + // + // *ExecCommandStreamResponse_Stdout + // *ExecCommandStreamResponse_Stderr + // *ExecCommandStreamResponse_Err + Content isExecCommandStreamResponse_Content `protobuf_oneof:"content"` +} + +func (x *ExecCommandStreamResponse) Reset() { + *x = ExecCommandStreamResponse{} + mi := &file_managei_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ExecCommandStreamResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExecCommandStreamResponse) ProtoMessage() {} + +func (x *ExecCommandStreamResponse) ProtoReflect() protoreflect.Message { + mi := &file_managei_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExecCommandStreamResponse.ProtoReflect.Descriptor instead. +func (*ExecCommandStreamResponse) Descriptor() ([]byte, []int) { + return file_managei_proto_rawDescGZIP(), []int{1} +} + +func (m *ExecCommandStreamResponse) GetContent() isExecCommandStreamResponse_Content { + if m != nil { + return m.Content + } + return nil +} + +func (x *ExecCommandStreamResponse) GetStdout() []byte { + if x, ok := x.GetContent().(*ExecCommandStreamResponse_Stdout); ok { + return x.Stdout + } + return nil +} + +func (x *ExecCommandStreamResponse) GetStderr() []byte { + if x, ok := x.GetContent().(*ExecCommandStreamResponse_Stderr); ok { + return x.Stderr + } + return nil +} + +func (x *ExecCommandStreamResponse) GetErr() string { + if x, ok := x.GetContent().(*ExecCommandStreamResponse_Err); ok { + return x.Err + } + return "" +} + +type isExecCommandStreamResponse_Content interface { + isExecCommandStreamResponse_Content() +} + +type ExecCommandStreamResponse_Stdout struct { + Stdout []byte `protobuf:"bytes,1,opt,name=stdout,proto3,oneof"` +} + +type ExecCommandStreamResponse_Stderr struct { + Stderr []byte `protobuf:"bytes,2,opt,name=stderr,proto3,oneof"` +} + +type ExecCommandStreamResponse_Err struct { + Err string `protobuf:"bytes,3,opt,name=err,proto3,oneof"` +} + +func (*ExecCommandStreamResponse_Stdout) isExecCommandStreamResponse_Content() {} + +func (*ExecCommandStreamResponse_Stderr) isExecCommandStreamResponse_Content() {} + +func (*ExecCommandStreamResponse_Err) isExecCommandStreamResponse_Content() {} + +type ExecCommandReturnStreamResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Content: + // + // *ExecCommandReturnStreamResponse_Output + // *ExecCommandReturnStreamResponse_Log + Content isExecCommandReturnStreamResponse_Content `protobuf_oneof:"content"` +} + +func (x *ExecCommandReturnStreamResponse) Reset() { + *x = ExecCommandReturnStreamResponse{} + mi := &file_managei_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ExecCommandReturnStreamResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExecCommandReturnStreamResponse) ProtoMessage() {} + +func (x *ExecCommandReturnStreamResponse) ProtoReflect() protoreflect.Message { + mi := &file_managei_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExecCommandReturnStreamResponse.ProtoReflect.Descriptor instead. +func (*ExecCommandReturnStreamResponse) Descriptor() ([]byte, []int) { + return file_managei_proto_rawDescGZIP(), []int{2} +} + +func (m *ExecCommandReturnStreamResponse) GetContent() isExecCommandReturnStreamResponse_Content { + if m != nil { + return m.Content + } + return nil +} + +func (x *ExecCommandReturnStreamResponse) GetOutput() []byte { + if x, ok := x.GetContent().(*ExecCommandReturnStreamResponse_Output); ok { + return x.Output + } + return nil +} + +func (x *ExecCommandReturnStreamResponse) GetLog() *Log { + if x, ok := x.GetContent().(*ExecCommandReturnStreamResponse_Log); ok { + return x.Log + } + return nil +} + +type isExecCommandReturnStreamResponse_Content interface { + isExecCommandReturnStreamResponse_Content() +} + +type ExecCommandReturnStreamResponse_Output struct { + Output []byte `protobuf:"bytes,1,opt,name=output,proto3,oneof"` +} + +type ExecCommandReturnStreamResponse_Log struct { + Log *Log `protobuf:"bytes,2,opt,name=log,proto3,oneof"` +} + +func (*ExecCommandReturnStreamResponse_Output) isExecCommandReturnStreamResponse_Content() {} + +func (*ExecCommandReturnStreamResponse_Log) isExecCommandReturnStreamResponse_Content() {} + +type TerminalSizeRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Width int32 `protobuf:"varint,1,opt,name=width,proto3" json:"width,omitempty"` + Height int32 `protobuf:"varint,2,opt,name=height,proto3" json:"height,omitempty"` +} + +func (x *TerminalSizeRequest) Reset() { + *x = TerminalSizeRequest{} + mi := &file_managei_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TerminalSizeRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TerminalSizeRequest) ProtoMessage() {} + +func (x *TerminalSizeRequest) ProtoReflect() protoreflect.Message { + mi := &file_managei_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TerminalSizeRequest.ProtoReflect.Descriptor instead. +func (*TerminalSizeRequest) Descriptor() ([]byte, []int) { + return file_managei_proto_rawDescGZIP(), []int{3} +} + +func (x *TerminalSizeRequest) GetWidth() int32 { + if x != nil { + return x.Width + } + return 0 +} + +func (x *TerminalSizeRequest) GetHeight() int32 { + if x != nil { + return x.Height + } + return 0 +} + +type ExecCommandRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Command string `protobuf:"bytes,1,opt,name=command,proto3" json:"command,omitempty"` + Args []string `protobuf:"bytes,2,rep,name=args,proto3" json:"args,omitempty"` + Tty bool `protobuf:"varint,3,opt,name=tty,proto3" json:"tty,omitempty"` +} + +func (x *ExecCommandRequest) Reset() { + *x = ExecCommandRequest{} + mi := &file_managei_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ExecCommandRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExecCommandRequest) ProtoMessage() {} + +func (x *ExecCommandRequest) ProtoReflect() protoreflect.Message { + mi := &file_managei_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExecCommandRequest.ProtoReflect.Descriptor instead. +func (*ExecCommandRequest) Descriptor() ([]byte, []int) { + return file_managei_proto_rawDescGZIP(), []int{4} +} + +func (x *ExecCommandRequest) GetCommand() string { + if x != nil { + return x.Command + } + return "" +} + +func (x *ExecCommandRequest) GetArgs() []string { + if x != nil { + return x.Args + } + return nil +} + +func (x *ExecCommandRequest) GetTty() bool { + if x != nil { + return x.Tty + } + return false +} + +type ExecCommandResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Output []byte `protobuf:"bytes,1,opt,name=output,proto3" json:"output,omitempty"` +} + +func (x *ExecCommandResponse) Reset() { + *x = ExecCommandResponse{} + mi := &file_managei_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ExecCommandResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExecCommandResponse) ProtoMessage() {} + +func (x *ExecCommandResponse) ProtoReflect() protoreflect.Message { + mi := &file_managei_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExecCommandResponse.ProtoReflect.Descriptor instead. +func (*ExecCommandResponse) Descriptor() ([]byte, []int) { + return file_managei_proto_rawDescGZIP(), []int{5} +} + +func (x *ExecCommandResponse) GetOutput() []byte { + if x != nil { + return x.Output + } + return nil +} + +type WriteFileRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Filepath string `protobuf:"bytes,1,opt,name=filepath,proto3" json:"filepath,omitempty"` + Filename string `protobuf:"bytes,2,opt,name=filename,proto3" json:"filename,omitempty"` + Content []byte `protobuf:"bytes,3,opt,name=content,proto3" json:"content,omitempty"` +} + +func (x *WriteFileRequest) Reset() { + *x = WriteFileRequest{} + mi := &file_managei_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *WriteFileRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WriteFileRequest) ProtoMessage() {} + +func (x *WriteFileRequest) ProtoReflect() protoreflect.Message { + mi := &file_managei_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WriteFileRequest.ProtoReflect.Descriptor instead. +func (*WriteFileRequest) Descriptor() ([]byte, []int) { + return file_managei_proto_rawDescGZIP(), []int{6} +} + +func (x *WriteFileRequest) GetFilepath() string { + if x != nil { + return x.Filepath + } + return "" +} + +func (x *WriteFileRequest) GetFilename() string { + if x != nil { + return x.Filename + } + return "" +} + +func (x *WriteFileRequest) GetContent() []byte { + if x != nil { + return x.Content + } + return nil +} + +type WriteFileResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *WriteFileResponse) Reset() { + *x = WriteFileResponse{} + mi := &file_managei_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *WriteFileResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WriteFileResponse) ProtoMessage() {} + +func (x *WriteFileResponse) ProtoReflect() protoreflect.Message { + mi := &file_managei_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WriteFileResponse.ProtoReflect.Descriptor instead. +func (*WriteFileResponse) Descriptor() ([]byte, []int) { + return file_managei_proto_rawDescGZIP(), []int{7} +} + +type ReadFileRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Filepath string `protobuf:"bytes,1,opt,name=filepath,proto3" json:"filepath,omitempty"` + Filename string `protobuf:"bytes,2,opt,name=filename,proto3" json:"filename,omitempty"` +} + +func (x *ReadFileRequest) Reset() { + *x = ReadFileRequest{} + mi := &file_managei_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ReadFileRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReadFileRequest) ProtoMessage() {} + +func (x *ReadFileRequest) ProtoReflect() protoreflect.Message { + mi := &file_managei_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReadFileRequest.ProtoReflect.Descriptor instead. +func (*ReadFileRequest) Descriptor() ([]byte, []int) { + return file_managei_proto_rawDescGZIP(), []int{8} +} + +func (x *ReadFileRequest) GetFilepath() string { + if x != nil { + return x.Filepath + } + return "" +} + +func (x *ReadFileRequest) GetFilename() string { + if x != nil { + return x.Filename + } + return "" +} + +type ReadFileResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Content []byte `protobuf:"bytes,3,opt,name=content,proto3" json:"content,omitempty"` +} + +func (x *ReadFileResponse) Reset() { + *x = ReadFileResponse{} + mi := &file_managei_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ReadFileResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReadFileResponse) ProtoMessage() {} + +func (x *ReadFileResponse) ProtoReflect() protoreflect.Message { + mi := &file_managei_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReadFileResponse.ProtoReflect.Descriptor instead. +func (*ReadFileResponse) Descriptor() ([]byte, []int) { + return file_managei_proto_rawDescGZIP(), []int{9} +} + +func (x *ReadFileResponse) GetContent() []byte { + if x != nil { + return x.Content + } + return nil +} + +type Log struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` +} + +func (x *Log) Reset() { + *x = Log{} + mi := &file_managei_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Log) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Log) ProtoMessage() {} + +func (x *Log) ProtoReflect() protoreflect.Message { + mi := &file_managei_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Log.ProtoReflect.Descriptor instead. +func (*Log) Descriptor() ([]byte, []int) { + return file_managei_proto_rawDescGZIP(), []int{10} +} + +func (x *Log) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +var File_managei_proto protoreflect.FileDescriptor + +var file_managei_proto_rawDesc = []byte{ + 0x0a, 0x0d, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, + 0x09, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x61, 0x70, 0x69, 0x22, 0xb6, 0x01, 0x0a, 0x18, 0x45, + 0x78, 0x65, 0x63, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x39, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, + 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, + 0x65, 0x61, 0x70, 0x69, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, + 0x6e, 0x64, 0x12, 0x16, 0x0a, 0x05, 0x73, 0x74, 0x64, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0c, 0x48, 0x00, 0x52, 0x05, 0x73, 0x74, 0x64, 0x69, 0x6e, 0x12, 0x3c, 0x0a, 0x08, 0x74, 0x65, + 0x72, 0x6d, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6d, + 0x61, 0x6e, 0x61, 0x67, 0x65, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, + 0x6c, 0x53, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x08, + 0x74, 0x65, 0x72, 0x6d, 0x73, 0x69, 0x7a, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x22, 0x6e, 0x0a, 0x19, 0x45, 0x78, 0x65, 0x63, 0x43, 0x6f, 0x6d, 0x6d, 0x61, + 0x6e, 0x64, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x18, 0x0a, 0x06, 0x73, 0x74, 0x64, 0x6f, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, + 0x48, 0x00, 0x52, 0x06, 0x73, 0x74, 0x64, 0x6f, 0x75, 0x74, 0x12, 0x18, 0x0a, 0x06, 0x73, 0x74, + 0x64, 0x65, 0x72, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x06, 0x73, 0x74, + 0x64, 0x65, 0x72, 0x72, 0x12, 0x12, 0x0a, 0x03, 0x65, 0x72, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x48, 0x00, 0x52, 0x03, 0x65, 0x72, 0x72, 0x42, 0x09, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x22, 0x6a, 0x0a, 0x1f, 0x45, 0x78, 0x65, 0x63, 0x43, 0x6f, 0x6d, 0x6d, 0x61, + 0x6e, 0x64, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, + 0x12, 0x22, 0x0a, 0x03, 0x6c, 0x6f, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, + 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x6f, 0x67, 0x48, 0x00, 0x52, + 0x03, 0x6c, 0x6f, 0x67, 0x42, 0x09, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, + 0x43, 0x0a, 0x13, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x53, 0x69, 0x7a, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x12, 0x16, 0x0a, 0x06, + 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x68, 0x65, + 0x69, 0x67, 0x68, 0x74, 0x22, 0x54, 0x0a, 0x12, 0x45, 0x78, 0x65, 0x63, 0x43, 0x6f, 0x6d, 0x6d, + 0x61, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, + 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, + 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x72, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x04, 0x61, 0x72, 0x67, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x74, 0x79, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x74, 0x74, 0x79, 0x22, 0x2d, 0x0a, 0x13, 0x45, 0x78, + 0x65, 0x63, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x22, 0x64, 0x0a, 0x10, 0x57, 0x72, 0x69, + 0x74, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, + 0x08, 0x66, 0x69, 0x6c, 0x65, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x66, 0x69, 0x6c, 0x65, 0x70, 0x61, 0x74, 0x68, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, + 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, + 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, + 0x13, 0x0a, 0x11, 0x57, 0x72, 0x69, 0x74, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x49, 0x0a, 0x0f, 0x52, 0x65, 0x61, 0x64, 0x46, 0x69, 0x6c, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x70, + 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x70, + 0x61, 0x74, 0x68, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x22, + 0x2c, 0x0a, 0x10, 0x52, 0x65, 0x61, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x1f, 0x0a, + 0x03, 0x4c, 0x6f, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0xac, + 0x03, 0x0a, 0x03, 0x41, 0x50, 0x49, 0x12, 0x62, 0x0a, 0x11, 0x45, 0x78, 0x65, 0x63, 0x43, 0x6f, + 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x23, 0x2e, 0x6d, 0x61, + 0x6e, 0x61, 0x67, 0x65, 0x61, 0x70, 0x69, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x43, 0x6f, 0x6d, 0x6d, + 0x61, 0x6e, 0x64, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x24, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x61, 0x70, 0x69, 0x2e, 0x45, 0x78, 0x65, + 0x63, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, 0x12, 0x66, 0x0a, 0x17, 0x45, 0x78, + 0x65, 0x63, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x53, + 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x1d, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x61, 0x70, + 0x69, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x61, 0x70, 0x69, + 0x2e, 0x45, 0x78, 0x65, 0x63, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x74, 0x75, + 0x72, 0x6e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x30, 0x01, 0x12, 0x4c, 0x0a, 0x0b, 0x45, 0x78, 0x65, 0x63, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, + 0x64, 0x12, 0x1d, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x61, 0x70, 0x69, 0x2e, 0x45, 0x78, + 0x65, 0x63, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1e, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x61, 0x70, 0x69, 0x2e, 0x45, 0x78, 0x65, + 0x63, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x46, 0x0a, 0x09, 0x57, 0x72, 0x69, 0x74, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x1b, 0x2e, + 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x61, 0x70, 0x69, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x46, + 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6d, 0x61, 0x6e, + 0x61, 0x67, 0x65, 0x61, 0x70, 0x69, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x46, 0x69, 0x6c, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x43, 0x0a, 0x08, 0x52, 0x65, 0x61, 0x64, + 0x46, 0x69, 0x6c, 0x65, 0x12, 0x1a, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x61, 0x70, 0x69, + 0x2e, 0x52, 0x65, 0x61, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1b, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x61, + 0x64, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x3f, 0x5a, + 0x3d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x65, 0x6e, 0x73, + 0x63, 0x68, 0x6c, 0x75, 0x65, 0x74, 0x65, 0x72, 0x2f, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, + 0x69, 0x6f, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x61, + 0x70, 0x69, 0x2f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_managei_proto_rawDescOnce sync.Once + file_managei_proto_rawDescData = file_managei_proto_rawDesc +) + +func file_managei_proto_rawDescGZIP() []byte { + file_managei_proto_rawDescOnce.Do(func() { + file_managei_proto_rawDescData = protoimpl.X.CompressGZIP(file_managei_proto_rawDescData) + }) + return file_managei_proto_rawDescData +} + +var file_managei_proto_msgTypes = make([]protoimpl.MessageInfo, 11) +var file_managei_proto_goTypes = []any{ + (*ExecCommandStreamRequest)(nil), // 0: manageapi.ExecCommandStreamRequest + (*ExecCommandStreamResponse)(nil), // 1: manageapi.ExecCommandStreamResponse + (*ExecCommandReturnStreamResponse)(nil), // 2: manageapi.ExecCommandReturnStreamResponse + (*TerminalSizeRequest)(nil), // 3: manageapi.TerminalSizeRequest + (*ExecCommandRequest)(nil), // 4: manageapi.ExecCommandRequest + (*ExecCommandResponse)(nil), // 5: manageapi.ExecCommandResponse + (*WriteFileRequest)(nil), // 6: manageapi.WriteFileRequest + (*WriteFileResponse)(nil), // 7: manageapi.WriteFileResponse + (*ReadFileRequest)(nil), // 8: manageapi.ReadFileRequest + (*ReadFileResponse)(nil), // 9: manageapi.ReadFileResponse + (*Log)(nil), // 10: manageapi.Log +} +var file_managei_proto_depIdxs = []int32{ + 4, // 0: manageapi.ExecCommandStreamRequest.command:type_name -> manageapi.ExecCommandRequest + 3, // 1: manageapi.ExecCommandStreamRequest.termsize:type_name -> manageapi.TerminalSizeRequest + 10, // 2: manageapi.ExecCommandReturnStreamResponse.log:type_name -> manageapi.Log + 0, // 3: manageapi.API.ExecCommandStream:input_type -> manageapi.ExecCommandStreamRequest + 4, // 4: manageapi.API.ExecCommandReturnStream:input_type -> manageapi.ExecCommandRequest + 4, // 5: manageapi.API.ExecCommand:input_type -> manageapi.ExecCommandRequest + 6, // 6: manageapi.API.WriteFile:input_type -> manageapi.WriteFileRequest + 8, // 7: manageapi.API.ReadFile:input_type -> manageapi.ReadFileRequest + 1, // 8: manageapi.API.ExecCommandStream:output_type -> manageapi.ExecCommandStreamResponse + 2, // 9: manageapi.API.ExecCommandReturnStream:output_type -> manageapi.ExecCommandReturnStreamResponse + 5, // 10: manageapi.API.ExecCommand:output_type -> manageapi.ExecCommandResponse + 7, // 11: manageapi.API.WriteFile:output_type -> manageapi.WriteFileResponse + 9, // 12: manageapi.API.ReadFile:output_type -> manageapi.ReadFileResponse + 8, // [8:13] is the sub-list for method output_type + 3, // [3:8] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name +} + +func init() { file_managei_proto_init() } +func file_managei_proto_init() { + if File_managei_proto != nil { + return + } + file_managei_proto_msgTypes[0].OneofWrappers = []any{ + (*ExecCommandStreamRequest_Command)(nil), + (*ExecCommandStreamRequest_Stdin)(nil), + (*ExecCommandStreamRequest_Termsize)(nil), + } + file_managei_proto_msgTypes[1].OneofWrappers = []any{ + (*ExecCommandStreamResponse_Stdout)(nil), + (*ExecCommandStreamResponse_Stderr)(nil), + (*ExecCommandStreamResponse_Err)(nil), + } + file_managei_proto_msgTypes[2].OneofWrappers = []any{ + (*ExecCommandReturnStreamResponse_Output)(nil), + (*ExecCommandReturnStreamResponse_Log)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_managei_proto_rawDesc, + NumEnums: 0, + NumMessages: 11, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_managei_proto_goTypes, + DependencyIndexes: file_managei_proto_depIdxs, + MessageInfos: file_managei_proto_msgTypes, + }.Build() + File_managei_proto = out.File + file_managei_proto_rawDesc = nil + file_managei_proto_goTypes = nil + file_managei_proto_depIdxs = nil +} diff --git a/agent/vmapi/vmproto/vmapi.proto b/agent/manageapi/manageproto/managei.proto similarity index 64% rename from agent/vmapi/vmproto/vmapi.proto rename to agent/manageapi/manageproto/managei.proto index e20ee78..14bd8a1 100644 --- a/agent/vmapi/vmproto/vmapi.proto +++ b/agent/manageapi/manageproto/managei.proto @@ -1,8 +1,8 @@ syntax = "proto3"; -package vmapi; +package manageapi; -option go_package = "github.com/benschlueter/delegatio/core/vmapi/vmproto"; +option go_package = "github.com/benschlueter/delegatio/agent/manageapi/manageproto"; service API { @@ -11,8 +11,6 @@ service API { rpc ExecCommand(ExecCommandRequest) returns (ExecCommandResponse); rpc WriteFile(WriteFileRequest) returns (WriteFileResponse); rpc ReadFile(ReadFileRequest) returns (ReadFileResponse); - rpc GetJoinDataKube(GetJoinDataKubeRequest) returns (GetJoinDataKubeResponse); - rpc InitFirstMaster(InitFirstMasterRequest) returns (stream InitFirstMasterResponse); } message ExecCommandStreamRequest { @@ -75,36 +73,3 @@ message ReadFileResponse { message Log { string message = 1; } - -message GetJoinDataKubeRequest { -} - -message JoinToken { - string token = 1; - string caCertHash = 2; - string apiServerEndpoint = 3; -} - -message File { - string name = 1; - bytes content = 2; -} - -message GetJoinDataKubeResponse { - JoinToken joinToken = 1; - repeated File files = 2; -} - -message InitFirstMasterRequest { - string command = 1; - repeated string args = 2; - bool tty = 3; -} - - -message InitFirstMasterResponse { - oneof content { - bytes output = 1; - Log log = 2; - } -} \ No newline at end of file diff --git a/agent/vmapi/vmproto/vmapi_grpc.pb.go b/agent/manageapi/manageproto/managei_grpc.pb.go similarity index 50% rename from agent/vmapi/vmproto/vmapi_grpc.pb.go rename to agent/manageapi/manageproto/managei_grpc.pb.go index 2a06e2d..94d60b4 100644 --- a/agent/vmapi/vmproto/vmapi_grpc.pb.go +++ b/agent/manageapi/manageproto/managei_grpc.pb.go @@ -1,10 +1,10 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.2.0 -// - protoc v4.22.0 -// source: vmapi.proto +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.28.3 +// source: managei.proto -package vmproto +package manageproto import ( context "context" @@ -15,20 +15,26 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + API_ExecCommandStream_FullMethodName = "/manageapi.API/ExecCommandStream" + API_ExecCommandReturnStream_FullMethodName = "/manageapi.API/ExecCommandReturnStream" + API_ExecCommand_FullMethodName = "/manageapi.API/ExecCommand" + API_WriteFile_FullMethodName = "/manageapi.API/WriteFile" + API_ReadFile_FullMethodName = "/manageapi.API/ReadFile" +) // APIClient is the client API for API service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type APIClient interface { - ExecCommandStream(ctx context.Context, opts ...grpc.CallOption) (API_ExecCommandStreamClient, error) - ExecCommandReturnStream(ctx context.Context, in *ExecCommandRequest, opts ...grpc.CallOption) (API_ExecCommandReturnStreamClient, error) + ExecCommandStream(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[ExecCommandStreamRequest, ExecCommandStreamResponse], error) + ExecCommandReturnStream(ctx context.Context, in *ExecCommandRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[ExecCommandReturnStreamResponse], error) ExecCommand(ctx context.Context, in *ExecCommandRequest, opts ...grpc.CallOption) (*ExecCommandResponse, error) WriteFile(ctx context.Context, in *WriteFileRequest, opts ...grpc.CallOption) (*WriteFileResponse, error) ReadFile(ctx context.Context, in *ReadFileRequest, opts ...grpc.CallOption) (*ReadFileResponse, error) - GetJoinDataKube(ctx context.Context, in *GetJoinDataKubeRequest, opts ...grpc.CallOption) (*GetJoinDataKubeResponse, error) - InitFirstMaster(ctx context.Context, in *InitFirstMasterRequest, opts ...grpc.CallOption) (API_InitFirstMasterClient, error) } type aPIClient struct { @@ -39,43 +45,26 @@ func NewAPIClient(cc grpc.ClientConnInterface) APIClient { return &aPIClient{cc} } -func (c *aPIClient) ExecCommandStream(ctx context.Context, opts ...grpc.CallOption) (API_ExecCommandStreamClient, error) { - stream, err := c.cc.NewStream(ctx, &API_ServiceDesc.Streams[0], "/vmapi.API/ExecCommandStream", opts...) +func (c *aPIClient) ExecCommandStream(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[ExecCommandStreamRequest, ExecCommandStreamResponse], error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + stream, err := c.cc.NewStream(ctx, &API_ServiceDesc.Streams[0], API_ExecCommandStream_FullMethodName, cOpts...) if err != nil { return nil, err } - x := &aPIExecCommandStreamClient{stream} + x := &grpc.GenericClientStream[ExecCommandStreamRequest, ExecCommandStreamResponse]{ClientStream: stream} return x, nil } -type API_ExecCommandStreamClient interface { - Send(*ExecCommandStreamRequest) error - Recv() (*ExecCommandStreamResponse, error) - grpc.ClientStream -} - -type aPIExecCommandStreamClient struct { - grpc.ClientStream -} - -func (x *aPIExecCommandStreamClient) Send(m *ExecCommandStreamRequest) error { - return x.ClientStream.SendMsg(m) -} - -func (x *aPIExecCommandStreamClient) Recv() (*ExecCommandStreamResponse, error) { - m := new(ExecCommandStreamResponse) - if err := x.ClientStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type API_ExecCommandStreamClient = grpc.BidiStreamingClient[ExecCommandStreamRequest, ExecCommandStreamResponse] -func (c *aPIClient) ExecCommandReturnStream(ctx context.Context, in *ExecCommandRequest, opts ...grpc.CallOption) (API_ExecCommandReturnStreamClient, error) { - stream, err := c.cc.NewStream(ctx, &API_ServiceDesc.Streams[1], "/vmapi.API/ExecCommandReturnStream", opts...) +func (c *aPIClient) ExecCommandReturnStream(ctx context.Context, in *ExecCommandRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[ExecCommandReturnStreamResponse], error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + stream, err := c.cc.NewStream(ctx, &API_ServiceDesc.Streams[1], API_ExecCommandReturnStream_FullMethodName, cOpts...) if err != nil { return nil, err } - x := &aPIExecCommandReturnStreamClient{stream} + x := &grpc.GenericClientStream[ExecCommandRequest, ExecCommandReturnStreamResponse]{ClientStream: stream} if err := x.ClientStream.SendMsg(in); err != nil { return nil, err } @@ -85,26 +74,13 @@ func (c *aPIClient) ExecCommandReturnStream(ctx context.Context, in *ExecCommand return x, nil } -type API_ExecCommandReturnStreamClient interface { - Recv() (*ExecCommandReturnStreamResponse, error) - grpc.ClientStream -} - -type aPIExecCommandReturnStreamClient struct { - grpc.ClientStream -} - -func (x *aPIExecCommandReturnStreamClient) Recv() (*ExecCommandReturnStreamResponse, error) { - m := new(ExecCommandReturnStreamResponse) - if err := x.ClientStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type API_ExecCommandReturnStreamClient = grpc.ServerStreamingClient[ExecCommandReturnStreamResponse] func (c *aPIClient) ExecCommand(ctx context.Context, in *ExecCommandRequest, opts ...grpc.CallOption) (*ExecCommandResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ExecCommandResponse) - err := c.cc.Invoke(ctx, "/vmapi.API/ExecCommand", in, out, opts...) + err := c.cc.Invoke(ctx, API_ExecCommand_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -112,8 +88,9 @@ func (c *aPIClient) ExecCommand(ctx context.Context, in *ExecCommandRequest, opt } func (c *aPIClient) WriteFile(ctx context.Context, in *WriteFileRequest, opts ...grpc.CallOption) (*WriteFileResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(WriteFileResponse) - err := c.cc.Invoke(ctx, "/vmapi.API/WriteFile", in, out, opts...) + err := c.cc.Invoke(ctx, API_WriteFile_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -121,77 +98,38 @@ func (c *aPIClient) WriteFile(ctx context.Context, in *WriteFileRequest, opts .. } func (c *aPIClient) ReadFile(ctx context.Context, in *ReadFileRequest, opts ...grpc.CallOption) (*ReadFileResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ReadFileResponse) - err := c.cc.Invoke(ctx, "/vmapi.API/ReadFile", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *aPIClient) GetJoinDataKube(ctx context.Context, in *GetJoinDataKubeRequest, opts ...grpc.CallOption) (*GetJoinDataKubeResponse, error) { - out := new(GetJoinDataKubeResponse) - err := c.cc.Invoke(ctx, "/vmapi.API/GetJoinDataKube", in, out, opts...) + err := c.cc.Invoke(ctx, API_ReadFile_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } -func (c *aPIClient) InitFirstMaster(ctx context.Context, in *InitFirstMasterRequest, opts ...grpc.CallOption) (API_InitFirstMasterClient, error) { - stream, err := c.cc.NewStream(ctx, &API_ServiceDesc.Streams[2], "/vmapi.API/InitFirstMaster", opts...) - if err != nil { - return nil, err - } - x := &aPIInitFirstMasterClient{stream} - if err := x.ClientStream.SendMsg(in); err != nil { - return nil, err - } - if err := x.ClientStream.CloseSend(); err != nil { - return nil, err - } - return x, nil -} - -type API_InitFirstMasterClient interface { - Recv() (*InitFirstMasterResponse, error) - grpc.ClientStream -} - -type aPIInitFirstMasterClient struct { - grpc.ClientStream -} - -func (x *aPIInitFirstMasterClient) Recv() (*InitFirstMasterResponse, error) { - m := new(InitFirstMasterResponse) - if err := x.ClientStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - // APIServer is the server API for API service. // All implementations must embed UnimplementedAPIServer -// for forward compatibility +// for forward compatibility. type APIServer interface { - ExecCommandStream(API_ExecCommandStreamServer) error - ExecCommandReturnStream(*ExecCommandRequest, API_ExecCommandReturnStreamServer) error + ExecCommandStream(grpc.BidiStreamingServer[ExecCommandStreamRequest, ExecCommandStreamResponse]) error + ExecCommandReturnStream(*ExecCommandRequest, grpc.ServerStreamingServer[ExecCommandReturnStreamResponse]) error ExecCommand(context.Context, *ExecCommandRequest) (*ExecCommandResponse, error) WriteFile(context.Context, *WriteFileRequest) (*WriteFileResponse, error) ReadFile(context.Context, *ReadFileRequest) (*ReadFileResponse, error) - GetJoinDataKube(context.Context, *GetJoinDataKubeRequest) (*GetJoinDataKubeResponse, error) - InitFirstMaster(*InitFirstMasterRequest, API_InitFirstMasterServer) error mustEmbedUnimplementedAPIServer() } -// UnimplementedAPIServer must be embedded to have forward compatible implementations. -type UnimplementedAPIServer struct { -} +// UnimplementedAPIServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedAPIServer struct{} -func (UnimplementedAPIServer) ExecCommandStream(API_ExecCommandStreamServer) error { +func (UnimplementedAPIServer) ExecCommandStream(grpc.BidiStreamingServer[ExecCommandStreamRequest, ExecCommandStreamResponse]) error { return status.Errorf(codes.Unimplemented, "method ExecCommandStream not implemented") } -func (UnimplementedAPIServer) ExecCommandReturnStream(*ExecCommandRequest, API_ExecCommandReturnStreamServer) error { +func (UnimplementedAPIServer) ExecCommandReturnStream(*ExecCommandRequest, grpc.ServerStreamingServer[ExecCommandReturnStreamResponse]) error { return status.Errorf(codes.Unimplemented, "method ExecCommandReturnStream not implemented") } func (UnimplementedAPIServer) ExecCommand(context.Context, *ExecCommandRequest) (*ExecCommandResponse, error) { @@ -203,13 +141,8 @@ func (UnimplementedAPIServer) WriteFile(context.Context, *WriteFileRequest) (*Wr func (UnimplementedAPIServer) ReadFile(context.Context, *ReadFileRequest) (*ReadFileResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ReadFile not implemented") } -func (UnimplementedAPIServer) GetJoinDataKube(context.Context, *GetJoinDataKubeRequest) (*GetJoinDataKubeResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetJoinDataKube not implemented") -} -func (UnimplementedAPIServer) InitFirstMaster(*InitFirstMasterRequest, API_InitFirstMasterServer) error { - return status.Errorf(codes.Unimplemented, "method InitFirstMaster not implemented") -} func (UnimplementedAPIServer) mustEmbedUnimplementedAPIServer() {} +func (UnimplementedAPIServer) testEmbeddedByValue() {} // UnsafeAPIServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to APIServer will @@ -219,55 +152,33 @@ type UnsafeAPIServer interface { } func RegisterAPIServer(s grpc.ServiceRegistrar, srv APIServer) { + // If the following call pancis, it indicates UnimplementedAPIServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&API_ServiceDesc, srv) } func _API_ExecCommandStream_Handler(srv interface{}, stream grpc.ServerStream) error { - return srv.(APIServer).ExecCommandStream(&aPIExecCommandStreamServer{stream}) -} - -type API_ExecCommandStreamServer interface { - Send(*ExecCommandStreamResponse) error - Recv() (*ExecCommandStreamRequest, error) - grpc.ServerStream -} - -type aPIExecCommandStreamServer struct { - grpc.ServerStream + return srv.(APIServer).ExecCommandStream(&grpc.GenericServerStream[ExecCommandStreamRequest, ExecCommandStreamResponse]{ServerStream: stream}) } -func (x *aPIExecCommandStreamServer) Send(m *ExecCommandStreamResponse) error { - return x.ServerStream.SendMsg(m) -} - -func (x *aPIExecCommandStreamServer) Recv() (*ExecCommandStreamRequest, error) { - m := new(ExecCommandStreamRequest) - if err := x.ServerStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type API_ExecCommandStreamServer = grpc.BidiStreamingServer[ExecCommandStreamRequest, ExecCommandStreamResponse] func _API_ExecCommandReturnStream_Handler(srv interface{}, stream grpc.ServerStream) error { m := new(ExecCommandRequest) if err := stream.RecvMsg(m); err != nil { return err } - return srv.(APIServer).ExecCommandReturnStream(m, &aPIExecCommandReturnStreamServer{stream}) + return srv.(APIServer).ExecCommandReturnStream(m, &grpc.GenericServerStream[ExecCommandRequest, ExecCommandReturnStreamResponse]{ServerStream: stream}) } -type API_ExecCommandReturnStreamServer interface { - Send(*ExecCommandReturnStreamResponse) error - grpc.ServerStream -} - -type aPIExecCommandReturnStreamServer struct { - grpc.ServerStream -} - -func (x *aPIExecCommandReturnStreamServer) Send(m *ExecCommandReturnStreamResponse) error { - return x.ServerStream.SendMsg(m) -} +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type API_ExecCommandReturnStreamServer = grpc.ServerStreamingServer[ExecCommandReturnStreamResponse] func _API_ExecCommand_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(ExecCommandRequest) @@ -279,7 +190,7 @@ func _API_ExecCommand_Handler(srv interface{}, ctx context.Context, dec func(int } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/vmapi.API/ExecCommand", + FullMethod: API_ExecCommand_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(APIServer).ExecCommand(ctx, req.(*ExecCommandRequest)) @@ -297,7 +208,7 @@ func _API_WriteFile_Handler(srv interface{}, ctx context.Context, dec func(inter } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/vmapi.API/WriteFile", + FullMethod: API_WriteFile_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(APIServer).WriteFile(ctx, req.(*WriteFileRequest)) @@ -315,7 +226,7 @@ func _API_ReadFile_Handler(srv interface{}, ctx context.Context, dec func(interf } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/vmapi.API/ReadFile", + FullMethod: API_ReadFile_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(APIServer).ReadFile(ctx, req.(*ReadFileRequest)) @@ -323,50 +234,11 @@ func _API_ReadFile_Handler(srv interface{}, ctx context.Context, dec func(interf return interceptor(ctx, in, info, handler) } -func _API_GetJoinDataKube_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(GetJoinDataKubeRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(APIServer).GetJoinDataKube(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/vmapi.API/GetJoinDataKube", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(APIServer).GetJoinDataKube(ctx, req.(*GetJoinDataKubeRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _API_InitFirstMaster_Handler(srv interface{}, stream grpc.ServerStream) error { - m := new(InitFirstMasterRequest) - if err := stream.RecvMsg(m); err != nil { - return err - } - return srv.(APIServer).InitFirstMaster(m, &aPIInitFirstMasterServer{stream}) -} - -type API_InitFirstMasterServer interface { - Send(*InitFirstMasterResponse) error - grpc.ServerStream -} - -type aPIInitFirstMasterServer struct { - grpc.ServerStream -} - -func (x *aPIInitFirstMasterServer) Send(m *InitFirstMasterResponse) error { - return x.ServerStream.SendMsg(m) -} - // API_ServiceDesc is the grpc.ServiceDesc for API service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) var API_ServiceDesc = grpc.ServiceDesc{ - ServiceName: "vmapi.API", + ServiceName: "manageapi.API", HandlerType: (*APIServer)(nil), Methods: []grpc.MethodDesc{ { @@ -381,10 +253,6 @@ var API_ServiceDesc = grpc.ServiceDesc{ MethodName: "ReadFile", Handler: _API_ReadFile_Handler, }, - { - MethodName: "GetJoinDataKube", - Handler: _API_GetJoinDataKube_Handler, - }, }, Streams: []grpc.StreamDesc{ { @@ -398,11 +266,6 @@ var API_ServiceDesc = grpc.ServiceDesc{ Handler: _API_ExecCommandReturnStream_Handler, ServerStreams: true, }, - { - StreamName: "InitFirstMaster", - Handler: _API_InitFirstMaster_Handler, - ServerStreams: true, - }, }, - Metadata: "vmapi.proto", + Metadata: "managei.proto", } diff --git a/agent/vmapi/size.go b/agent/manageapi/size.go similarity index 98% rename from agent/vmapi/size.go rename to agent/manageapi/size.go index 16ebe4e..7ebddd0 100644 --- a/agent/vmapi/size.go +++ b/agent/manageapi/size.go @@ -2,7 +2,7 @@ * Copyright (c) Benedict Schlueter */ -package vmapi +package manageapi import ( "errors" diff --git a/agent/core/core.go b/agent/vm/core/core.go similarity index 98% rename from agent/core/core.go rename to agent/vm/core/core.go index 10dd6c0..f2047bb 100644 --- a/agent/core/core.go +++ b/agent/vm/core/core.go @@ -17,8 +17,8 @@ import ( "sync" "time" - "github.com/benschlueter/delegatio/agent/core/state" - "github.com/benschlueter/delegatio/agent/vmapi/vmproto" + "github.com/benschlueter/delegatio/agent/vm/core/state" + "github.com/benschlueter/delegatio/agent/vm/vmapi/vmproto" "github.com/benschlueter/delegatio/internal/config" "go.uber.org/zap" "google.golang.org/grpc" diff --git a/agent/core/state/state.go b/agent/vm/core/state/state.go similarity index 100% rename from agent/core/state/state.go rename to agent/vm/core/state/state.go diff --git a/agent/core/state/state_string.go b/agent/vm/core/state/state_string.go similarity index 100% rename from agent/core/state/state_string.go rename to agent/vm/core/state/state_string.go diff --git a/agent/vm/main.go b/agent/vm/main.go new file mode 100644 index 0000000..fdc6628 --- /dev/null +++ b/agent/vm/main.go @@ -0,0 +1,80 @@ +/* SPDX-License-Identifier: AGPL-3.0-only + * Copyright (c) Benedict Schlueter + */ + +package main + +import ( + "flag" + "log" + "net" + + "cloud.google.com/go/compute/metadata" + "github.com/benschlueter/delegatio/internal/config" + "github.com/benschlueter/delegatio/internal/config/definitions" + grpc_zap "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap" + "go.uber.org/zap" +) + +/* + * main is run in every docker container to allow agents to communicate with it. + * It sets up the gRPC server and listens for incoming connections. + * The SSH agents uses the stream exec to forward its incomming requests + * + * The same binary is also used in the VM to allow bootstrapping to take place via + * CLI rpc calls. + */ +func main() { + var bindIP, bindPort string + cfg := zap.NewDevelopmentConfig() + + logLevelUser := flag.Bool("debug", false, "enables gRPC debug output") + containerMode := flag.Bool("container", false, "signals that the agent is running in a container") + flag.Parse() + cfg.Level.SetLevel(zap.DebugLevel) + + zapLogger, err := cfg.Build() + if err != nil { + log.Fatal(err) + } + if *logLevelUser { + grpc_zap.ReplaceGrpcLoggerV2(zapLogger.Named("gRPC")) + } else { + grpc_zap.ReplaceGrpcLoggerV2(zapLogger.WithOptions(zap.IncreaseLevel(zap.WarnLevel)).Named("gRPC")) + } + zapLoggerCore := zapLogger.Named("core") + + bindIP = config.DefaultIP + bindPort = config.PublicAPIport + dialer := &net.Dialer{} + + var ipAddr string + if metadata.OnGCE() { + ipAddr, err = metadata.InstanceAttributeValue("loadbalancer") + if err != nil { + zapLoggerCore.Fatal("failed to get loadbalancer ip from metadata | not running in cloud", zap.Error(err)) + } + + localIP, err := metadata.InternalIP() + if err != nil { + zapLoggerCore.Fatal("failed to get local ip from metadata", zap.Error(err)) + } + zapLoggerCore.Info("local ip", zap.String("ip", localIP)) + + attr, err := metadata.ProjectAttributes() + if err != nil { + zapLoggerCore.Fatal("failed to get project attributes from metadata", zap.Error(err)) + } + zapLoggerCore.Info("project attributes", zap.Any("attributes", attr)) + + iattr, err := metadata.InstanceAttributes() + if err != nil { + zapLoggerCore.Fatal("failed to get instance attributes from metadata", zap.Error(err)) + } + zapLoggerCore.Info("instance attributes", zap.Any("attributes", iattr)) + } else { + ipAddr = definitions.NetworkXMLConfig.IPs[0].Address + } + + run(dialer, bindIP, bindPort, zapLoggerCore, containerMode, ipAddr) +} diff --git a/agent/server/run.go b/agent/vm/run.go similarity index 84% rename from agent/server/run.go rename to agent/vm/run.go index 365ff8d..681c494 100644 --- a/agent/server/run.go +++ b/agent/vm/run.go @@ -11,10 +11,12 @@ import ( "net" "sync" - "github.com/benschlueter/delegatio/agent/core" - "github.com/benschlueter/delegatio/agent/core/state" - "github.com/benschlueter/delegatio/agent/vmapi" - "github.com/benschlueter/delegatio/agent/vmapi/vmproto" + "github.com/benschlueter/delegatio/agent/manageapi" + "github.com/benschlueter/delegatio/agent/manageapi/manageproto" + "github.com/benschlueter/delegatio/agent/vm/core" + "github.com/benschlueter/delegatio/agent/vm/core/state" + "github.com/benschlueter/delegatio/agent/vm/vmapi" + "github.com/benschlueter/delegatio/agent/vm/vmapi/vmproto" "github.com/benschlueter/delegatio/internal/config" grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware" grpc_zap "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap" @@ -47,6 +49,7 @@ func run(dialer vmapi.Dialer, bindIP, bindPort string, zapLoggerCore *zap.Logger } vapi := vmapi.New(zapLoggerCore.Named("vmapi"), core, dialer) + mapi := manageapi.New(zapLoggerCore.Named("manageapi"), core, dialer) zapLoggergRPC := zapLoggerCore.Named("gRPC") grpcServer := grpc.NewServer( @@ -61,6 +64,7 @@ func run(dialer vmapi.Dialer, bindIP, bindPort string, zapLoggerCore *zap.Logger )), ) vmproto.RegisterAPIServer(grpcServer, vapi) + manageproto.RegisterAPIServer(grpcServer, mapi) lis, err := net.Listen("tcp", net.JoinHostPort(bindIP, bindPort)) if err != nil { diff --git a/agent/vmapi/core.go b/agent/vm/vmapi/core.go similarity index 100% rename from agent/vmapi/core.go rename to agent/vm/vmapi/core.go diff --git a/agent/vmapi/kube.go b/agent/vm/vmapi/kube.go similarity index 89% rename from agent/vmapi/kube.go rename to agent/vm/vmapi/kube.go index 1498b4a..8ebfdb0 100644 --- a/agent/vmapi/kube.go +++ b/agent/vm/vmapi/kube.go @@ -11,7 +11,7 @@ import ( "os/exec" "time" - "github.com/benschlueter/delegatio/agent/vmapi/vmproto" + "github.com/benschlueter/delegatio/agent/vm/vmapi/vmproto" "go.uber.org/zap" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -83,3 +83,18 @@ func (a *API) InitFirstMaster(in *vmproto.InitFirstMasterRequest, srv vmproto.AP a.core.SetInitialized() return srv.Send(&vmproto.InitFirstMasterResponse{Content: &vmproto.InitFirstMasterResponse_Output{Output: stdoutBuf.Bytes()}}) } + +type streamWriterWrapper struct { + forwardFunc func([]byte) error +} + +func (sw *streamWriterWrapper) Write(p []byte) (int, error) { + if err := sw.forwardFunc(p); err != nil { + return 0, err + } + return len(p), nil +} + +func (sw *streamWriterWrapper) Close() error { + return nil +} diff --git a/agent/vm/vmapi/vmapi.go b/agent/vm/vmapi/vmapi.go new file mode 100644 index 0000000..58f4c95 --- /dev/null +++ b/agent/vm/vmapi/vmapi.go @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: AGPL-3.0-only + * Copyright (c) Benedict Schlueter + */ + +package vmapi + +import ( + "context" + "net" + + "github.com/benschlueter/delegatio/agent/manageapi/manageproto" + "github.com/benschlueter/delegatio/agent/vm/vmapi/vmproto" + "go.uber.org/zap" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +type vmprotoWrapper struct { + vmproto.UnimplementedAPIServer +} + +type manageprotoWrapper struct { + manageproto.UnimplementedAPIServer +} + +// API is the API. +type API struct { + logger *zap.Logger + core Core + dialer Dialer + vmprotoWrapper + manageprotoWrapper +} + +// New creates a new API. +func New(logger *zap.Logger, core Core, dialer Dialer) *API { + return &API{ + logger: logger, + core: core, + dialer: dialer, + } +} + +func (a *API) dialInsecure(ctx context.Context, target string) (*grpc.ClientConn, error) { + return grpc.DialContext(ctx, target, + a.grpcWithDialer(), + grpc.WithTransportCredentials(insecure.NewCredentials()), + grpc.WithBlock(), + ) +} + +func (a *API) grpcWithDialer() grpc.DialOption { + return grpc.WithContextDialer(func(ctx context.Context, addr string) (net.Conn, error) { + return a.dialer.DialContext(ctx, "tcp", addr) + }) +} + +// Dialer is the dial interface. Necessary to stub network connections for local testing +// with bufconns. +type Dialer interface { + DialContext(ctx context.Context, network, address string) (net.Conn, error) +} + +// ToDo: Put Kubernetes functions here to make use of the dial functions? diff --git a/agent/vmapi/vmproto/Dockerfile.gen-proto b/agent/vm/vmapi/vmproto/Dockerfile.gen-proto similarity index 93% rename from agent/vmapi/vmproto/Dockerfile.gen-proto rename to agent/vm/vmapi/vmproto/Dockerfile.gen-proto index 2cca2ab..fe9644a 100644 --- a/agent/vmapi/vmproto/Dockerfile.gen-proto +++ b/agent/vm/vmapi/vmproto/Dockerfile.gen-proto @@ -1,9 +1,9 @@ FROM ubuntu@sha256:7cc0576c7c0ec2384de5cbf245f41567e922aab1b075f3e8ad565f508032df17 as build -ARG GO_VER=1.20.1 -ARG GEN_GO_VER=1.28.1 -ARG GEN_GO_GRPC_VER=1.2 -ARG PB_VER=22.0 +ARG GO_VER=1.23.1 +ARG GEN_GO_VER=1.35.1 +ARG GEN_GO_GRPC_VER=1.5.1 +ARG PB_VER=28.3 ENV DEBIAN_FRONTEND="noninteractive" RUN apt-get update && apt-get install -y wget tar unzip diff --git a/agent/vm/vmapi/vmproto/README.md b/agent/vm/vmapi/vmproto/README.md new file mode 100644 index 0000000..5d721de --- /dev/null +++ b/agent/vm/vmapi/vmproto/README.md @@ -0,0 +1,11 @@ +## Proto generation + +To generate Go source files from proto, we use docker. + +The following command will generate Go source code files in docker and save the output to the current directory. +Run this once every time you make any changes or additions to the `.proto` files. +Add the generated `.go` files, and any changes to the `.proto` files, to your branch before creating a PR. + +```bash +DOCKER_BUILDKIT=1 docker build -o .. -f Dockerfile.gen-proto .. +``` \ No newline at end of file diff --git a/agent/vm/vmapi/vmproto/vmapi.pb.go b/agent/vm/vmapi/vmproto/vmapi.pb.go new file mode 100644 index 0000000..24595f3 --- /dev/null +++ b/agent/vm/vmapi/vmproto/vmapi.pb.go @@ -0,0 +1,529 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.35.1 +// protoc v5.28.3 +// source: vmapi.proto + +package vmproto + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type Log struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` +} + +func (x *Log) Reset() { + *x = Log{} + mi := &file_vmapi_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Log) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Log) ProtoMessage() {} + +func (x *Log) ProtoReflect() protoreflect.Message { + mi := &file_vmapi_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Log.ProtoReflect.Descriptor instead. +func (*Log) Descriptor() ([]byte, []int) { + return file_vmapi_proto_rawDescGZIP(), []int{0} +} + +func (x *Log) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +type GetJoinDataKubeRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *GetJoinDataKubeRequest) Reset() { + *x = GetJoinDataKubeRequest{} + mi := &file_vmapi_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetJoinDataKubeRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetJoinDataKubeRequest) ProtoMessage() {} + +func (x *GetJoinDataKubeRequest) ProtoReflect() protoreflect.Message { + mi := &file_vmapi_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetJoinDataKubeRequest.ProtoReflect.Descriptor instead. +func (*GetJoinDataKubeRequest) Descriptor() ([]byte, []int) { + return file_vmapi_proto_rawDescGZIP(), []int{1} +} + +type JoinToken struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"` + CaCertHash string `protobuf:"bytes,2,opt,name=caCertHash,proto3" json:"caCertHash,omitempty"` + ApiServerEndpoint string `protobuf:"bytes,3,opt,name=apiServerEndpoint,proto3" json:"apiServerEndpoint,omitempty"` +} + +func (x *JoinToken) Reset() { + *x = JoinToken{} + mi := &file_vmapi_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *JoinToken) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*JoinToken) ProtoMessage() {} + +func (x *JoinToken) ProtoReflect() protoreflect.Message { + mi := &file_vmapi_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use JoinToken.ProtoReflect.Descriptor instead. +func (*JoinToken) Descriptor() ([]byte, []int) { + return file_vmapi_proto_rawDescGZIP(), []int{2} +} + +func (x *JoinToken) GetToken() string { + if x != nil { + return x.Token + } + return "" +} + +func (x *JoinToken) GetCaCertHash() string { + if x != nil { + return x.CaCertHash + } + return "" +} + +func (x *JoinToken) GetApiServerEndpoint() string { + if x != nil { + return x.ApiServerEndpoint + } + return "" +} + +type File struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Content []byte `protobuf:"bytes,2,opt,name=content,proto3" json:"content,omitempty"` +} + +func (x *File) Reset() { + *x = File{} + mi := &file_vmapi_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *File) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*File) ProtoMessage() {} + +func (x *File) ProtoReflect() protoreflect.Message { + mi := &file_vmapi_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use File.ProtoReflect.Descriptor instead. +func (*File) Descriptor() ([]byte, []int) { + return file_vmapi_proto_rawDescGZIP(), []int{3} +} + +func (x *File) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *File) GetContent() []byte { + if x != nil { + return x.Content + } + return nil +} + +type GetJoinDataKubeResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + JoinToken *JoinToken `protobuf:"bytes,1,opt,name=joinToken,proto3" json:"joinToken,omitempty"` + Files []*File `protobuf:"bytes,2,rep,name=files,proto3" json:"files,omitempty"` +} + +func (x *GetJoinDataKubeResponse) Reset() { + *x = GetJoinDataKubeResponse{} + mi := &file_vmapi_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetJoinDataKubeResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetJoinDataKubeResponse) ProtoMessage() {} + +func (x *GetJoinDataKubeResponse) ProtoReflect() protoreflect.Message { + mi := &file_vmapi_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetJoinDataKubeResponse.ProtoReflect.Descriptor instead. +func (*GetJoinDataKubeResponse) Descriptor() ([]byte, []int) { + return file_vmapi_proto_rawDescGZIP(), []int{4} +} + +func (x *GetJoinDataKubeResponse) GetJoinToken() *JoinToken { + if x != nil { + return x.JoinToken + } + return nil +} + +func (x *GetJoinDataKubeResponse) GetFiles() []*File { + if x != nil { + return x.Files + } + return nil +} + +type InitFirstMasterRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Command string `protobuf:"bytes,1,opt,name=command,proto3" json:"command,omitempty"` + Args []string `protobuf:"bytes,2,rep,name=args,proto3" json:"args,omitempty"` + Tty bool `protobuf:"varint,3,opt,name=tty,proto3" json:"tty,omitempty"` +} + +func (x *InitFirstMasterRequest) Reset() { + *x = InitFirstMasterRequest{} + mi := &file_vmapi_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *InitFirstMasterRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InitFirstMasterRequest) ProtoMessage() {} + +func (x *InitFirstMasterRequest) ProtoReflect() protoreflect.Message { + mi := &file_vmapi_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InitFirstMasterRequest.ProtoReflect.Descriptor instead. +func (*InitFirstMasterRequest) Descriptor() ([]byte, []int) { + return file_vmapi_proto_rawDescGZIP(), []int{5} +} + +func (x *InitFirstMasterRequest) GetCommand() string { + if x != nil { + return x.Command + } + return "" +} + +func (x *InitFirstMasterRequest) GetArgs() []string { + if x != nil { + return x.Args + } + return nil +} + +func (x *InitFirstMasterRequest) GetTty() bool { + if x != nil { + return x.Tty + } + return false +} + +type InitFirstMasterResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Content: + // + // *InitFirstMasterResponse_Output + // *InitFirstMasterResponse_Log + Content isInitFirstMasterResponse_Content `protobuf_oneof:"content"` +} + +func (x *InitFirstMasterResponse) Reset() { + *x = InitFirstMasterResponse{} + mi := &file_vmapi_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *InitFirstMasterResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InitFirstMasterResponse) ProtoMessage() {} + +func (x *InitFirstMasterResponse) ProtoReflect() protoreflect.Message { + mi := &file_vmapi_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InitFirstMasterResponse.ProtoReflect.Descriptor instead. +func (*InitFirstMasterResponse) Descriptor() ([]byte, []int) { + return file_vmapi_proto_rawDescGZIP(), []int{6} +} + +func (m *InitFirstMasterResponse) GetContent() isInitFirstMasterResponse_Content { + if m != nil { + return m.Content + } + return nil +} + +func (x *InitFirstMasterResponse) GetOutput() []byte { + if x, ok := x.GetContent().(*InitFirstMasterResponse_Output); ok { + return x.Output + } + return nil +} + +func (x *InitFirstMasterResponse) GetLog() *Log { + if x, ok := x.GetContent().(*InitFirstMasterResponse_Log); ok { + return x.Log + } + return nil +} + +type isInitFirstMasterResponse_Content interface { + isInitFirstMasterResponse_Content() +} + +type InitFirstMasterResponse_Output struct { + Output []byte `protobuf:"bytes,1,opt,name=output,proto3,oneof"` +} + +type InitFirstMasterResponse_Log struct { + Log *Log `protobuf:"bytes,2,opt,name=log,proto3,oneof"` +} + +func (*InitFirstMasterResponse_Output) isInitFirstMasterResponse_Content() {} + +func (*InitFirstMasterResponse_Log) isInitFirstMasterResponse_Content() {} + +var File_vmapi_proto protoreflect.FileDescriptor + +var file_vmapi_proto_rawDesc = []byte{ + 0x0a, 0x0b, 0x76, 0x6d, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x76, + 0x6d, 0x61, 0x70, 0x69, 0x22, 0x1f, 0x0a, 0x03, 0x4c, 0x6f, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x18, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x69, 0x6e, + 0x44, 0x61, 0x74, 0x61, 0x4b, 0x75, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, + 0x6f, 0x0a, 0x09, 0x4a, 0x6f, 0x69, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x14, 0x0a, 0x05, + 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, + 0x65, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x61, 0x43, 0x65, 0x72, 0x74, 0x48, 0x61, 0x73, 0x68, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x61, 0x43, 0x65, 0x72, 0x74, 0x48, 0x61, + 0x73, 0x68, 0x12, 0x2c, 0x0a, 0x11, 0x61, 0x70, 0x69, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, + 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x61, + 0x70, 0x69, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, + 0x22, 0x34, 0x0a, 0x04, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x6c, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x69, + 0x6e, 0x44, 0x61, 0x74, 0x61, 0x4b, 0x75, 0x62, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x2e, 0x0a, 0x09, 0x6a, 0x6f, 0x69, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x76, 0x6d, 0x61, 0x70, 0x69, 0x2e, 0x4a, 0x6f, 0x69, + 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x09, 0x6a, 0x6f, 0x69, 0x6e, 0x54, 0x6f, 0x6b, 0x65, + 0x6e, 0x12, 0x21, 0x0a, 0x05, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x0b, 0x2e, 0x76, 0x6d, 0x61, 0x70, 0x69, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x05, 0x66, + 0x69, 0x6c, 0x65, 0x73, 0x22, 0x58, 0x0a, 0x16, 0x49, 0x6e, 0x69, 0x74, 0x46, 0x69, 0x72, 0x73, + 0x74, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, + 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x72, 0x67, 0x73, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x61, 0x72, 0x67, 0x73, 0x12, 0x10, 0x0a, 0x03, + 0x74, 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x74, 0x74, 0x79, 0x22, 0x5e, + 0x0a, 0x17, 0x49, 0x6e, 0x69, 0x74, 0x46, 0x69, 0x72, 0x73, 0x74, 0x4d, 0x61, 0x73, 0x74, 0x65, + 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x06, 0x6f, 0x75, 0x74, + 0x70, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x06, 0x6f, 0x75, 0x74, + 0x70, 0x75, 0x74, 0x12, 0x1e, 0x0a, 0x03, 0x6c, 0x6f, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x0a, 0x2e, 0x76, 0x6d, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x6f, 0x67, 0x48, 0x00, 0x52, 0x03, + 0x6c, 0x6f, 0x67, 0x42, 0x09, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x32, 0xab, + 0x01, 0x0a, 0x03, 0x41, 0x50, 0x49, 0x12, 0x50, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x69, + 0x6e, 0x44, 0x61, 0x74, 0x61, 0x4b, 0x75, 0x62, 0x65, 0x12, 0x1d, 0x2e, 0x76, 0x6d, 0x61, 0x70, + 0x69, 0x2e, 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x69, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x4b, 0x75, 0x62, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x76, 0x6d, 0x61, 0x70, 0x69, + 0x2e, 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x69, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x4b, 0x75, 0x62, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x52, 0x0a, 0x0f, 0x49, 0x6e, 0x69, 0x74, + 0x46, 0x69, 0x72, 0x73, 0x74, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x12, 0x1d, 0x2e, 0x76, 0x6d, + 0x61, 0x70, 0x69, 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x46, 0x69, 0x72, 0x73, 0x74, 0x4d, 0x61, 0x73, + 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x76, 0x6d, 0x61, + 0x70, 0x69, 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x46, 0x69, 0x72, 0x73, 0x74, 0x4d, 0x61, 0x73, 0x74, + 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x42, 0x3a, 0x5a, 0x38, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x65, 0x6e, 0x73, 0x63, + 0x68, 0x6c, 0x75, 0x65, 0x74, 0x65, 0x72, 0x2f, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, + 0x6f, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2f, 0x76, 0x6d, 0x2f, 0x76, 0x6d, 0x61, 0x70, 0x69, + 0x2f, 0x76, 0x6d, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_vmapi_proto_rawDescOnce sync.Once + file_vmapi_proto_rawDescData = file_vmapi_proto_rawDesc +) + +func file_vmapi_proto_rawDescGZIP() []byte { + file_vmapi_proto_rawDescOnce.Do(func() { + file_vmapi_proto_rawDescData = protoimpl.X.CompressGZIP(file_vmapi_proto_rawDescData) + }) + return file_vmapi_proto_rawDescData +} + +var file_vmapi_proto_msgTypes = make([]protoimpl.MessageInfo, 7) +var file_vmapi_proto_goTypes = []any{ + (*Log)(nil), // 0: vmapi.Log + (*GetJoinDataKubeRequest)(nil), // 1: vmapi.GetJoinDataKubeRequest + (*JoinToken)(nil), // 2: vmapi.JoinToken + (*File)(nil), // 3: vmapi.File + (*GetJoinDataKubeResponse)(nil), // 4: vmapi.GetJoinDataKubeResponse + (*InitFirstMasterRequest)(nil), // 5: vmapi.InitFirstMasterRequest + (*InitFirstMasterResponse)(nil), // 6: vmapi.InitFirstMasterResponse +} +var file_vmapi_proto_depIdxs = []int32{ + 2, // 0: vmapi.GetJoinDataKubeResponse.joinToken:type_name -> vmapi.JoinToken + 3, // 1: vmapi.GetJoinDataKubeResponse.files:type_name -> vmapi.File + 0, // 2: vmapi.InitFirstMasterResponse.log:type_name -> vmapi.Log + 1, // 3: vmapi.API.GetJoinDataKube:input_type -> vmapi.GetJoinDataKubeRequest + 5, // 4: vmapi.API.InitFirstMaster:input_type -> vmapi.InitFirstMasterRequest + 4, // 5: vmapi.API.GetJoinDataKube:output_type -> vmapi.GetJoinDataKubeResponse + 6, // 6: vmapi.API.InitFirstMaster:output_type -> vmapi.InitFirstMasterResponse + 5, // [5:7] is the sub-list for method output_type + 3, // [3:5] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name +} + +func init() { file_vmapi_proto_init() } +func file_vmapi_proto_init() { + if File_vmapi_proto != nil { + return + } + file_vmapi_proto_msgTypes[6].OneofWrappers = []any{ + (*InitFirstMasterResponse_Output)(nil), + (*InitFirstMasterResponse_Log)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_vmapi_proto_rawDesc, + NumEnums: 0, + NumMessages: 7, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_vmapi_proto_goTypes, + DependencyIndexes: file_vmapi_proto_depIdxs, + MessageInfos: file_vmapi_proto_msgTypes, + }.Build() + File_vmapi_proto = out.File + file_vmapi_proto_rawDesc = nil + file_vmapi_proto_goTypes = nil + file_vmapi_proto_depIdxs = nil +} diff --git a/agent/vm/vmapi/vmproto/vmapi.proto b/agent/vm/vmapi/vmproto/vmapi.proto new file mode 100644 index 0000000..67796e7 --- /dev/null +++ b/agent/vm/vmapi/vmproto/vmapi.proto @@ -0,0 +1,48 @@ +syntax = "proto3"; + +package vmapi; + +option go_package = "github.com/benschlueter/delegatio/agent/vm/vmapi/vmproto"; + + +service API { + rpc GetJoinDataKube(GetJoinDataKubeRequest) returns (GetJoinDataKubeResponse); + rpc InitFirstMaster(InitFirstMasterRequest) returns (stream InitFirstMasterResponse); +} + +message Log { + string message = 1; +} + +message GetJoinDataKubeRequest { +} + +message JoinToken { + string token = 1; + string caCertHash = 2; + string apiServerEndpoint = 3; +} + +message File { + string name = 1; + bytes content = 2; +} + +message GetJoinDataKubeResponse { + JoinToken joinToken = 1; + repeated File files = 2; +} + +message InitFirstMasterRequest { + string command = 1; + repeated string args = 2; + bool tty = 3; +} + + +message InitFirstMasterResponse { + oneof content { + bytes output = 1; + Log log = 2; + } +} \ No newline at end of file diff --git a/agent/vm/vmapi/vmproto/vmapi_grpc.pb.go b/agent/vm/vmapi/vmproto/vmapi_grpc.pb.go new file mode 100644 index 0000000..1f7e930 --- /dev/null +++ b/agent/vm/vmapi/vmproto/vmapi_grpc.pb.go @@ -0,0 +1,163 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.28.3 +// source: vmapi.proto + +package vmproto + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + API_GetJoinDataKube_FullMethodName = "/vmapi.API/GetJoinDataKube" + API_InitFirstMaster_FullMethodName = "/vmapi.API/InitFirstMaster" +) + +// APIClient is the client API for API service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type APIClient interface { + GetJoinDataKube(ctx context.Context, in *GetJoinDataKubeRequest, opts ...grpc.CallOption) (*GetJoinDataKubeResponse, error) + InitFirstMaster(ctx context.Context, in *InitFirstMasterRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[InitFirstMasterResponse], error) +} + +type aPIClient struct { + cc grpc.ClientConnInterface +} + +func NewAPIClient(cc grpc.ClientConnInterface) APIClient { + return &aPIClient{cc} +} + +func (c *aPIClient) GetJoinDataKube(ctx context.Context, in *GetJoinDataKubeRequest, opts ...grpc.CallOption) (*GetJoinDataKubeResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetJoinDataKubeResponse) + err := c.cc.Invoke(ctx, API_GetJoinDataKube_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *aPIClient) InitFirstMaster(ctx context.Context, in *InitFirstMasterRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[InitFirstMasterResponse], error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + stream, err := c.cc.NewStream(ctx, &API_ServiceDesc.Streams[0], API_InitFirstMaster_FullMethodName, cOpts...) + if err != nil { + return nil, err + } + x := &grpc.GenericClientStream[InitFirstMasterRequest, InitFirstMasterResponse]{ClientStream: stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type API_InitFirstMasterClient = grpc.ServerStreamingClient[InitFirstMasterResponse] + +// APIServer is the server API for API service. +// All implementations must embed UnimplementedAPIServer +// for forward compatibility. +type APIServer interface { + GetJoinDataKube(context.Context, *GetJoinDataKubeRequest) (*GetJoinDataKubeResponse, error) + InitFirstMaster(*InitFirstMasterRequest, grpc.ServerStreamingServer[InitFirstMasterResponse]) error + mustEmbedUnimplementedAPIServer() +} + +// UnimplementedAPIServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedAPIServer struct{} + +func (UnimplementedAPIServer) GetJoinDataKube(context.Context, *GetJoinDataKubeRequest) (*GetJoinDataKubeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetJoinDataKube not implemented") +} +func (UnimplementedAPIServer) InitFirstMaster(*InitFirstMasterRequest, grpc.ServerStreamingServer[InitFirstMasterResponse]) error { + return status.Errorf(codes.Unimplemented, "method InitFirstMaster not implemented") +} +func (UnimplementedAPIServer) mustEmbedUnimplementedAPIServer() {} +func (UnimplementedAPIServer) testEmbeddedByValue() {} + +// UnsafeAPIServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to APIServer will +// result in compilation errors. +type UnsafeAPIServer interface { + mustEmbedUnimplementedAPIServer() +} + +func RegisterAPIServer(s grpc.ServiceRegistrar, srv APIServer) { + // If the following call pancis, it indicates UnimplementedAPIServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&API_ServiceDesc, srv) +} + +func _API_GetJoinDataKube_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetJoinDataKubeRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(APIServer).GetJoinDataKube(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: API_GetJoinDataKube_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(APIServer).GetJoinDataKube(ctx, req.(*GetJoinDataKubeRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _API_InitFirstMaster_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(InitFirstMasterRequest) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(APIServer).InitFirstMaster(m, &grpc.GenericServerStream[InitFirstMasterRequest, InitFirstMasterResponse]{ServerStream: stream}) +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type API_InitFirstMasterServer = grpc.ServerStreamingServer[InitFirstMasterResponse] + +// API_ServiceDesc is the grpc.ServiceDesc for API service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var API_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "vmapi.API", + HandlerType: (*APIServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetJoinDataKube", + Handler: _API_GetJoinDataKube_Handler, + }, + }, + Streams: []grpc.StreamDesc{ + { + StreamName: "InitFirstMaster", + Handler: _API_InitFirstMaster_Handler, + ServerStreams: true, + }, + }, + Metadata: "vmapi.proto", +} diff --git a/agent/vmapi/vmproto/vmapi.pb.go b/agent/vmapi/vmproto/vmapi.pb.go deleted file mode 100644 index 644098d..0000000 --- a/agent/vmapi/vmproto/vmapi.pb.go +++ /dev/null @@ -1,1502 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.28.1 -// protoc v4.22.0 -// source: vmapi.proto - -package vmproto - -import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -type ExecCommandStreamRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Types that are assignable to Content: - // - // *ExecCommandStreamRequest_Command - // *ExecCommandStreamRequest_Stdin - // *ExecCommandStreamRequest_Termsize - Content isExecCommandStreamRequest_Content `protobuf_oneof:"content"` -} - -func (x *ExecCommandStreamRequest) Reset() { - *x = ExecCommandStreamRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_vmapi_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ExecCommandStreamRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ExecCommandStreamRequest) ProtoMessage() {} - -func (x *ExecCommandStreamRequest) ProtoReflect() protoreflect.Message { - mi := &file_vmapi_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ExecCommandStreamRequest.ProtoReflect.Descriptor instead. -func (*ExecCommandStreamRequest) Descriptor() ([]byte, []int) { - return file_vmapi_proto_rawDescGZIP(), []int{0} -} - -func (m *ExecCommandStreamRequest) GetContent() isExecCommandStreamRequest_Content { - if m != nil { - return m.Content - } - return nil -} - -func (x *ExecCommandStreamRequest) GetCommand() *ExecCommandRequest { - if x, ok := x.GetContent().(*ExecCommandStreamRequest_Command); ok { - return x.Command - } - return nil -} - -func (x *ExecCommandStreamRequest) GetStdin() []byte { - if x, ok := x.GetContent().(*ExecCommandStreamRequest_Stdin); ok { - return x.Stdin - } - return nil -} - -func (x *ExecCommandStreamRequest) GetTermsize() *TerminalSizeRequest { - if x, ok := x.GetContent().(*ExecCommandStreamRequest_Termsize); ok { - return x.Termsize - } - return nil -} - -type isExecCommandStreamRequest_Content interface { - isExecCommandStreamRequest_Content() -} - -type ExecCommandStreamRequest_Command struct { - Command *ExecCommandRequest `protobuf:"bytes,1,opt,name=command,proto3,oneof"` -} - -type ExecCommandStreamRequest_Stdin struct { - Stdin []byte `protobuf:"bytes,2,opt,name=stdin,proto3,oneof"` -} - -type ExecCommandStreamRequest_Termsize struct { - Termsize *TerminalSizeRequest `protobuf:"bytes,3,opt,name=termsize,proto3,oneof"` -} - -func (*ExecCommandStreamRequest_Command) isExecCommandStreamRequest_Content() {} - -func (*ExecCommandStreamRequest_Stdin) isExecCommandStreamRequest_Content() {} - -func (*ExecCommandStreamRequest_Termsize) isExecCommandStreamRequest_Content() {} - -type ExecCommandStreamResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Types that are assignable to Content: - // - // *ExecCommandStreamResponse_Stdout - // *ExecCommandStreamResponse_Stderr - // *ExecCommandStreamResponse_Err - Content isExecCommandStreamResponse_Content `protobuf_oneof:"content"` -} - -func (x *ExecCommandStreamResponse) Reset() { - *x = ExecCommandStreamResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_vmapi_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ExecCommandStreamResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ExecCommandStreamResponse) ProtoMessage() {} - -func (x *ExecCommandStreamResponse) ProtoReflect() protoreflect.Message { - mi := &file_vmapi_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ExecCommandStreamResponse.ProtoReflect.Descriptor instead. -func (*ExecCommandStreamResponse) Descriptor() ([]byte, []int) { - return file_vmapi_proto_rawDescGZIP(), []int{1} -} - -func (m *ExecCommandStreamResponse) GetContent() isExecCommandStreamResponse_Content { - if m != nil { - return m.Content - } - return nil -} - -func (x *ExecCommandStreamResponse) GetStdout() []byte { - if x, ok := x.GetContent().(*ExecCommandStreamResponse_Stdout); ok { - return x.Stdout - } - return nil -} - -func (x *ExecCommandStreamResponse) GetStderr() []byte { - if x, ok := x.GetContent().(*ExecCommandStreamResponse_Stderr); ok { - return x.Stderr - } - return nil -} - -func (x *ExecCommandStreamResponse) GetErr() string { - if x, ok := x.GetContent().(*ExecCommandStreamResponse_Err); ok { - return x.Err - } - return "" -} - -type isExecCommandStreamResponse_Content interface { - isExecCommandStreamResponse_Content() -} - -type ExecCommandStreamResponse_Stdout struct { - Stdout []byte `protobuf:"bytes,1,opt,name=stdout,proto3,oneof"` -} - -type ExecCommandStreamResponse_Stderr struct { - Stderr []byte `protobuf:"bytes,2,opt,name=stderr,proto3,oneof"` -} - -type ExecCommandStreamResponse_Err struct { - Err string `protobuf:"bytes,3,opt,name=err,proto3,oneof"` -} - -func (*ExecCommandStreamResponse_Stdout) isExecCommandStreamResponse_Content() {} - -func (*ExecCommandStreamResponse_Stderr) isExecCommandStreamResponse_Content() {} - -func (*ExecCommandStreamResponse_Err) isExecCommandStreamResponse_Content() {} - -type ExecCommandReturnStreamResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Types that are assignable to Content: - // - // *ExecCommandReturnStreamResponse_Output - // *ExecCommandReturnStreamResponse_Log - Content isExecCommandReturnStreamResponse_Content `protobuf_oneof:"content"` -} - -func (x *ExecCommandReturnStreamResponse) Reset() { - *x = ExecCommandReturnStreamResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_vmapi_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ExecCommandReturnStreamResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ExecCommandReturnStreamResponse) ProtoMessage() {} - -func (x *ExecCommandReturnStreamResponse) ProtoReflect() protoreflect.Message { - mi := &file_vmapi_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ExecCommandReturnStreamResponse.ProtoReflect.Descriptor instead. -func (*ExecCommandReturnStreamResponse) Descriptor() ([]byte, []int) { - return file_vmapi_proto_rawDescGZIP(), []int{2} -} - -func (m *ExecCommandReturnStreamResponse) GetContent() isExecCommandReturnStreamResponse_Content { - if m != nil { - return m.Content - } - return nil -} - -func (x *ExecCommandReturnStreamResponse) GetOutput() []byte { - if x, ok := x.GetContent().(*ExecCommandReturnStreamResponse_Output); ok { - return x.Output - } - return nil -} - -func (x *ExecCommandReturnStreamResponse) GetLog() *Log { - if x, ok := x.GetContent().(*ExecCommandReturnStreamResponse_Log); ok { - return x.Log - } - return nil -} - -type isExecCommandReturnStreamResponse_Content interface { - isExecCommandReturnStreamResponse_Content() -} - -type ExecCommandReturnStreamResponse_Output struct { - Output []byte `protobuf:"bytes,1,opt,name=output,proto3,oneof"` -} - -type ExecCommandReturnStreamResponse_Log struct { - Log *Log `protobuf:"bytes,2,opt,name=log,proto3,oneof"` -} - -func (*ExecCommandReturnStreamResponse_Output) isExecCommandReturnStreamResponse_Content() {} - -func (*ExecCommandReturnStreamResponse_Log) isExecCommandReturnStreamResponse_Content() {} - -type TerminalSizeRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Width int32 `protobuf:"varint,1,opt,name=width,proto3" json:"width,omitempty"` - Height int32 `protobuf:"varint,2,opt,name=height,proto3" json:"height,omitempty"` -} - -func (x *TerminalSizeRequest) Reset() { - *x = TerminalSizeRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_vmapi_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TerminalSizeRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TerminalSizeRequest) ProtoMessage() {} - -func (x *TerminalSizeRequest) ProtoReflect() protoreflect.Message { - mi := &file_vmapi_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TerminalSizeRequest.ProtoReflect.Descriptor instead. -func (*TerminalSizeRequest) Descriptor() ([]byte, []int) { - return file_vmapi_proto_rawDescGZIP(), []int{3} -} - -func (x *TerminalSizeRequest) GetWidth() int32 { - if x != nil { - return x.Width - } - return 0 -} - -func (x *TerminalSizeRequest) GetHeight() int32 { - if x != nil { - return x.Height - } - return 0 -} - -type ExecCommandRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Command string `protobuf:"bytes,1,opt,name=command,proto3" json:"command,omitempty"` - Args []string `protobuf:"bytes,2,rep,name=args,proto3" json:"args,omitempty"` - Tty bool `protobuf:"varint,3,opt,name=tty,proto3" json:"tty,omitempty"` -} - -func (x *ExecCommandRequest) Reset() { - *x = ExecCommandRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_vmapi_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ExecCommandRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ExecCommandRequest) ProtoMessage() {} - -func (x *ExecCommandRequest) ProtoReflect() protoreflect.Message { - mi := &file_vmapi_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ExecCommandRequest.ProtoReflect.Descriptor instead. -func (*ExecCommandRequest) Descriptor() ([]byte, []int) { - return file_vmapi_proto_rawDescGZIP(), []int{4} -} - -func (x *ExecCommandRequest) GetCommand() string { - if x != nil { - return x.Command - } - return "" -} - -func (x *ExecCommandRequest) GetArgs() []string { - if x != nil { - return x.Args - } - return nil -} - -func (x *ExecCommandRequest) GetTty() bool { - if x != nil { - return x.Tty - } - return false -} - -type ExecCommandResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Output []byte `protobuf:"bytes,1,opt,name=output,proto3" json:"output,omitempty"` -} - -func (x *ExecCommandResponse) Reset() { - *x = ExecCommandResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_vmapi_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ExecCommandResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ExecCommandResponse) ProtoMessage() {} - -func (x *ExecCommandResponse) ProtoReflect() protoreflect.Message { - mi := &file_vmapi_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ExecCommandResponse.ProtoReflect.Descriptor instead. -func (*ExecCommandResponse) Descriptor() ([]byte, []int) { - return file_vmapi_proto_rawDescGZIP(), []int{5} -} - -func (x *ExecCommandResponse) GetOutput() []byte { - if x != nil { - return x.Output - } - return nil -} - -type WriteFileRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Filepath string `protobuf:"bytes,1,opt,name=filepath,proto3" json:"filepath,omitempty"` - Filename string `protobuf:"bytes,2,opt,name=filename,proto3" json:"filename,omitempty"` - Content []byte `protobuf:"bytes,3,opt,name=content,proto3" json:"content,omitempty"` -} - -func (x *WriteFileRequest) Reset() { - *x = WriteFileRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_vmapi_proto_msgTypes[6] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *WriteFileRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*WriteFileRequest) ProtoMessage() {} - -func (x *WriteFileRequest) ProtoReflect() protoreflect.Message { - mi := &file_vmapi_proto_msgTypes[6] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use WriteFileRequest.ProtoReflect.Descriptor instead. -func (*WriteFileRequest) Descriptor() ([]byte, []int) { - return file_vmapi_proto_rawDescGZIP(), []int{6} -} - -func (x *WriteFileRequest) GetFilepath() string { - if x != nil { - return x.Filepath - } - return "" -} - -func (x *WriteFileRequest) GetFilename() string { - if x != nil { - return x.Filename - } - return "" -} - -func (x *WriteFileRequest) GetContent() []byte { - if x != nil { - return x.Content - } - return nil -} - -type WriteFileResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *WriteFileResponse) Reset() { - *x = WriteFileResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_vmapi_proto_msgTypes[7] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *WriteFileResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*WriteFileResponse) ProtoMessage() {} - -func (x *WriteFileResponse) ProtoReflect() protoreflect.Message { - mi := &file_vmapi_proto_msgTypes[7] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use WriteFileResponse.ProtoReflect.Descriptor instead. -func (*WriteFileResponse) Descriptor() ([]byte, []int) { - return file_vmapi_proto_rawDescGZIP(), []int{7} -} - -type ReadFileRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Filepath string `protobuf:"bytes,1,opt,name=filepath,proto3" json:"filepath,omitempty"` - Filename string `protobuf:"bytes,2,opt,name=filename,proto3" json:"filename,omitempty"` -} - -func (x *ReadFileRequest) Reset() { - *x = ReadFileRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_vmapi_proto_msgTypes[8] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ReadFileRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ReadFileRequest) ProtoMessage() {} - -func (x *ReadFileRequest) ProtoReflect() protoreflect.Message { - mi := &file_vmapi_proto_msgTypes[8] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ReadFileRequest.ProtoReflect.Descriptor instead. -func (*ReadFileRequest) Descriptor() ([]byte, []int) { - return file_vmapi_proto_rawDescGZIP(), []int{8} -} - -func (x *ReadFileRequest) GetFilepath() string { - if x != nil { - return x.Filepath - } - return "" -} - -func (x *ReadFileRequest) GetFilename() string { - if x != nil { - return x.Filename - } - return "" -} - -type ReadFileResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Content []byte `protobuf:"bytes,3,opt,name=content,proto3" json:"content,omitempty"` -} - -func (x *ReadFileResponse) Reset() { - *x = ReadFileResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_vmapi_proto_msgTypes[9] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ReadFileResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ReadFileResponse) ProtoMessage() {} - -func (x *ReadFileResponse) ProtoReflect() protoreflect.Message { - mi := &file_vmapi_proto_msgTypes[9] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ReadFileResponse.ProtoReflect.Descriptor instead. -func (*ReadFileResponse) Descriptor() ([]byte, []int) { - return file_vmapi_proto_rawDescGZIP(), []int{9} -} - -func (x *ReadFileResponse) GetContent() []byte { - if x != nil { - return x.Content - } - return nil -} - -type Log struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` -} - -func (x *Log) Reset() { - *x = Log{} - if protoimpl.UnsafeEnabled { - mi := &file_vmapi_proto_msgTypes[10] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Log) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Log) ProtoMessage() {} - -func (x *Log) ProtoReflect() protoreflect.Message { - mi := &file_vmapi_proto_msgTypes[10] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Log.ProtoReflect.Descriptor instead. -func (*Log) Descriptor() ([]byte, []int) { - return file_vmapi_proto_rawDescGZIP(), []int{10} -} - -func (x *Log) GetMessage() string { - if x != nil { - return x.Message - } - return "" -} - -type GetJoinDataKubeRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *GetJoinDataKubeRequest) Reset() { - *x = GetJoinDataKubeRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_vmapi_proto_msgTypes[11] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetJoinDataKubeRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetJoinDataKubeRequest) ProtoMessage() {} - -func (x *GetJoinDataKubeRequest) ProtoReflect() protoreflect.Message { - mi := &file_vmapi_proto_msgTypes[11] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetJoinDataKubeRequest.ProtoReflect.Descriptor instead. -func (*GetJoinDataKubeRequest) Descriptor() ([]byte, []int) { - return file_vmapi_proto_rawDescGZIP(), []int{11} -} - -type JoinToken struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"` - CaCertHash string `protobuf:"bytes,2,opt,name=caCertHash,proto3" json:"caCertHash,omitempty"` - ApiServerEndpoint string `protobuf:"bytes,3,opt,name=apiServerEndpoint,proto3" json:"apiServerEndpoint,omitempty"` -} - -func (x *JoinToken) Reset() { - *x = JoinToken{} - if protoimpl.UnsafeEnabled { - mi := &file_vmapi_proto_msgTypes[12] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *JoinToken) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*JoinToken) ProtoMessage() {} - -func (x *JoinToken) ProtoReflect() protoreflect.Message { - mi := &file_vmapi_proto_msgTypes[12] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use JoinToken.ProtoReflect.Descriptor instead. -func (*JoinToken) Descriptor() ([]byte, []int) { - return file_vmapi_proto_rawDescGZIP(), []int{12} -} - -func (x *JoinToken) GetToken() string { - if x != nil { - return x.Token - } - return "" -} - -func (x *JoinToken) GetCaCertHash() string { - if x != nil { - return x.CaCertHash - } - return "" -} - -func (x *JoinToken) GetApiServerEndpoint() string { - if x != nil { - return x.ApiServerEndpoint - } - return "" -} - -type File struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - Content []byte `protobuf:"bytes,2,opt,name=content,proto3" json:"content,omitempty"` -} - -func (x *File) Reset() { - *x = File{} - if protoimpl.UnsafeEnabled { - mi := &file_vmapi_proto_msgTypes[13] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *File) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*File) ProtoMessage() {} - -func (x *File) ProtoReflect() protoreflect.Message { - mi := &file_vmapi_proto_msgTypes[13] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use File.ProtoReflect.Descriptor instead. -func (*File) Descriptor() ([]byte, []int) { - return file_vmapi_proto_rawDescGZIP(), []int{13} -} - -func (x *File) GetName() string { - if x != nil { - return x.Name - } - return "" -} - -func (x *File) GetContent() []byte { - if x != nil { - return x.Content - } - return nil -} - -type GetJoinDataKubeResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - JoinToken *JoinToken `protobuf:"bytes,1,opt,name=joinToken,proto3" json:"joinToken,omitempty"` - Files []*File `protobuf:"bytes,2,rep,name=files,proto3" json:"files,omitempty"` -} - -func (x *GetJoinDataKubeResponse) Reset() { - *x = GetJoinDataKubeResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_vmapi_proto_msgTypes[14] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetJoinDataKubeResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetJoinDataKubeResponse) ProtoMessage() {} - -func (x *GetJoinDataKubeResponse) ProtoReflect() protoreflect.Message { - mi := &file_vmapi_proto_msgTypes[14] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetJoinDataKubeResponse.ProtoReflect.Descriptor instead. -func (*GetJoinDataKubeResponse) Descriptor() ([]byte, []int) { - return file_vmapi_proto_rawDescGZIP(), []int{14} -} - -func (x *GetJoinDataKubeResponse) GetJoinToken() *JoinToken { - if x != nil { - return x.JoinToken - } - return nil -} - -func (x *GetJoinDataKubeResponse) GetFiles() []*File { - if x != nil { - return x.Files - } - return nil -} - -type InitFirstMasterRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Command string `protobuf:"bytes,1,opt,name=command,proto3" json:"command,omitempty"` - Args []string `protobuf:"bytes,2,rep,name=args,proto3" json:"args,omitempty"` - Tty bool `protobuf:"varint,3,opt,name=tty,proto3" json:"tty,omitempty"` -} - -func (x *InitFirstMasterRequest) Reset() { - *x = InitFirstMasterRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_vmapi_proto_msgTypes[15] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *InitFirstMasterRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*InitFirstMasterRequest) ProtoMessage() {} - -func (x *InitFirstMasterRequest) ProtoReflect() protoreflect.Message { - mi := &file_vmapi_proto_msgTypes[15] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use InitFirstMasterRequest.ProtoReflect.Descriptor instead. -func (*InitFirstMasterRequest) Descriptor() ([]byte, []int) { - return file_vmapi_proto_rawDescGZIP(), []int{15} -} - -func (x *InitFirstMasterRequest) GetCommand() string { - if x != nil { - return x.Command - } - return "" -} - -func (x *InitFirstMasterRequest) GetArgs() []string { - if x != nil { - return x.Args - } - return nil -} - -func (x *InitFirstMasterRequest) GetTty() bool { - if x != nil { - return x.Tty - } - return false -} - -type InitFirstMasterResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Types that are assignable to Content: - // - // *InitFirstMasterResponse_Output - // *InitFirstMasterResponse_Log - Content isInitFirstMasterResponse_Content `protobuf_oneof:"content"` -} - -func (x *InitFirstMasterResponse) Reset() { - *x = InitFirstMasterResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_vmapi_proto_msgTypes[16] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *InitFirstMasterResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*InitFirstMasterResponse) ProtoMessage() {} - -func (x *InitFirstMasterResponse) ProtoReflect() protoreflect.Message { - mi := &file_vmapi_proto_msgTypes[16] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use InitFirstMasterResponse.ProtoReflect.Descriptor instead. -func (*InitFirstMasterResponse) Descriptor() ([]byte, []int) { - return file_vmapi_proto_rawDescGZIP(), []int{16} -} - -func (m *InitFirstMasterResponse) GetContent() isInitFirstMasterResponse_Content { - if m != nil { - return m.Content - } - return nil -} - -func (x *InitFirstMasterResponse) GetOutput() []byte { - if x, ok := x.GetContent().(*InitFirstMasterResponse_Output); ok { - return x.Output - } - return nil -} - -func (x *InitFirstMasterResponse) GetLog() *Log { - if x, ok := x.GetContent().(*InitFirstMasterResponse_Log); ok { - return x.Log - } - return nil -} - -type isInitFirstMasterResponse_Content interface { - isInitFirstMasterResponse_Content() -} - -type InitFirstMasterResponse_Output struct { - Output []byte `protobuf:"bytes,1,opt,name=output,proto3,oneof"` -} - -type InitFirstMasterResponse_Log struct { - Log *Log `protobuf:"bytes,2,opt,name=log,proto3,oneof"` -} - -func (*InitFirstMasterResponse_Output) isInitFirstMasterResponse_Content() {} - -func (*InitFirstMasterResponse_Log) isInitFirstMasterResponse_Content() {} - -var File_vmapi_proto protoreflect.FileDescriptor - -var file_vmapi_proto_rawDesc = []byte{ - 0x0a, 0x0b, 0x76, 0x6d, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x76, - 0x6d, 0x61, 0x70, 0x69, 0x22, 0xae, 0x01, 0x0a, 0x18, 0x45, 0x78, 0x65, 0x63, 0x43, 0x6f, 0x6d, - 0x6d, 0x61, 0x6e, 0x64, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x35, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x76, 0x6d, 0x61, 0x70, 0x69, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x43, - 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, - 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x16, 0x0a, 0x05, 0x73, 0x74, 0x64, 0x69, - 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x05, 0x73, 0x74, 0x64, 0x69, 0x6e, - 0x12, 0x38, 0x0a, 0x08, 0x74, 0x65, 0x72, 0x6d, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x76, 0x6d, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x65, 0x72, 0x6d, 0x69, - 0x6e, 0x61, 0x6c, 0x53, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, - 0x52, 0x08, 0x74, 0x65, 0x72, 0x6d, 0x73, 0x69, 0x7a, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x6e, 0x0a, 0x19, 0x45, 0x78, 0x65, 0x63, 0x43, 0x6f, 0x6d, - 0x6d, 0x61, 0x6e, 0x64, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x18, 0x0a, 0x06, 0x73, 0x74, 0x64, 0x6f, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0c, 0x48, 0x00, 0x52, 0x06, 0x73, 0x74, 0x64, 0x6f, 0x75, 0x74, 0x12, 0x18, 0x0a, 0x06, - 0x73, 0x74, 0x64, 0x65, 0x72, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x06, - 0x73, 0x74, 0x64, 0x65, 0x72, 0x72, 0x12, 0x12, 0x0a, 0x03, 0x65, 0x72, 0x72, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x03, 0x65, 0x72, 0x72, 0x42, 0x09, 0x0a, 0x07, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x66, 0x0a, 0x1f, 0x45, 0x78, 0x65, 0x63, 0x43, 0x6f, 0x6d, - 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, - 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, - 0x75, 0x74, 0x12, 0x1e, 0x0a, 0x03, 0x6c, 0x6f, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x0a, 0x2e, 0x76, 0x6d, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x6f, 0x67, 0x48, 0x00, 0x52, 0x03, 0x6c, - 0x6f, 0x67, 0x42, 0x09, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x43, 0x0a, - 0x13, 0x54, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x53, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65, - 0x69, 0x67, 0x68, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, - 0x68, 0x74, 0x22, 0x54, 0x0a, 0x12, 0x45, 0x78, 0x65, 0x63, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, - 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, - 0x61, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, - 0x6e, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x72, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, - 0x52, 0x04, 0x61, 0x72, 0x67, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x74, 0x79, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x03, 0x74, 0x74, 0x79, 0x22, 0x2d, 0x0a, 0x13, 0x45, 0x78, 0x65, 0x63, - 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x16, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x22, 0x64, 0x0a, 0x10, 0x57, 0x72, 0x69, 0x74, 0x65, - 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x66, - 0x69, 0x6c, 0x65, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, - 0x69, 0x6c, 0x65, 0x70, 0x61, 0x74, 0x68, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, - 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x13, 0x0a, - 0x11, 0x57, 0x72, 0x69, 0x74, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x49, 0x0a, 0x0f, 0x52, 0x65, 0x61, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x70, 0x61, 0x74, - 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x70, 0x61, 0x74, - 0x68, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x2c, 0x0a, - 0x10, 0x52, 0x65, 0x61, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x1f, 0x0a, 0x03, 0x4c, - 0x6f, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x18, 0x0a, 0x16, - 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x69, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x4b, 0x75, 0x62, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x6f, 0x0a, 0x09, 0x4a, 0x6f, 0x69, 0x6e, 0x54, 0x6f, - 0x6b, 0x65, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x61, 0x43, - 0x65, 0x72, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, - 0x61, 0x43, 0x65, 0x72, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x2c, 0x0a, 0x11, 0x61, 0x70, 0x69, - 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x61, 0x70, 0x69, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, - 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x22, 0x34, 0x0a, 0x04, 0x46, 0x69, 0x6c, 0x65, 0x12, - 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x6c, 0x0a, - 0x17, 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x69, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x4b, 0x75, 0x62, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x09, 0x6a, 0x6f, 0x69, 0x6e, - 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x76, 0x6d, - 0x61, 0x70, 0x69, 0x2e, 0x4a, 0x6f, 0x69, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x09, 0x6a, - 0x6f, 0x69, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x21, 0x0a, 0x05, 0x66, 0x69, 0x6c, 0x65, - 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x76, 0x6d, 0x61, 0x70, 0x69, 0x2e, - 0x46, 0x69, 0x6c, 0x65, 0x52, 0x05, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x22, 0x58, 0x0a, 0x16, 0x49, - 0x6e, 0x69, 0x74, 0x46, 0x69, 0x72, 0x73, 0x74, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, - 0x12, 0x0a, 0x04, 0x61, 0x72, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x61, - 0x72, 0x67, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x03, 0x74, 0x74, 0x79, 0x22, 0x5e, 0x0a, 0x17, 0x49, 0x6e, 0x69, 0x74, 0x46, 0x69, 0x72, - 0x73, 0x74, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x18, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, - 0x48, 0x00, 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x1e, 0x0a, 0x03, 0x6c, 0x6f, - 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x76, 0x6d, 0x61, 0x70, 0x69, 0x2e, - 0x4c, 0x6f, 0x67, 0x48, 0x00, 0x52, 0x03, 0x6c, 0x6f, 0x67, 0x42, 0x09, 0x0a, 0x07, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x32, 0xaa, 0x04, 0x0a, 0x03, 0x41, 0x50, 0x49, 0x12, 0x5a, 0x0a, - 0x11, 0x45, 0x78, 0x65, 0x63, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x53, 0x74, 0x72, 0x65, - 0x61, 0x6d, 0x12, 0x1f, 0x2e, 0x76, 0x6d, 0x61, 0x70, 0x69, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x43, - 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x76, 0x6d, 0x61, 0x70, 0x69, 0x2e, 0x45, 0x78, 0x65, 0x63, - 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, 0x12, 0x5e, 0x0a, 0x17, 0x45, 0x78, 0x65, - 0x63, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x53, 0x74, - 0x72, 0x65, 0x61, 0x6d, 0x12, 0x19, 0x2e, 0x76, 0x6d, 0x61, 0x70, 0x69, 0x2e, 0x45, 0x78, 0x65, - 0x63, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x26, 0x2e, 0x76, 0x6d, 0x61, 0x70, 0x69, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x43, 0x6f, 0x6d, 0x6d, - 0x61, 0x6e, 0x64, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x44, 0x0a, 0x0b, 0x45, 0x78, 0x65, - 0x63, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x19, 0x2e, 0x76, 0x6d, 0x61, 0x70, 0x69, - 0x2e, 0x45, 0x78, 0x65, 0x63, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x76, 0x6d, 0x61, 0x70, 0x69, 0x2e, 0x45, 0x78, 0x65, 0x63, - 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x3e, 0x0a, 0x09, 0x57, 0x72, 0x69, 0x74, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x17, 0x2e, 0x76, - 0x6d, 0x61, 0x70, 0x69, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x76, 0x6d, 0x61, 0x70, 0x69, 0x2e, 0x57, 0x72, - 0x69, 0x74, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x3b, 0x0a, 0x08, 0x52, 0x65, 0x61, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x16, 0x2e, 0x76, 0x6d, - 0x61, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x76, 0x6d, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x61, 0x64, - 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x0f, - 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x69, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x4b, 0x75, 0x62, 0x65, 0x12, - 0x1d, 0x2e, 0x76, 0x6d, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x69, 0x6e, 0x44, - 0x61, 0x74, 0x61, 0x4b, 0x75, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, - 0x2e, 0x76, 0x6d, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x69, 0x6e, 0x44, 0x61, - 0x74, 0x61, 0x4b, 0x75, 0x62, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x52, - 0x0a, 0x0f, 0x49, 0x6e, 0x69, 0x74, 0x46, 0x69, 0x72, 0x73, 0x74, 0x4d, 0x61, 0x73, 0x74, 0x65, - 0x72, 0x12, 0x1d, 0x2e, 0x76, 0x6d, 0x61, 0x70, 0x69, 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x46, 0x69, - 0x72, 0x73, 0x74, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x1e, 0x2e, 0x76, 0x6d, 0x61, 0x70, 0x69, 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x46, 0x69, 0x72, - 0x73, 0x74, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x30, 0x01, 0x42, 0x36, 0x5a, 0x34, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, - 0x2f, 0x62, 0x65, 0x6e, 0x73, 0x63, 0x68, 0x6c, 0x75, 0x65, 0x74, 0x65, 0x72, 0x2f, 0x64, 0x65, - 0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x76, 0x6d, 0x61, - 0x70, 0x69, 0x2f, 0x76, 0x6d, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, -} - -var ( - file_vmapi_proto_rawDescOnce sync.Once - file_vmapi_proto_rawDescData = file_vmapi_proto_rawDesc -) - -func file_vmapi_proto_rawDescGZIP() []byte { - file_vmapi_proto_rawDescOnce.Do(func() { - file_vmapi_proto_rawDescData = protoimpl.X.CompressGZIP(file_vmapi_proto_rawDescData) - }) - return file_vmapi_proto_rawDescData -} - -var file_vmapi_proto_msgTypes = make([]protoimpl.MessageInfo, 17) -var file_vmapi_proto_goTypes = []interface{}{ - (*ExecCommandStreamRequest)(nil), // 0: vmapi.ExecCommandStreamRequest - (*ExecCommandStreamResponse)(nil), // 1: vmapi.ExecCommandStreamResponse - (*ExecCommandReturnStreamResponse)(nil), // 2: vmapi.ExecCommandReturnStreamResponse - (*TerminalSizeRequest)(nil), // 3: vmapi.TerminalSizeRequest - (*ExecCommandRequest)(nil), // 4: vmapi.ExecCommandRequest - (*ExecCommandResponse)(nil), // 5: vmapi.ExecCommandResponse - (*WriteFileRequest)(nil), // 6: vmapi.WriteFileRequest - (*WriteFileResponse)(nil), // 7: vmapi.WriteFileResponse - (*ReadFileRequest)(nil), // 8: vmapi.ReadFileRequest - (*ReadFileResponse)(nil), // 9: vmapi.ReadFileResponse - (*Log)(nil), // 10: vmapi.Log - (*GetJoinDataKubeRequest)(nil), // 11: vmapi.GetJoinDataKubeRequest - (*JoinToken)(nil), // 12: vmapi.JoinToken - (*File)(nil), // 13: vmapi.File - (*GetJoinDataKubeResponse)(nil), // 14: vmapi.GetJoinDataKubeResponse - (*InitFirstMasterRequest)(nil), // 15: vmapi.InitFirstMasterRequest - (*InitFirstMasterResponse)(nil), // 16: vmapi.InitFirstMasterResponse -} -var file_vmapi_proto_depIdxs = []int32{ - 4, // 0: vmapi.ExecCommandStreamRequest.command:type_name -> vmapi.ExecCommandRequest - 3, // 1: vmapi.ExecCommandStreamRequest.termsize:type_name -> vmapi.TerminalSizeRequest - 10, // 2: vmapi.ExecCommandReturnStreamResponse.log:type_name -> vmapi.Log - 12, // 3: vmapi.GetJoinDataKubeResponse.joinToken:type_name -> vmapi.JoinToken - 13, // 4: vmapi.GetJoinDataKubeResponse.files:type_name -> vmapi.File - 10, // 5: vmapi.InitFirstMasterResponse.log:type_name -> vmapi.Log - 0, // 6: vmapi.API.ExecCommandStream:input_type -> vmapi.ExecCommandStreamRequest - 4, // 7: vmapi.API.ExecCommandReturnStream:input_type -> vmapi.ExecCommandRequest - 4, // 8: vmapi.API.ExecCommand:input_type -> vmapi.ExecCommandRequest - 6, // 9: vmapi.API.WriteFile:input_type -> vmapi.WriteFileRequest - 8, // 10: vmapi.API.ReadFile:input_type -> vmapi.ReadFileRequest - 11, // 11: vmapi.API.GetJoinDataKube:input_type -> vmapi.GetJoinDataKubeRequest - 15, // 12: vmapi.API.InitFirstMaster:input_type -> vmapi.InitFirstMasterRequest - 1, // 13: vmapi.API.ExecCommandStream:output_type -> vmapi.ExecCommandStreamResponse - 2, // 14: vmapi.API.ExecCommandReturnStream:output_type -> vmapi.ExecCommandReturnStreamResponse - 5, // 15: vmapi.API.ExecCommand:output_type -> vmapi.ExecCommandResponse - 7, // 16: vmapi.API.WriteFile:output_type -> vmapi.WriteFileResponse - 9, // 17: vmapi.API.ReadFile:output_type -> vmapi.ReadFileResponse - 14, // 18: vmapi.API.GetJoinDataKube:output_type -> vmapi.GetJoinDataKubeResponse - 16, // 19: vmapi.API.InitFirstMaster:output_type -> vmapi.InitFirstMasterResponse - 13, // [13:20] is the sub-list for method output_type - 6, // [6:13] is the sub-list for method input_type - 6, // [6:6] is the sub-list for extension type_name - 6, // [6:6] is the sub-list for extension extendee - 0, // [0:6] is the sub-list for field type_name -} - -func init() { file_vmapi_proto_init() } -func file_vmapi_proto_init() { - if File_vmapi_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_vmapi_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ExecCommandStreamRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_vmapi_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ExecCommandStreamResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_vmapi_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ExecCommandReturnStreamResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_vmapi_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TerminalSizeRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_vmapi_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ExecCommandRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_vmapi_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ExecCommandResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_vmapi_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*WriteFileRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_vmapi_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*WriteFileResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_vmapi_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ReadFileRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_vmapi_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ReadFileResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_vmapi_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Log); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_vmapi_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetJoinDataKubeRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_vmapi_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*JoinToken); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_vmapi_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*File); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_vmapi_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetJoinDataKubeResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_vmapi_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*InitFirstMasterRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_vmapi_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*InitFirstMasterResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - file_vmapi_proto_msgTypes[0].OneofWrappers = []interface{}{ - (*ExecCommandStreamRequest_Command)(nil), - (*ExecCommandStreamRequest_Stdin)(nil), - (*ExecCommandStreamRequest_Termsize)(nil), - } - file_vmapi_proto_msgTypes[1].OneofWrappers = []interface{}{ - (*ExecCommandStreamResponse_Stdout)(nil), - (*ExecCommandStreamResponse_Stderr)(nil), - (*ExecCommandStreamResponse_Err)(nil), - } - file_vmapi_proto_msgTypes[2].OneofWrappers = []interface{}{ - (*ExecCommandReturnStreamResponse_Output)(nil), - (*ExecCommandReturnStreamResponse_Log)(nil), - } - file_vmapi_proto_msgTypes[16].OneofWrappers = []interface{}{ - (*InitFirstMasterResponse_Output)(nil), - (*InitFirstMasterResponse_Log)(nil), - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_vmapi_proto_rawDesc, - NumEnums: 0, - NumMessages: 17, - NumExtensions: 0, - NumServices: 1, - }, - GoTypes: file_vmapi_proto_goTypes, - DependencyIndexes: file_vmapi_proto_depIdxs, - MessageInfos: file_vmapi_proto_msgTypes, - }.Build() - File_vmapi_proto = out.File - file_vmapi_proto_rawDesc = nil - file_vmapi_proto_goTypes = nil - file_vmapi_proto_depIdxs = nil -} diff --git a/cli/bootstrapper/kubernetes/exec.go b/cli/bootstrapper/kubernetes/exec.go index ae0eb8e..d41f9a1 100644 --- a/cli/bootstrapper/kubernetes/exec.go +++ b/cli/bootstrapper/kubernetes/exec.go @@ -9,14 +9,12 @@ import ( "fmt" "net" - "github.com/benschlueter/delegatio/agent/vmapi/vmproto" + "github.com/benschlueter/delegatio/agent/manageapi/manageproto" + "github.com/benschlueter/delegatio/agent/vm/vmapi/vmproto" "github.com/benschlueter/delegatio/internal/config" "go.uber.org/zap" - "golang.org/x/sync/errgroup" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" - - kubeadm "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta4" ) // InstallKubernetes initializes a kubernetes cluster using the gRPC API. @@ -26,73 +24,15 @@ func (a *Bootstrapper) InstallKubernetes(ctx context.Context, kubernetesInitConf return err } defer conn.Close() - client := vmproto.NewAPIClient(conn) - if err := a.executeWriteInitConfiguration(ctx, client, kubernetesInitConfiguration); err != nil { + manageClient := manageproto.NewAPIClient(conn) + if err := a.executeWriteInitConfiguration(ctx, manageClient, kubernetesInitConfiguration); err != nil { return err } - _, err = a.executeKubeadm(ctx, client) + vmClient := vmproto.NewAPIClient(conn) + _, err = a.executeKubeadm(ctx, vmClient) return err } -// JoinClusterCoordinator coordinates cluster joining for all worker nodes. -func (a *Bootstrapper) JoinClusterCoordinator(ctx context.Context, joinToken *kubeadm.BootstrapTokenDiscovery) (err error) { - a.log.Info("coordinating kubeadm join") - g, ctxGo := errgroup.WithContext(ctx) - for name, addr := range a.workerIPs { - func(nodeName, nodeIP string) { - g.Go(func() error { - return a.joinCluster(ctxGo, nodeName, nodeIP, joinToken) - }) - }(name, addr) - } - if err := g.Wait(); err != nil { - a.log.Error("some nodes failed to join the cluster", zap.Error(err)) - return err - } - return nil -} - -// joinCluster connects to a node and executes kubeadm join. -func (a *Bootstrapper) joinCluster(ctx context.Context, id, ip string, joinToken *kubeadm.BootstrapTokenDiscovery) (err error) { - a.log.Info("executing kubeadm join", zap.String("id", id), zap.String("ip", ip)) - conn, err := grpc.DialContext(ctx, net.JoinHostPort(ip, config.PublicAPIport), grpc.WithTransportCredentials(insecure.NewCredentials())) - if err != nil { - return err - } - defer conn.Close() - client := vmproto.NewAPIClient(conn) - resp, err := client.ExecCommandReturnStream(ctx, &vmproto.ExecCommandRequest{ - Command: "/usr/bin/kubeadm", - Args: []string{ - "join", joinToken.APIServerEndpoint, - "--token", joinToken.Token, - "--discovery-token-ca-cert-hash", joinToken.CACertHashes[0], - "--node-name", id, - }, - }) - if err != nil { - return err - } - for { - select { - case <-ctx.Done(): - return ctx.Err() - default: - data, err := resp.Recv() - if err != nil { - return err - } - if len(data.GetOutput()) > 0 { - a.log.Info("kubeadm join succeed", zap.String("id", id), zap.String("ip", ip)) - return nil - } - if len(data.GetLog().GetMessage()) > 0 { - fmt.Println(data.GetLog().GetMessage()) - } - } - } -} - func (a *Bootstrapper) executeKubeadm(ctx context.Context, client vmproto.APIClient) (output []byte, err error) { a.log.Info("execute executeKubeadm") resp, err := client.InitFirstMaster(ctx, &vmproto.InitFirstMasterRequest{ @@ -128,9 +68,9 @@ func (a *Bootstrapper) executeKubeadm(ctx context.Context, client vmproto.APICli } } -func (a *Bootstrapper) executeWriteInitConfiguration(ctx context.Context, client vmproto.APIClient, initConfigKubernetes []byte) (err error) { +func (a *Bootstrapper) executeWriteInitConfiguration(ctx context.Context, client manageproto.APIClient, initConfigKubernetes []byte) (err error) { a.log.Info("write initconfig", zap.String("config", string(initConfigKubernetes))) - _, err = client.WriteFile(ctx, &vmproto.WriteFileRequest{ + _, err = client.WriteFile(ctx, &manageproto.WriteFileRequest{ Filepath: "/tmp", Filename: "kubeadmconf.yaml", Content: initConfigKubernetes, diff --git a/cli/bootstrapper/kubernetes/get.go b/cli/bootstrapper/kubernetes/get.go index 224bf6f..aae7315 100644 --- a/cli/bootstrapper/kubernetes/get.go +++ b/cli/bootstrapper/kubernetes/get.go @@ -6,24 +6,12 @@ package kubernetes import ( "context" - "crypto/x509" - "encoding/pem" - "errors" - "fmt" "net" - "time" - "github.com/benschlueter/delegatio/agent/vmapi/vmproto" + "github.com/benschlueter/delegatio/agent/manageapi/manageproto" "github.com/benschlueter/delegatio/internal/config" - "go.uber.org/zap" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - bootstraputil "k8s.io/cluster-bootstrap/token/util" - tokenv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/bootstraptoken/v1" - kubeadmv1beta4 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta4" - tokenphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/bootstraptoken/node" - "k8s.io/kubernetes/cmd/kubeadm/app/util/pubkeypin" ) func (a *Bootstrapper) getKubernetesConfig(ctx context.Context) (output []byte, err error) { @@ -32,8 +20,8 @@ func (a *Bootstrapper) getKubernetesConfig(ctx context.Context) (output []byte, return nil, err } defer conn.Close() - client := vmproto.NewAPIClient(conn) - resp, err := client.ReadFile(ctx, &vmproto.ReadFileRequest{ + client := manageproto.NewAPIClient(conn) + resp, err := client.ReadFile(ctx, &manageproto.ReadFileRequest{ Filepath: "/etc/kubernetes", Filename: "/admin.conf", }) @@ -45,66 +33,6 @@ func (a *Bootstrapper) getKubernetesConfig(ctx context.Context) (output []byte, return adminConfData, nil } -func (a *Bootstrapper) getKubernetesRootCert(ctx context.Context) (output []byte, err error) { - conn, err := grpc.DialContext(ctx, net.JoinHostPort(a.controlPlaneIP, config.PublicAPIport), grpc.WithTransportCredentials(insecure.NewCredentials())) - if err != nil { - return nil, err - } - defer conn.Close() - client := vmproto.NewAPIClient(conn) - resp, err := client.ReadFile(ctx, &vmproto.ReadFileRequest{ - Filepath: "/etc/kubernetes/pki/", - Filename: "/ca.crt", - }) - if err != nil { - return - } - return resp.GetContent(), nil -} - -// getJoinToken creates a new bootstrap (join) token, which a node can use to join the cluster. -func (a *Bootstrapper) getJoinToken(ttl time.Duration, caFileContentPem []byte) (*kubeadmv1beta4.BootstrapTokenDiscovery, error) { - a.log.Info("generating new random bootstrap token") - rawToken, err := bootstraputil.GenerateBootstrapToken() - if err != nil { - return nil, fmt.Errorf("couldn't generate random token: %w", err) - } - tokenStr, err := tokenv1.NewBootstrapTokenString(rawToken) - if err != nil { - return nil, fmt.Errorf("invalid token: %w", err) - } - token := tokenv1.BootstrapToken{ - Token: tokenStr, - Description: "Bootstrap token generated by delegatio cli", - TTL: &metav1.Duration{Duration: ttl}, - Usages: tokenv1.DefaultTokenUsages, - Groups: tokenv1.DefaultTokenGroups, - } - // create the token in Kubernetes - a.log.Info("creating bootstrap token in Kubernetes") - if err := tokenphase.CreateNewTokens(a.client, []tokenv1.BootstrapToken{token}); err != nil { - return nil, fmt.Errorf("creating bootstrap token: %w", err) - } - // parse Kubernetes CA certs - a.log.Info("Preparing join token for new node") - - caFileContent, _ := pem.Decode(caFileContentPem) - if caFileContent == nil { - return nil, errors.New("no PEM data found in CA cert") - } - caCertX509, err := x509.ParseCertificate(caFileContent.Bytes) - if err != nil { - return nil, fmt.Errorf("parsing CA certs: %w", err) - } - bootstrapToken := &kubeadmv1beta4.BootstrapTokenDiscovery{ - Token: tokenStr.String(), - APIServerEndpoint: net.JoinHostPort(a.controlPlaneIP, "6443"), - CACertHashes: []string{pubkeypin.Hash(caCertX509)}, - } - a.log.Info("Join token creation successful", zap.Any("token", bootstrapToken)) - return bootstrapToken, nil -} - // getEtcdCredentials returns the etcd credentials for the instance. func (a *Bootstrapper) getEtcdCredentials(ctx context.Context) (*config.EtcdCredentials, error) { conn, err := grpc.DialContext(ctx, net.JoinHostPort(a.controlPlaneIP, config.PublicAPIport), grpc.WithTransportCredentials(insecure.NewCredentials())) @@ -112,9 +40,9 @@ func (a *Bootstrapper) getEtcdCredentials(ctx context.Context) (*config.EtcdCred return nil, err } defer conn.Close() - client := vmproto.NewAPIClient(conn) + client := manageproto.NewAPIClient(conn) // Get the peer cert - resp, err := client.ReadFile(ctx, &vmproto.ReadFileRequest{ + resp, err := client.ReadFile(ctx, &manageproto.ReadFileRequest{ Filepath: "/etc/kubernetes/pki/etcd/", Filename: "ca.key", }) @@ -123,7 +51,7 @@ func (a *Bootstrapper) getEtcdCredentials(ctx context.Context) (*config.EtcdCred } caKey := resp.Content // get the CA cert - resp, err = client.ReadFile(ctx, &vmproto.ReadFileRequest{ + resp, err = client.ReadFile(ctx, &manageproto.ReadFileRequest{ Filepath: "/etc/kubernetes/pki/etcd/", Filename: "ca.crt", }) diff --git a/cli/bootstrapper/kubernetes/kubernetes.go b/cli/bootstrapper/kubernetes/kubernetes.go index a265fd1..1c8b33b 100644 --- a/cli/bootstrapper/kubernetes/kubernetes.go +++ b/cli/bootstrapper/kubernetes/kubernetes.go @@ -7,14 +7,12 @@ package kubernetes import ( "context" "errors" - "fmt" "os" "github.com/benschlueter/delegatio/internal/config" "go.uber.org/zap" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd" - "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta4" ) // Bootstrapper communicates with the agent inside the control-plane VM after Kubernetes was initialized. @@ -48,38 +46,24 @@ func (a *Bootstrapper) BootstrapKubernetes(ctx context.Context) (*config.EtcdCre return nil, err } a.log.Info("kubernetes init successful") - joinToken, err := a.configureKubernetes(ctx) - if err != nil { - return nil, err - } - a.log.Info("join token generated") - if err := a.JoinClusterCoordinator(ctx, joinToken); err != nil { + + if err := a.configureKubernetes(ctx); err != nil { return nil, err } return a.getEtcdCredentials(ctx) } // configureKubernetes configures the kubernetes cluster. -func (a *Bootstrapper) configureKubernetes(ctx context.Context) (*v1beta4.BootstrapTokenDiscovery, error) { +func (a *Bootstrapper) configureKubernetes(ctx context.Context) error { if err := a.writeKubeconfigToDisk(ctx); err != nil { - return nil, err + return err } a.log.Info("admin.conf written to disk") if err := a.establishClientGoConnection(); err != nil { - return nil, err + return err } a.log.Info("client-go connection established") - caFileContentPem, err := a.getKubernetesRootCert(ctx) - if err != nil { - return nil, fmt.Errorf("loading ca.crt file: %w", err) - } - a.log.Info("ca.crt loaded") - joinToken, err := a.getJoinToken(config.DefaultTimeout, caFileContentPem) - if err != nil { - return nil, err - } - a.log.Info("join token generated") - return joinToken, nil + return nil } // establishClientGoConnection configures the client-go connection. diff --git a/cli/infrastructure/qemu/block.go b/cli/infrastructure/qemu/block.go index 95c4f23..01e8ba4 100644 --- a/cli/infrastructure/qemu/block.go +++ b/cli/infrastructure/qemu/block.go @@ -10,7 +10,7 @@ import ( "net" "time" - "github.com/benschlueter/delegatio/agent/vmapi/vmproto" + "github.com/benschlueter/delegatio/agent/manageapi/manageproto" "github.com/benschlueter/delegatio/internal/config" "github.com/benschlueter/delegatio/internal/config/definitions" "go.uber.org/zap" @@ -105,14 +105,14 @@ func (l *LibvirtInstance) blockUntilDelegatioAgentIsReady(ctx context.Context, i return err } defer conn.Close() - client := vmproto.NewAPIClient(conn) + client := manageproto.NewAPIClient(conn) for { select { case <-ctx.Done(): l.Log.Info("context cancel during waiting for vm init") return ctx.Err() default: - _, err := client.ExecCommand(ctx, &vmproto.ExecCommandRequest{ + _, err := client.ExecCommand(ctx, &manageproto.ExecCommandRequest{ Command: "hostnamectl", Args: []string{"set-hostname", id}, }) diff --git a/container/challenges/testing/Dockerfile.archlinux b/container/challenges/testing/Dockerfile.archlinux index d384840..2c8d032 100644 --- a/container/challenges/testing/Dockerfile.archlinux +++ b/container/challenges/testing/Dockerfile.archlinux @@ -8,7 +8,7 @@ RUN go mod download COPY ./ /delegatio -WORKDIR /delegatio/agent/server +WORKDIR /delegatio/agent/container RUN go build -o agent . WORKDIR /delegatio/grader/user @@ -19,7 +19,7 @@ FROM archlinux:latest RUN useradd -d /home/user -s /bin/bash -u 1001 user -COPY --from=0 /delegatio/agent/server/agent / +COPY --from=0 /delegatio/agent/container/agent / COPY --from=0 /delegatio/grader/user/agent-user / RUN pacman -Syy #RUN pacman -Sy --noconfirm archlinux-keyring diff --git a/haproxy.cfg b/haproxy.cfg index b5dac7b..9dad4df 100644 --- a/haproxy.cfg +++ b/haproxy.cfg @@ -42,6 +42,8 @@ backend apiserverbackend mode tcp balance roundrobin server delegatio-master-0 delegatio-master-0:6443 check + server delegatio-master-1 delegatio-master-1:6443 check + server delegatio-master-2 delegatio-master-2:6443 check #--------------------------------------------------------------------- # apiserver frontend which proxys to the control plane nodes #--------------------------------------------------------------------- @@ -73,4 +75,6 @@ backend etcdserverbackend mode tcp balance roundrobin server delegatio-master-0 delegatio-master-0:2379 check + server delegatio-master-1 delegatio-master-1:2379 check + server delegatio-master-2 delegatio-master-2:2379 check diff --git a/ssh/kubernetes/api.go b/ssh/kubernetes/api.go index 8ce0cd8..ef1f174 100644 --- a/ssh/kubernetes/api.go +++ b/ssh/kubernetes/api.go @@ -10,8 +10,8 @@ import ( "net" "time" - "github.com/benschlueter/delegatio/agent/core" - "github.com/benschlueter/delegatio/agent/vmapi" + "github.com/benschlueter/delegatio/agent/container/containerapi" + "github.com/benschlueter/delegatio/agent/container/core" "github.com/benschlueter/delegatio/internal/config" "github.com/benschlueter/delegatio/internal/k8sapi" "github.com/benschlueter/delegatio/internal/store" @@ -29,7 +29,7 @@ type K8sAPI interface { // K8sAPIWrapper is the struct used to access kubernetes helpers. type K8sAPIWrapper struct { Client *k8sapi.Client - API *vmapi.API + API containerapi.ContainerAPI logger *zap.Logger } @@ -42,11 +42,11 @@ func NewK8sAPIWrapper(logger *zap.Logger) (*K8sAPIWrapper, error) { return nil, err } // TODO: split core and vmapi into multiple packages / services - core, err := core.NewCore(logger, "") + core, err := core.NewCore(logger) if err != nil { return nil, err } - api := vmapi.New(logger, core, &net.Dialer{}) + api := containerapi.New(logger, core, &net.Dialer{}) return &K8sAPIWrapper{ Client: client,