Skip to content

Commit 3e92760

Browse files
Revert revert provider integration (#3199)
1 parent 9c1f0a1 commit 3e92760

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1347
-3
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ require (
4646
github.com/confluentinc/ccloud-sdk-go-v2/networking-ip v0.2.0
4747
github.com/confluentinc/ccloud-sdk-go-v2/networking-privatelink v0.3.0
4848
github.com/confluentinc/ccloud-sdk-go-v2/org v0.9.0
49-
github.com/confluentinc/ccloud-sdk-go-v2/provider-integration v0.1.0
49+
github.com/confluentinc/ccloud-sdk-go-v2/provider-integration v0.2.0
5050
github.com/confluentinc/ccloud-sdk-go-v2/service-quota v0.2.0
5151
github.com/confluentinc/ccloud-sdk-go-v2/srcm v0.7.3
5252
github.com/confluentinc/ccloud-sdk-go-v2/sso v0.0.1

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -250,8 +250,8 @@ github.com/confluentinc/ccloud-sdk-go-v2/networking-privatelink v0.3.0 h1:mC0E1n
250250
github.com/confluentinc/ccloud-sdk-go-v2/networking-privatelink v0.3.0/go.mod h1:GIHF2cYOUKx+6ycYokr4i8E4cuNBC22xqvO/IhqZ31U=
251251
github.com/confluentinc/ccloud-sdk-go-v2/org v0.9.0 h1:FtaqHX0kBTK7fCQK+9SJcOso+XpWCWzY2roT3gBQGfw=
252252
github.com/confluentinc/ccloud-sdk-go-v2/org v0.9.0/go.mod h1:X0uaTYPp+mr19W1R/Z1LuB1ePZJZrH7kxnQckDx6zoc=
253-
github.com/confluentinc/ccloud-sdk-go-v2/provider-integration v0.1.0 h1:a6GlDTUoeX5zRlIPVToH3Aa779QA2Ajj/LYyJC5UQN8=
254-
github.com/confluentinc/ccloud-sdk-go-v2/provider-integration v0.1.0/go.mod h1:aNAIuiIUbfvqtQrl4yp1f7dMdUInXs+PDrHLvKCr0PE=
253+
github.com/confluentinc/ccloud-sdk-go-v2/provider-integration v0.2.0 h1:UN2a+aqYhk95ro+wVLkeB/8W7n+UV2KsE3jNFbbDCSw=
254+
github.com/confluentinc/ccloud-sdk-go-v2/provider-integration v0.2.0/go.mod h1:TzompS9F0G6awN5xMC+nguNG8ULElN5UqX2XOBOIPuM=
255255
github.com/confluentinc/ccloud-sdk-go-v2/service-quota v0.2.0 h1:xVSmwdycExze1E2Jta99CaFuMOlL6k6KExOOSY1hSFg=
256256
github.com/confluentinc/ccloud-sdk-go-v2/service-quota v0.2.0/go.mod h1:zZWZoGWJuO0Qm4lO6H2KlXMx4OoB/yhD8y6J1ZB/97Q=
257257
github.com/confluentinc/ccloud-sdk-go-v2/srcm v0.7.3 h1:ozdDSJHruQIgtxS5hwz8Rp8pUSX0i4h9besp2H9NYzU=

internal/provider-integration/command.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package providerintegration
33
import (
44
"github.com/spf13/cobra"
55

6+
v2 "github.com/confluentinc/cli/v4/internal/provider-integration/v2"
67
pcmd "github.com/confluentinc/cli/v4/pkg/cmd"
78
)
89

@@ -35,6 +36,7 @@ func New(prerunner pcmd.PreRunner) *cobra.Command {
3536
cmd.AddCommand(c.newDeleteCommand())
3637
cmd.AddCommand(c.newDescribeCommand())
3738
cmd.AddCommand(c.newListCommand())
39+
cmd.AddCommand(v2.New(prerunner))
3840

3941
return cmd
4042
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Copyright 2024 Confluent Inc. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package v2
16+
17+
import (
18+
"github.com/spf13/cobra"
19+
20+
pcmd "github.com/confluentinc/cli/v4/pkg/cmd"
21+
)
22+
23+
type command struct {
24+
*pcmd.AuthenticatedCLICommand
25+
}
26+
27+
func New(prerunner pcmd.PreRunner) *cobra.Command {
28+
cmd := &cobra.Command{
29+
Use: "v2",
30+
Short: "Manage provider integrations (v2).",
31+
Long: "Manage provider integrations that allow users to configure access to cloud provider resources through Confluent resources.\n\nCurrently supports: Azure and GCP.",
32+
Annotations: map[string]string{pcmd.RunRequirement: pcmd.RequireCloudLogin},
33+
}
34+
35+
c := &command{
36+
AuthenticatedCLICommand: pcmd.NewAuthenticatedCLICommand(cmd, prerunner),
37+
}
38+
39+
cmd.AddCommand(c.newCreateCommand())
40+
cmd.AddCommand(c.newDeleteCommand())
41+
cmd.AddCommand(c.newDescribeCommand())
42+
cmd.AddCommand(c.newListCommand())
43+
44+
return cmd
45+
}
46+
47+
const (
48+
// Provider constants
49+
providerAzure = "azure"
50+
providerGcp = "gcp"
51+
)
Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
// Copyright 2024 Confluent Inc. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package v2
16+
17+
import (
18+
"fmt"
19+
"strings"
20+
21+
"github.com/spf13/cobra"
22+
"golang.org/x/text/cases"
23+
"golang.org/x/text/language"
24+
25+
piv2 "github.com/confluentinc/ccloud-sdk-go-v2/provider-integration/v2"
26+
27+
pcmd "github.com/confluentinc/cli/v4/pkg/cmd"
28+
"github.com/confluentinc/cli/v4/pkg/examples"
29+
"github.com/confluentinc/cli/v4/pkg/output"
30+
)
31+
32+
func (c *command) newCreateCommand() *cobra.Command {
33+
cmd := &cobra.Command{
34+
Use: "create <display-name>",
35+
Short: "Create a provider integration.",
36+
Long: "Create a provider integration that allows users to manage access to cloud provider resources through Confluent resources.",
37+
Args: cobra.ExactArgs(1),
38+
RunE: c.create,
39+
Example: examples.BuildExampleString(
40+
examples.Example{
41+
Text: `Create and configure Azure provider integration "azure-integration" in the current environment.`,
42+
Code: "confluent provider-integration v2 create azure-integration --cloud azure --azure-tenant-id 00000000-0000-0000-0000-000000000000",
43+
},
44+
examples.Example{
45+
Text: `Create and configure GCP provider integration "gcp-integration" in environment "env-123456".`,
46+
Code: "confluent provider-integration v2 create gcp-integration --cloud gcp --gcp-service-account my-sa@my-project.iam.gserviceaccount.com --environment env-123456",
47+
},
48+
),
49+
}
50+
51+
cmd.Flags().String("cloud", "", fmt.Sprintf("Cloud provider (%s or %s).", providerAzure, providerGcp))
52+
cmd.Flags().String("azure-tenant-id", "", "Azure Tenant ID (required for Azure provider).")
53+
cmd.Flags().String("gcp-service-account", "", "Customer Google Service Account (required for GCP provider).")
54+
pcmd.AddEnvironmentFlag(cmd, c.AuthenticatedCLICommand)
55+
pcmd.AddContextFlag(cmd, c.CLICommand)
56+
pcmd.AddOutputFlag(cmd)
57+
58+
cobra.CheckErr(cmd.MarkFlagRequired("cloud"))
59+
60+
return cmd
61+
}
62+
63+
func (c *command) create(cmd *cobra.Command, args []string) error {
64+
displayName := args[0]
65+
66+
cloud, err := cmd.Flags().GetString("cloud")
67+
if err != nil {
68+
return err
69+
}
70+
71+
cloud = strings.ToLower(cloud)
72+
if cloud != providerAzure && cloud != providerGcp {
73+
return fmt.Errorf("cloud provider must be either %s or %s", providerAzure, providerGcp)
74+
}
75+
76+
// Get provider-specific configuration
77+
var azureTenantId, gcpServiceAccount string
78+
switch cloud {
79+
case providerAzure:
80+
azureTenantId, err = cmd.Flags().GetString("azure-tenant-id")
81+
if err != nil {
82+
return err
83+
}
84+
if azureTenantId == "" {
85+
return fmt.Errorf("--azure-tenant-id is required for Azure provider integrations")
86+
}
87+
case providerGcp:
88+
gcpServiceAccount, err = cmd.Flags().GetString("gcp-service-account")
89+
if err != nil {
90+
return err
91+
}
92+
if gcpServiceAccount == "" {
93+
return fmt.Errorf("--gcp-service-account is required for GCP provider integrations")
94+
}
95+
}
96+
97+
environmentId, err := c.Context.EnvironmentId()
98+
if err != nil {
99+
return err
100+
}
101+
102+
// Step 1: Create the integration in DRAFT state
103+
request := piv2.PimV2Integration{
104+
DisplayName: &displayName,
105+
Provider: &cloud,
106+
Environment: &piv2.ObjectReference{Id: environmentId},
107+
}
108+
109+
providerIntegration, err := c.V2Client.CreatePimV2Integration(cmd.Context(), request)
110+
if err != nil {
111+
return err
112+
}
113+
114+
integrationId := providerIntegration.GetId()
115+
cmd.Printf("Created provider integration %s in DRAFT state.\n", integrationId)
116+
117+
// Step 2: Authorize with provider-specific configuration
118+
var updateConfig piv2.PimV2IntegrationUpdateConfigOneOf
119+
120+
switch cloud {
121+
case providerAzure:
122+
azureConfig := &piv2.PimV2AzureIntegrationConfig{
123+
Kind: "AzureIntegrationConfig",
124+
CustomerAzureTenantId: &azureTenantId,
125+
}
126+
updateConfig = piv2.PimV2AzureIntegrationConfigAsPimV2IntegrationUpdateConfigOneOf(azureConfig)
127+
case providerGcp:
128+
gcpConfig := &piv2.PimV2GcpIntegrationConfig{
129+
Kind: "GcpIntegrationConfig",
130+
CustomerGoogleServiceAccount: &gcpServiceAccount,
131+
}
132+
updateConfig = piv2.PimV2GcpIntegrationConfigAsPimV2IntegrationUpdateConfigOneOf(gcpConfig)
133+
}
134+
135+
updateReq := piv2.PimV2IntegrationUpdate{
136+
Config: &updateConfig,
137+
Environment: &piv2.ObjectReference{Id: environmentId},
138+
}
139+
140+
updated, err := c.V2Client.UpdatePimV2Integration(cmd.Context(), integrationId, updateReq)
141+
if err != nil {
142+
// Extract the specific error message from the backend response
143+
errorMsg := err.Error()
144+
if errorMsg == "" {
145+
errorMsg = "configuration error"
146+
}
147+
148+
// If update fails, clean up the draft integration to make the operation atomic
149+
cmd.Printf("Cleaning up DRAFT provider integration %s due to failure: %v\n", integrationId, errorMsg)
150+
if deleteErr := c.V2Client.DeletePimV2Integration(cmd.Context(), integrationId, environmentId); deleteErr != nil {
151+
cmd.Printf("Warning: Failed to clean up DRAFT provider integration %s: %v\n", integrationId, deleteErr)
152+
} else {
153+
cmd.Printf("Cleaned up DRAFT provider integration %s", integrationId)
154+
}
155+
return err
156+
}
157+
158+
cmd.Printf("Configured %s provider settings.\n", cloud)
159+
160+
// Step 3: Validate the setup
161+
validateReq := piv2.PimV2IntegrationValidateRequest{
162+
Id: &integrationId,
163+
Environment: &piv2.GlobalObjectReference{Id: environmentId},
164+
}
165+
166+
if err := c.V2Client.ValidatePimV2Integration(cmd.Context(), validateReq); err != nil {
167+
// Show setup instructions if validation fails
168+
if updated.Config != nil {
169+
switch cloud {
170+
case providerAzure:
171+
if updated.Config.PimV2AzureIntegrationConfig != nil {
172+
azureConfig := updated.Config.PimV2AzureIntegrationConfig
173+
cmd.Println("\n⏳ Azure setup required:")
174+
cmd.Printf("1. Run: az ad sp create --id %s\n", azureConfig.GetConfluentMultiTenantAppId())
175+
cmd.Println("2. Check Azure Portal → Enterprise Applications to ensure it appears")
176+
cmd.Println("3. Grant necessary permissions to the service principal")
177+
cmd.Printf("\nRun 'confluent provider-integration v2 describe %s' to check status.\n", integrationId)
178+
}
179+
case providerGcp:
180+
if updated.Config.PimV2GcpIntegrationConfig != nil {
181+
gcpConfig := updated.Config.PimV2GcpIntegrationConfig
182+
cmd.Println("\n⏳ GCP setup required:")
183+
cmd.Printf("1. Grant Service Account Token Creator role:\n")
184+
cmd.Printf(" gcloud projects add-iam-policy-binding YOUR_PROJECT_ID \\\n")
185+
cmd.Printf(" --member=\"serviceAccount:%s\" \\\n", gcpConfig.GetGoogleServiceAccount())
186+
cmd.Printf(" --role=\"roles/iam.serviceAccountTokenCreator\" \\\n")
187+
cmd.Printf(" --condition=\"expression=request.auth.claims.sub=='%s'\"\n\n", gcpConfig.GetGoogleServiceAccount())
188+
cmd.Printf("2. Grant your service account (%s) permissions based on your connector needs\n", gcpConfig.GetCustomerGoogleServiceAccount())
189+
cmd.Printf("\nRun 'confluent provider-integration v2 describe %s' to check status.\n", integrationId)
190+
cmd.Println("\nNote: IAM changes may take 1-7 minutes to propagate.")
191+
}
192+
}
193+
}
194+
} else {
195+
cmd.Printf("\n✓ %s setup validated successfully!\n", cases.Title(language.English).String(cloud))
196+
}
197+
198+
// Display the final configuration
199+
table := output.NewTable(cmd)
200+
out := &providerIntegrationOut{
201+
Id: updated.GetId(),
202+
DisplayName: updated.GetDisplayName(),
203+
Provider: updated.GetProvider(),
204+
Environment: updated.Environment.GetId(),
205+
Status: updated.GetStatus(),
206+
}
207+
208+
table.Add(out)
209+
table.Filter([]string{"Id", "DisplayName", "Provider", "Environment", "Status"})
210+
return table.Print()
211+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// Copyright 2024 Confluent Inc. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package v2
16+
17+
import (
18+
"github.com/spf13/cobra"
19+
20+
pcmd "github.com/confluentinc/cli/v4/pkg/cmd"
21+
"github.com/confluentinc/cli/v4/pkg/deletion"
22+
"github.com/confluentinc/cli/v4/pkg/examples"
23+
"github.com/confluentinc/cli/v4/pkg/resource"
24+
)
25+
26+
func (c *command) newDeleteCommand() *cobra.Command {
27+
cmd := &cobra.Command{
28+
Use: "delete <id-1> [id-2] ... [id-n]",
29+
Short: "Delete one or more provider integrations.",
30+
Long: "Delete one or more provider integrations. This operation cannot be undone.",
31+
Args: cobra.MinimumNArgs(1),
32+
RunE: c.delete,
33+
Example: examples.BuildExampleString(
34+
examples.Example{
35+
Text: "Delete provider integration \"pi-123456\" in the current environment.",
36+
Code: "confluent provider-integration v2 delete pi-123456",
37+
},
38+
examples.Example{
39+
Text: "Delete provider integrations \"pi-123456\" and \"pi-789012\" in environment \"env-345678\".",
40+
Code: "confluent provider-integration v2 delete pi-123456 pi-789012 --environment env-345678",
41+
},
42+
),
43+
}
44+
45+
cmd.Flags().Bool("force", false, "Skip the deletion confirmation prompt.")
46+
pcmd.AddEnvironmentFlag(cmd, c.AuthenticatedCLICommand)
47+
pcmd.AddContextFlag(cmd, c.CLICommand)
48+
49+
return cmd
50+
}
51+
52+
func (c *command) delete(cmd *cobra.Command, args []string) error {
53+
environmentId, err := c.Context.EnvironmentId()
54+
if err != nil {
55+
return err
56+
}
57+
58+
existenceFunc := func(id string) bool {
59+
integration, err := c.V2Client.GetPimV2Integration(cmd.Context(), id, environmentId)
60+
if err != nil {
61+
return false
62+
}
63+
// Check if the integration has any usages
64+
if len(integration.GetUsages()) > 0 {
65+
cmd.Printf("Warning: provider integration %q is currently in use by %d resource(s). Remove all usages before deleting.\n", id, len(integration.GetUsages()))
66+
return false
67+
}
68+
return true
69+
}
70+
71+
if err := deletion.ValidateAndConfirm(cmd, args, existenceFunc, resource.ProviderIntegration); err != nil {
72+
return err
73+
}
74+
75+
deleteFunc := func(id string) error {
76+
return c.V2Client.DeletePimV2Integration(cmd.Context(), id, environmentId)
77+
}
78+
79+
_, err = deletion.Delete(cmd, args, deleteFunc, resource.ProviderIntegration)
80+
return err
81+
}

0 commit comments

Comments
 (0)