Skip to content

Commit 49ba38d

Browse files
Promote gemini_* resources to ga (#12747) (#20941)
[upstream:b5bdbf8875474068e54a77780dc9e53e0ddfbc0d] Signed-off-by: Modular Magician <[email protected]>
1 parent 23db44f commit 49ba38d

22 files changed

+2746
-33
lines changed

.changelog/12747.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note: enhancement
2+
gemini: promoted resources `gemini_code_repository_index`, `gemini_repository_group` to GA.
3+
```

google/acctest/bootstrap_test_utils.go

Lines changed: 311 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"fmt"
88
"log"
99
"maps"
10+
"net/http"
1011
"os"
1112
"strings"
1213
"testing"
@@ -1426,6 +1427,316 @@ func SetupProjectsAndGetAccessToken(org, billing, pid, service string, config *t
14261427
return accessToken, nil
14271428
}
14281429

1430+
// For bootstrapping Developer Connect git repository link
1431+
const SharedGitRepositoryLinkIdPrefix = "tf-bootstrap-git-repository-"
1432+
1433+
func BootstrapGitRepository(t *testing.T, gitRepositoryLinkId, location, cloneUri, parentConnectionId string) string {
1434+
gitRepositoryLinkId = SharedGitRepositoryLinkIdPrefix + gitRepositoryLinkId
1435+
1436+
config := BootstrapConfig(t)
1437+
if config == nil {
1438+
t.Fatal("Could not bootstrap config.")
1439+
}
1440+
1441+
log.Printf("[DEBUG] Getting shared git repository link %q", gitRepositoryLinkId)
1442+
1443+
getURL := fmt.Sprintf("%sprojects/%s/locations/%s/connections/%s/gitRepositoryLinks/%s",
1444+
config.DeveloperConnectBasePath, config.Project, location, parentConnectionId, gitRepositoryLinkId)
1445+
1446+
headers := make(http.Header)
1447+
_, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
1448+
Config: config,
1449+
Method: "GET",
1450+
Project: config.Project,
1451+
RawURL: getURL,
1452+
UserAgent: config.UserAgent,
1453+
Headers: headers,
1454+
})
1455+
1456+
if err != nil && transport_tpg.IsGoogleApiErrorWithCode(err, 404) {
1457+
log.Printf("[DEBUG] Git repository link %q not found, bootstrapping", gitRepositoryLinkId)
1458+
obj := map[string]interface{}{
1459+
"clone_uri": cloneUri,
1460+
"annotations": map[string]string{},
1461+
}
1462+
1463+
postURL := fmt.Sprintf("%sprojects/%s/locations/%s/connections/%s/gitRepositoryLinks?gitRepositoryLinkId=%s",
1464+
config.DeveloperConnectBasePath, config.Project, location, parentConnectionId, gitRepositoryLinkId)
1465+
headers := make(http.Header)
1466+
_, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
1467+
Config: config,
1468+
Method: "POST",
1469+
Project: config.Project,
1470+
RawURL: postURL,
1471+
UserAgent: config.UserAgent,
1472+
Body: obj,
1473+
Timeout: 20 * time.Minute,
1474+
Headers: headers,
1475+
})
1476+
if err != nil {
1477+
t.Fatalf("Error bootstrapping git repository link %q: %s", gitRepositoryLinkId, err)
1478+
}
1479+
1480+
_, err = transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
1481+
Config: config,
1482+
Method: "GET",
1483+
Project: config.Project,
1484+
RawURL: getURL,
1485+
UserAgent: config.UserAgent,
1486+
Timeout: 20 * time.Minute,
1487+
Headers: headers,
1488+
})
1489+
if err != nil {
1490+
t.Fatalf("Error getting git repository link %q: %s", gitRepositoryLinkId, err)
1491+
}
1492+
}
1493+
1494+
return gitRepositoryLinkId
1495+
}
1496+
1497+
const SharedConnectionIdPrefix = "tf-bootstrap-developer-connect-connection-"
1498+
1499+
// For bootstrapping Developer Connect connection resources
1500+
func BootstrapDeveloperConnection(t *testing.T, connectionId, location, tokenResource string, appInstallationId int) string {
1501+
connectionId = SharedConnectionIdPrefix + connectionId
1502+
1503+
config := BootstrapConfig(t)
1504+
if config == nil {
1505+
t.Fatal("Could not bootstrap config.")
1506+
}
1507+
1508+
log.Printf("[DEBUG] Getting shared developer connection %q", connectionId)
1509+
1510+
getURL := fmt.Sprintf("%sprojects/%s/locations/%s/connections/%s",
1511+
config.DeveloperConnectBasePath, config.Project, location, connectionId)
1512+
1513+
headers := make(http.Header)
1514+
_, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
1515+
Config: config,
1516+
Method: "GET",
1517+
Project: config.Project,
1518+
RawURL: getURL,
1519+
UserAgent: config.UserAgent,
1520+
Headers: headers,
1521+
})
1522+
1523+
if err != nil {
1524+
log.Printf("[DEBUG] Developer connection %q not found, bootstrapping", connectionId)
1525+
authorizerCredential := map[string]string{
1526+
"oauth_token_secret_version": tokenResource,
1527+
}
1528+
githubConfig := map[string]interface{}{
1529+
"github_app": "DEVELOPER_CONNECT",
1530+
"app_installation_id": appInstallationId,
1531+
"authorizer_credential": authorizerCredential,
1532+
}
1533+
obj := map[string]interface{}{
1534+
"disabled": false,
1535+
"github_config": githubConfig,
1536+
}
1537+
1538+
postURL := fmt.Sprintf("%sprojects/%s/locations/%s/connections?connectionId=%s",
1539+
config.DeveloperConnectBasePath, config.Project, location, connectionId)
1540+
headers := make(http.Header)
1541+
_, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
1542+
Config: config,
1543+
Method: "POST",
1544+
Project: config.Project,
1545+
RawURL: postURL,
1546+
UserAgent: config.UserAgent,
1547+
Body: obj,
1548+
Timeout: 20 * time.Minute,
1549+
Headers: headers,
1550+
})
1551+
if err != nil {
1552+
t.Fatalf("Error bootstrapping developer connection %q: %s", connectionId, err)
1553+
}
1554+
1555+
_, err = transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
1556+
Config: config,
1557+
Method: "GET",
1558+
Project: config.Project,
1559+
RawURL: getURL,
1560+
UserAgent: config.UserAgent,
1561+
Timeout: 20 * time.Minute,
1562+
Headers: headers,
1563+
})
1564+
if err != nil {
1565+
t.Fatalf("Error getting developer connection %q: %s", connectionId, err)
1566+
}
1567+
}
1568+
1569+
return connectionId
1570+
}
1571+
1572+
const SharedRepositoryGroupPrefix = "tf-bootstrap-repo-group-"
1573+
1574+
func BoostrapSharedRepositoryGroup(t *testing.T, repositoryGroupId, location, labels, codeRepositoryIndexId, resource string) string {
1575+
repositoryGroupId = SharedRepositoryGroupPrefix + repositoryGroupId
1576+
1577+
config := BootstrapConfig(t)
1578+
if config == nil {
1579+
t.Fatal("Could not bootstrap config.")
1580+
}
1581+
1582+
log.Printf("[DEBUG] Getting shared repository group %q", repositoryGroupId)
1583+
1584+
getURL := fmt.Sprintf("%sprojects/%s/locations/%s/codeRepositoryIndexes/%s/repositoryGroups/%s",
1585+
config.GeminiBasePath, config.Project, location, codeRepositoryIndexId, repositoryGroupId)
1586+
1587+
headers := make(http.Header)
1588+
_, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
1589+
Config: config,
1590+
Method: "GET",
1591+
Project: config.Project,
1592+
RawURL: getURL,
1593+
UserAgent: config.UserAgent,
1594+
Headers: headers,
1595+
})
1596+
if err != nil {
1597+
log.Printf("[DEBUG] Repository group %q not found, bootstrapping", codeRepositoryIndexId)
1598+
repositories := [1]interface{}{map[string]string{
1599+
"resource": resource,
1600+
"branch_pattern": "main",
1601+
}}
1602+
postURL := fmt.Sprintf("%sprojects/%s/locations/%s/codeRepositoryIndexes/%s/repositoryGroups?repositoryGroupId=%s",
1603+
config.GeminiBasePath, config.Project, location, codeRepositoryIndexId, repositoryGroupId)
1604+
obj := map[string]interface{}{
1605+
"repositories": repositories,
1606+
}
1607+
if labels != "" {
1608+
obj["labels"] = labels
1609+
}
1610+
1611+
headers := make(http.Header)
1612+
for {
1613+
_, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
1614+
Config: config,
1615+
Method: "POST",
1616+
Project: config.Project,
1617+
RawURL: postURL,
1618+
UserAgent: config.UserAgent,
1619+
Body: obj,
1620+
Timeout: 20 * time.Minute,
1621+
Headers: headers,
1622+
})
1623+
if err != nil {
1624+
if transport_tpg.IsGoogleApiErrorWithCode(err, 409) {
1625+
errMsg := fmt.Sprintf("%s", err)
1626+
if strings.Contains(errMsg, "unable to queue the operation") {
1627+
log.Printf("[DEBUG] Waiting for enqueued operation to finish before creating RepositoryGroup: %#v", obj)
1628+
time.Sleep(10 * time.Second)
1629+
} else if strings.Contains(errMsg, "parent resource not in ready state") {
1630+
log.Printf("[DEBUG] Waiting for parent resource to become active before creating RepositoryGroup: %#v", obj)
1631+
time.Sleep(1 * time.Minute)
1632+
} else {
1633+
t.Fatalf("Error creating RepositoryGroup: %s", err)
1634+
}
1635+
} else {
1636+
t.Fatalf("Error creating repository group %q: %s", repositoryGroupId, err)
1637+
}
1638+
} else {
1639+
break
1640+
}
1641+
}
1642+
1643+
_, err = transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
1644+
Config: config,
1645+
Method: "GET",
1646+
Project: config.Project,
1647+
RawURL: getURL,
1648+
UserAgent: config.UserAgent,
1649+
Timeout: 20 * time.Minute,
1650+
Headers: headers,
1651+
})
1652+
if err != nil {
1653+
t.Errorf("Error getting repository group %q: %s", repositoryGroupId, err)
1654+
}
1655+
}
1656+
1657+
return repositoryGroupId
1658+
}
1659+
1660+
// BootstrapSharedCodeRepositoryIndex will create a code repository index
1661+
// if it hasn't been created in the test project.
1662+
//
1663+
// BootstrapSharedCodeRepositoryIndex returns a persistent code repository index
1664+
// for a test or set of tests.
1665+
//
1666+
// Deletion of code repository index takes a few minutes, and creation of it
1667+
// currently takes about half an hour.
1668+
// That is the reason to use the shared code repository indexes for test resources.
1669+
const SharedCodeRepositoryIndexPrefix = "tf-bootstrap-cri-"
1670+
1671+
func BootstrapSharedCodeRepositoryIndex(t *testing.T, codeRepositoryIndexId, location, kmsKey string, labels map[string]string) string {
1672+
codeRepositoryIndexId = SharedCodeRepositoryIndexPrefix + codeRepositoryIndexId
1673+
1674+
config := BootstrapConfig(t)
1675+
if config == nil {
1676+
t.Fatal("Could not bootstrap config.")
1677+
}
1678+
1679+
log.Printf("[DEBUG] Getting shared code repository index %q", codeRepositoryIndexId)
1680+
1681+
getURL := fmt.Sprintf("%sprojects/%s/locations/%s/codeRepositoryIndexes/%s", config.GeminiBasePath, config.Project, location, codeRepositoryIndexId)
1682+
1683+
headers := make(http.Header)
1684+
_, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
1685+
Config: config,
1686+
Method: "GET",
1687+
Project: config.Project,
1688+
RawURL: getURL,
1689+
UserAgent: config.UserAgent,
1690+
Timeout: 90 * time.Minute,
1691+
Headers: headers,
1692+
})
1693+
1694+
// CRI not found responds with 404 not found
1695+
if err != nil && transport_tpg.IsGoogleApiErrorWithCode(err, 404) {
1696+
log.Printf("[DEBUG] Code repository index %q not found, bootstrapping", codeRepositoryIndexId)
1697+
postURL := fmt.Sprintf("%sprojects/%s/locations/%s/codeRepositoryIndexes?codeRepositoryIndexId=%s", config.GeminiBasePath, config.Project, location, codeRepositoryIndexId)
1698+
obj := make(map[string]interface{})
1699+
if labels != nil {
1700+
obj["labels"] = labels
1701+
}
1702+
if kmsKey != "" {
1703+
obj["kmsKey"] = kmsKey
1704+
}
1705+
1706+
headers := make(http.Header)
1707+
_, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
1708+
Config: config,
1709+
Method: "POST",
1710+
Project: config.Project,
1711+
RawURL: postURL,
1712+
UserAgent: config.UserAgent,
1713+
Body: obj,
1714+
Timeout: 90 * time.Minute,
1715+
Headers: headers,
1716+
})
1717+
if err != nil {
1718+
t.Fatalf("Error creating code repository index %q: %s", codeRepositoryIndexId, err)
1719+
}
1720+
1721+
_, err = transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
1722+
Config: config,
1723+
Method: "GET",
1724+
Project: config.Project,
1725+
RawURL: getURL,
1726+
UserAgent: config.UserAgent,
1727+
Timeout: 90 * time.Minute,
1728+
Headers: headers,
1729+
})
1730+
if err != nil {
1731+
t.Fatalf("Error getting code repository index %q: %s", codeRepositoryIndexId, err)
1732+
}
1733+
} else if err != nil {
1734+
t.Fatalf("Error getting code repository index %q: %s", codeRepositoryIndexId, err)
1735+
}
1736+
1737+
return codeRepositoryIndexId
1738+
}
1739+
14291740
const sharedTagKeyPrefix = "tf-bootstrap-tagkey"
14301741

14311742
func BootstrapSharedTestTagKey(t *testing.T, testId string) string {

google/fwmodels/provider_model.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ type ProviderModel struct {
9696
FilestoreCustomEndpoint types.String `tfsdk:"filestore_custom_endpoint"`
9797
FirebaseAppCheckCustomEndpoint types.String `tfsdk:"firebase_app_check_custom_endpoint"`
9898
FirestoreCustomEndpoint types.String `tfsdk:"firestore_custom_endpoint"`
99+
GeminiCustomEndpoint types.String `tfsdk:"gemini_custom_endpoint"`
99100
GKEBackupCustomEndpoint types.String `tfsdk:"gke_backup_custom_endpoint"`
100101
GKEHubCustomEndpoint types.String `tfsdk:"gke_hub_custom_endpoint"`
101102
GKEHub2CustomEndpoint types.String `tfsdk:"gke_hub2_custom_endpoint"`

google/fwprovider/framework_provider.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,12 @@ func (p *FrameworkProvider) Schema(_ context.Context, _ provider.SchemaRequest,
556556
transport_tpg.CustomEndpointValidator(),
557557
},
558558
},
559+
"gemini_custom_endpoint": &schema.StringAttribute{
560+
Optional: true,
561+
Validators: []validator.String{
562+
transport_tpg.CustomEndpointValidator(),
563+
},
564+
},
559565
"gke_backup_custom_endpoint": &schema.StringAttribute{
560566
Optional: true,
561567
Validators: []validator.String{

google/provider/provider.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,11 @@ func Provider() *schema.Provider {
478478
Optional: true,
479479
ValidateFunc: transport_tpg.ValidateCustomEndpoint,
480480
},
481+
"gemini_custom_endpoint": {
482+
Type: schema.TypeString,
483+
Optional: true,
484+
ValidateFunc: transport_tpg.ValidateCustomEndpoint,
485+
},
481486
"gke_backup_custom_endpoint": {
482487
Type: schema.TypeString,
483488
Optional: true,
@@ -1060,6 +1065,7 @@ func ProviderConfigure(ctx context.Context, d *schema.ResourceData, p *schema.Pr
10601065
config.FilestoreBasePath = d.Get("filestore_custom_endpoint").(string)
10611066
config.FirebaseAppCheckBasePath = d.Get("firebase_app_check_custom_endpoint").(string)
10621067
config.FirestoreBasePath = d.Get("firestore_custom_endpoint").(string)
1068+
config.GeminiBasePath = d.Get("gemini_custom_endpoint").(string)
10631069
config.GKEBackupBasePath = d.Get("gke_backup_custom_endpoint").(string)
10641070
config.GKEHubBasePath = d.Get("gke_hub_custom_endpoint").(string)
10651071
config.GKEHub2BasePath = d.Get("gke_hub2_custom_endpoint").(string)

0 commit comments

Comments
 (0)