diff --git a/pkg/apis/alerting/v1/alerting.endpoint.pb.go b/pkg/apis/alerting/v1/alerting.endpoint.pb.go index bf3d29078f..3ac47f4540 100644 --- a/pkg/apis/alerting/v1/alerting.endpoint.pb.go +++ b/pkg/apis/alerting/v1/alerting.endpoint.pb.go @@ -2222,7 +2222,7 @@ var file_github_com_rancher_opni_pkg_apis_alerting_v1_alerting_endpoint_proto_ra 0x6e, 0x76, 0x6f, 0x6c, 0x76, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x25, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, - 0x65, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x32, 0xf2, 0x04, 0x0a, 0x0e, 0x41, 0x6c, 0x65, + 0x65, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x32, 0xf5, 0x04, 0x0a, 0x0e, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x12, 0x56, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x17, 0x2e, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x41, 0x6c, @@ -2248,24 +2248,24 @@ var file_github_com_rancher_opni_pkg_apis_alerting_v1_alerting_endpoint_proto_ra 0x6c, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x6c, 0x76, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x15, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0f, 0x3a, 0x01, 0x2a, 0x1a, 0x0a, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, - 0x65, 0x12, 0x6a, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x6c, 0x65, 0x72, 0x74, + 0x65, 0x12, 0x6d, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x24, 0x2e, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x49, 0x6e, 0x76, 0x6f, 0x6c, 0x76, - 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x0f, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x09, 0x22, 0x07, 0x2f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x6e, 0x0a, - 0x11, 0x54, 0x65, 0x73, 0x74, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, - 0x6e, 0x74, 0x12, 0x22, 0x2e, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x54, 0x65, - 0x73, 0x74, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x69, 0x6e, - 0x67, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x45, 0x6e, 0x64, 0x70, 0x6f, - 0x69, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x10, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x0a, 0x3a, 0x01, 0x2a, 0x22, 0x05, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x42, 0x2e, 0x5a, - 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x61, 0x6e, 0x63, - 0x68, 0x65, 0x72, 0x2f, 0x6f, 0x70, 0x6e, 0x69, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x61, 0x70, 0x69, - 0x73, 0x2f, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x12, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x0c, 0x3a, 0x01, 0x2a, 0x22, 0x07, 0x2f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x12, 0x6e, 0x0a, 0x11, 0x54, 0x65, 0x73, 0x74, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x45, 0x6e, 0x64, + 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x22, 0x2e, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x67, + 0x2e, 0x54, 0x65, 0x73, 0x74, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, + 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x61, 0x6c, 0x65, 0x72, + 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x45, 0x6e, + 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x10, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0a, 0x3a, 0x01, 0x2a, 0x22, 0x05, 0x2f, 0x74, 0x65, 0x73, 0x74, + 0x42, 0x2e, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, + 0x61, 0x6e, 0x63, 0x68, 0x65, 0x72, 0x2f, 0x6f, 0x70, 0x6e, 0x69, 0x2f, 0x70, 0x6b, 0x67, 0x2f, + 0x61, 0x70, 0x69, 0x73, 0x2f, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x76, 0x31, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/pkg/apis/alerting/v1/alerting.endpoint.pb.gw.go b/pkg/apis/alerting/v1/alerting.endpoint.pb.gw.go index 90c002e49c..ff49a48514 100644 --- a/pkg/apis/alerting/v1/alerting.endpoint.pb.gw.go +++ b/pkg/apis/alerting/v1/alerting.endpoint.pb.gw.go @@ -186,18 +186,15 @@ func local_request_AlertEndpoints_UpdateAlertEndpoint_0(ctx context.Context, mar } -var ( - filter_AlertEndpoints_DeleteAlertEndpoint_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} -) - func request_AlertEndpoints_DeleteAlertEndpoint_0(ctx context.Context, marshaler runtime.Marshaler, client AlertEndpointsClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq DeleteAlertEndpointRequest var metadata runtime.ServerMetadata - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_AlertEndpoints_DeleteAlertEndpoint_0); err != nil { + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -210,10 +207,11 @@ func local_request_AlertEndpoints_DeleteAlertEndpoint_0(ctx context.Context, mar var protoReq DeleteAlertEndpointRequest var metadata runtime.ServerMetadata - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_AlertEndpoints_DeleteAlertEndpoint_0); err != nil { + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } diff --git a/pkg/apis/alerting/v1/alerting.endpoint.proto b/pkg/apis/alerting/v1/alerting.endpoint.proto index 457a716f28..a0c9a89fc3 100644 --- a/pkg/apis/alerting/v1/alerting.endpoint.proto +++ b/pkg/apis/alerting/v1/alerting.endpoint.proto @@ -61,6 +61,7 @@ service AlertEndpoints{ returns (InvolvedConditions) { option (google.api.http) = { post : "/delete" + body : "*" }; } @@ -195,7 +196,6 @@ message UpdateAlertEndpointRequest { message DeleteAlertEndpointRequest { bool forceDelete = 1; core.Reference id = 2; - } message TestAlertEndpointRequest { diff --git a/plugins/alerting/pkg/alerting/api_endpoints.go b/plugins/alerting/pkg/alerting/api_endpoints.go index b2bc38bdc9..3005915dde 100644 --- a/plugins/alerting/pkg/alerting/api_endpoints.go +++ b/plugins/alerting/pkg/alerting/api_endpoints.go @@ -10,6 +10,8 @@ import ( alertingv1 "github.com/rancher/opni/pkg/apis/alerting/v1" corev1 "github.com/rancher/opni/pkg/apis/core/v1" "github.com/rancher/opni/pkg/validation" + "github.com/samber/lo" + lop "github.com/samber/lo/parallel" "golang.org/x/exp/slices" "google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/emptypb" @@ -68,7 +70,8 @@ func (p *Plugin) UpdateAlertEndpoint(ctx context.Context, req *alertingv1.Update if len(refList.Items) > 0 && !req.ForceUpdate { return refList, nil } - + // force the new endpoint to preserve the original endpoint id + req.UpdateAlert.Id = req.Id.Id req.UpdateAlert.LastUpdated = timestamppb.Now() if err := p.storageClientSet.Get().Endpoints().Put(ctx, req.Id.Id, req.GetUpdateAlert()); err != nil { return nil, err @@ -122,6 +125,21 @@ func (p *Plugin) DeleteAlertEndpoint(ctx context.Context, req *alertingv1.Delete if err := p.storageClientSet.Get().Endpoints().Delete(ctx, req.Id.Id); err != nil { return nil, err } + lop.ForEach(refList.Items, func(condRef *corev1.Reference, _ int) { + // delete endpoint metadata from each condition + cond, err := p.storageClientSet.Get().Conditions().Get(ctx, condRef.Id) + if err != nil { + return + } + if cond.AttachedEndpoints != nil && len(cond.AttachedEndpoints.Items) > 0 { + cond.AttachedEndpoints.Items = lo.Filter(cond.AttachedEndpoints.Items, func(item *alertingv1.AttachedEndpoint, _ int) bool { + return item.EndpointId != req.Id.Id + }) + } + if err := p.storageClientSet.Get().Conditions().Put(ctx, condRef.Id, cond); err != nil { + return + } + }) return refList, nil } diff --git a/test/integration/alerting/alerting_test.go b/test/integration/alerting/alerting_test.go index 66f7916a77..9e70adde1e 100644 --- a/test/integration/alerting/alerting_test.go +++ b/test/integration/alerting/alerting_test.go @@ -147,7 +147,7 @@ func BuildAlertingClusterIntegrationTests( }) It("should be able to create some endpoints", func() { - numServers := 5 + numServers := numAgents servers = env.CreateWebhookServer(env.Context(), numServers) for _, server := range servers { ref, err := alertEndpointsClient.CreateAlertEndpoint(env.Context(), server.Endpoint()) @@ -393,8 +393,66 @@ func BuildAlertingClusterIntegrationTests( } else { Expect(item.Windows).To(HaveLen(0), "conditions that have not fired should not show up on timeline, but do") } + } + + By("verifying we can edit Alert Endpoints in use by Alert Conditions") + endpList, err := alertEndpointsClient.ListAlertEndpoints(env.Context(), &alertingv1.ListAlertEndpointsRequest{}) + Expect(err).NotTo(HaveOccurred()) + Expect(len(endpList.Items)).To(BeNumerically(">", 0)) + for _, endp := range endpList.Items { + _, err := alertEndpointsClient.UpdateAlertEndpoint(env.Context(), &alertingv1.UpdateAlertEndpointRequest{ + Id: &corev1.Reference{ + Id: endp.Id.Id, + }, + UpdateAlert: &alertingv1.AlertEndpoint{ + Name: "update", + Description: "update", + Endpoint: &alertingv1.AlertEndpoint_Webhook{ + Webhook: &alertingv1.WebhookEndpoint{ + Url: "http://example.com", + }, + }, + Id: "id", + }, + ForceUpdate: true, + }) + Expect(err).NotTo(HaveOccurred()) + } + endpList, err = alertEndpointsClient.ListAlertEndpoints(env.Context(), &alertingv1.ListAlertEndpointsRequest{}) + Expect(err).NotTo(HaveOccurred()) + Expect(endpList.Items).To(HaveLen(numAgents)) + updatedList := lo.Filter(endpList.Items, func(item *alertingv1.AlertEndpointWithId, _ int) bool { + if item.Endpoint.GetWebhook() != nil { + return item.Endpoint.GetWebhook().Url == "http://example.com" && item.Endpoint.GetName() == "update" && item.Endpoint.GetDescription() == "update" + } + return false + }) + Expect(updatedList).To(HaveLen(len(endpList.Items))) + By("verifying we can delete Alert Endpoint in use by Alert Conditions") + for _, endp := range endpList.Items { + _, err := alertEndpointsClient.DeleteAlertEndpoint(env.Context(), &alertingv1.DeleteAlertEndpointRequest{ + Id: &corev1.Reference{ + Id: endp.Id.Id, + }, + ForceDelete: true, + }) + Expect(err).NotTo(HaveOccurred()) } + endpList, err = alertEndpointsClient.ListAlertEndpoints(env.Context(), &alertingv1.ListAlertEndpointsRequest{}) + Expect(err).NotTo(HaveOccurred()) + Expect(endpList.Items).To(HaveLen(0)) + + condList, err = alertConditionsClient.ListAlertConditions(env.Context(), &alertingv1.ListAlertConditionRequest{}) + Expect(err).NotTo(HaveOccurred()) + Expect(condList.Items).NotTo(HaveLen(0)) + hasEndpoints := lo.Filter(condList.Items, func(item *alertingv1.AlertConditionWithId, _ int) bool { + if item.AlertCondition.AttachedEndpoints != nil { + return len(item.AlertCondition.AttachedEndpoints.Items) != 0 + } + return false + }) + Expect(hasEndpoints).To(HaveLen(0)) }) It("should delete the downstream agents", func() {