Skip to content

Commit 094315d

Browse files
authored
Delete target from CLI (#4652)
1 parent 71615a8 commit 094315d

File tree

7 files changed

+123
-51
lines changed

7 files changed

+123
-51
lines changed

api/client/deployment_target.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,16 @@ func (c *Client) ListDeploymentTargets(
4444

4545
return resp, err
4646
}
47+
48+
// DeleteDeploymentTarget deletes a deployment target in a project
49+
func (c *Client) DeleteDeploymentTarget(
50+
ctx context.Context,
51+
projectId uint,
52+
deploymentTargetName string,
53+
) error {
54+
return c.deleteRequest(
55+
fmt.Sprintf("/projects/%d/targets/%s", projectId, deploymentTargetName),
56+
nil,
57+
nil,
58+
)
59+
}

api/server/handlers/deployment_target/delete.go

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,12 @@ import (
1010
"github.com/porter-dev/porter/api/server/shared"
1111
"github.com/porter-dev/porter/api/server/shared/apierrors"
1212
"github.com/porter-dev/porter/api/server/shared/config"
13-
"github.com/porter-dev/porter/api/server/shared/requestutils"
1413
"github.com/porter-dev/porter/api/types"
1514
"github.com/porter-dev/porter/internal/models"
1615
"github.com/porter-dev/porter/internal/telemetry"
1716
)
1817

19-
// DeleteDeploymentTargetHandler is the handler for DELETE /api/projects/{project_id}/clusters/{cluster_id}/deployment-targets/{deployment_target_id}
18+
// DeleteDeploymentTargetHandler is the handler for DELETE /api/projects/{project_id}/targets/{deployment_target_identifier}
2019
type DeleteDeploymentTargetHandler struct {
2120
handlers.PorterHandlerReadWriter
2221
authz.KubernetesAgentGetter
@@ -34,28 +33,20 @@ func NewDeleteDeploymentTargetHandler(
3433
}
3534
}
3635

37-
// ServeHTTP deletes the deployment target from the cluster
36+
// ServeHTTP deletes the deployment target from the project
3837
func (c *DeleteDeploymentTargetHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
39-
ctx, span := telemetry.NewSpan(r.Context(), "server-delete-deployment-target-by-id")
38+
ctx, span := telemetry.NewSpan(r.Context(), "serve-delete-deployment-target")
4039
defer span.End()
4140

4241
project, _ := ctx.Value(types.ProjectScope).(*models.Project)
43-
44-
deploymentTargetID, reqErr := requestutils.GetURLParamString(r, types.URLParamDeploymentTargetID)
45-
if reqErr != nil {
46-
err := telemetry.Error(ctx, span, reqErr, "error parsing deployment target id")
47-
c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusBadRequest))
48-
return
49-
}
50-
if deploymentTargetID == "" {
51-
err := telemetry.Error(ctx, span, nil, "deployment target id cannot be empty")
52-
c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusBadRequest))
53-
return
54-
}
42+
deploymentTarget, _ := ctx.Value(types.DeploymentTargetScope).(types.DeploymentTarget)
5543

5644
deleteReq := connect.NewRequest(&porterv1.DeleteDeploymentTargetRequest{
57-
ProjectId: int64(project.ID),
58-
DeploymentTargetId: deploymentTargetID,
45+
ProjectId: int64(project.ID),
46+
DeploymentTargetIdentifier: &porterv1.DeploymentTargetIdentifier{
47+
Id: deploymentTarget.ID.String(),
48+
Name: deploymentTarget.Name,
49+
},
5950
})
6051

6152
_, err := c.Config().ClusterControlPlaneClient.DeleteDeploymentTarget(ctx, deleteReq)

api/server/router/deployment_target.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,35 @@ func getDeploymentTargetRoutes(
8989
Router: r,
9090
})
9191

92+
// DELETE /api/projects/{project_id}/targets/{deployment_target_identifier} -> deployment_target.DeleteDeploymentTargetHandler
93+
deleteDeploymentTargetEndpoint := factory.NewAPIEndpoint(
94+
&types.APIRequestMetadata{
95+
Verb: types.APIVerbDelete,
96+
Method: types.HTTPVerbDelete,
97+
Path: &types.Path{
98+
Parent: basePath,
99+
RelativePath: relPath,
100+
},
101+
Scopes: []types.PermissionScope{
102+
types.UserScope,
103+
types.ProjectScope,
104+
types.DeploymentTargetScope,
105+
},
106+
},
107+
)
108+
109+
deleteDeploymentTargetHandler := deployment_target.NewDeleteDeploymentTargetHandler(
110+
config,
111+
factory.GetDecoderValidator(),
112+
factory.GetResultWriter(),
113+
)
114+
115+
routes = append(routes, &router.Route{
116+
Endpoint: deleteDeploymentTargetEndpoint,
117+
Handler: deleteDeploymentTargetHandler,
118+
Router: r,
119+
})
120+
92121
// GET /api/projects/{project_id}/targets/{deployment_target_identifier}/apps/{porter_app_name}/cloudsql -> porter_app.GetCloudSqlSecretHandler
93122
getCloudSqlSecretEndpoint := factory.NewAPIEndpoint(
94123
&types.APIRequestMetadata{

api/server/router/deployment_target_legacy.go

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -119,35 +119,6 @@ func getLegacyDeploymentTargetRoutes(
119119
Router: r,
120120
})
121121

122-
// DELETE /api/projects/{project_id}/clusters/{cluster_id}/deployment-targets/{deployment_target_id} -> deployment_target.DeleteDeploymentTargetHandler
123-
deleteDeploymentTargetEndpoint := factory.NewAPIEndpoint(
124-
&types.APIRequestMetadata{
125-
Verb: types.APIVerbDelete,
126-
Method: types.HTTPVerbDelete,
127-
Path: &types.Path{
128-
Parent: basePath,
129-
RelativePath: fmt.Sprintf("%s/{%s}", relPath, types.URLParamDeploymentTargetID),
130-
},
131-
Scopes: []types.PermissionScope{
132-
types.UserScope,
133-
types.ProjectScope,
134-
types.ClusterScope,
135-
},
136-
},
137-
)
138-
139-
deleteDeploymentTargetHandler := deployment_target.NewDeleteDeploymentTargetHandler(
140-
config,
141-
factory.GetDecoderValidator(),
142-
factory.GetResultWriter(),
143-
)
144-
145-
routes = append(routes, &router.Route{
146-
Endpoint: deleteDeploymentTargetEndpoint,
147-
Handler: deleteDeploymentTargetHandler,
148-
Router: r,
149-
})
150-
151122
// GET /api/projects/{project_id}/clusters/{cluster_id}/deployment-targets/{deployment_target_id} -> deployment_target.GetDeploymentTargetHandler
152123
getDeploymentTargetEndpoint := factory.NewAPIEndpoint(
153124
&types.APIRequestMetadata{

cli/cmd/commands/target.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
package commands
22

33
import (
4+
"bufio"
45
"context"
56
"fmt"
67
"os"
78
"sort"
9+
"strings"
810
"text/tabwriter"
911

1012
"github.com/fatih/color"
@@ -61,6 +63,23 @@ If the --preview flag is set, only deployment targets for preview environments w
6163
listTargetCmd.Flags().BoolVar(&includePreviews, "preview", false, "List preview environments")
6264
targetCmd.AddCommand(listTargetCmd)
6365

66+
deleteTargetCmd := &cobra.Command{
67+
Use: "delete",
68+
Short: "Deletes a deployment target",
69+
Long: `Deletes a deployment target in the project. Currently, this command only supports the deletion of preview environments.`,
70+
Run: func(cmd *cobra.Command, args []string) {
71+
err := checkLoginAndRunWithConfig(cmd, cliConf, args, deleteTarget)
72+
if err != nil {
73+
os.Exit(1)
74+
}
75+
},
76+
}
77+
78+
deleteTargetCmd.Flags().StringVar(&targetName, "name", "", "Name of deployment target")
79+
deleteTargetCmd.Flags().BoolP("force", "f", false, "Force deletion without confirmation")
80+
deleteTargetCmd.MarkFlagRequired("name") // nolint:errcheck,gosec
81+
targetCmd.AddCommand(deleteTargetCmd)
82+
6483
return targetCmd
6584
}
6685

@@ -126,6 +145,57 @@ func listTargets(ctx context.Context, user *types.GetAuthenticatedUserResponse,
126145
return nil
127146
}
128147

148+
func deleteTarget(ctx context.Context, _ *types.GetAuthenticatedUserResponse, client api.Client, cliConf config.CLIConfig, featureFlags config.FeatureFlags, cmd *cobra.Command, args []string) error {
149+
name, err := cmd.Flags().GetString("name")
150+
if err != nil {
151+
return fmt.Errorf("error finding name flag: %w", err)
152+
}
153+
if name == "" {
154+
return fmt.Errorf("name flag must be set")
155+
}
156+
157+
force, err := cmd.Flags().GetBool("force")
158+
if err != nil {
159+
return fmt.Errorf("error finding force flag: %w", err)
160+
}
161+
162+
var confirmed bool
163+
if !force {
164+
confirmed, err = confirmAction(fmt.Sprintf("Are you sure you want to delete target '%s'?", name))
165+
if err != nil {
166+
return fmt.Errorf("error confirming action: %w", err)
167+
}
168+
}
169+
if !confirmed && !force {
170+
color.New(color.FgYellow).Println("Deletion aborted") // nolint:errcheck,gosec
171+
return nil
172+
}
173+
174+
err = client.DeleteDeploymentTarget(ctx, cliConf.Project, name)
175+
if err != nil {
176+
return fmt.Errorf("error deleting target: %w", err)
177+
}
178+
179+
color.New(color.FgGreen).Printf("Deleted target '%s'\n", name) // nolint:errcheck,gosec
180+
181+
return nil
182+
}
183+
184+
func confirmAction(prompt string) (bool, error) {
185+
reader := bufio.NewReader(os.Stdin)
186+
fmt.Printf("%s [Y/n]: ", prompt)
187+
188+
response, err := reader.ReadString('\n')
189+
if err != nil {
190+
return false, fmt.Errorf("error reading input: %w", err)
191+
}
192+
193+
response = strings.TrimSpace(response)
194+
confirmed := strings.ToLower(response) == "y" || response == ""
195+
196+
return confirmed, nil
197+
}
198+
129199
func checkmark(b bool) string {
130200
if b {
131201
return "✓"

dashboard/src/main/home/app-dashboard/apps/Apps.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,6 @@ const Apps: React.FC = () => {
226226
{},
227227
{
228228
project_id: currentProject.id,
229-
cluster_id: currentCluster.id,
230229
deployment_target_id: currentDeploymentTarget.id,
231230
}
232231
);

dashboard/src/shared/api.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -997,11 +997,10 @@ const deleteDeploymentTarget = baseApi<
997997
{},
998998
{
999999
project_id: number;
1000-
cluster_id: number;
10011000
deployment_target_id: string;
10021001
}
1003-
>("DELETE", ({ project_id, cluster_id, deployment_target_id }) => {
1004-
return `/api/projects/${project_id}/clusters/${cluster_id}/deployment-targets/${deployment_target_id}`;
1002+
>("DELETE", ({ project_id, deployment_target_id }) => {
1003+
return `/api/projects/${project_id}/targets/${deployment_target_id}`;
10051004
});
10061005

10071006
const getBranchHead = baseApi<

0 commit comments

Comments
 (0)