diff --git a/doc/index.html b/doc/index.html index 5f1cbd5d..e64b4a49 100644 --- a/doc/index.html +++ b/doc/index.html @@ -1980,6 +1980,14 @@

Table of Contents

MUpdateBMCInfoResponse +
  • + MWaitForMachineEventRequest +
  • + +
  • + MWaitForMachineEventResponse +
  • + @@ -15621,6 +15629,20 @@

    UpdateBMCInfoResponse

    +

    WaitForMachineEventRequest

    +

    WaitForMachineEventRequest

    + + + + + +

    WaitForMachineEventResponse

    +

    WaitForMachineEventResponse

    + + + + + @@ -15642,6 +15664,13 @@

    BMCService

    UpdateBMCInfo

    + + WaitForMachineEvent + WaitForMachineEventRequest + WaitForMachineEventResponse stream +

    WaitForMachineEvent is called by the metal-bmc and is returned with a bmc command to execute.

    + + diff --git a/generate/go_client.tpl b/generate/go_client.tpl index c2ffaec9..3f076aeb 100644 --- a/generate/go_client.tpl +++ b/generate/go_client.tpl @@ -2,7 +2,6 @@ package client import ( - "context" "sync" "connectrpc.com/connect" @@ -53,33 +52,17 @@ func New(config *DialConfig) (Client, error) { interceptors: []connect.Interceptor{}, } - authInterceptor := connect.UnaryInterceptorFunc(func(next connect.UnaryFunc) connect.UnaryFunc { - return connect.UnaryFunc(func(ctx context.Context, request connect.AnyRequest) (connect.AnyResponse, error) { - request.Header().Add("Authorization", "Bearer "+config.Token) - return next(ctx, request) - }) - }) - - loggingInterceptor := connect.UnaryInterceptorFunc(func(next connect.UnaryFunc) connect.UnaryFunc { - return connect.UnaryFunc(func(ctx context.Context, request connect.AnyRequest) (connect.AnyResponse, error) { - config.Log.Debug("intercept", "request procedure", request.Spec().Procedure, "body", request.Any()) - response, err := next(ctx, request) - if err != nil { - return nil, err - } - config.Log.Debug("intercept", "request procedure", request.Spec().Procedure, "response", response.Any()) - return response, err - }) - }) - if config.Token != "" { + authInterceptor := &authInterceptor{config: config} c.interceptors = append(c.interceptors, authInterceptor) } if config.Log != nil { + loggingInterceptor := &loggingInterceptor{config: config} c.interceptors = append(c.interceptors, loggingInterceptor) } c.interceptors = append(c.interceptors, config.Interceptors...) + // TODO convert to interceptor go c.startTokenRenewal() return c, nil diff --git a/go.mod b/go.mod index b0c5974f..463acc71 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( buf.build/go/protovalidate v1.1.0 connectrpc.com/connect v1.19.1 github.com/bufbuild/protocompile v0.14.1 + github.com/davecgh/go-spew v1.1.1 github.com/go-task/slim-sprig/v3 v3.0.0 github.com/golang-jwt/jwt/v5 v5.3.0 github.com/google/go-cmp v0.7.0 @@ -18,7 +19,6 @@ require ( require ( cel.dev/expr v0.25.1 // indirect github.com/antlr4-go/antlr/v4 v4.13.1 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect github.com/google/cel-go v0.26.1 // indirect github.com/klauspost/compress v1.18.2 // indirect github.com/kr/pretty v0.3.1 // indirect diff --git a/go/client/client-interceptors.go b/go/client/client-interceptors.go new file mode 100644 index 00000000..0d9c678e --- /dev/null +++ b/go/client/client-interceptors.go @@ -0,0 +1,67 @@ +package client + +import ( + "context" + + "connectrpc.com/connect" +) + +// authinterceptor adds the required auth headers +type authInterceptor struct { + config *DialConfig +} + +func (i *authInterceptor) WrapUnary(next connect.UnaryFunc) connect.UnaryFunc { + return connect.UnaryFunc(func(ctx context.Context, request connect.AnyRequest) (connect.AnyResponse, error) { + request.Header().Add("Authorization", "Bearer "+i.config.Token) + return next(ctx, request) + }) +} + +func (i *authInterceptor) WrapStreamingClient(next connect.StreamingClientFunc) connect.StreamingClientFunc { + return func(ctx context.Context, spec connect.Spec) connect.StreamingClientConn { + return &streamingInterceptorConn{ + StreamingClientConn: next(ctx, spec), + token: i.config.Token, + } + } +} + +func (i *authInterceptor) WrapStreamingHandler(next connect.StreamingHandlerFunc) connect.StreamingHandlerFunc { + return next +} + +type streamingInterceptorConn struct { + connect.StreamingClientConn + token string +} + +func (conn *streamingInterceptorConn) Send(m any) error { + conn.RequestHeader().Add("Authorization", "Bearer "+conn.token) + return conn.StreamingClientConn.Send(m) +} + +type loggingInterceptor struct { + config *DialConfig +} + +func (i *loggingInterceptor) WrapUnary(next connect.UnaryFunc) connect.UnaryFunc { + return connect.UnaryFunc(func(ctx context.Context, request connect.AnyRequest) (connect.AnyResponse, error) { + i.config.Log.Debug("intercept", "request procedure", request.Spec().Procedure, "body", request.Any()) + response, err := next(ctx, request) + if err != nil { + return nil, err + } + i.config.Log.Debug("intercept", "request procedure", request.Spec().Procedure, "response", response.Any()) + return response, err + }) +} + +func (i *loggingInterceptor) WrapStreamingClient(next connect.StreamingClientFunc) connect.StreamingClientFunc { + // TODO also log here + return next +} + +func (i *loggingInterceptor) WrapStreamingHandler(next connect.StreamingHandlerFunc) connect.StreamingHandlerFunc { + return next +} diff --git a/go/client/client.go b/go/client/client.go index ff4d4730..374b5cc2 100755 --- a/go/client/client.go +++ b/go/client/client.go @@ -2,7 +2,6 @@ package client import ( - "context" "sync" "connectrpc.com/connect" @@ -114,33 +113,17 @@ func New(config *DialConfig) (Client, error) { interceptors: []connect.Interceptor{}, } - authInterceptor := connect.UnaryInterceptorFunc(func(next connect.UnaryFunc) connect.UnaryFunc { - return connect.UnaryFunc(func(ctx context.Context, request connect.AnyRequest) (connect.AnyResponse, error) { - request.Header().Add("Authorization", "Bearer "+config.Token) - return next(ctx, request) - }) - }) - - loggingInterceptor := connect.UnaryInterceptorFunc(func(next connect.UnaryFunc) connect.UnaryFunc { - return connect.UnaryFunc(func(ctx context.Context, request connect.AnyRequest) (connect.AnyResponse, error) { - config.Log.Debug("intercept", "request procedure", request.Spec().Procedure, "body", request.Any()) - response, err := next(ctx, request) - if err != nil { - return nil, err - } - config.Log.Debug("intercept", "request procedure", request.Spec().Procedure, "response", response.Any()) - return response, err - }) - }) - if config.Token != "" { + authInterceptor := &authInterceptor{config: config} c.interceptors = append(c.interceptors, authInterceptor) } if config.Log != nil { + loggingInterceptor := &loggingInterceptor{config: config} c.interceptors = append(c.interceptors, loggingInterceptor) } c.interceptors = append(c.interceptors, config.Interceptors...) + // TODO convert to interceptor go c.startTokenRenewal() return c, nil diff --git a/go/client/client_test.go b/go/client/client_test.go index 64cf3fe0..c5b1e3e4 100644 --- a/go/client/client_test.go +++ b/go/client/client_test.go @@ -20,6 +20,8 @@ import ( "github.com/metal-stack/api/go/client" apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" "github.com/metal-stack/api/go/metalstack/api/v2/apiv2connect" + infrav2 "github.com/metal-stack/api/go/metalstack/infra/v2" + "github.com/metal-stack/api/go/metalstack/infra/v2/infrav2connect" "github.com/stretchr/testify/require" ) @@ -155,3 +157,74 @@ func (m *mockTokenService) Revoke(context.Context, *apiv2.TokenServiceRevokeRequ func (m *mockTokenService) Update(context.Context, *apiv2.TokenServiceUpdateRequest) (*apiv2.TokenServiceUpdateResponse, error) { panic("unimplemented") } + +func Test_ClientInterceptors(t *testing.T) { + var ( + bs = &mockBMCService{} + mux = http.NewServeMux() + log = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug})) + ctx = t.Context() + ) + + mux.Handle(infrav2connect.NewBMCServiceHandler(bs)) + server := httptest.NewTLSServer(mux) + server.EnableHTTP2 = true + defer func() { + server.Close() + }() + + tokenString, err := generateToken(1 * time.Second) + require.NoError(t, err) + + c, err := client.New(&client.DialConfig{ + BaseURL: server.URL, + Token: tokenString, + Transport: server.Client().Transport, + Log: log, + }) + require.NoError(t, err) + + // Synchronous call has authheader set + resp, err := c.Infrav2().BMC().UpdateBMCInfo(ctx, &infrav2.UpdateBMCInfoRequest{}) + require.NoError(t, err) + require.NotNil(t, resp) + require.Equal(t, tokenString, bs.token) + bs.token = "" + + // Asynchronous call has authheader set + stream, err := c.Infrav2().BMC().WaitForMachineEvent(ctx, &infrav2.WaitForMachineEventRequest{}) + require.NoError(t, err) + require.NotNil(t, stream) + require.Equal(t, tokenString, bs.token) +} + +type mockBMCService struct { + token string +} + +func (m *mockBMCService) UpdateBMCInfo(ctx context.Context, _ *infrav2.UpdateBMCInfoRequest) (*infrav2.UpdateBMCInfoResponse, error) { + callinfo, _ := connect.CallInfoForHandlerContext(ctx) + authHeader := callinfo.RequestHeader().Get("Authorization") + + _, token, found := strings.Cut(authHeader, "Bearer ") + + if !found { + return nil, fmt.Errorf("unable to extract token from header:%s", authHeader) + } + m.token = token + return &infrav2.UpdateBMCInfoResponse{}, nil +} + +func (m *mockBMCService) WaitForMachineEvent(ctx context.Context, _ *infrav2.WaitForMachineEventRequest, stream *connect.ServerStream[infrav2.WaitForMachineEventResponse]) error { + callinfo, _ := connect.CallInfoForHandlerContext(ctx) + authHeader := callinfo.RequestHeader().Get("Authorization") + + _, token, found := strings.Cut(authHeader, "Bearer ") + + if !found { + return fmt.Errorf("unable to extract token from header:%s", authHeader) + } + + m.token = token + return stream.Send(&infrav2.WaitForMachineEventResponse{}) +} diff --git a/go/metalstack/infra/v2/bmc.pb.go b/go/metalstack/infra/v2/bmc.pb.go index f5457b09..e0836a17 100644 --- a/go/metalstack/infra/v2/bmc.pb.go +++ b/go/metalstack/infra/v2/bmc.pb.go @@ -96,16 +96,93 @@ func (*UpdateBMCInfoResponse) Descriptor() ([]byte, []int) { return file_metalstack_infra_v2_bmc_proto_rawDescGZIP(), []int{1} } +// WaitForMachineEventRequest +type WaitForMachineEventRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *WaitForMachineEventRequest) Reset() { + *x = WaitForMachineEventRequest{} + mi := &file_metalstack_infra_v2_bmc_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *WaitForMachineEventRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WaitForMachineEventRequest) ProtoMessage() {} + +func (x *WaitForMachineEventRequest) ProtoReflect() protoreflect.Message { + mi := &file_metalstack_infra_v2_bmc_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WaitForMachineEventRequest.ProtoReflect.Descriptor instead. +func (*WaitForMachineEventRequest) Descriptor() ([]byte, []int) { + return file_metalstack_infra_v2_bmc_proto_rawDescGZIP(), []int{2} +} + +// WaitForMachineEventResponse +type WaitForMachineEventResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *WaitForMachineEventResponse) Reset() { + *x = WaitForMachineEventResponse{} + mi := &file_metalstack_infra_v2_bmc_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *WaitForMachineEventResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WaitForMachineEventResponse) ProtoMessage() {} + +func (x *WaitForMachineEventResponse) ProtoReflect() protoreflect.Message { + mi := &file_metalstack_infra_v2_bmc_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WaitForMachineEventResponse.ProtoReflect.Descriptor instead. +func (*WaitForMachineEventResponse) Descriptor() ([]byte, []int) { + return file_metalstack_infra_v2_bmc_proto_rawDescGZIP(), []int{3} +} + var File_metalstack_infra_v2_bmc_proto protoreflect.FileDescriptor const file_metalstack_infra_v2_bmc_proto_rawDesc = "" + "\n" + "\x1dmetalstack/infra/v2/bmc.proto\x12\x13metalstack.infra.v2\x1a\x1emetalstack/api/v2/common.proto\"\x16\n" + "\x14UpdateBMCInfoRequest\"\x17\n" + - "\x15UpdateBMCInfoResponse2\x7f\n" + + "\x15UpdateBMCInfoResponse\"\x1c\n" + + "\x1aWaitForMachineEventRequest\"\x1d\n" + + "\x1bWaitForMachineEventResponse2\x87\x02\n" + "\n" + "BMCService\x12q\n" + - "\rUpdateBMCInfo\x12).metalstack.infra.v2.UpdateBMCInfoRequest\x1a*.metalstack.infra.v2.UpdateBMCInfoResponse\"\t\xe0\xf3\x18\x02\xea\xf3\x18\x01\x01B\xcc\x01\n" + + "\rUpdateBMCInfo\x12).metalstack.infra.v2.UpdateBMCInfoRequest\x1a*.metalstack.infra.v2.UpdateBMCInfoResponse\"\t\xe0\xf3\x18\x02\xea\xf3\x18\x01\x01\x12\x85\x01\n" + + "\x13WaitForMachineEvent\x12/.metalstack.infra.v2.WaitForMachineEventRequest\x1a0.metalstack.infra.v2.WaitForMachineEventResponse\"\t\xe0\xf3\x18\x02\xea\xf3\x18\x01\x010\x01B\xcc\x01\n" + "\x17com.metalstack.infra.v2B\bBmcProtoP\x01Z9github.com/metal-stack/api/go/metalstack/infra/v2;infrav2\xa2\x02\x03MIX\xaa\x02\x13Metalstack.Infra.V2\xca\x02\x13Metalstack\\Infra\\V2\xe2\x02\x1fMetalstack\\Infra\\V2\\GPBMetadata\xea\x02\x15Metalstack::Infra::V2b\x06proto3" var ( @@ -120,16 +197,20 @@ func file_metalstack_infra_v2_bmc_proto_rawDescGZIP() []byte { return file_metalstack_infra_v2_bmc_proto_rawDescData } -var file_metalstack_infra_v2_bmc_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_metalstack_infra_v2_bmc_proto_msgTypes = make([]protoimpl.MessageInfo, 4) var file_metalstack_infra_v2_bmc_proto_goTypes = []any{ - (*UpdateBMCInfoRequest)(nil), // 0: metalstack.infra.v2.UpdateBMCInfoRequest - (*UpdateBMCInfoResponse)(nil), // 1: metalstack.infra.v2.UpdateBMCInfoResponse + (*UpdateBMCInfoRequest)(nil), // 0: metalstack.infra.v2.UpdateBMCInfoRequest + (*UpdateBMCInfoResponse)(nil), // 1: metalstack.infra.v2.UpdateBMCInfoResponse + (*WaitForMachineEventRequest)(nil), // 2: metalstack.infra.v2.WaitForMachineEventRequest + (*WaitForMachineEventResponse)(nil), // 3: metalstack.infra.v2.WaitForMachineEventResponse } var file_metalstack_infra_v2_bmc_proto_depIdxs = []int32{ 0, // 0: metalstack.infra.v2.BMCService.UpdateBMCInfo:input_type -> metalstack.infra.v2.UpdateBMCInfoRequest - 1, // 1: metalstack.infra.v2.BMCService.UpdateBMCInfo:output_type -> metalstack.infra.v2.UpdateBMCInfoResponse - 1, // [1:2] is the sub-list for method output_type - 0, // [0:1] is the sub-list for method input_type + 2, // 1: metalstack.infra.v2.BMCService.WaitForMachineEvent:input_type -> metalstack.infra.v2.WaitForMachineEventRequest + 1, // 2: metalstack.infra.v2.BMCService.UpdateBMCInfo:output_type -> metalstack.infra.v2.UpdateBMCInfoResponse + 3, // 3: metalstack.infra.v2.BMCService.WaitForMachineEvent:output_type -> metalstack.infra.v2.WaitForMachineEventResponse + 2, // [2:4] is the sub-list for method output_type + 0, // [0:2] is the sub-list for method input_type 0, // [0:0] is the sub-list for extension type_name 0, // [0:0] is the sub-list for extension extendee 0, // [0:0] is the sub-list for field type_name @@ -146,7 +227,7 @@ func file_metalstack_infra_v2_bmc_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_metalstack_infra_v2_bmc_proto_rawDesc), len(file_metalstack_infra_v2_bmc_proto_rawDesc)), NumEnums: 0, - NumMessages: 2, + NumMessages: 4, NumExtensions: 0, NumServices: 1, }, diff --git a/go/metalstack/infra/v2/infrav2connect/bmc.connect.go b/go/metalstack/infra/v2/infrav2connect/bmc.connect.go index 33234330..d4a2a591 100644 --- a/go/metalstack/infra/v2/infrav2connect/bmc.connect.go +++ b/go/metalstack/infra/v2/infrav2connect/bmc.connect.go @@ -36,12 +36,17 @@ const ( // BMCServiceUpdateBMCInfoProcedure is the fully-qualified name of the BMCService's UpdateBMCInfo // RPC. BMCServiceUpdateBMCInfoProcedure = "/metalstack.infra.v2.BMCService/UpdateBMCInfo" + // BMCServiceWaitForMachineEventProcedure is the fully-qualified name of the BMCService's + // WaitForMachineEvent RPC. + BMCServiceWaitForMachineEventProcedure = "/metalstack.infra.v2.BMCService/WaitForMachineEvent" ) // BMCServiceClient is a client for the metalstack.infra.v2.BMCService service. type BMCServiceClient interface { // UpdateBMCInfo UpdateBMCInfo(context.Context, *v2.UpdateBMCInfoRequest) (*v2.UpdateBMCInfoResponse, error) + // WaitForMachineEvent is called by the metal-bmc and is returned with a bmc command to execute. + WaitForMachineEvent(context.Context, *v2.WaitForMachineEventRequest) (*connect.ServerStreamForClient[v2.WaitForMachineEventResponse], error) } // NewBMCServiceClient constructs a client for the metalstack.infra.v2.BMCService service. By @@ -61,12 +66,19 @@ func NewBMCServiceClient(httpClient connect.HTTPClient, baseURL string, opts ... connect.WithSchema(bMCServiceMethods.ByName("UpdateBMCInfo")), connect.WithClientOptions(opts...), ), + waitForMachineEvent: connect.NewClient[v2.WaitForMachineEventRequest, v2.WaitForMachineEventResponse]( + httpClient, + baseURL+BMCServiceWaitForMachineEventProcedure, + connect.WithSchema(bMCServiceMethods.ByName("WaitForMachineEvent")), + connect.WithClientOptions(opts...), + ), } } // bMCServiceClient implements BMCServiceClient. type bMCServiceClient struct { - updateBMCInfo *connect.Client[v2.UpdateBMCInfoRequest, v2.UpdateBMCInfoResponse] + updateBMCInfo *connect.Client[v2.UpdateBMCInfoRequest, v2.UpdateBMCInfoResponse] + waitForMachineEvent *connect.Client[v2.WaitForMachineEventRequest, v2.WaitForMachineEventResponse] } // UpdateBMCInfo calls metalstack.infra.v2.BMCService.UpdateBMCInfo. @@ -78,10 +90,17 @@ func (c *bMCServiceClient) UpdateBMCInfo(ctx context.Context, req *v2.UpdateBMCI return nil, err } +// WaitForMachineEvent calls metalstack.infra.v2.BMCService.WaitForMachineEvent. +func (c *bMCServiceClient) WaitForMachineEvent(ctx context.Context, req *v2.WaitForMachineEventRequest) (*connect.ServerStreamForClient[v2.WaitForMachineEventResponse], error) { + return c.waitForMachineEvent.CallServerStream(ctx, connect.NewRequest(req)) +} + // BMCServiceHandler is an implementation of the metalstack.infra.v2.BMCService service. type BMCServiceHandler interface { // UpdateBMCInfo UpdateBMCInfo(context.Context, *v2.UpdateBMCInfoRequest) (*v2.UpdateBMCInfoResponse, error) + // WaitForMachineEvent is called by the metal-bmc and is returned with a bmc command to execute. + WaitForMachineEvent(context.Context, *v2.WaitForMachineEventRequest, *connect.ServerStream[v2.WaitForMachineEventResponse]) error } // NewBMCServiceHandler builds an HTTP handler from the service implementation. It returns the path @@ -97,10 +116,18 @@ func NewBMCServiceHandler(svc BMCServiceHandler, opts ...connect.HandlerOption) connect.WithSchema(bMCServiceMethods.ByName("UpdateBMCInfo")), connect.WithHandlerOptions(opts...), ) + bMCServiceWaitForMachineEventHandler := connect.NewServerStreamHandlerSimple( + BMCServiceWaitForMachineEventProcedure, + svc.WaitForMachineEvent, + connect.WithSchema(bMCServiceMethods.ByName("WaitForMachineEvent")), + connect.WithHandlerOptions(opts...), + ) return "/metalstack.infra.v2.BMCService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.URL.Path { case BMCServiceUpdateBMCInfoProcedure: bMCServiceUpdateBMCInfoHandler.ServeHTTP(w, r) + case BMCServiceWaitForMachineEventProcedure: + bMCServiceWaitForMachineEventHandler.ServeHTTP(w, r) default: http.NotFound(w, r) } @@ -113,3 +140,7 @@ type UnimplementedBMCServiceHandler struct{} func (UnimplementedBMCServiceHandler) UpdateBMCInfo(context.Context, *v2.UpdateBMCInfoRequest) (*v2.UpdateBMCInfoResponse, error) { return nil, connect.NewError(connect.CodeUnimplemented, errors.New("metalstack.infra.v2.BMCService.UpdateBMCInfo is not implemented")) } + +func (UnimplementedBMCServiceHandler) WaitForMachineEvent(context.Context, *v2.WaitForMachineEventRequest, *connect.ServerStream[v2.WaitForMachineEventResponse]) error { + return connect.NewError(connect.CodeUnimplemented, errors.New("metalstack.infra.v2.BMCService.WaitForMachineEvent is not implemented")) +} diff --git a/go/permissions/servicepermissions.go b/go/permissions/servicepermissions.go index d98d2474..e0bffa0b 100755 --- a/go/permissions/servicepermissions.go +++ b/go/permissions/servicepermissions.go @@ -100,6 +100,7 @@ func GetServicePermissions() *ServicePermissions { Infra: Infra{ "INFRA_ROLE_EDITOR": []string{ "/metalstack.infra.v2.BMCService/UpdateBMCInfo", + "/metalstack.infra.v2.BMCService/WaitForMachineEvent", "/metalstack.infra.v2.EventService/Send", "/metalstack.infra.v2.SwitchService/Get", "/metalstack.infra.v2.SwitchService/Register", @@ -298,6 +299,7 @@ func GetServicePermissions() *ServicePermissions { "/metalstack.api.v2.UserService/Get": true, "/metalstack.api.v2.VersionService/Get": true, "/metalstack.infra.v2.BMCService/UpdateBMCInfo": true, + "/metalstack.infra.v2.BMCService/WaitForMachineEvent": true, "/metalstack.infra.v2.EventService/Send": true, "/metalstack.infra.v2.SwitchService/Get": true, "/metalstack.infra.v2.SwitchService/Heartbeat": true, @@ -377,11 +379,12 @@ func GetServicePermissions() *ServicePermissions { "/metalstack.admin.v2.VPNService/ListNodes": true, }, Infra: map[string]bool{ - "/metalstack.infra.v2.BMCService/UpdateBMCInfo": true, - "/metalstack.infra.v2.EventService/Send": true, - "/metalstack.infra.v2.SwitchService/Get": true, - "/metalstack.infra.v2.SwitchService/Heartbeat": true, - "/metalstack.infra.v2.SwitchService/Register": true, + "/metalstack.infra.v2.BMCService/UpdateBMCInfo": true, + "/metalstack.infra.v2.BMCService/WaitForMachineEvent": true, + "/metalstack.infra.v2.EventService/Send": true, + "/metalstack.infra.v2.SwitchService/Get": true, + "/metalstack.infra.v2.SwitchService/Heartbeat": true, + "/metalstack.infra.v2.SwitchService/Register": true, }, Tenant: map[string]bool{ "/metalstack.api.v2.ProjectService/Create": true, @@ -424,110 +427,111 @@ func GetServicePermissions() *ServicePermissions { }, }, Auditable: map[string]bool{ - "/metalstack.admin.v2.FilesystemService/Create": true, - "/metalstack.admin.v2.FilesystemService/Delete": true, - "/metalstack.admin.v2.FilesystemService/Update": true, - "/metalstack.admin.v2.IPService/List": false, - "/metalstack.admin.v2.ImageService/Create": true, - "/metalstack.admin.v2.ImageService/Delete": true, - "/metalstack.admin.v2.ImageService/Update": true, - "/metalstack.admin.v2.ImageService/Usage": true, - "/metalstack.admin.v2.MachineService/Get": false, - "/metalstack.admin.v2.MachineService/List": false, - "/metalstack.admin.v2.NetworkService/Create": true, - "/metalstack.admin.v2.NetworkService/Delete": true, - "/metalstack.admin.v2.NetworkService/Get": false, - "/metalstack.admin.v2.NetworkService/List": false, - "/metalstack.admin.v2.NetworkService/Update": true, - "/metalstack.admin.v2.PartitionService/Capacity": false, - "/metalstack.admin.v2.PartitionService/Create": true, - "/metalstack.admin.v2.PartitionService/Delete": true, - "/metalstack.admin.v2.PartitionService/Update": true, - "/metalstack.admin.v2.ProjectService/List": false, - "/metalstack.admin.v2.SizeService/Create": true, - "/metalstack.admin.v2.SizeService/Delete": true, - "/metalstack.admin.v2.SizeService/Update": true, - "/metalstack.admin.v2.SwitchService/Delete": true, - "/metalstack.admin.v2.SwitchService/Get": false, - "/metalstack.admin.v2.SwitchService/List": false, - "/metalstack.admin.v2.SwitchService/Migrate": true, - "/metalstack.admin.v2.SwitchService/Port": true, - "/metalstack.admin.v2.SwitchService/Update": true, - "/metalstack.admin.v2.TenantService/Create": true, - "/metalstack.admin.v2.TenantService/List": true, - "/metalstack.admin.v2.TokenService/Create": true, - "/metalstack.admin.v2.TokenService/List": true, - "/metalstack.admin.v2.TokenService/Revoke": true, - "/metalstack.admin.v2.VPNService/AuthKey": true, - "/metalstack.admin.v2.VPNService/ListNodes": true, - "/metalstack.api.v2.FilesystemService/Get": false, - "/metalstack.api.v2.FilesystemService/List": false, - "/metalstack.api.v2.FilesystemService/Match": false, - "/metalstack.api.v2.HealthService/Get": false, - "/metalstack.api.v2.IPService/Create": true, - "/metalstack.api.v2.IPService/Delete": true, - "/metalstack.api.v2.IPService/Get": false, - "/metalstack.api.v2.IPService/List": false, - "/metalstack.api.v2.IPService/Update": true, - "/metalstack.api.v2.ImageService/Get": false, - "/metalstack.api.v2.ImageService/Latest": false, - "/metalstack.api.v2.ImageService/List": false, - "/metalstack.api.v2.MachineService/Create": true, - "/metalstack.api.v2.MachineService/Delete": true, - "/metalstack.api.v2.MachineService/Get": false, - "/metalstack.api.v2.MachineService/List": false, - "/metalstack.api.v2.MachineService/Update": true, - "/metalstack.api.v2.MethodService/List": true, - "/metalstack.api.v2.MethodService/TokenScopedList": true, - "/metalstack.api.v2.NetworkService/Create": true, - "/metalstack.api.v2.NetworkService/Delete": true, - "/metalstack.api.v2.NetworkService/Get": false, - "/metalstack.api.v2.NetworkService/List": false, - "/metalstack.api.v2.NetworkService/ListBaseNetworks": false, - "/metalstack.api.v2.NetworkService/Update": true, - "/metalstack.api.v2.PartitionService/Get": false, - "/metalstack.api.v2.PartitionService/List": false, - "/metalstack.api.v2.ProjectService/Create": true, - "/metalstack.api.v2.ProjectService/Delete": true, - "/metalstack.api.v2.ProjectService/Get": false, - "/metalstack.api.v2.ProjectService/Invite": true, - "/metalstack.api.v2.ProjectService/InviteAccept": true, - "/metalstack.api.v2.ProjectService/InviteDelete": true, - "/metalstack.api.v2.ProjectService/InviteGet": false, - "/metalstack.api.v2.ProjectService/InvitesList": false, - "/metalstack.api.v2.ProjectService/Leave": true, - "/metalstack.api.v2.ProjectService/List": false, - "/metalstack.api.v2.ProjectService/RemoveMember": true, - "/metalstack.api.v2.ProjectService/Update": true, - "/metalstack.api.v2.ProjectService/UpdateMember": true, - "/metalstack.api.v2.SizeService/Get": false, - "/metalstack.api.v2.SizeService/List": false, - "/metalstack.api.v2.TenantService/Create": true, - "/metalstack.api.v2.TenantService/Delete": true, - "/metalstack.api.v2.TenantService/Get": false, - "/metalstack.api.v2.TenantService/Invite": true, - "/metalstack.api.v2.TenantService/InviteAccept": true, - "/metalstack.api.v2.TenantService/InviteDelete": true, - "/metalstack.api.v2.TenantService/InviteGet": false, - "/metalstack.api.v2.TenantService/InvitesList": false, - "/metalstack.api.v2.TenantService/Leave": true, - "/metalstack.api.v2.TenantService/List": false, - "/metalstack.api.v2.TenantService/RemoveMember": true, - "/metalstack.api.v2.TenantService/Update": true, - "/metalstack.api.v2.TenantService/UpdateMember": true, - "/metalstack.api.v2.TokenService/Create": true, - "/metalstack.api.v2.TokenService/Get": true, - "/metalstack.api.v2.TokenService/List": true, - "/metalstack.api.v2.TokenService/Refresh": true, - "/metalstack.api.v2.TokenService/Revoke": true, - "/metalstack.api.v2.TokenService/Update": true, - "/metalstack.api.v2.UserService/Get": true, - "/metalstack.api.v2.VersionService/Get": false, - "/metalstack.infra.v2.BMCService/UpdateBMCInfo": false, - "/metalstack.infra.v2.EventService/Send": false, - "/metalstack.infra.v2.SwitchService/Get": false, - "/metalstack.infra.v2.SwitchService/Heartbeat": false, - "/metalstack.infra.v2.SwitchService/Register": false, + "/metalstack.admin.v2.FilesystemService/Create": true, + "/metalstack.admin.v2.FilesystemService/Delete": true, + "/metalstack.admin.v2.FilesystemService/Update": true, + "/metalstack.admin.v2.IPService/List": false, + "/metalstack.admin.v2.ImageService/Create": true, + "/metalstack.admin.v2.ImageService/Delete": true, + "/metalstack.admin.v2.ImageService/Update": true, + "/metalstack.admin.v2.ImageService/Usage": true, + "/metalstack.admin.v2.MachineService/Get": false, + "/metalstack.admin.v2.MachineService/List": false, + "/metalstack.admin.v2.NetworkService/Create": true, + "/metalstack.admin.v2.NetworkService/Delete": true, + "/metalstack.admin.v2.NetworkService/Get": false, + "/metalstack.admin.v2.NetworkService/List": false, + "/metalstack.admin.v2.NetworkService/Update": true, + "/metalstack.admin.v2.PartitionService/Capacity": false, + "/metalstack.admin.v2.PartitionService/Create": true, + "/metalstack.admin.v2.PartitionService/Delete": true, + "/metalstack.admin.v2.PartitionService/Update": true, + "/metalstack.admin.v2.ProjectService/List": false, + "/metalstack.admin.v2.SizeService/Create": true, + "/metalstack.admin.v2.SizeService/Delete": true, + "/metalstack.admin.v2.SizeService/Update": true, + "/metalstack.admin.v2.SwitchService/Delete": true, + "/metalstack.admin.v2.SwitchService/Get": false, + "/metalstack.admin.v2.SwitchService/List": false, + "/metalstack.admin.v2.SwitchService/Migrate": true, + "/metalstack.admin.v2.SwitchService/Port": true, + "/metalstack.admin.v2.SwitchService/Update": true, + "/metalstack.admin.v2.TenantService/Create": true, + "/metalstack.admin.v2.TenantService/List": true, + "/metalstack.admin.v2.TokenService/Create": true, + "/metalstack.admin.v2.TokenService/List": true, + "/metalstack.admin.v2.TokenService/Revoke": true, + "/metalstack.admin.v2.VPNService/AuthKey": true, + "/metalstack.admin.v2.VPNService/ListNodes": true, + "/metalstack.api.v2.FilesystemService/Get": false, + "/metalstack.api.v2.FilesystemService/List": false, + "/metalstack.api.v2.FilesystemService/Match": false, + "/metalstack.api.v2.HealthService/Get": false, + "/metalstack.api.v2.IPService/Create": true, + "/metalstack.api.v2.IPService/Delete": true, + "/metalstack.api.v2.IPService/Get": false, + "/metalstack.api.v2.IPService/List": false, + "/metalstack.api.v2.IPService/Update": true, + "/metalstack.api.v2.ImageService/Get": false, + "/metalstack.api.v2.ImageService/Latest": false, + "/metalstack.api.v2.ImageService/List": false, + "/metalstack.api.v2.MachineService/Create": true, + "/metalstack.api.v2.MachineService/Delete": true, + "/metalstack.api.v2.MachineService/Get": false, + "/metalstack.api.v2.MachineService/List": false, + "/metalstack.api.v2.MachineService/Update": true, + "/metalstack.api.v2.MethodService/List": true, + "/metalstack.api.v2.MethodService/TokenScopedList": true, + "/metalstack.api.v2.NetworkService/Create": true, + "/metalstack.api.v2.NetworkService/Delete": true, + "/metalstack.api.v2.NetworkService/Get": false, + "/metalstack.api.v2.NetworkService/List": false, + "/metalstack.api.v2.NetworkService/ListBaseNetworks": false, + "/metalstack.api.v2.NetworkService/Update": true, + "/metalstack.api.v2.PartitionService/Get": false, + "/metalstack.api.v2.PartitionService/List": false, + "/metalstack.api.v2.ProjectService/Create": true, + "/metalstack.api.v2.ProjectService/Delete": true, + "/metalstack.api.v2.ProjectService/Get": false, + "/metalstack.api.v2.ProjectService/Invite": true, + "/metalstack.api.v2.ProjectService/InviteAccept": true, + "/metalstack.api.v2.ProjectService/InviteDelete": true, + "/metalstack.api.v2.ProjectService/InviteGet": false, + "/metalstack.api.v2.ProjectService/InvitesList": false, + "/metalstack.api.v2.ProjectService/Leave": true, + "/metalstack.api.v2.ProjectService/List": false, + "/metalstack.api.v2.ProjectService/RemoveMember": true, + "/metalstack.api.v2.ProjectService/Update": true, + "/metalstack.api.v2.ProjectService/UpdateMember": true, + "/metalstack.api.v2.SizeService/Get": false, + "/metalstack.api.v2.SizeService/List": false, + "/metalstack.api.v2.TenantService/Create": true, + "/metalstack.api.v2.TenantService/Delete": true, + "/metalstack.api.v2.TenantService/Get": false, + "/metalstack.api.v2.TenantService/Invite": true, + "/metalstack.api.v2.TenantService/InviteAccept": true, + "/metalstack.api.v2.TenantService/InviteDelete": true, + "/metalstack.api.v2.TenantService/InviteGet": false, + "/metalstack.api.v2.TenantService/InvitesList": false, + "/metalstack.api.v2.TenantService/Leave": true, + "/metalstack.api.v2.TenantService/List": false, + "/metalstack.api.v2.TenantService/RemoveMember": true, + "/metalstack.api.v2.TenantService/Update": true, + "/metalstack.api.v2.TenantService/UpdateMember": true, + "/metalstack.api.v2.TokenService/Create": true, + "/metalstack.api.v2.TokenService/Get": true, + "/metalstack.api.v2.TokenService/List": true, + "/metalstack.api.v2.TokenService/Refresh": true, + "/metalstack.api.v2.TokenService/Revoke": true, + "/metalstack.api.v2.TokenService/Update": true, + "/metalstack.api.v2.UserService/Get": true, + "/metalstack.api.v2.VersionService/Get": false, + "/metalstack.infra.v2.BMCService/UpdateBMCInfo": false, + "/metalstack.infra.v2.BMCService/WaitForMachineEvent": false, + "/metalstack.infra.v2.EventService/Send": false, + "/metalstack.infra.v2.SwitchService/Get": false, + "/metalstack.infra.v2.SwitchService/Heartbeat": false, + "/metalstack.infra.v2.SwitchService/Register": false, }, } } diff --git a/go/tests/mocks/metalstack/infra/v2/infrav2connect/BMCServiceClient.go b/go/tests/mocks/metalstack/infra/v2/infrav2connect/BMCServiceClient.go index da746095..9ce708b0 100644 --- a/go/tests/mocks/metalstack/infra/v2/infrav2connect/BMCServiceClient.go +++ b/go/tests/mocks/metalstack/infra/v2/infrav2connect/BMCServiceClient.go @@ -7,6 +7,7 @@ package infrav2connect import ( "context" + "connectrpc.com/connect" "github.com/metal-stack/api/go/metalstack/infra/v2" mock "github.com/stretchr/testify/mock" ) @@ -105,3 +106,71 @@ func (_c *BMCServiceClient_UpdateBMCInfo_Call) RunAndReturn(run func(context1 co _c.Call.Return(run) return _c } + +// WaitForMachineEvent provides a mock function for the type BMCServiceClient +func (_mock *BMCServiceClient) WaitForMachineEvent(context1 context.Context, waitForMachineEventRequest *infrav2.WaitForMachineEventRequest) (*connect.ServerStreamForClient[infrav2.WaitForMachineEventResponse], error) { + ret := _mock.Called(context1, waitForMachineEventRequest) + + if len(ret) == 0 { + panic("no return value specified for WaitForMachineEvent") + } + + var r0 *connect.ServerStreamForClient[infrav2.WaitForMachineEventResponse] + var r1 error + if returnFunc, ok := ret.Get(0).(func(context.Context, *infrav2.WaitForMachineEventRequest) (*connect.ServerStreamForClient[infrav2.WaitForMachineEventResponse], error)); ok { + return returnFunc(context1, waitForMachineEventRequest) + } + if returnFunc, ok := ret.Get(0).(func(context.Context, *infrav2.WaitForMachineEventRequest) *connect.ServerStreamForClient[infrav2.WaitForMachineEventResponse]); ok { + r0 = returnFunc(context1, waitForMachineEventRequest) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*connect.ServerStreamForClient[infrav2.WaitForMachineEventResponse]) + } + } + if returnFunc, ok := ret.Get(1).(func(context.Context, *infrav2.WaitForMachineEventRequest) error); ok { + r1 = returnFunc(context1, waitForMachineEventRequest) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// BMCServiceClient_WaitForMachineEvent_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WaitForMachineEvent' +type BMCServiceClient_WaitForMachineEvent_Call struct { + *mock.Call +} + +// WaitForMachineEvent is a helper method to define mock.On call +// - context1 context.Context +// - waitForMachineEventRequest *infrav2.WaitForMachineEventRequest +func (_e *BMCServiceClient_Expecter) WaitForMachineEvent(context1 interface{}, waitForMachineEventRequest interface{}) *BMCServiceClient_WaitForMachineEvent_Call { + return &BMCServiceClient_WaitForMachineEvent_Call{Call: _e.mock.On("WaitForMachineEvent", context1, waitForMachineEventRequest)} +} + +func (_c *BMCServiceClient_WaitForMachineEvent_Call) Run(run func(context1 context.Context, waitForMachineEventRequest *infrav2.WaitForMachineEventRequest)) *BMCServiceClient_WaitForMachineEvent_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 *infrav2.WaitForMachineEventRequest + if args[1] != nil { + arg1 = args[1].(*infrav2.WaitForMachineEventRequest) + } + run( + arg0, + arg1, + ) + }) + return _c +} + +func (_c *BMCServiceClient_WaitForMachineEvent_Call) Return(serverStreamForClient *connect.ServerStreamForClient[infrav2.WaitForMachineEventResponse], err error) *BMCServiceClient_WaitForMachineEvent_Call { + _c.Call.Return(serverStreamForClient, err) + return _c +} + +func (_c *BMCServiceClient_WaitForMachineEvent_Call) RunAndReturn(run func(context1 context.Context, waitForMachineEventRequest *infrav2.WaitForMachineEventRequest) (*connect.ServerStreamForClient[infrav2.WaitForMachineEventResponse], error)) *BMCServiceClient_WaitForMachineEvent_Call { + _c.Call.Return(run) + return _c +} diff --git a/go/tests/mocks/metalstack/infra/v2/infrav2connect/BMCServiceHandler.go b/go/tests/mocks/metalstack/infra/v2/infrav2connect/BMCServiceHandler.go index 6442a23d..f566efd2 100644 --- a/go/tests/mocks/metalstack/infra/v2/infrav2connect/BMCServiceHandler.go +++ b/go/tests/mocks/metalstack/infra/v2/infrav2connect/BMCServiceHandler.go @@ -7,6 +7,7 @@ package infrav2connect import ( "context" + "connectrpc.com/connect" "github.com/metal-stack/api/go/metalstack/infra/v2" mock "github.com/stretchr/testify/mock" ) @@ -105,3 +106,66 @@ func (_c *BMCServiceHandler_UpdateBMCInfo_Call) RunAndReturn(run func(context1 c _c.Call.Return(run) return _c } + +// WaitForMachineEvent provides a mock function for the type BMCServiceHandler +func (_mock *BMCServiceHandler) WaitForMachineEvent(context1 context.Context, waitForMachineEventRequest *infrav2.WaitForMachineEventRequest, serverStream *connect.ServerStream[infrav2.WaitForMachineEventResponse]) error { + ret := _mock.Called(context1, waitForMachineEventRequest, serverStream) + + if len(ret) == 0 { + panic("no return value specified for WaitForMachineEvent") + } + + var r0 error + if returnFunc, ok := ret.Get(0).(func(context.Context, *infrav2.WaitForMachineEventRequest, *connect.ServerStream[infrav2.WaitForMachineEventResponse]) error); ok { + r0 = returnFunc(context1, waitForMachineEventRequest, serverStream) + } else { + r0 = ret.Error(0) + } + return r0 +} + +// BMCServiceHandler_WaitForMachineEvent_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WaitForMachineEvent' +type BMCServiceHandler_WaitForMachineEvent_Call struct { + *mock.Call +} + +// WaitForMachineEvent is a helper method to define mock.On call +// - context1 context.Context +// - waitForMachineEventRequest *infrav2.WaitForMachineEventRequest +// - serverStream *connect.ServerStream[infrav2.WaitForMachineEventResponse] +func (_e *BMCServiceHandler_Expecter) WaitForMachineEvent(context1 interface{}, waitForMachineEventRequest interface{}, serverStream interface{}) *BMCServiceHandler_WaitForMachineEvent_Call { + return &BMCServiceHandler_WaitForMachineEvent_Call{Call: _e.mock.On("WaitForMachineEvent", context1, waitForMachineEventRequest, serverStream)} +} + +func (_c *BMCServiceHandler_WaitForMachineEvent_Call) Run(run func(context1 context.Context, waitForMachineEventRequest *infrav2.WaitForMachineEventRequest, serverStream *connect.ServerStream[infrav2.WaitForMachineEventResponse])) *BMCServiceHandler_WaitForMachineEvent_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 *infrav2.WaitForMachineEventRequest + if args[1] != nil { + arg1 = args[1].(*infrav2.WaitForMachineEventRequest) + } + var arg2 *connect.ServerStream[infrav2.WaitForMachineEventResponse] + if args[2] != nil { + arg2 = args[2].(*connect.ServerStream[infrav2.WaitForMachineEventResponse]) + } + run( + arg0, + arg1, + arg2, + ) + }) + return _c +} + +func (_c *BMCServiceHandler_WaitForMachineEvent_Call) Return(err error) *BMCServiceHandler_WaitForMachineEvent_Call { + _c.Call.Return(err) + return _c +} + +func (_c *BMCServiceHandler_WaitForMachineEvent_Call) RunAndReturn(run func(context1 context.Context, waitForMachineEventRequest *infrav2.WaitForMachineEventRequest, serverStream *connect.ServerStream[infrav2.WaitForMachineEventResponse]) error) *BMCServiceHandler_WaitForMachineEvent_Call { + _c.Call.Return(run) + return _c +} diff --git a/proto/metalstack/infra/v2/bmc.proto b/proto/metalstack/infra/v2/bmc.proto index 06de6530..fd229b55 100644 --- a/proto/metalstack/infra/v2/bmc.proto +++ b/proto/metalstack/infra/v2/bmc.proto @@ -11,6 +11,11 @@ service BMCService { option (metalstack.api.v2.infra_roles) = INFRA_ROLE_EDITOR; option (metalstack.api.v2.auditing) = AUDITING_EXCLUDED; } + // WaitForMachineEvent is called by the metal-bmc and is returned with a bmc command to execute. + rpc WaitForMachineEvent(WaitForMachineEventRequest) returns (stream WaitForMachineEventResponse) { + option (metalstack.api.v2.infra_roles) = INFRA_ROLE_EDITOR; + option (metalstack.api.v2.auditing) = AUDITING_EXCLUDED; + } } // UpdateBMCInfoRequest @@ -18,3 +23,9 @@ message UpdateBMCInfoRequest {} // UpdateBMCInfoResponse message UpdateBMCInfoResponse {} + +// WaitForMachineEventRequest +message WaitForMachineEventRequest {} + +// WaitForMachineEventResponse +message WaitForMachineEventResponse {} diff --git a/python/metalstack/infra/v2/bmc_connect.py b/python/metalstack/infra/v2/bmc_connect.py index 1afc8521..bf9951a0 100644 --- a/python/metalstack/infra/v2/bmc_connect.py +++ b/python/metalstack/infra/v2/bmc_connect.py @@ -19,6 +19,9 @@ class BMCService(Protocol): async def update_b_m_c_info(self, request: metalstack_dot_infra_dot_v2_dot_bmc__pb2.UpdateBMCInfoRequest, ctx: RequestContext) -> metalstack_dot_infra_dot_v2_dot_bmc__pb2.UpdateBMCInfoResponse: raise ConnectError(Code.UNIMPLEMENTED, "Not implemented") + def wait_for_machine_event(self, request: metalstack_dot_infra_dot_v2_dot_bmc__pb2.WaitForMachineEventRequest, ctx: RequestContext) -> AsyncIterator[metalstack_dot_infra_dot_v2_dot_bmc__pb2.WaitForMachineEventResponse]: + raise ConnectError(Code.UNIMPLEMENTED, "Not implemented") + class BMCServiceASGIApplication(ConnectASGIApplication): def __init__(self, service: BMCService, *, interceptors: Iterable[Interceptor]=(), read_max_bytes: int | None = None) -> None: @@ -34,6 +37,16 @@ def __init__(self, service: BMCService, *, interceptors: Iterable[Interceptor]=( ), function=service.update_b_m_c_info, ), + "/metalstack.infra.v2.BMCService/WaitForMachineEvent": Endpoint.server_stream( + method=MethodInfo( + name="WaitForMachineEvent", + service_name="metalstack.infra.v2.BMCService", + input=metalstack_dot_infra_dot_v2_dot_bmc__pb2.WaitForMachineEventRequest, + output=metalstack_dot_infra_dot_v2_dot_bmc__pb2.WaitForMachineEventResponse, + idempotency_level=IdempotencyLevel.UNKNOWN, + ), + function=service.wait_for_machine_event, + ), }, interceptors=interceptors, read_max_bytes=read_max_bytes, @@ -66,10 +79,32 @@ async def update_b_m_c_info( timeout_ms=timeout_ms, ) + def wait_for_machine_event( + self, + request: metalstack_dot_infra_dot_v2_dot_bmc__pb2.WaitForMachineEventRequest, + *, + headers: Headers | Mapping[str, str] | None = None, + timeout_ms: int | None = None, + ) -> AsyncIterator[metalstack_dot_infra_dot_v2_dot_bmc__pb2.WaitForMachineEventResponse]: + return self.execute_server_stream( + request=request, + method=MethodInfo( + name="WaitForMachineEvent", + service_name="metalstack.infra.v2.BMCService", + input=metalstack_dot_infra_dot_v2_dot_bmc__pb2.WaitForMachineEventRequest, + output=metalstack_dot_infra_dot_v2_dot_bmc__pb2.WaitForMachineEventResponse, + idempotency_level=IdempotencyLevel.UNKNOWN, + ), + headers=headers, + timeout_ms=timeout_ms, + ) + class BMCServiceSync(Protocol): def update_b_m_c_info(self, request: metalstack_dot_infra_dot_v2_dot_bmc__pb2.UpdateBMCInfoRequest, ctx: RequestContext) -> metalstack_dot_infra_dot_v2_dot_bmc__pb2.UpdateBMCInfoResponse: raise ConnectError(Code.UNIMPLEMENTED, "Not implemented") + def wait_for_machine_event(self, request: metalstack_dot_infra_dot_v2_dot_bmc__pb2.WaitForMachineEventRequest, ctx: RequestContext) -> Iterator[metalstack_dot_infra_dot_v2_dot_bmc__pb2.WaitForMachineEventResponse]: + raise ConnectError(Code.UNIMPLEMENTED, "Not implemented") class BMCServiceWSGIApplication(ConnectWSGIApplication): @@ -86,6 +121,16 @@ def __init__(self, service: BMCServiceSync, interceptors: Iterable[InterceptorSy ), function=service.update_b_m_c_info, ), + "/metalstack.infra.v2.BMCService/WaitForMachineEvent": EndpointSync.server_stream( + method=MethodInfo( + name="WaitForMachineEvent", + service_name="metalstack.infra.v2.BMCService", + input=metalstack_dot_infra_dot_v2_dot_bmc__pb2.WaitForMachineEventRequest, + output=metalstack_dot_infra_dot_v2_dot_bmc__pb2.WaitForMachineEventResponse, + idempotency_level=IdempotencyLevel.UNKNOWN, + ), + function=service.wait_for_machine_event, + ), }, interceptors=interceptors, read_max_bytes=read_max_bytes, @@ -117,3 +162,23 @@ def update_b_m_c_info( headers=headers, timeout_ms=timeout_ms, ) + + def wait_for_machine_event( + self, + request: metalstack_dot_infra_dot_v2_dot_bmc__pb2.WaitForMachineEventRequest, + *, + headers: Headers | Mapping[str, str] | None = None, + timeout_ms: int | None = None, + ) -> Iterator[metalstack_dot_infra_dot_v2_dot_bmc__pb2.WaitForMachineEventResponse]: + return self.execute_server_stream( + request=request, + method=MethodInfo( + name="WaitForMachineEvent", + service_name="metalstack.infra.v2.BMCService", + input=metalstack_dot_infra_dot_v2_dot_bmc__pb2.WaitForMachineEventRequest, + output=metalstack_dot_infra_dot_v2_dot_bmc__pb2.WaitForMachineEventResponse, + idempotency_level=IdempotencyLevel.UNKNOWN, + ), + headers=headers, + timeout_ms=timeout_ms, + ) diff --git a/python/metalstack/infra/v2/bmc_pb2.py b/python/metalstack/infra/v2/bmc_pb2.py index 6a849b24..fb5c4d19 100644 --- a/python/metalstack/infra/v2/bmc_pb2.py +++ b/python/metalstack/infra/v2/bmc_pb2.py @@ -25,7 +25,7 @@ from metalstack.api.v2 import common_pb2 as metalstack_dot_api_dot_v2_dot_common__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1dmetalstack/infra/v2/bmc.proto\x12\x13metalstack.infra.v2\x1a\x1emetalstack/api/v2/common.proto\"\x16\n\x14UpdateBMCInfoRequest\"\x17\n\x15UpdateBMCInfoResponse2\x7f\n\nBMCService\x12q\n\rUpdateBMCInfo\x12).metalstack.infra.v2.UpdateBMCInfoRequest\x1a*.metalstack.infra.v2.UpdateBMCInfoResponse\"\t\xe0\xf3\x18\x02\xea\xf3\x18\x01\x01\x42\xcc\x01\n\x17\x63om.metalstack.infra.v2B\x08\x42mcProtoP\x01Z9github.com/metal-stack/api/go/metalstack/infra/v2;infrav2\xa2\x02\x03MIX\xaa\x02\x13Metalstack.Infra.V2\xca\x02\x13Metalstack\\Infra\\V2\xe2\x02\x1fMetalstack\\Infra\\V2\\GPBMetadata\xea\x02\x15Metalstack::Infra::V2b\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1dmetalstack/infra/v2/bmc.proto\x12\x13metalstack.infra.v2\x1a\x1emetalstack/api/v2/common.proto\"\x16\n\x14UpdateBMCInfoRequest\"\x17\n\x15UpdateBMCInfoResponse\"\x1c\n\x1aWaitForMachineEventRequest\"\x1d\n\x1bWaitForMachineEventResponse2\x87\x02\n\nBMCService\x12q\n\rUpdateBMCInfo\x12).metalstack.infra.v2.UpdateBMCInfoRequest\x1a*.metalstack.infra.v2.UpdateBMCInfoResponse\"\t\xe0\xf3\x18\x02\xea\xf3\x18\x01\x01\x12\x85\x01\n\x13WaitForMachineEvent\x12/.metalstack.infra.v2.WaitForMachineEventRequest\x1a\x30.metalstack.infra.v2.WaitForMachineEventResponse\"\t\xe0\xf3\x18\x02\xea\xf3\x18\x01\x01\x30\x01\x42\xcc\x01\n\x17\x63om.metalstack.infra.v2B\x08\x42mcProtoP\x01Z9github.com/metal-stack/api/go/metalstack/infra/v2;infrav2\xa2\x02\x03MIX\xaa\x02\x13Metalstack.Infra.V2\xca\x02\x13Metalstack\\Infra\\V2\xe2\x02\x1fMetalstack\\Infra\\V2\\GPBMetadata\xea\x02\x15Metalstack::Infra::V2b\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) @@ -35,10 +35,16 @@ _globals['DESCRIPTOR']._serialized_options = b'\n\027com.metalstack.infra.v2B\010BmcProtoP\001Z9github.com/metal-stack/api/go/metalstack/infra/v2;infrav2\242\002\003MIX\252\002\023Metalstack.Infra.V2\312\002\023Metalstack\\Infra\\V2\342\002\037Metalstack\\Infra\\V2\\GPBMetadata\352\002\025Metalstack::Infra::V2' _globals['_BMCSERVICE'].methods_by_name['UpdateBMCInfo']._loaded_options = None _globals['_BMCSERVICE'].methods_by_name['UpdateBMCInfo']._serialized_options = b'\340\363\030\002\352\363\030\001\001' + _globals['_BMCSERVICE'].methods_by_name['WaitForMachineEvent']._loaded_options = None + _globals['_BMCSERVICE'].methods_by_name['WaitForMachineEvent']._serialized_options = b'\340\363\030\002\352\363\030\001\001' _globals['_UPDATEBMCINFOREQUEST']._serialized_start=86 _globals['_UPDATEBMCINFOREQUEST']._serialized_end=108 _globals['_UPDATEBMCINFORESPONSE']._serialized_start=110 _globals['_UPDATEBMCINFORESPONSE']._serialized_end=133 - _globals['_BMCSERVICE']._serialized_start=135 - _globals['_BMCSERVICE']._serialized_end=262 + _globals['_WAITFORMACHINEEVENTREQUEST']._serialized_start=135 + _globals['_WAITFORMACHINEEVENTREQUEST']._serialized_end=163 + _globals['_WAITFORMACHINEEVENTRESPONSE']._serialized_start=165 + _globals['_WAITFORMACHINEEVENTRESPONSE']._serialized_end=194 + _globals['_BMCSERVICE']._serialized_start=197 + _globals['_BMCSERVICE']._serialized_end=460 # @@protoc_insertion_point(module_scope) diff --git a/python/metalstack/infra/v2/bmc_pb2.pyi b/python/metalstack/infra/v2/bmc_pb2.pyi index fa266305..64e5eb11 100644 --- a/python/metalstack/infra/v2/bmc_pb2.pyi +++ b/python/metalstack/infra/v2/bmc_pb2.pyi @@ -12,3 +12,11 @@ class UpdateBMCInfoRequest(_message.Message): class UpdateBMCInfoResponse(_message.Message): __slots__ = () def __init__(self) -> None: ... + +class WaitForMachineEventRequest(_message.Message): + __slots__ = () + def __init__(self) -> None: ... + +class WaitForMachineEventResponse(_message.Message): + __slots__ = () + def __init__(self) -> None: ...