(ctx context.Context, req *adminv1.CreateAlertRequest)
| 126 | } |
| 127 | |
| 128 | func (s *Server) CreateAlert(ctx context.Context, req *adminv1.CreateAlertRequest) (*adminv1.CreateAlertResponse, error) { |
| 129 | observability.AddRequestAttributes(ctx, |
| 130 | attribute.String("args.organization", req.Org), |
| 131 | attribute.String("args.project", req.Project), |
| 132 | ) |
| 133 | |
| 134 | proj, err := s.admin.DB.FindProjectByName(ctx, req.Org, req.Project) |
| 135 | if err != nil { |
| 136 | return nil, err |
| 137 | } |
| 138 | |
| 139 | claims := auth.GetClaims(ctx) |
| 140 | permissions := claims.ProjectPermissions(ctx, proj.OrganizationID, proj.ID) |
| 141 | if !permissions.CreateAlerts { |
| 142 | return nil, status.Error(codes.PermissionDenied, "does not have permission to read project repo") |
| 143 | } |
| 144 | |
| 145 | if claims.OwnerType() != auth.OwnerTypeUser { |
| 146 | return nil, status.Error(codes.PermissionDenied, "only users can create alerts") |
| 147 | } |
| 148 | |
| 149 | if proj.PrimaryDeploymentID == nil { |
| 150 | return nil, status.Error(codes.FailedPrecondition, "project does not have a production deployment") |
| 151 | } |
| 152 | |
| 153 | depl, err := s.admin.DB.FindDeployment(ctx, *proj.PrimaryDeploymentID) |
| 154 | if err != nil { |
| 155 | return nil, err |
| 156 | } |
| 157 | |
| 158 | name, err := s.generateAlertName(ctx, depl, req.Options.DisplayName) |
| 159 | if err != nil { |
| 160 | return nil, err |
| 161 | } |
| 162 | |
| 163 | data, err := s.yamlForManagedAlert(req.Options, claims.OwnerID()) |
| 164 | if err != nil { |
| 165 | return nil, status.Errorf(codes.InvalidArgument, "failed to generate alert YAML: %s", err.Error()) |
| 166 | } |
| 167 | |
| 168 | err = s.admin.DB.UpsertVirtualFile(ctx, &database.InsertVirtualFileOptions{ |
| 169 | ProjectID: proj.ID, |
| 170 | Environment: "prod", |
| 171 | Path: virtualFilePathForManagedAlert(name), |
| 172 | Data: data, |
| 173 | }) |
| 174 | if err != nil { |
| 175 | return nil, fmt.Errorf("failed to insert virtual file: %w", err) |
| 176 | } |
| 177 | |
| 178 | err = s.admin.TriggerParserAndAwaitResource(ctx, depl, name, runtime.ResourceKindAlert) |
| 179 | if err != nil { |
| 180 | if errors.Is(err, context.DeadlineExceeded) { |
| 181 | return nil, status.Error(codes.DeadlineExceeded, "timed out waiting for alert to be created") |
| 182 | } |
| 183 | return nil, fmt.Errorf("failed to reconcile alert: %w", err) |
| 184 | } |
| 185 |
nothing calls this directly
no test coverage detected