| 2799 | } |
| 2800 | |
| 2801 | func InsertWorkspaceResource(ctx context.Context, db database.Store, jobID uuid.UUID, transition database.WorkspaceTransition, protoResource *sdkproto.Resource, snapshot *telemetry.Snapshot, opt ...InsertWorkspaceResourceOption) error { |
| 2802 | opts := &insertWorkspaceResourceOptions{} |
| 2803 | for _, o := range opt { |
| 2804 | o(opts) |
| 2805 | } |
| 2806 | |
| 2807 | resource, err := db.InsertWorkspaceResource(ctx, database.InsertWorkspaceResourceParams{ |
| 2808 | ID: uuid.New(), |
| 2809 | CreatedAt: dbtime.Now(), |
| 2810 | JobID: jobID, |
| 2811 | Transition: transition, |
| 2812 | Type: protoResource.Type, |
| 2813 | Name: protoResource.Name, |
| 2814 | Hide: protoResource.Hide, |
| 2815 | Icon: protoResource.Icon, |
| 2816 | DailyCost: protoResource.DailyCost, |
| 2817 | InstanceType: sql.NullString{ |
| 2818 | String: protoResource.InstanceType, |
| 2819 | Valid: protoResource.InstanceType != "", |
| 2820 | }, |
| 2821 | ModulePath: sql.NullString{ |
| 2822 | String: protoResource.ModulePath, |
| 2823 | // empty string is root module |
| 2824 | Valid: true, |
| 2825 | }, |
| 2826 | }) |
| 2827 | if err != nil { |
| 2828 | return xerrors.Errorf("insert provisioner job resource %q: %w", protoResource.Name, err) |
| 2829 | } |
| 2830 | snapshot.WorkspaceResources = append(snapshot.WorkspaceResources, telemetry.ConvertWorkspaceResource(resource)) |
| 2831 | |
| 2832 | var ( |
| 2833 | agentNames = make(map[string]struct{}) |
| 2834 | appSlugs = make(map[string]struct{}) |
| 2835 | ) |
| 2836 | for _, prAgent := range protoResource.Agents { |
| 2837 | // Similar logic is duplicated in terraform/resources.go. |
| 2838 | if prAgent.Name == "" { |
| 2839 | return xerrors.Errorf("agent name cannot be empty") |
| 2840 | } |
| 2841 | // In 2025-02 we removed support for underscores in agent names. To |
| 2842 | // provide a nicer error message, we check the regex first and check |
| 2843 | // for underscores if it fails. |
| 2844 | if !provisioner.AgentNameRegex.MatchString(prAgent.Name) { |
| 2845 | if strings.Contains(prAgent.Name, "_") { |
| 2846 | return xerrors.Errorf("agent name %q contains underscores which are no longer supported, please use hyphens instead (regex: %q)", prAgent.Name, provisioner.AgentNameRegex.String()) |
| 2847 | } |
| 2848 | return xerrors.Errorf("agent name %q does not match regex %q", prAgent.Name, provisioner.AgentNameRegex.String()) |
| 2849 | } |
| 2850 | // Agent names must be case-insensitive-unique, to be unambiguous in |
| 2851 | // `coder_app`s and CoderVPN DNS names. |
| 2852 | if _, ok := agentNames[strings.ToLower(prAgent.Name)]; ok { |
| 2853 | return xerrors.Errorf("duplicate agent name %q", prAgent.Name) |
| 2854 | } |
| 2855 | agentNames[strings.ToLower(prAgent.Name)] = struct{}{} |
| 2856 | |
| 2857 | var instanceID sql.NullString |
| 2858 | if prAgent.GetInstanceId() != "" { |