Skip to content

Commit 52808da

Browse files
authored
support target CLI (#4465)
1 parent 361483f commit 52808da

File tree

11 files changed

+311
-55
lines changed

11 files changed

+311
-55
lines changed

api/client/deployment_target.go

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,40 @@ import (
44
"context"
55
"fmt"
66

7-
"github.com/porter-dev/porter/api/server/handlers/deployment_target"
7+
"github.com/porter-dev/porter/api/types"
88
)
99

10-
// CreateDeploymentTarget creates a new deployment target for a given project and cluster with the provided name
10+
// CreateDeploymentTarget creates a deployment target with the given request options
1111
func (c *Client) CreateDeploymentTarget(
1212
ctx context.Context,
13-
projectID, clusterID uint,
14-
selector string,
15-
preview bool,
16-
) (*deployment_target.CreateDeploymentTargetResponse, error) {
17-
resp := &deployment_target.CreateDeploymentTargetResponse{}
18-
19-
req := &deployment_target.CreateDeploymentTargetRequest{
20-
Selector: selector,
21-
Preview: preview,
22-
}
13+
projectId uint,
14+
req *types.CreateDeploymentTargetRequest,
15+
) (*types.CreateDeploymentTargetResponse, error) {
16+
resp := &types.CreateDeploymentTargetResponse{}
2317

2418
err := c.postRequest(
25-
fmt.Sprintf(
26-
"/projects/%d/clusters/%d/deployment-targets",
27-
projectID, clusterID,
28-
),
19+
fmt.Sprintf("/projects/%d/targets", projectId),
20+
req,
21+
resp,
22+
)
23+
24+
return resp, err
25+
}
26+
27+
// ListDeploymentTargets retrieves all deployment targets in a project
28+
func (c *Client) ListDeploymentTargets(
29+
ctx context.Context,
30+
projectId uint,
31+
includePreviews bool,
32+
) (*types.ListDeploymentTargetsResponse, error) {
33+
resp := &types.ListDeploymentTargetsResponse{}
34+
35+
req := &types.ListDeploymentTargetsRequest{
36+
Preview: includePreviews,
37+
}
38+
39+
err := c.getRequest(
40+
fmt.Sprintf("/projects/%d/targets", projectId),
2941
req,
3042
resp,
3143
)

api/server/handlers/deployment_target/create.go

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -30,34 +30,21 @@ func NewCreateDeploymentTargetHandler(
3030
}
3131
}
3232

33-
// CreateDeploymentTargetRequest is the request object for the /deployment-targets POST endpoint
34-
type CreateDeploymentTargetRequest struct {
35-
// Deprecated: use name instead
36-
Selector string `json:"selector"`
37-
Name string `json:"name,omitempty"`
38-
Preview bool `json:"preview"`
39-
}
40-
41-
// CreateDeploymentTargetResponse is the response object for the /deployment-targets POST endpoint
42-
type CreateDeploymentTargetResponse struct {
43-
DeploymentTargetID string `json:"deployment_target_id"`
44-
}
45-
4633
// ServeHTTP handles POST requests to create a new deployment target
4734
func (c *CreateDeploymentTargetHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
4835
ctx, span := telemetry.NewSpan(r.Context(), "serve-create-deployment-target")
4936
defer span.End()
5037

5138
project, _ := ctx.Value(types.ProjectScope).(*models.Project)
52-
cluster, _ := ctx.Value(types.ClusterScope).(*models.Cluster)
5339

40+
cluster, clusterOk := ctx.Value(types.ClusterScope).(*models.Cluster)
5441
if !project.GetFeatureFlag(models.ValidateApplyV2, c.Config().LaunchDarklyClient) {
5542
err := telemetry.Error(ctx, span, nil, "project does not have validate apply v2 enabled")
5643
c.HandleAPIError(w, r, apierrors.NewErrForbidden(err))
5744
return
5845
}
5946

60-
request := &CreateDeploymentTargetRequest{}
47+
request := &types.CreateDeploymentTargetRequest{}
6148
if ok := c.DecodeAndValidate(w, r, request); !ok {
6249
err := telemetry.Error(ctx, span, nil, "error decoding request")
6350
c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusBadRequest))
@@ -69,14 +56,24 @@ func (c *CreateDeploymentTargetHandler) ServeHTTP(w http.ResponseWriter, r *http
6956
return
7057
}
7158

59+
clusterId := request.ClusterId
60+
if clusterOk {
61+
clusterId = cluster.ID
62+
}
63+
if clusterId == 0 {
64+
err := telemetry.Error(ctx, span, nil, "cluster id is required")
65+
c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusBadRequest))
66+
return
67+
}
68+
7269
name := request.Name
7370
if name == "" {
7471
name = request.Selector
7572
}
7673

7774
createReq := connect.NewRequest(&porterv1.CreateDeploymentTargetRequest{
7875
ProjectId: int64(project.ID),
79-
ClusterId: int64(cluster.ID),
76+
ClusterId: int64(clusterId),
8077
Name: name,
8178
Namespace: name,
8279
IsPreview: request.Preview,
@@ -99,7 +96,9 @@ func (c *CreateDeploymentTargetHandler) ServeHTTP(w http.ResponseWriter, r *http
9996
return
10097
}
10198

102-
res := &CreateDeploymentTargetResponse{
99+
telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "deployment-target-id", Value: ccpResp.Msg.DeploymentTargetId})
100+
101+
res := &types.CreateDeploymentTargetResponse{
103102
DeploymentTargetID: ccpResp.Msg.DeploymentTargetId,
104103
}
105104

api/server/handlers/deployment_target/list.go

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -28,44 +28,48 @@ func NewListDeploymentTargetsHandler(
2828
}
2929
}
3030

31-
// ListDeploymentTargetsRequest is the request object for the /deployment-targets GET endpoint
32-
type ListDeploymentTargetsRequest struct {
33-
Preview bool `json:"preview"`
34-
}
35-
36-
// ListDeploymentTargetsResponse is the response object for the /deployment-targets GET endpoint
37-
type ListDeploymentTargetsResponse struct {
38-
DeploymentTargets []types.DeploymentTarget `json:"deployment_targets"`
39-
}
40-
4131
func (c *ListDeploymentTargetsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
4232
ctx, span := telemetry.NewSpan(r.Context(), "serve-list-deployment-targets")
4333
defer span.End()
4434

4535
project, _ := ctx.Value(types.ProjectScope).(*models.Project)
4636
cluster, _ := ctx.Value(types.ClusterScope).(*models.Cluster)
4737

38+
telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "cluster-provided", Value: cluster != nil})
39+
4840
if !project.GetFeatureFlag(models.ValidateApplyV2, c.Config().LaunchDarklyClient) {
4941
err := telemetry.Error(ctx, span, nil, "project does not have validate apply v2 enabled")
5042
c.HandleAPIError(w, r, apierrors.NewErrForbidden(err))
5143
return
5244
}
5345

54-
request := &ListDeploymentTargetsRequest{}
46+
request := &types.ListDeploymentTargetsRequest{}
5547
if ok := c.DecodeAndValidate(w, r, request); !ok {
5648
err := telemetry.Error(ctx, span, nil, "error decoding request")
5749
c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusBadRequest))
5850
return
5951
}
6052

61-
deploymentTargets, err := c.Repo().DeploymentTarget().List(project.ID, cluster.ID, request.Preview)
62-
if err != nil {
63-
err := telemetry.Error(ctx, span, err, "error retrieving deployment targets")
64-
c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
65-
return
53+
var deploymentTargets []*models.DeploymentTarget
54+
var err error
55+
56+
if cluster != nil {
57+
deploymentTargets, err = c.Repo().DeploymentTarget().ListForCluster(project.ID, cluster.ID, request.Preview)
58+
if err != nil {
59+
err := telemetry.Error(ctx, span, err, "error retrieving deployment targets for cluster")
60+
c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
61+
return
62+
}
63+
} else {
64+
deploymentTargets, err = c.Repo().DeploymentTarget().List(project.ID, request.Preview)
65+
if err != nil {
66+
err := telemetry.Error(ctx, span, err, "error retrieving deployment targets for project")
67+
c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
68+
return
69+
}
6670
}
6771

68-
response := ListDeploymentTargetsResponse{
72+
response := types.ListDeploymentTargetsResponse{
6973
DeploymentTargets: make([]types.DeploymentTarget, 0),
7074
}
7175

api/server/router/project.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package router
33
import (
44
"fmt"
55

6+
"github.com/porter-dev/porter/api/server/handlers/deployment_target"
7+
68
"github.com/go-chi/chi/v5"
79
apiContract "github.com/porter-dev/porter/api/server/handlers/api_contract"
810
"github.com/porter-dev/porter/api/server/handlers/api_token"
@@ -1740,5 +1742,61 @@ func getProjectRoutes(
17401742
Router: r,
17411743
})
17421744

1745+
// GET /api/projects/{project_id}/targets -> deployment_target.ListDeploymentTargetHandler
1746+
listDeploymentTargetEndpoint := factory.NewAPIEndpoint(
1747+
&types.APIRequestMetadata{
1748+
Verb: types.APIVerbGet,
1749+
Method: types.HTTPVerbGet,
1750+
Path: &types.Path{
1751+
Parent: basePath,
1752+
RelativePath: fmt.Sprintf("%s/targets", relPath),
1753+
},
1754+
Scopes: []types.PermissionScope{
1755+
types.UserScope,
1756+
types.ProjectScope,
1757+
},
1758+
},
1759+
)
1760+
1761+
listDeploymentTargetHandler := deployment_target.NewListDeploymentTargetsHandler(
1762+
config,
1763+
factory.GetDecoderValidator(),
1764+
factory.GetResultWriter(),
1765+
)
1766+
1767+
routes = append(routes, &router.Route{
1768+
Endpoint: listDeploymentTargetEndpoint,
1769+
Handler: listDeploymentTargetHandler,
1770+
Router: r,
1771+
})
1772+
1773+
// GET /api/projects/{project_id}/targets -> deployment_target.ListDeploymentTargetHandler
1774+
createDeploymentTargetEndpoint := factory.NewAPIEndpoint(
1775+
&types.APIRequestMetadata{
1776+
Verb: types.APIVerbCreate,
1777+
Method: types.HTTPVerbPost,
1778+
Path: &types.Path{
1779+
Parent: basePath,
1780+
RelativePath: fmt.Sprintf("%s/targets", relPath),
1781+
},
1782+
Scopes: []types.PermissionScope{
1783+
types.UserScope,
1784+
types.ProjectScope,
1785+
},
1786+
},
1787+
)
1788+
1789+
createDeploymentTargetHandler := deployment_target.NewCreateDeploymentTargetHandler(
1790+
config,
1791+
factory.GetDecoderValidator(),
1792+
factory.GetResultWriter(),
1793+
)
1794+
1795+
routes = append(routes, &router.Route{
1796+
Endpoint: createDeploymentTargetEndpoint,
1797+
Handler: createDeploymentTargetHandler,
1798+
Router: r,
1799+
})
1800+
17431801
return routes, newPath
17441802
}

api/types/deployment_target.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,28 @@ type DeploymentTarget struct {
1919
CreatedAtUTC time.Time `json:"created_at"`
2020
UpdatedAtUTC time.Time `json:"updated_at"`
2121
}
22+
23+
// CreateDeploymentTargetRequest is the request object for the /deployment-targets POST endpoint
24+
type CreateDeploymentTargetRequest struct {
25+
// Deprecated: use name instead
26+
Selector string `json:"selector"`
27+
Name string `json:"name,omitempty"`
28+
Preview bool `json:"preview"`
29+
// required if using the project-scoped endpoint
30+
ClusterId uint `json:"cluster_id"`
31+
}
32+
33+
// CreateDeploymentTargetResponse is the response object for the /deployment-targets POST endpoint
34+
type CreateDeploymentTargetResponse struct {
35+
DeploymentTargetID string `json:"deployment_target_id"`
36+
}
37+
38+
// ListDeploymentTargetsRequest is the request object for the /deployment-targets GET endpoint
39+
type ListDeploymentTargetsRequest struct {
40+
Preview bool `json:"preview"`
41+
}
42+
43+
// ListDeploymentTargetsResponse is the response object for the /deployment-targets GET endpoint
44+
type ListDeploymentTargetsResponse struct {
45+
DeploymentTargets []DeploymentTarget `json:"deployment_targets"`
46+
}

cli/cmd/commands/all.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ func RegisterCommands() (*cobra.Command, error) {
4646
rootCmd.AddCommand(registerCommand_Run(cliConf))
4747
rootCmd.AddCommand(registerCommand_Server(cliConf))
4848
rootCmd.AddCommand(registerCommand_Stack(cliConf))
49+
rootCmd.AddCommand(registerCommand_Target(cliConf))
4950
rootCmd.AddCommand(registerCommand_Update(cliConf))
5051
rootCmd.AddCommand(registerCommand_Version(cliConf))
5152
rootCmd.AddCommand(registerCommand_Env(cliConf))

0 commit comments

Comments
 (0)