From 94ff33b4c4cdaabc2aa4e57161107a83a38ae773 Mon Sep 17 00:00:00 2001 From: Spencer Smith Date: Wed, 5 May 2021 09:26:48 -0400 Subject: [PATCH] feat: enable auto-setup of BMC This PR will enable the ability to automatically configure a sidero user in the BMC if we can complete the process. It removes the need for users to configure this info per-server if enabled. Signed-off-by: Spencer Smith --- Dockerfile | 8 + .../config/rbac/role.yaml | 4 + .../controllers/metalmachine_controller.go | 2 +- .../api/v1alpha1/server_types.go | 27 +- .../api/v1alpha1/zz_generated.deepcopy.go | 19 +- .../cmd/agent/main.go | 189 ++++++- .../crd/bases/metal.sidero.dev_servers.yaml | 29 +- .../config/manager/manager.yaml | 1 + .../config/rbac/role.yaml | 12 + .../controllers/server_controller.go | 1 + .../internal/api/api.pb.go | 532 +++++++++++++----- .../internal/api/api.proto | 17 +- .../internal/api/api_grpc.pb.go | 37 ++ .../internal/power/ipmi/ipmi.go | 167 +++++- .../internal/power/metal/metal.go | 4 + .../internal/server/server.go | 125 +++- app/metal-controller-manager/main.go | 4 +- .../docs/v0.3/Configuration/servers.md | 6 +- .../docs/v0.3/Getting Started/installation.md | 1 + go.mod | 10 +- go.sum | 16 +- sfyra/go.sum | 9 +- 22 files changed, 1009 insertions(+), 211 deletions(-) diff --git a/Dockerfile b/Dockerfile index 84a9b2a6f..659ac644d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -136,6 +136,10 @@ RUN chmod +x /agent FROM base AS initramfs-archive-amd64 WORKDIR /initramfs +COPY --from=pkg-ca-certificates / . +COPY --from=pkg-musl / . +COPY --from=pkg-libressl / . +COPY --from=pkg-ipmitool / . COPY --from=agent-build-amd64 /agent ./init COPY --from=pkg-linux-firmware-amd64 /lib/firmware/bnx2 ./lib/firmware/bnx2 COPY --from=pkg-linux-firmware-amd64 /lib/firmware/bnx2x ./lib/firmware/bnx2x @@ -143,6 +147,10 @@ RUN set -o pipefail && find . 2>/dev/null | cpio -H newc -o | xz -v -C crc32 -0 FROM base AS initramfs-archive-arm64 WORKDIR /initramfs +COPY --from=pkg-ca-certificates / . +COPY --from=pkg-musl / . +COPY --from=pkg-libressl / . +COPY --from=pkg-ipmitool / . COPY --from=agent-build-arm64 /agent ./init COPY --from=pkg-linux-firmware-arm64 /lib/firmware/bnx2 ./lib/firmware/bnx2 COPY --from=pkg-linux-firmware-arm64 /lib/firmware/bnx2x ./lib/firmware/bnx2x diff --git a/app/cluster-api-provider-sidero/config/rbac/role.yaml b/app/cluster-api-provider-sidero/config/rbac/role.yaml index bca712099..923a7b8e5 100644 --- a/app/cluster-api-provider-sidero/config/rbac/role.yaml +++ b/app/cluster-api-provider-sidero/config/rbac/role.yaml @@ -18,8 +18,12 @@ rules: resources: - secrets verbs: + - create + - delete - get - list + - patch + - update - watch - apiGroups: - cluster.x-k8s.io diff --git a/app/cluster-api-provider-sidero/controllers/metalmachine_controller.go b/app/cluster-api-provider-sidero/controllers/metalmachine_controller.go index 5e5086930..125bf499f 100644 --- a/app/cluster-api-provider-sidero/controllers/metalmachine_controller.go +++ b/app/cluster-api-provider-sidero/controllers/metalmachine_controller.go @@ -51,7 +51,7 @@ type MetalMachineReconciler struct { // +kubebuilder:rbac:groups=metal.sidero.dev,resources=serverclasses/status,verbs=get;list;watch; // +kubebuilder:rbac:groups=metal.sidero.dev,resources=servers,verbs=get;list;watch; // +kubebuilder:rbac:groups=metal.sidero.dev,resources=servers/status,verbs=get;update;patch -// +kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch +// +kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups="",resources=events,verbs=create;patch func (r *MetalMachineReconciler) Reconcile(req ctrl.Request) (_ ctrl.Result, err error) { diff --git a/app/metal-controller-manager/api/v1alpha1/server_types.go b/app/metal-controller-manager/api/v1alpha1/server_types.go index 36d104cfe..4c8831907 100644 --- a/app/metal-controller-manager/api/v1alpha1/server_types.go +++ b/app/metal-controller-manager/api/v1alpha1/server_types.go @@ -11,6 +11,7 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha3" "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -34,13 +35,24 @@ type BMC struct { // Source for the password value. Cannot be used if Pass is not empty. // +optional PassFrom *CredentialSource `json:"passFrom,omitempty"` + // BMC Interface Type. Defaults to lanplus. + // +optional + Interface string `json:"interface,omitempty"` } // CredentialSource defines a reference to the credential value. type CredentialSource struct { - // Selects a key of a secret in the cluster namespace - // +optional - SecretKeyRef *corev1.SecretKeySelector `json:"secretKeyRef,omitempty"` + SecretKeyRef *SecretKeyRef `json:"secretKeyRef,omitempty"` +} + +// SecretKeyRef defines a ref to a given key within a secret. +type SecretKeyRef struct { + // Namespace and name of credential secret + // nb: can't use namespacedname here b/c it doesn't have json tags in the struct :( + Namespace string `json:"namespace"` + Name string `json:"name"` + // Key to select + Key string `json:"key"` } // Resolve the value using the references. @@ -55,7 +67,14 @@ func (source *CredentialSource) Resolve(ctx context.Context, reader client.Clien var secrets corev1.Secret - if err := reader.Get(ctx, client.ObjectKey{Namespace: corev1.NamespaceDefault, Name: source.SecretKeyRef.Name}, &secrets); err != nil { + if err := reader.Get( + ctx, + types.NamespacedName{ + Namespace: source.SecretKeyRef.Namespace, + Name: source.SecretKeyRef.Name, + }, + &secrets, + ); err != nil { return "", fmt.Errorf("error getting secret %q: %w", source.SecretKeyRef.Name, err) } diff --git a/app/metal-controller-manager/api/v1alpha1/zz_generated.deepcopy.go b/app/metal-controller-manager/api/v1alpha1/zz_generated.deepcopy.go index b81991fbe..6d49b0628 100644 --- a/app/metal-controller-manager/api/v1alpha1/zz_generated.deepcopy.go +++ b/app/metal-controller-manager/api/v1alpha1/zz_generated.deepcopy.go @@ -106,8 +106,8 @@ func (in *CredentialSource) DeepCopyInto(out *CredentialSource) { *out = *in if in.SecretKeyRef != nil { in, out := &in.SecretKeyRef, &out.SecretKeyRef - *out = new(v1.SecretKeySelector) - (*in).DeepCopyInto(*out) + *out = new(SecretKeyRef) + **out = **in } } @@ -307,6 +307,21 @@ func (in *Qualifiers) DeepCopy() *Qualifiers { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SecretKeyRef) DeepCopyInto(out *SecretKeyRef) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretKeyRef. +func (in *SecretKeyRef) DeepCopy() *SecretKeyRef { + if in == nil { + return nil + } + out := new(SecretKeyRef) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Server) DeepCopyInto(out *Server) { *out = *in diff --git a/app/metal-controller-manager/cmd/agent/main.go b/app/metal-controller-manager/cmd/agent/main.go index 3127f445d..5f01828a5 100644 --- a/app/metal-controller-manager/cmd/agent/main.go +++ b/app/metal-controller-manager/cmd/agent/main.go @@ -6,8 +6,11 @@ package main import ( "context" + "crypto/rand" + "errors" "fmt" "log" + "math/big" "net" "os" "sync" @@ -15,6 +18,7 @@ import ( "github.com/talos-systems/go-blockdevice/blockdevice" "github.com/talos-systems/go-blockdevice/blockdevice/util" + kmsg "github.com/talos-systems/go-kmsg" "github.com/talos-systems/go-procfs/procfs" "github.com/talos-systems/go-retry/retry" "github.com/talos-systems/go-smbios/smbios" @@ -23,7 +27,9 @@ import ( "golang.org/x/sys/unix" "google.golang.org/grpc" + "github.com/talos-systems/sidero/app/metal-controller-manager/api/v1alpha1" "github.com/talos-systems/sidero/app/metal-controller-manager/internal/api" + "github.com/talos-systems/sidero/app/metal-controller-manager/internal/power/ipmi" "github.com/talos-systems/sidero/app/metal-controller-manager/pkg/constants" ) @@ -68,14 +74,14 @@ func setup() error { return err } - kmsg, err := os.OpenFile("/dev/kmsg", os.O_RDWR|unix.O_CLOEXEC|unix.O_NONBLOCK|unix.O_NOCTTY, 0o666) - if err != nil { - return fmt.Errorf("failed to open /dev/kmsg: %w", err) + if err := kmsg.SetupLogger(nil, "[sidero]", nil); err != nil { + return err } - log.SetOutput(kmsg) - log.SetPrefix("[sidero]" + " ") - log.SetFlags(0) + // Set the PATH env var. + if err := os.Setenv("PATH", "/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin"); err != nil { + return errors.New("error setting PATH") + } return nil } @@ -239,6 +245,17 @@ func mainFunc() error { log.Println("Registration complete") + if createResp.GetSetupBmc() { + log.Println("Attempting to automatically discover and configure BMC") + + // nb: we don't consider failure to get BMC info a hard failure. + // users can always patch the bmc info to the server themselves. + err := attemptBMCSetup(ctx, client, s) + if err != nil { + log.Printf("encountered error setting up BMC. skipping setup: %q", err.Error()) + } + } + ips, err := talosnet.IPAddrs() if err != nil { log.Println("failed to discover IPs") @@ -349,3 +366,163 @@ func mainFunc() error { func main() { shutdown(mainFunc()) } + +func attemptBMCSetup(ctx context.Context, client api.AgentClient, s *smbios.SMBIOS) error { + uuid, err := s.SystemInformation().UUID() + if err != nil { + return err + } + + bmcInfo := &api.BMCInfo{} + + // Create "open" client + bmcSpec := v1alpha1.BMC{ + Interface: "open", + } + + ipmiClient, err := ipmi.NewClient(bmcSpec) + if err != nil { + return err + } + + // Fetch BMC IP + ipResp, err := ipmiClient.GetBMCIP() + if err != nil { + return err + } + + bmcIP := net.IP(ipResp.Data) + bmcInfo.Ip = bmcIP.String() + + // Get user summary to see how many user slots + summResp, err := ipmiClient.GetUserSummary() + if err != nil { + return err + } + + maxUsers := summResp.MaxUsers & 0x1F // Only bits [0:5] provide this number + + // Check if sidero user already exists by combing through all userIDs + // nb: we start looking at user id 2, because 1 should always be an unamed admin user and + // we don't want to confuse that unnamed admin with an open slot we can take over. + exists := false + sideroUserID := uint8(0) + + for i := uint8(2); i <= maxUsers; i++ { + userRes, err := ipmiClient.GetUserName(i) + if err != nil { + // nb: A failure here actually seems to mean that the user slot is unused, + // even though you can also have a slot with empty user as well. *scratches head* + // We'll take note of this spot if we haven't already found another empty one. + if sideroUserID == 0 { + sideroUserID = i + } + + continue + } + + // Found pre-existing sidero user + if userRes.Username == "sidero" { + exists = true + sideroUserID = i + log.Printf("Sidero user already present in slot %d. We'll claim it as our very own.\n", i) + + break + } else if userRes.Username == "" && sideroUserID == 0 { + // If this is the first empty user that's not the UID 1 (which we skip), + // we'll take this spot for sidero user + log.Printf("Found empty user slot %d. Noting as a possible place for sidero user.\n", i) + sideroUserID = i + } + } + + // User didn't pre-exist and there's no room + // Return without sidero user :( + if sideroUserID == 0 { + return errors.New("no slot available for sidero user") + } + + // Not already present and there's an empty slot so we add sidero user + if !exists { + log.Printf("Adding sidero user to slot %d\n", sideroUserID) + + _, err := ipmiClient.SetUserName(sideroUserID, "sidero") + if err != nil { + return err + } + } + + // Reset pass for sidero user + // nb: we _always_ reset the user pass because we can't ever get + // it back out when we find an existing sidero user. + pass, err := genPass16() + if err != nil { + return err + } + + _, err = ipmiClient.SetUserPass(sideroUserID, pass) + if err != nil { + return err + } + + // Make sidero an admin + // Options: 0xD1 == Callin false, Link false, IPMI Msg true, Channel 1 + // Limits: 0x03 == Administrator + // Session: 0x00 No session limit + _, err = ipmiClient.SetUserAccess(0xD1, sideroUserID, 0x04, 0x00) + if err != nil { + return err + } + + // Enable the sidero user + _, err = ipmiClient.EnableUser(sideroUserID) + if err != nil { + return err + } + + // Finally fill in info for update request + bmcInfo.User = "sidero" + bmcInfo.Pass = pass + + // Attempt to update server object + err = retry.Constant(5*time.Minute, retry.WithUnits(30*time.Second), retry.WithErrorLogging(true)).Retry(func() error { + ctx, cancel := context.WithTimeout(ctx, 30*time.Second) + defer cancel() + + _, err = client.UpdateBMCInfo( + ctx, + &api.UpdateBMCInfoRequest{ + Uuid: uuid.String(), + BmcInfo: bmcInfo, + }, + ) + + if err != nil { + return retry.ExpectedError(err) + } + + return nil + }) + + return nil +} + +// Returns a random pass string of len 16. +func genPass16() (string, error) { + letterRunes := []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") + + b := make([]rune, 16) + for i := range b { + rando, err := rand.Int( + rand.Reader, + big.NewInt(int64(len(letterRunes))), + ) + if err != nil { + return "", err + } + + b[i] = letterRunes[rando.Int64()] + } + + return string(b), nil +} diff --git a/app/metal-controller-manager/config/crd/bases/metal.sidero.dev_servers.yaml b/app/metal-controller-manager/config/crd/bases/metal.sidero.dev_servers.yaml index ea5c50069..3cfcc08ef 100644 --- a/app/metal-controller-manager/config/crd/bases/metal.sidero.dev_servers.yaml +++ b/app/metal-controller-manager/config/crd/bases/metal.sidero.dev_servers.yaml @@ -61,6 +61,9 @@ spec: endpoint: description: BMC endpoint. type: string + interface: + description: BMC Interface Type. Defaults to lanplus. + type: string pass: description: BMC password value. type: string @@ -68,19 +71,20 @@ spec: description: Source for the password value. Cannot be used if Pass is not empty. properties: secretKeyRef: - description: Selects a key of a secret in the cluster namespace + description: SecretKeyRef defines a ref to a given key within a secret properties: key: - description: The key of the secret to select from. Must be a valid secret key. + description: Key to select type: string name: - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' type: string - optional: - description: Specify whether the Secret or its key must be defined - type: boolean + namespace: + description: 'Namespace and name of credential secret nb: can''t use namespacedname here b/c it doesn''t have json tags in the struct :(' + type: string required: - key + - name + - namespace type: object type: object user: @@ -90,19 +94,20 @@ spec: description: Source for the user value. Cannot be used if User is not empty. properties: secretKeyRef: - description: Selects a key of a secret in the cluster namespace + description: SecretKeyRef defines a ref to a given key within a secret properties: key: - description: The key of the secret to select from. Must be a valid secret key. + description: Key to select type: string name: - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' type: string - optional: - description: Specify whether the Secret or its key must be defined - type: boolean + namespace: + description: 'Namespace and name of credential secret nb: can''t use namespacedname here b/c it doesn''t have json tags in the struct :(' + type: string required: - key + - name + - namespace type: object type: object required: diff --git a/app/metal-controller-manager/config/manager/manager.yaml b/app/metal-controller-manager/config/manager/manager.yaml index 71196490c..88674197e 100644 --- a/app/metal-controller-manager/config/manager/manager.yaml +++ b/app/metal-controller-manager/config/manager/manager.yaml @@ -64,6 +64,7 @@ spec: - --extra-agent-kernel-args=${SIDERO_CONTROLLER_MANAGER_EXTRA_AGENT_KERNEL_ARGS:=-} - --auto-accept-servers=${SIDERO_CONTROLLER_MANAGER_AUTO_ACCEPT_SERVERS:=false} - --insecure-wipe=${SIDERO_CONTROLLER_MANAGER_INSECURE_WIPE:=true} + - --auto-bmc-setup=${SIDERO_CONTROLLER_MANAGER_AUTO_BMC_SETUP:=true} - --server-reboot-timeout=${SIDERO_CONTROLLER_MANAGER_SERVER_REBOOT_TIMEOUT:=20m} - --test-power-simulated-explicit-failure-prob=${SIDERO_CONTROLLER_MANAGER_TEST_POWER_EXPLICIT_FAILURE:=0} - --test-power-simulated-silent-failure-prob=${SIDERO_CONTROLLER_MANAGER_TEST_POWER_SILENT_FAILURE:=0} diff --git a/app/metal-controller-manager/config/rbac/role.yaml b/app/metal-controller-manager/config/rbac/role.yaml index 6df2ff9e2..483594ae1 100644 --- a/app/metal-controller-manager/config/rbac/role.yaml +++ b/app/metal-controller-manager/config/rbac/role.yaml @@ -13,6 +13,18 @@ rules: verbs: - create - patch +- apiGroups: + - "" + resources: + - secrets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch - apiGroups: - infrastructure.cluster.x-k8s.io resources: diff --git a/app/metal-controller-manager/controllers/server_controller.go b/app/metal-controller-manager/controllers/server_controller.go index 9c212f27f..e73cd4d21 100644 --- a/app/metal-controller-manager/controllers/server_controller.go +++ b/app/metal-controller-manager/controllers/server_controller.go @@ -58,6 +58,7 @@ type ServerReconciler struct { // +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=metalmachines,verbs=get;list;watch // +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=metalmachines/status,verbs=get // +kubebuilder:rbac:groups="",resources=events,verbs=create;patch +// +kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch;create;update;patch;delete func (r *ServerReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) { ctx := context.Background() diff --git a/app/metal-controller-manager/internal/api/api.pb.go b/app/metal-controller-manager/internal/api/api.pb.go index fc9e8ebd4..faac2f9f8 100644 --- a/app/metal-controller-manager/internal/api/api.pb.go +++ b/app/metal-controller-manager/internal/api/api.pb.go @@ -21,6 +21,69 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +type BMCInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Ip string `protobuf:"bytes,1,opt,name=ip,proto3" json:"ip,omitempty"` + User string `protobuf:"bytes,2,opt,name=user,proto3" json:"user,omitempty"` + Pass string `protobuf:"bytes,3,opt,name=pass,proto3" json:"pass,omitempty"` +} + +func (x *BMCInfo) Reset() { + *x = BMCInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BMCInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BMCInfo) ProtoMessage() {} + +func (x *BMCInfo) ProtoReflect() protoreflect.Message { + mi := &file_api_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 BMCInfo.ProtoReflect.Descriptor instead. +func (*BMCInfo) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{0} +} + +func (x *BMCInfo) GetIp() string { + if x != nil { + return x.Ip + } + return "" +} + +func (x *BMCInfo) GetUser() string { + if x != nil { + return x.User + } + return "" +} + +func (x *BMCInfo) GetPass() string { + if x != nil { + return x.Pass + } + return "" +} + type SystemInformation struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -38,7 +101,7 @@ type SystemInformation struct { func (x *SystemInformation) Reset() { *x = SystemInformation{} if protoimpl.UnsafeEnabled { - mi := &file_api_proto_msgTypes[0] + mi := &file_api_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -51,7 +114,7 @@ func (x *SystemInformation) String() string { func (*SystemInformation) ProtoMessage() {} func (x *SystemInformation) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_msgTypes[0] + mi := &file_api_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -64,7 +127,7 @@ func (x *SystemInformation) ProtoReflect() protoreflect.Message { // Deprecated: Use SystemInformation.ProtoReflect.Descriptor instead. func (*SystemInformation) Descriptor() ([]byte, []int) { - return file_api_proto_rawDescGZIP(), []int{0} + return file_api_proto_rawDescGZIP(), []int{1} } func (x *SystemInformation) GetUuid() string { @@ -128,7 +191,7 @@ type CPU struct { func (x *CPU) Reset() { *x = CPU{} if protoimpl.UnsafeEnabled { - mi := &file_api_proto_msgTypes[1] + mi := &file_api_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -141,7 +204,7 @@ func (x *CPU) String() string { func (*CPU) ProtoMessage() {} func (x *CPU) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_msgTypes[1] + mi := &file_api_proto_msgTypes[2] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -154,7 +217,7 @@ func (x *CPU) ProtoReflect() protoreflect.Message { // Deprecated: Use CPU.ProtoReflect.Descriptor instead. func (*CPU) Descriptor() ([]byte, []int) { - return file_api_proto_rawDescGZIP(), []int{1} + return file_api_proto_rawDescGZIP(), []int{2} } func (x *CPU) GetManufacturer() string { @@ -184,7 +247,7 @@ type CreateServerRequest struct { func (x *CreateServerRequest) Reset() { *x = CreateServerRequest{} if protoimpl.UnsafeEnabled { - mi := &file_api_proto_msgTypes[2] + mi := &file_api_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -197,7 +260,7 @@ func (x *CreateServerRequest) String() string { func (*CreateServerRequest) ProtoMessage() {} func (x *CreateServerRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_msgTypes[2] + mi := &file_api_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -210,7 +273,7 @@ func (x *CreateServerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateServerRequest.ProtoReflect.Descriptor instead. func (*CreateServerRequest) Descriptor() ([]byte, []int) { - return file_api_proto_rawDescGZIP(), []int{2} + return file_api_proto_rawDescGZIP(), []int{3} } func (x *CreateServerRequest) GetSystemInformation() *SystemInformation { @@ -246,7 +309,7 @@ type Address struct { func (x *Address) Reset() { *x = Address{} if protoimpl.UnsafeEnabled { - mi := &file_api_proto_msgTypes[3] + mi := &file_api_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -259,7 +322,7 @@ func (x *Address) String() string { func (*Address) ProtoMessage() {} func (x *Address) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_msgTypes[3] + mi := &file_api_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -272,7 +335,7 @@ func (x *Address) ProtoReflect() protoreflect.Message { // Deprecated: Use Address.ProtoReflect.Descriptor instead. func (*Address) Descriptor() ([]byte, []int) { - return file_api_proto_rawDescGZIP(), []int{3} + return file_api_proto_rawDescGZIP(), []int{4} } func (x *Address) GetType() string { @@ -296,13 +359,14 @@ type CreateServerResponse struct { Wipe bool `protobuf:"varint,1,opt,name=wipe,proto3" json:"wipe,omitempty"` InsecureWipe bool `protobuf:"varint,2,opt,name=insecure_wipe,json=insecureWipe,proto3" json:"insecure_wipe,omitempty"` - RebootTimeout float64 `protobuf:"fixed64,3,opt,name=reboot_timeout,json=rebootTimeout,proto3" json:"reboot_timeout,omitempty"` + SetupBmc bool `protobuf:"varint,3,opt,name=setup_bmc,json=setupBmc,proto3" json:"setup_bmc,omitempty"` + RebootTimeout float64 `protobuf:"fixed64,4,opt,name=reboot_timeout,json=rebootTimeout,proto3" json:"reboot_timeout,omitempty"` } func (x *CreateServerResponse) Reset() { *x = CreateServerResponse{} if protoimpl.UnsafeEnabled { - mi := &file_api_proto_msgTypes[4] + mi := &file_api_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -315,7 +379,7 @@ func (x *CreateServerResponse) String() string { func (*CreateServerResponse) ProtoMessage() {} func (x *CreateServerResponse) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_msgTypes[4] + mi := &file_api_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -328,7 +392,7 @@ func (x *CreateServerResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateServerResponse.ProtoReflect.Descriptor instead. func (*CreateServerResponse) Descriptor() ([]byte, []int) { - return file_api_proto_rawDescGZIP(), []int{4} + return file_api_proto_rawDescGZIP(), []int{5} } func (x *CreateServerResponse) GetWipe() bool { @@ -345,6 +409,13 @@ func (x *CreateServerResponse) GetInsecureWipe() bool { return false } +func (x *CreateServerResponse) GetSetupBmc() bool { + if x != nil { + return x.SetupBmc + } + return false +} + func (x *CreateServerResponse) GetRebootTimeout() float64 { if x != nil { return x.RebootTimeout @@ -363,7 +434,7 @@ type MarkServerAsWipedRequest struct { func (x *MarkServerAsWipedRequest) Reset() { *x = MarkServerAsWipedRequest{} if protoimpl.UnsafeEnabled { - mi := &file_api_proto_msgTypes[5] + mi := &file_api_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -376,7 +447,7 @@ func (x *MarkServerAsWipedRequest) String() string { func (*MarkServerAsWipedRequest) ProtoMessage() {} func (x *MarkServerAsWipedRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_msgTypes[5] + mi := &file_api_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -389,7 +460,7 @@ func (x *MarkServerAsWipedRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use MarkServerAsWipedRequest.ProtoReflect.Descriptor instead. func (*MarkServerAsWipedRequest) Descriptor() ([]byte, []int) { - return file_api_proto_rawDescGZIP(), []int{5} + return file_api_proto_rawDescGZIP(), []int{6} } func (x *MarkServerAsWipedRequest) GetUuid() string { @@ -410,7 +481,7 @@ type HeartbeatRequest struct { func (x *HeartbeatRequest) Reset() { *x = HeartbeatRequest{} if protoimpl.UnsafeEnabled { - mi := &file_api_proto_msgTypes[6] + mi := &file_api_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -423,7 +494,7 @@ func (x *HeartbeatRequest) String() string { func (*HeartbeatRequest) ProtoMessage() {} func (x *HeartbeatRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_msgTypes[6] + mi := &file_api_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -436,7 +507,7 @@ func (x *HeartbeatRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use HeartbeatRequest.ProtoReflect.Descriptor instead. func (*HeartbeatRequest) Descriptor() ([]byte, []int) { - return file_api_proto_rawDescGZIP(), []int{6} + return file_api_proto_rawDescGZIP(), []int{7} } func (x *HeartbeatRequest) GetUuid() string { @@ -455,7 +526,7 @@ type MarkServerAsWipedResponse struct { func (x *MarkServerAsWipedResponse) Reset() { *x = MarkServerAsWipedResponse{} if protoimpl.UnsafeEnabled { - mi := &file_api_proto_msgTypes[7] + mi := &file_api_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -468,7 +539,7 @@ func (x *MarkServerAsWipedResponse) String() string { func (*MarkServerAsWipedResponse) ProtoMessage() {} func (x *MarkServerAsWipedResponse) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_msgTypes[7] + mi := &file_api_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -481,7 +552,7 @@ func (x *MarkServerAsWipedResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use MarkServerAsWipedResponse.ProtoReflect.Descriptor instead. func (*MarkServerAsWipedResponse) Descriptor() ([]byte, []int) { - return file_api_proto_rawDescGZIP(), []int{7} + return file_api_proto_rawDescGZIP(), []int{8} } type HeartbeatResponse struct { @@ -493,7 +564,7 @@ type HeartbeatResponse struct { func (x *HeartbeatResponse) Reset() { *x = HeartbeatResponse{} if protoimpl.UnsafeEnabled { - mi := &file_api_proto_msgTypes[8] + mi := &file_api_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -506,7 +577,7 @@ func (x *HeartbeatResponse) String() string { func (*HeartbeatResponse) ProtoMessage() {} func (x *HeartbeatResponse) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_msgTypes[8] + mi := &file_api_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -519,7 +590,100 @@ func (x *HeartbeatResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use HeartbeatResponse.ProtoReflect.Descriptor instead. func (*HeartbeatResponse) Descriptor() ([]byte, []int) { - return file_api_proto_rawDescGZIP(), []int{8} + return file_api_proto_rawDescGZIP(), []int{9} +} + +type UpdateBMCInfoRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Uuid string `protobuf:"bytes,1,opt,name=uuid,proto3" json:"uuid,omitempty"` + BmcInfo *BMCInfo `protobuf:"bytes,2,opt,name=bmc_info,json=bmcInfo,proto3" json:"bmc_info,omitempty"` +} + +func (x *UpdateBMCInfoRequest) Reset() { + *x = UpdateBMCInfoRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateBMCInfoRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateBMCInfoRequest) ProtoMessage() {} + +func (x *UpdateBMCInfoRequest) ProtoReflect() protoreflect.Message { + mi := &file_api_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 UpdateBMCInfoRequest.ProtoReflect.Descriptor instead. +func (*UpdateBMCInfoRequest) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{10} +} + +func (x *UpdateBMCInfoRequest) GetUuid() string { + if x != nil { + return x.Uuid + } + return "" +} + +func (x *UpdateBMCInfoRequest) GetBmcInfo() *BMCInfo { + if x != nil { + return x.BmcInfo + } + return nil +} + +type UpdateBMCInfoResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *UpdateBMCInfoResponse) Reset() { + *x = UpdateBMCInfoResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateBMCInfoResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateBMCInfoResponse) ProtoMessage() {} + +func (x *UpdateBMCInfoResponse) ProtoReflect() protoreflect.Message { + mi := &file_api_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 UpdateBMCInfoResponse.ProtoReflect.Descriptor instead. +func (*UpdateBMCInfoResponse) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{11} } type ReconcileServerAddressesRequest struct { @@ -534,7 +698,7 @@ type ReconcileServerAddressesRequest struct { func (x *ReconcileServerAddressesRequest) Reset() { *x = ReconcileServerAddressesRequest{} if protoimpl.UnsafeEnabled { - mi := &file_api_proto_msgTypes[9] + mi := &file_api_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -547,7 +711,7 @@ func (x *ReconcileServerAddressesRequest) String() string { func (*ReconcileServerAddressesRequest) ProtoMessage() {} func (x *ReconcileServerAddressesRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_msgTypes[9] + mi := &file_api_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -560,7 +724,7 @@ func (x *ReconcileServerAddressesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReconcileServerAddressesRequest.ProtoReflect.Descriptor instead. func (*ReconcileServerAddressesRequest) Descriptor() ([]byte, []int) { - return file_api_proto_rawDescGZIP(), []int{9} + return file_api_proto_rawDescGZIP(), []int{12} } func (x *ReconcileServerAddressesRequest) GetUuid() string { @@ -586,7 +750,7 @@ type ReconcileServerAddressesResponse struct { func (x *ReconcileServerAddressesResponse) Reset() { *x = ReconcileServerAddressesResponse{} if protoimpl.UnsafeEnabled { - mi := &file_api_proto_msgTypes[10] + mi := &file_api_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -599,7 +763,7 @@ func (x *ReconcileServerAddressesResponse) String() string { func (*ReconcileServerAddressesResponse) ProtoMessage() {} func (x *ReconcileServerAddressesResponse) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_msgTypes[10] + mi := &file_api_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -612,95 +776,113 @@ func (x *ReconcileServerAddressesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReconcileServerAddressesResponse.ProtoReflect.Descriptor instead. func (*ReconcileServerAddressesResponse) Descriptor() ([]byte, []int) { - return file_api_proto_rawDescGZIP(), []int{10} + return file_api_proto_rawDescGZIP(), []int{13} } var File_api_proto protoreflect.FileDescriptor var file_api_proto_rawDesc = []byte{ 0x0a, 0x09, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x03, 0x61, 0x70, 0x69, - 0x22, 0xe4, 0x01, 0x0a, 0x11, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x72, - 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x6d, 0x61, - 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0c, 0x6d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72, 0x65, 0x72, 0x12, 0x21, - 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x4e, 0x61, 0x6d, - 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x73, - 0x65, 0x72, 0x69, 0x61, 0x6c, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0c, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, - 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x6b, 0x75, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x6b, 0x75, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, - 0x16, 0x0a, 0x06, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x22, 0x43, 0x0a, 0x03, 0x43, 0x50, 0x55, 0x12, 0x22, - 0x0a, 0x0c, 0x6d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72, 0x65, 0x72, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72, - 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x94, 0x01, 0x0a, - 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x45, 0x0a, 0x12, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x69, - 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x49, 0x6e, 0x66, - 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x11, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, - 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x03, 0x63, - 0x70, 0x75, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, - 0x50, 0x55, 0x52, 0x03, 0x63, 0x70, 0x75, 0x12, 0x1a, 0x0a, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, - 0x61, 0x6d, 0x65, 0x22, 0x37, 0x0a, 0x07, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, - 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, - 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x76, 0x0a, 0x14, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x77, 0x69, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x04, 0x77, 0x69, 0x70, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e, 0x73, 0x65, - 0x63, 0x75, 0x72, 0x65, 0x5f, 0x77, 0x69, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x0c, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x57, 0x69, 0x70, 0x65, 0x12, 0x25, 0x0a, - 0x0e, 0x72, 0x65, 0x62, 0x6f, 0x6f, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0d, 0x72, 0x65, 0x62, 0x6f, 0x6f, 0x74, 0x54, 0x69, 0x6d, - 0x65, 0x6f, 0x75, 0x74, 0x22, 0x2e, 0x0a, 0x18, 0x4d, 0x61, 0x72, 0x6b, 0x53, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x41, 0x73, 0x57, 0x69, 0x70, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x75, 0x75, 0x69, 0x64, 0x22, 0x26, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, - 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64, 0x22, 0x1b, 0x0a, 0x19, - 0x4d, 0x61, 0x72, 0x6b, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x73, 0x57, 0x69, 0x70, 0x65, - 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x13, 0x0a, 0x11, 0x48, 0x65, 0x61, - 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5d, - 0x0a, 0x1f, 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x63, 0x69, 0x6c, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x22, 0x41, 0x0a, 0x07, 0x42, 0x4d, 0x43, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x75, + 0x73, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, + 0x12, 0x0a, 0x04, 0x70, 0x61, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, + 0x61, 0x73, 0x73, 0x22, 0xe4, 0x01, 0x0a, 0x11, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x49, 0x6e, + 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64, 0x12, 0x22, 0x0a, + 0x0c, 0x6d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72, 0x65, 0x72, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72, 0x65, + 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, + 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x23, + 0x0a, 0x0d, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x4e, 0x75, 0x6d, + 0x62, 0x65, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x6b, 0x75, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, + 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x6b, 0x75, 0x4e, 0x75, 0x6d, 0x62, + 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x22, 0x43, 0x0a, 0x03, 0x43, 0x50, + 0x55, 0x12, 0x22, 0x0a, 0x0c, 0x6d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72, 0x65, + 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, + 0x74, 0x75, 0x72, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, + 0x94, 0x01, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x45, 0x0a, 0x12, 0x73, 0x79, 0x73, 0x74, 0x65, + 0x6d, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, + 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x11, 0x73, 0x79, 0x73, + 0x74, 0x65, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, + 0x0a, 0x03, 0x63, 0x70, 0x75, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x43, 0x50, 0x55, 0x52, 0x03, 0x63, 0x70, 0x75, 0x12, 0x1a, 0x0a, 0x08, 0x68, 0x6f, + 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f, + 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x37, 0x0a, 0x07, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, + 0x93, 0x01, 0x0a, 0x14, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x77, 0x69, 0x70, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x77, 0x69, 0x70, 0x65, 0x12, 0x23, 0x0a, 0x0d, + 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x5f, 0x77, 0x69, 0x70, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x0c, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x57, 0x69, 0x70, + 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x65, 0x74, 0x75, 0x70, 0x5f, 0x62, 0x6d, 0x63, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x73, 0x65, 0x74, 0x75, 0x70, 0x42, 0x6d, 0x63, 0x12, 0x25, + 0x0a, 0x0e, 0x72, 0x65, 0x62, 0x6f, 0x6f, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0d, 0x72, 0x65, 0x62, 0x6f, 0x6f, 0x74, 0x54, 0x69, + 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x22, 0x2e, 0x0a, 0x18, 0x4d, 0x61, 0x72, 0x6b, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x41, 0x73, 0x57, 0x69, 0x70, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x75, 0x75, 0x69, 0x64, 0x12, 0x26, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x22, 0x0a, - 0x20, 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x63, 0x69, 0x6c, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x32, 0xc5, 0x02, 0x0a, 0x05, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x43, 0x0a, 0x0c, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x18, 0x2e, 0x61, 0x70, - 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x52, 0x0a, 0x11, 0x4d, 0x61, 0x72, 0x6b, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x73, - 0x57, 0x69, 0x70, 0x65, 0x64, 0x12, 0x1d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x61, 0x72, 0x6b, - 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x73, 0x57, 0x69, 0x70, 0x65, 0x64, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x61, 0x72, 0x6b, 0x53, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x73, 0x57, 0x69, 0x70, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x67, 0x0a, 0x18, 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x63, 0x69, 0x6c, - 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, - 0x12, 0x24, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x63, 0x69, 0x6c, 0x65, - 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x63, - 0x6f, 0x6e, 0x63, 0x69, 0x6c, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3a, 0x0a, - 0x09, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x12, 0x15, 0x2e, 0x61, 0x70, 0x69, - 0x2e, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, - 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x4b, 0x5a, 0x49, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x2d, 0x73, 0x79, - 0x73, 0x74, 0x65, 0x6d, 0x73, 0x2f, 0x73, 0x69, 0x64, 0x65, 0x72, 0x6f, 0x2f, 0x61, 0x70, 0x70, - 0x2f, 0x6d, 0x65, 0x74, 0x61, 0x6c, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, - 0x72, 0x2d, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, - 0x61, 0x6c, 0x2f, 0x61, 0x70, 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x04, 0x75, 0x75, 0x69, 0x64, 0x22, 0x26, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, + 0x61, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64, 0x22, 0x1b, 0x0a, + 0x19, 0x4d, 0x61, 0x72, 0x6b, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x73, 0x57, 0x69, 0x70, + 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x13, 0x0a, 0x11, 0x48, 0x65, + 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x53, 0x0a, 0x14, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x42, 0x4d, 0x43, 0x49, 0x6e, 0x66, 0x6f, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64, 0x12, 0x27, 0x0a, 0x08, 0x62, + 0x6d, 0x63, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, + 0x61, 0x70, 0x69, 0x2e, 0x42, 0x4d, 0x43, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x62, 0x6d, 0x63, + 0x49, 0x6e, 0x66, 0x6f, 0x22, 0x17, 0x0a, 0x15, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x42, 0x4d, + 0x43, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5d, 0x0a, + 0x1f, 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x63, 0x69, 0x6c, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x75, 0x75, 0x69, 0x64, 0x12, 0x26, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x22, 0x0a, 0x20, + 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x63, 0x69, 0x6c, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x32, 0x8d, 0x03, 0x0a, 0x05, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x43, 0x0a, 0x0c, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x18, 0x2e, 0x61, 0x70, 0x69, + 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x52, 0x0a, 0x11, 0x4d, 0x61, 0x72, 0x6b, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x73, 0x57, + 0x69, 0x70, 0x65, 0x64, 0x12, 0x1d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x61, 0x72, 0x6b, 0x53, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x73, 0x57, 0x69, 0x70, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x61, 0x72, 0x6b, 0x53, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x41, 0x73, 0x57, 0x69, 0x70, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x67, 0x0a, 0x18, 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x63, 0x69, 0x6c, 0x65, + 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, + 0x24, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x63, 0x69, 0x6c, 0x65, 0x53, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x63, 0x6f, + 0x6e, 0x63, 0x69, 0x6c, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3a, 0x0a, 0x09, + 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x12, 0x15, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x0d, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x42, 0x4d, 0x43, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x19, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x42, 0x4d, 0x43, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x42, 0x4d, 0x43, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x42, 0x4b, 0x5a, 0x49, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, + 0x61, 0x6c, 0x6f, 0x73, 0x2d, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x2f, 0x73, 0x69, 0x64, + 0x65, 0x72, 0x6f, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x6d, 0x65, 0x74, 0x61, 0x6c, 0x2d, 0x63, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2d, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, + 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x61, 0x70, 0x69, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -716,39 +898,45 @@ func file_api_proto_rawDescGZIP() []byte { } var ( - file_api_proto_msgTypes = make([]protoimpl.MessageInfo, 11) + file_api_proto_msgTypes = make([]protoimpl.MessageInfo, 14) file_api_proto_goTypes = []interface{}{ - (*SystemInformation)(nil), // 0: api.SystemInformation - (*CPU)(nil), // 1: api.CPU - (*CreateServerRequest)(nil), // 2: api.CreateServerRequest - (*Address)(nil), // 3: api.Address - (*CreateServerResponse)(nil), // 4: api.CreateServerResponse - (*MarkServerAsWipedRequest)(nil), // 5: api.MarkServerAsWipedRequest - (*HeartbeatRequest)(nil), // 6: api.HeartbeatRequest - (*MarkServerAsWipedResponse)(nil), // 7: api.MarkServerAsWipedResponse - (*HeartbeatResponse)(nil), // 8: api.HeartbeatResponse - (*ReconcileServerAddressesRequest)(nil), // 9: api.ReconcileServerAddressesRequest - (*ReconcileServerAddressesResponse)(nil), // 10: api.ReconcileServerAddressesResponse + (*BMCInfo)(nil), // 0: api.BMCInfo + (*SystemInformation)(nil), // 1: api.SystemInformation + (*CPU)(nil), // 2: api.CPU + (*CreateServerRequest)(nil), // 3: api.CreateServerRequest + (*Address)(nil), // 4: api.Address + (*CreateServerResponse)(nil), // 5: api.CreateServerResponse + (*MarkServerAsWipedRequest)(nil), // 6: api.MarkServerAsWipedRequest + (*HeartbeatRequest)(nil), // 7: api.HeartbeatRequest + (*MarkServerAsWipedResponse)(nil), // 8: api.MarkServerAsWipedResponse + (*HeartbeatResponse)(nil), // 9: api.HeartbeatResponse + (*UpdateBMCInfoRequest)(nil), // 10: api.UpdateBMCInfoRequest + (*UpdateBMCInfoResponse)(nil), // 11: api.UpdateBMCInfoResponse + (*ReconcileServerAddressesRequest)(nil), // 12: api.ReconcileServerAddressesRequest + (*ReconcileServerAddressesResponse)(nil), // 13: api.ReconcileServerAddressesResponse } ) var file_api_proto_depIdxs = []int32{ - 0, // 0: api.CreateServerRequest.system_information:type_name -> api.SystemInformation - 1, // 1: api.CreateServerRequest.cpu:type_name -> api.CPU - 3, // 2: api.ReconcileServerAddressesRequest.address:type_name -> api.Address - 2, // 3: api.Agent.CreateServer:input_type -> api.CreateServerRequest - 5, // 4: api.Agent.MarkServerAsWiped:input_type -> api.MarkServerAsWipedRequest - 9, // 5: api.Agent.ReconcileServerAddresses:input_type -> api.ReconcileServerAddressesRequest - 6, // 6: api.Agent.Heartbeat:input_type -> api.HeartbeatRequest - 4, // 7: api.Agent.CreateServer:output_type -> api.CreateServerResponse - 7, // 8: api.Agent.MarkServerAsWiped:output_type -> api.MarkServerAsWipedResponse - 10, // 9: api.Agent.ReconcileServerAddresses:output_type -> api.ReconcileServerAddressesResponse - 8, // 10: api.Agent.Heartbeat:output_type -> api.HeartbeatResponse - 7, // [7:11] is the sub-list for method output_type - 3, // [3:7] 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 + 1, // 0: api.CreateServerRequest.system_information:type_name -> api.SystemInformation + 2, // 1: api.CreateServerRequest.cpu:type_name -> api.CPU + 0, // 2: api.UpdateBMCInfoRequest.bmc_info:type_name -> api.BMCInfo + 4, // 3: api.ReconcileServerAddressesRequest.address:type_name -> api.Address + 3, // 4: api.Agent.CreateServer:input_type -> api.CreateServerRequest + 6, // 5: api.Agent.MarkServerAsWiped:input_type -> api.MarkServerAsWipedRequest + 12, // 6: api.Agent.ReconcileServerAddresses:input_type -> api.ReconcileServerAddressesRequest + 7, // 7: api.Agent.Heartbeat:input_type -> api.HeartbeatRequest + 10, // 8: api.Agent.UpdateBMCInfo:input_type -> api.UpdateBMCInfoRequest + 5, // 9: api.Agent.CreateServer:output_type -> api.CreateServerResponse + 8, // 10: api.Agent.MarkServerAsWiped:output_type -> api.MarkServerAsWipedResponse + 13, // 11: api.Agent.ReconcileServerAddresses:output_type -> api.ReconcileServerAddressesResponse + 9, // 12: api.Agent.Heartbeat:output_type -> api.HeartbeatResponse + 11, // 13: api.Agent.UpdateBMCInfo:output_type -> api.UpdateBMCInfoResponse + 9, // [9:14] is the sub-list for method output_type + 4, // [4:9] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name } func init() { file_api_proto_init() } @@ -758,7 +946,7 @@ func file_api_proto_init() { } if !protoimpl.UnsafeEnabled { file_api_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SystemInformation); i { + switch v := v.(*BMCInfo); i { case 0: return &v.state case 1: @@ -770,7 +958,7 @@ func file_api_proto_init() { } } file_api_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CPU); i { + switch v := v.(*SystemInformation); i { case 0: return &v.state case 1: @@ -782,7 +970,7 @@ func file_api_proto_init() { } } file_api_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateServerRequest); i { + switch v := v.(*CPU); i { case 0: return &v.state case 1: @@ -794,7 +982,7 @@ func file_api_proto_init() { } } file_api_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Address); i { + switch v := v.(*CreateServerRequest); i { case 0: return &v.state case 1: @@ -806,7 +994,7 @@ func file_api_proto_init() { } } file_api_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateServerResponse); i { + switch v := v.(*Address); i { case 0: return &v.state case 1: @@ -818,7 +1006,7 @@ func file_api_proto_init() { } } file_api_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MarkServerAsWipedRequest); i { + switch v := v.(*CreateServerResponse); i { case 0: return &v.state case 1: @@ -830,7 +1018,7 @@ func file_api_proto_init() { } } file_api_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*HeartbeatRequest); i { + switch v := v.(*MarkServerAsWipedRequest); i { case 0: return &v.state case 1: @@ -842,7 +1030,7 @@ func file_api_proto_init() { } } file_api_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MarkServerAsWipedResponse); i { + switch v := v.(*HeartbeatRequest); i { case 0: return &v.state case 1: @@ -854,7 +1042,7 @@ func file_api_proto_init() { } } file_api_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*HeartbeatResponse); i { + switch v := v.(*MarkServerAsWipedResponse); i { case 0: return &v.state case 1: @@ -866,7 +1054,7 @@ func file_api_proto_init() { } } file_api_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ReconcileServerAddressesRequest); i { + switch v := v.(*HeartbeatResponse); i { case 0: return &v.state case 1: @@ -878,6 +1066,42 @@ func file_api_proto_init() { } } file_api_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateBMCInfoRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateBMCInfoResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ReconcileServerAddressesRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ReconcileServerAddressesResponse); i { case 0: return &v.state @@ -896,7 +1120,7 @@ func file_api_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_api_proto_rawDesc, NumEnums: 0, - NumMessages: 11, + NumMessages: 14, NumExtensions: 0, NumServices: 1, }, diff --git a/app/metal-controller-manager/internal/api/api.proto b/app/metal-controller-manager/internal/api/api.proto index 0990a6d58..aff7e97f1 100644 --- a/app/metal-controller-manager/internal/api/api.proto +++ b/app/metal-controller-manager/internal/api/api.proto @@ -12,6 +12,13 @@ service Agent { rpc ReconcileServerAddresses(ReconcileServerAddressesRequest) returns(ReconcileServerAddressesResponse); rpc Heartbeat(HeartbeatRequest) returns(HeartbeatResponse); + rpc UpdateBMCInfo(UpdateBMCInfoRequest) returns(UpdateBMCInfoResponse); +} + +message BMCInfo { + string ip = 1; + string user = 2; + string pass = 3; } message SystemInformation { @@ -43,7 +50,8 @@ message Address { message CreateServerResponse { bool wipe = 1; bool insecure_wipe = 2; - double reboot_timeout = 3; + bool setup_bmc = 3; + double reboot_timeout = 4; } message MarkServerAsWipedRequest { string uuid = 1; } @@ -52,6 +60,13 @@ message HeartbeatRequest { string uuid = 1; } message MarkServerAsWipedResponse {} message HeartbeatResponse {} +message UpdateBMCInfoRequest { + string uuid = 1; + BMCInfo bmc_info = 2; +} + +message UpdateBMCInfoResponse {} + message ReconcileServerAddressesRequest { string uuid = 1; repeated Address address = 2; diff --git a/app/metal-controller-manager/internal/api/api_grpc.pb.go b/app/metal-controller-manager/internal/api/api_grpc.pb.go index 311de9b51..35b2c7993 100644 --- a/app/metal-controller-manager/internal/api/api_grpc.pb.go +++ b/app/metal-controller-manager/internal/api/api_grpc.pb.go @@ -23,6 +23,7 @@ type AgentClient interface { MarkServerAsWiped(ctx context.Context, in *MarkServerAsWipedRequest, opts ...grpc.CallOption) (*MarkServerAsWipedResponse, error) ReconcileServerAddresses(ctx context.Context, in *ReconcileServerAddressesRequest, opts ...grpc.CallOption) (*ReconcileServerAddressesResponse, error) Heartbeat(ctx context.Context, in *HeartbeatRequest, opts ...grpc.CallOption) (*HeartbeatResponse, error) + UpdateBMCInfo(ctx context.Context, in *UpdateBMCInfoRequest, opts ...grpc.CallOption) (*UpdateBMCInfoResponse, error) } type agentClient struct { @@ -69,6 +70,15 @@ func (c *agentClient) Heartbeat(ctx context.Context, in *HeartbeatRequest, opts return out, nil } +func (c *agentClient) UpdateBMCInfo(ctx context.Context, in *UpdateBMCInfoRequest, opts ...grpc.CallOption) (*UpdateBMCInfoResponse, error) { + out := new(UpdateBMCInfoResponse) + err := c.cc.Invoke(ctx, "/api.Agent/UpdateBMCInfo", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // AgentServer is the server API for Agent service. // All implementations must embed UnimplementedAgentServer // for forward compatibility @@ -77,6 +87,7 @@ type AgentServer interface { MarkServerAsWiped(context.Context, *MarkServerAsWipedRequest) (*MarkServerAsWipedResponse, error) ReconcileServerAddresses(context.Context, *ReconcileServerAddressesRequest) (*ReconcileServerAddressesResponse, error) Heartbeat(context.Context, *HeartbeatRequest) (*HeartbeatResponse, error) + UpdateBMCInfo(context.Context, *UpdateBMCInfoRequest) (*UpdateBMCInfoResponse, error) mustEmbedUnimplementedAgentServer() } @@ -98,6 +109,10 @@ func (UnimplementedAgentServer) ReconcileServerAddresses(context.Context, *Recon func (UnimplementedAgentServer) Heartbeat(context.Context, *HeartbeatRequest) (*HeartbeatResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Heartbeat not implemented") } + +func (UnimplementedAgentServer) UpdateBMCInfo(context.Context, *UpdateBMCInfoRequest) (*UpdateBMCInfoResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateBMCInfo not implemented") +} func (UnimplementedAgentServer) mustEmbedUnimplementedAgentServer() {} // UnsafeAgentServer may be embedded to opt out of forward compatibility for this service. @@ -183,6 +198,24 @@ func _Agent_Heartbeat_Handler(srv interface{}, ctx context.Context, dec func(int return interceptor(ctx, in, info, handler) } +func _Agent_UpdateBMCInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateBMCInfoRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AgentServer).UpdateBMCInfo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/api.Agent/UpdateBMCInfo", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AgentServer).UpdateBMCInfo(ctx, req.(*UpdateBMCInfoRequest)) + } + return interceptor(ctx, in, info, handler) +} + // Agent_ServiceDesc is the grpc.ServiceDesc for Agent service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -206,6 +239,10 @@ var Agent_ServiceDesc = grpc.ServiceDesc{ MethodName: "Heartbeat", Handler: _Agent_Heartbeat_Handler, }, + { + MethodName: "UpdateBMCInfo", + Handler: _Agent_UpdateBMCInfo_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "api.proto", diff --git a/app/metal-controller-manager/internal/power/ipmi/ipmi.go b/app/metal-controller-manager/internal/power/ipmi/ipmi.go index b539ebc49..c36309c1b 100644 --- a/app/metal-controller-manager/internal/power/ipmi/ipmi.go +++ b/app/metal-controller-manager/internal/power/ipmi/ipmi.go @@ -10,8 +10,9 @@ import ( metalv1alpha1 "github.com/talos-systems/sidero/app/metal-controller-manager/api/v1alpha1" ) -// Note (rsmitty): This pkg is pretty sparse right now, but I wanted to go ahead and create -// it in case we want to do something more complex w/ IPMI in the future. +// Link to the IPMI spec: https://www.intel.com/content/dam/www/public/us/en/documents/product-briefs/ipmi-second-gen-interface-spec-v2-rev1-1.pdf +// Referenced in some of the comments below +// Future TODO(rsmitty): support "channels" other than #1 // Client is a holder for the IPMIClient. type Client struct { @@ -24,7 +25,7 @@ func NewClient(bmcInfo metalv1alpha1.BMC) (*Client, error) { Hostname: bmcInfo.Endpoint, Username: bmcInfo.User, Password: bmcInfo.Pass, - Interface: "lanplus", + Interface: bmcInfo.Interface, } ipmiClient, err := goipmi.NewClient(conn) @@ -35,9 +36,6 @@ func NewClient(bmcInfo metalv1alpha1.BMC) (*Client, error) { return &Client{IPMIClient: ipmiClient}, nil } -// Note (rsmitty): I think checking this system power isn't really necessary, but we may want -// to make more complex power decisions later on. - // PowerOn will power on a given machine. func (c *Client) PowerOn() error { return c.IPMIClient.Control(goipmi.ControlPowerUp) @@ -86,6 +84,163 @@ func (c *Client) SetPXE() error { return c.IPMIClient.SetBootDeviceEFI(goipmi.BootDevicePxe) } +// GetLANConfig fetches LAN Config param 3 which contains BMC IP. (see 23.2). +func (c *Client) GetBMCIP() (*goipmi.LANConfigResponse, error) { + req := &goipmi.Request{ + NetworkFunction: goipmi.NetworkFunctionTransport, + Command: goipmi.CommandGetLANConfig, + Data: &goipmi.LANConfigRequest{ + ChannelNumber: 0x01, + Param: 0x03, + }, + } + + res := &goipmi.LANConfigResponse{} + + err := c.IPMIClient.Send(req, res) + if err != nil { + return nil, err + } + + return res, nil +} + +// +// User management functions +// + +// GetUserSummary returns stats about user table, including max users allowed. +func (c *Client) GetUserSummary() (*goipmi.GetUserSummaryResponse, error) { + req := &goipmi.Request{ + NetworkFunction: goipmi.NetworkFunctionApp, + Command: goipmi.CommandGetUserSummary, + Data: &goipmi.GetUserSummaryRequest{ + ChannelNumber: 0x01, + UserID: 0x01, + }, + } + + res := &goipmi.GetUserSummaryResponse{} + + err := c.IPMIClient.Send(req, res) + if err != nil { + return nil, err + } + + return res, nil +} + +// GetUserName fetches a un string given a uid. This is how we check if a user slot is available. +// nb: a "failure" here can actually mean that the slot is just open for use +// or you can also have a user with "" as the name which won't +// fail this check and is still open for use. +// (see 22.29). +func (c *Client) GetUserName(uid byte) (*goipmi.GetUserNameResponse, error) { + req := &goipmi.Request{ + NetworkFunction: goipmi.NetworkFunctionApp, + Command: goipmi.CommandGetUserName, + Data: &goipmi.GetUserNameRequest{ + UserID: uid, + }, + } + + res := &goipmi.GetUserNameResponse{} + + err := c.IPMIClient.Send(req, res) + if err != nil { + return nil, err + } + + return res, nil +} + +// SetUserName sets a string for the given uid (see 22.28). +func (c *Client) SetUserName(uid byte, name string) (*goipmi.SetUserNameResponse, error) { + req := &goipmi.Request{ + NetworkFunction: goipmi.NetworkFunctionApp, + Command: goipmi.CommandSetUserName, + Data: &goipmi.SetUserNameRequest{ + UserID: uid, + Username: name, + }, + } + + res := &goipmi.SetUserNameResponse{} + + err := c.IPMIClient.Send(req, res) + if err != nil { + return nil, err + } + + return res, nil +} + +// SetUserPass sets the password for a given uid (see 22.30). +// nb: This naively assumes you'll pass a 16 char or less pw string. +// The goipmi function does not support longer right now. +func (c *Client) SetUserPass(uid byte, pass string) (*goipmi.SetUserPassResponse, error) { + req := &goipmi.Request{ + NetworkFunction: goipmi.NetworkFunctionApp, + Command: goipmi.CommandSetUserPass, + Data: &goipmi.SetUserPassRequest{ + UserID: uid, + Pass: []byte(pass), + }, + } + + res := &goipmi.SetUserPassResponse{} + + err := c.IPMIClient.Send(req, res) + if err != nil { + return nil, err + } + + return res, nil +} + +// SetUserAccess tweaks the privileges for a given uid (see 22.26). +func (c *Client) SetUserAccess(options, uid, limits, session byte) (*goipmi.SetUserAccessResponse, error) { + req := &goipmi.Request{ + NetworkFunction: goipmi.NetworkFunctionApp, + Command: goipmi.CommandSetUserAccess, + Data: &goipmi.SetUserAccessRequest{ + AccessOptions: options, + UserID: uid, + UserLimits: limits, + UserSessionLimit: session, + }, + } + + res := &goipmi.SetUserAccessResponse{} + + err := c.IPMIClient.Send(req, res) + if err != nil { + return nil, err + } + + return res, nil +} + +// EnableUser sets a user as enabled. Actually the same underlying command as SetUserPass (see 22.30). +func (c *Client) EnableUser(uid byte) (*goipmi.EnableUserResponse, error) { + req := &goipmi.Request{ + NetworkFunction: goipmi.NetworkFunctionApp, + Command: goipmi.CommandEnableUser, + Data: &goipmi.EnableUserRequest{ + UserID: uid, + }, + } + + res := &goipmi.EnableUserResponse{} + + err := c.IPMIClient.Send(req, res) + if err != nil { + return nil, err + } + + return res, nil +} + // IsFake returns false. func (c *Client) IsFake() bool { return false diff --git a/app/metal-controller-manager/internal/power/metal/metal.go b/app/metal-controller-manager/internal/power/metal/metal.go index 148fa78d1..5942cd653 100644 --- a/app/metal-controller-manager/internal/power/metal/metal.go +++ b/app/metal-controller-manager/internal/power/metal/metal.go @@ -47,6 +47,10 @@ func NewManagementClient(ctx context.Context, client client.Client, spec *v1alph } } + if bmcSpec.Interface == "" { + bmcSpec.Interface = "lanplus" + } + return ipmi.NewClient(bmcSpec) case spec.ManagementAPI != nil: return api.NewClient(*spec.ManagementAPI) diff --git a/app/metal-controller-manager/internal/server/server.go b/app/metal-controller-manager/internal/server/server.go index 380fd4f81..4d414d019 100644 --- a/app/metal-controller-manager/internal/server/server.go +++ b/app/metal-controller-manager/internal/server/server.go @@ -15,7 +15,7 @@ import ( "google.golang.org/grpc" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/tools/record" @@ -38,6 +38,7 @@ type server struct { autoAccept bool insecureWipe bool + autoBMC bool c controllerclient.Client scheme *runtime.Scheme @@ -55,11 +56,11 @@ func (s *server) CreateServer(ctx context.Context, in *api.CreateServerRequest) } obj = &metalv1alpha1.Server{ - TypeMeta: v1.TypeMeta{ + TypeMeta: metav1.TypeMeta{ Kind: "Server", APIVersion: metalv1alpha1.GroupVersion.Version, }, - ObjectMeta: v1.ObjectMeta{ + ObjectMeta: metav1.ObjectMeta{ Name: in.GetSystemInformation().GetUuid(), }, Spec: metalv1alpha1.ServerSpec{ @@ -96,14 +97,26 @@ func (s *server) CreateServer(ctx context.Context, in *api.CreateServerRequest) resp := &api.CreateServerResponse{} - // Only return a wipe directive is the server is not clean *AND* it has been accepted. - // This avoids the possibility of a random device PXE booting against us, registering, then getting blown away. - if !obj.Status.IsClean && obj.Spec.Accepted { - log.Printf("Server %q needs wipe", obj.Name) + // Make BMC and wiping decisions only if server is accepted + // to avoid hijacking random devices that PXE boot against us. + if obj.Spec.Accepted { + // Respond to agent whether it should attempt bmc setup + // We will only tell it to attempt autoconfig if there's not already data there. + if obj.Spec.BMC == nil && s.autoBMC { + log.Printf("Server %q needs BMC setup", obj.Name) - resp.Wipe = true - resp.InsecureWipe = s.insecureWipe - resp.RebootTimeout = s.rebootTimeout.Seconds() + resp.SetupBmc = true + } + + // Only return a wipe directive is the server is not clean *AND* it has been accepted. + // This avoids the possibility of a random device PXE booting against us, registering, then getting blown away. + if !obj.Status.IsClean { + log.Printf("Server %q needs wipe", obj.Name) + + resp.Wipe = true + resp.InsecureWipe = s.insecureWipe + resp.RebootTimeout = s.rebootTimeout.Seconds() + } } return resp, nil @@ -258,7 +271,96 @@ func (s *server) Heartbeat(ctx context.Context, in *api.HeartbeatRequest) (*api. return resp, nil } -func Serve(c controllerclient.Client, recorder record.EventRecorder, scheme *runtime.Scheme, autoAccept, insecureWipe bool, rebootTimeout time.Duration) error { +func (s *server) UpdateBMCInfo(ctx context.Context, in *api.UpdateBMCInfoRequest) (*api.UpdateBMCInfoResponse, error) { + if in.GetBmcInfo() != nil { + bmcSecretName := in.GetUuid() + "-bmc" + + // Create or update creds secret + credsSecret := &corev1.Secret{} + exists := true + + // Fetch corresponding server + obj := &metalv1alpha1.Server{} + + if err := s.c.Get(ctx, types.NamespacedName{Name: in.GetUuid()}, obj); err != nil { + return nil, err + } + + // For auto-created BMC info, we will *always* drop the creds in default namespace + // This ensures they'll come along for the ride in a "default" clusterctl move based on our cluster templates. + if err := s.c.Get(ctx, types.NamespacedName{Namespace: corev1.NamespaceDefault, Name: bmcSecretName}, credsSecret); err != nil { + if !apierrors.IsNotFound(err) { + return nil, err + } + + log.Printf("BMC secret doesn't exist for server %q, creating.", in.GetUuid()) + + credsSecret.ObjectMeta = metav1.ObjectMeta{ + Namespace: corev1.NamespaceDefault, + Name: bmcSecretName, + OwnerReferences: []metav1.OwnerReference{ + *metav1.NewControllerRef(obj, metalv1alpha1.GroupVersion.WithKind("Server")), + }, + } + + exists = false + } + + credsSecret.Data = map[string][]byte{ + "user": []byte(in.GetBmcInfo().GetUser()), + "pass": []byte(in.GetBmcInfo().GetPass()), + } + + if exists { + if err := s.c.Update(ctx, credsSecret); err != nil { + return nil, err + } + } else { + if err := s.c.Create(ctx, credsSecret); err != nil { + return nil, err + } + } + + // Update server spec with pointers to endpoint and creds secret + + obj.Spec.BMC = &metalv1alpha1.BMC{ + Endpoint: in.GetBmcInfo().GetIp(), + UserFrom: &metalv1alpha1.CredentialSource{ + SecretKeyRef: &metalv1alpha1.SecretKeyRef{ + Namespace: corev1.NamespaceDefault, + Name: bmcSecretName, + Key: "user", + }, + }, + PassFrom: &metalv1alpha1.CredentialSource{ + SecretKeyRef: &metalv1alpha1.SecretKeyRef{ + Namespace: corev1.NamespaceDefault, + Name: bmcSecretName, + Key: "pass", + }, + }, + } + + log.Printf("Updating server %q with BMC info", in.GetUuid()) + + if err := s.c.Update(ctx, obj); err != nil { + return nil, err + } + + ref, err := reference.GetReference(s.scheme, obj) + if err != nil { + return nil, err + } + + s.recorder.Event(ref, corev1.EventTypeNormal, "BMC Update", "BMC info updated via API.") + } + + resp := &api.UpdateBMCInfoResponse{} + + return resp, nil +} + +func Serve(c controllerclient.Client, recorder record.EventRecorder, scheme *runtime.Scheme, autoAccept, insecureWipe, autoBMC bool, rebootTimeout time.Duration) error { lis, err := net.Listen("tcp", ":"+Port) if err != nil { return fmt.Errorf("failed to listen: %v", err) @@ -269,6 +371,7 @@ func Serve(c controllerclient.Client, recorder record.EventRecorder, scheme *run api.RegisterAgentServer(s, &server{ autoAccept: autoAccept, insecureWipe: insecureWipe, + autoBMC: autoBMC, c: c, scheme: scheme, recorder: recorder, diff --git a/app/metal-controller-manager/main.go b/app/metal-controller-manager/main.go index 224437281..773431cf6 100644 --- a/app/metal-controller-manager/main.go +++ b/app/metal-controller-manager/main.go @@ -58,6 +58,7 @@ func main() { enableLeaderElection bool autoAcceptServers bool insecureWipe bool + autoBMCSetup bool serverRebootTimeout time.Duration testPowerSimulatedExplicitFailureProb float64 @@ -70,6 +71,7 @@ func main() { flag.BoolVar(&enableLeaderElection, "enable-leader-election", true, "Enable leader election for controller manager. Enabling this will ensure there is only one active controller manager.") flag.BoolVar(&autoAcceptServers, "auto-accept-servers", false, "Add servers as 'accepted' when they register with Sidero API.") flag.BoolVar(&insecureWipe, "insecure-wipe", true, "Wipe head of the disk only (if false, wipe whole disk).") + flag.BoolVar(&autoBMCSetup, "auto-bmc-setup", true, "Attempt to setup BMC info automatically when agent boots.") flag.DurationVar(&serverRebootTimeout, "server-reboot-timeout", constants.DefaultServerRebootTimeout, "Timeout to wait for the server to restart and start wipe.") flag.Float64Var(&testPowerSimulatedExplicitFailureProb, "test-power-simulated-explicit-failure-prob", 0, "Test failure simulation setting.") flag.Float64Var(&testPowerSimulatedSilentFailureProb, "test-power-simulated-silent-failure-prob", 0, "Test failure simulation setting.") @@ -185,7 +187,7 @@ func main() { mgr.GetScheme(), corev1.EventSource{Component: "sidero-server"}) - if err := server.Serve(mgr.GetClient(), recorder, mgr.GetScheme(), autoAcceptServers, insecureWipe, serverRebootTimeout); err != nil { + if err := server.Serve(mgr.GetClient(), recorder, mgr.GetScheme(), autoAcceptServers, insecureWipe, autoBMCSetup, serverRebootTimeout); err != nil { setupLog.Error(err, "unable to start API server", "controller", "Environment") os.Exit(1) } diff --git a/docs/website/content/docs/v0.3/Configuration/servers.md b/docs/website/content/docs/v0.3/Configuration/servers.md index 3ff360a8d..0c66f647e 100644 --- a/docs/website/content/docs/v0.3/Configuration/servers.md +++ b/docs/website/content/docs/v0.3/Configuration/servers.md @@ -77,7 +77,7 @@ Sidero will never write to or wipe any disk on a computer which is not marked as This can be tedious for systems in which all attached computers should be considered to be under the control of Sidero. Thus, you may also choose to automatically accept any machine into Sidero on its discovery. Please keep in mind that this means that any newly-connected computer **WILL BE WIPED** automatically. -You can enable auto-acceptance by pasing the `--auto-accept-servers=true` flag to `sidero-controller-manager`. +You can enable auto-acceptance by passing the `--auto-accept-servers=true` flag to `sidero-controller-manager`. Once accepted, a server will be reset (all disks wiped) and then made available to Sidero. @@ -90,7 +90,9 @@ its exit. Sidero can use IPMI information to control `Server` power state, reboot servers and set boot order. -IMPI connection information can be set in the `Server` spec after initial registration: +IPMI information will be, by default, setup automatically if possible as part of the acceptance process. In this design, a "sidero" user will be added to the IPMI user list and a randomly generated password will be issued. This information is then squirreled away in a Kubernetes secret in the `sidero-system` namespace, with a name format of `-bmc`. Users wishing to turn off this feature can pass the `--auto-bmc-setup=false` flag to `sidero-controller-manager` + +IMPI connection information can also be set manually in the `Server` spec after initial registration: ```yaml apiVersion: metal.sidero.dev/v1alpha1 diff --git a/docs/website/content/docs/v0.3/Getting Started/installation.md b/docs/website/content/docs/v0.3/Getting Started/installation.md index 216c993ab..80bc3f4d3 100644 --- a/docs/website/content/docs/v0.3/Getting Started/installation.md +++ b/docs/website/content/docs/v0.3/Getting Started/installation.md @@ -20,6 +20,7 @@ variables or as variables in the `clusterctl` configuration: * `SIDERO_CONTROLLER_MANAGER_API_ENDPOINT` (empty): specifies the IP address controller manager can be reached on, defaults to the node IP * `SIDERO_CONTROLLER_MANAGER_EXTRA_AGENT_KERNEL_ARGS` (empty): specifies additional Linux kernel arguments for the Sidero agent (for example, different console settings) * `SIDERO_CONTROLLER_MANAGER_AUTO_ACCEPT_SERVERS` (`false`): automatically accept discovered servers, by default `.spec.accepted` should be changed to `true` to accept the server +* `SIDERO_CONTROLLER_MANAGER_AUTO_BMC_SETUP` (`true`): automatically attempt to configure the BMC with a `sidero` user that will be used for all IPMI tasks. * `SIDERO_CONTROLLER_MANAGER_INSECURE_WIPE` (`true`): wipe only the first megabyte of each disk on the server, otherwise wipe the full disk * `SIDERO_CONTROLLER_MANAGER_SERVER_REBOOT_TIMEOUT` (`20m`): timeout for the server reboot (how long it might take for the server to be rebooted before Sidero retries an IPMI reboot operation) * `SIDERO_METADATA_SERVER_HOST_NETWORK` (`false`): run `sidero-metadta-server` on host network diff --git a/go.mod b/go.mod index ee1885f59..bf381f2eb 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,10 @@ module github.com/talos-systems/sidero go 1.16 -replace sigs.k8s.io/cluster-api v0.3.12 => sigs.k8s.io/cluster-api v0.3.9 +replace ( + github.com/pensando/goipmi v0.0.0-20200303170213-e858ec1cf0b5 => github.com/talos-systems/goipmi v0.0.0-20210504182258-b54796c8d678 + sigs.k8s.io/cluster-api v0.3.12 => sigs.k8s.io/cluster-api v0.3.9 +) require ( github.com/evanphx/json-patch v4.9.0+incompatible @@ -19,6 +22,7 @@ require ( github.com/talos-systems/cluster-api-bootstrap-provider-talos v0.2.0-alpha.11 github.com/talos-systems/cluster-api-control-plane-provider-talos v0.1.0-alpha.11 github.com/talos-systems/go-blockdevice v0.1.1-0.20201218174450-f2728a581972 + github.com/talos-systems/go-kmsg v0.1.0 github.com/talos-systems/go-procfs v0.0.0-20210108152626-8cbc42d3dc24 github.com/talos-systems/go-retry v0.2.0 github.com/talos-systems/go-smbios v0.0.0-20210422124317-d3a32bea731a @@ -26,8 +30,10 @@ require ( github.com/talos-systems/talos/pkg/machinery v0.0.0-20210416105550-2b83440d6f7f // v0.9.3 go.uber.org/zap v1.16.0 // indirect golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392 // indirect + golang.org/x/mod v0.4.0 // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c - golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 + golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6 + golang.org/x/tools v0.0.0-20210101214203-2dba1e4ea05c // indirect google.golang.org/grpc v1.37.0 google.golang.org/protobuf v1.26.0 k8s.io/api v0.19.3 diff --git a/go.sum b/go.sum index 469b3a114..9d8ca1a14 100644 --- a/go.sum +++ b/go.sum @@ -396,8 +396,6 @@ github.com/opencontainers/runtime-spec v1.0.3-0.20200728170252-4d89ac9fbff6/go.m github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys= -github.com/pensando/goipmi v0.0.0-20200303170213-e858ec1cf0b5 h1:a41wKpVAU/3/GhwOsZpPl6f+WUR2c5vCFl1djHEOf+Q= -github.com/pensando/goipmi v0.0.0-20200303170213-e858ec1cf0b5/go.mod h1:QLBJjgtBVGb/ASpeJtyLLswnrdesGrNWMDpPmzDyfKM= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pin/tftp v2.1.1-0.20200117065540-2f79be2dba4e+incompatible h1:zQDvVdw4rn2smQfJZwbD5FboCiiTgw/1lpER60easPM= github.com/pin/tftp v2.1.1-0.20200117065540-2f79be2dba4e+incompatible/go.mod h1:xVpZOMCXTy+A5QMjEVN0Glwa1sUvaJhFXbr/aAxuxGY= @@ -490,6 +488,8 @@ github.com/talos-systems/crypto v0.2.1-0.20210202170911-39584f1b6e54 h1:2IGs3f0q github.com/talos-systems/crypto v0.2.1-0.20210202170911-39584f1b6e54/go.mod h1:OXCK52Q0dzm88YRG4VdTBdidkPUtqrCxCyW7bUs4DAw= github.com/talos-systems/go-blockdevice v0.1.1-0.20201218174450-f2728a581972 h1:/yEPl6h6+pK9XIfQEiZ989GDuw6dCUBeinzUcCu6dyY= github.com/talos-systems/go-blockdevice v0.1.1-0.20201218174450-f2728a581972/go.mod h1:efEE9wjtgxiovqsZAV39xlOd/AOI/0sLuZqb5jEgeqo= +github.com/talos-systems/go-kmsg v0.1.0 h1:juoZn+XioduYvtie6nqi/miKGJPLYSBNXRv5jRe6+lE= +github.com/talos-systems/go-kmsg v0.1.0/go.mod h1:dppwQn+/mrdvsziGMbXjzfc4E+75oZhr39UIP6LgL0w= github.com/talos-systems/go-procfs v0.0.0-20210108152626-8cbc42d3dc24 h1:fN8vYvlB9XBQ5aImb1vLgR0ZaDwvfZfBMptqkpi3aEg= github.com/talos-systems/go-procfs v0.0.0-20210108152626-8cbc42d3dc24/go.mod h1:ATyUGFQIW8OnbnmvqefZWVPgL9g+CAmXHfkgny21xX8= github.com/talos-systems/go-retry v0.1.0/go.mod h1:HiXQqyVStZ35uSY/MTLWVvQVmC3lIW2MS5VdDaMtoKM= @@ -497,6 +497,8 @@ github.com/talos-systems/go-retry v0.2.0 h1:YpQHmtTZ2k0i/bBYRIasdVmF0XaiISVJUOrm github.com/talos-systems/go-retry v0.2.0/go.mod h1:HiXQqyVStZ35uSY/MTLWVvQVmC3lIW2MS5VdDaMtoKM= github.com/talos-systems/go-smbios v0.0.0-20210422124317-d3a32bea731a h1:uUAH6oFZwHdWRlHyBIsM8SEYU4fLM6KGu6bmPZOUKd8= github.com/talos-systems/go-smbios v0.0.0-20210422124317-d3a32bea731a/go.mod h1:HxhrzAoTZ7ed5Z5VvtCvnCIrOxyXDS7V2B5hCetAMW8= +github.com/talos-systems/goipmi v0.0.0-20210504182258-b54796c8d678 h1:udj668k0XBRUBVATjkgjUfW25OS4/aH9sZnMQkmCOXE= +github.com/talos-systems/goipmi v0.0.0-20210504182258-b54796c8d678/go.mod h1:Vr1Oadtcem03hG2RUT/dpSQS5md9d6rJ9nA0lUBC91Q= github.com/talos-systems/net v0.2.1-0.20210121122956-005a94f8b36b/go.mod h1:VreSAyRmxMtqussAHSKMKkJQa1YwBTSVfkmE4Jydam4= github.com/talos-systems/net v0.2.1-0.20210212213224-05190541b0fa h1:XqOMTt0Q6mjsk8Dea5wUpgcdtf+AzesH11m4AozWSxw= github.com/talos-systems/net v0.2.1-0.20210212213224-05190541b0fa/go.mod h1:VreSAyRmxMtqussAHSKMKkJQa1YwBTSVfkmE4Jydam4= @@ -584,8 +586,9 @@ golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKG golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0 h1:8pl+sMODzuvGJkmj2W4kZihvVb5mKm8pB/X44PIQHv8= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 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= @@ -674,8 +677,8 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201130171929-760e229fe7c5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 h1:dXfMednGJh/SUUFjTLsWJz3P+TQt9qnR11GgeI3vWKs= -golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6 h1:cdsMqa2nXzqlgs183pHxtvoVwU7CyzaCTAUOg94af4c= +golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -726,8 +729,9 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e h1:4nW4NLDYnU28ojHaHO8OVxFHk/aQ33U01a9cjED+pzE= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210101214203-2dba1e4ea05c h1:dS09fXwOFF9cXBnIzZexIuUBj95U1NyQjkEhkgidDow= +golang.org/x/tools v0.0.0-20210101214203-2dba1e4ea05c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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= diff --git a/sfyra/go.sum b/sfyra/go.sum index 6dd64c5ed..32e4f7c86 100644 --- a/sfyra/go.sum +++ b/sfyra/go.sum @@ -958,6 +958,7 @@ github.com/talos-systems/go-blockdevice v0.2.1-0.20210305142622-bb3ad73f6983 h1: github.com/talos-systems/go-blockdevice v0.2.1-0.20210305142622-bb3ad73f6983/go.mod h1:Wt0/JMsa+WysYRDlNo6fu9rdn/re73uRnktFWyVUqjs= github.com/talos-systems/go-cmd v0.0.0-20210216164758-68eb0067e0f0 h1:DI+BjK+fcrLBc70Fi50dZocQcaHosqsuWHrGHKp2NzE= github.com/talos-systems/go-cmd v0.0.0-20210216164758-68eb0067e0f0/go.mod h1:kf+rZzTEmlDiYQ6ulslvRONnKLQH8x83TowltGMhO+k= +github.com/talos-systems/go-kmsg v0.1.0/go.mod h1:dppwQn+/mrdvsziGMbXjzfc4E+75oZhr39UIP6LgL0w= github.com/talos-systems/go-loadbalancer v0.1.0/go.mod h1:D5Qjfz+29WVjONWECZvOkmaLsBb3f5YeWME0u/5HmIc= github.com/talos-systems/go-loadbalancer v0.1.1 h1:qjC0uWHu6O7VXG9EN4ovVPg79sRbypXTrJZJskdaa2k= github.com/talos-systems/go-loadbalancer v0.1.1/go.mod h1:L0uLhCBUQVkdBqtnxqbrw+wzopQyoeluPos8okqdxLo= @@ -1122,8 +1123,9 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0 h1:8pl+sMODzuvGJkmj2W4kZihvVb5mKm8pB/X44PIQHv8= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 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= @@ -1295,8 +1297,8 @@ golang.org/x/sys v0.0.0-20210123111255-9b0068b26619/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210301091718-77cc2087c03b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 h1:dXfMednGJh/SUUFjTLsWJz3P+TQt9qnR11GgeI3vWKs= -golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6 h1:cdsMqa2nXzqlgs183pHxtvoVwU7CyzaCTAUOg94af4c= +golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -1383,6 +1385,7 @@ golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210101214203-2dba1e4ea05c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=