Skip to content

Commit 02cb6d6

Browse files
committed
wip
1 parent 2f12f00 commit 02cb6d6

File tree

2 files changed

+198
-1
lines changed

2 files changed

+198
-1
lines changed

client/client.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ type endpoints struct {
4545
LandingZones *url.URL `json:"meshlandingzones"`
4646
Platforms *url.URL `json:"meshplatforms"`
4747
PaymentMethods *url.URL `json:"meshpaymentmethods"`
48+
Integrations *url.URL `json:"meshintegrations"`
4849
}
4950

5051
type loginRequest struct {
@@ -82,6 +83,7 @@ func NewClient(rootUrl *url.URL, apiKey string, apiSecret string) (*MeshStackPro
8283
LandingZones: rootUrl.JoinPath(apiMeshObjectsRoot, "meshlandingzones"),
8384
Platforms: rootUrl.JoinPath(apiMeshObjectsRoot, "meshplatforms"),
8485
PaymentMethods: rootUrl.JoinPath(apiMeshObjectsRoot, "meshpaymentmethods"),
86+
Integrations: rootUrl.JoinPath(apiMeshObjectsRoot, "meshintegrations"),
8587
}
8688

8789
return client, nil
@@ -111,7 +113,7 @@ func (c *MeshStackProviderClient) login() error {
111113
if err != nil {
112114
return err
113115
} else if res.StatusCode != 200 {
114-
return errors.New(fmt.Sprintf("Status %d: %s", res.StatusCode, ERROR_AUTHENTICATION_FAILURE))
116+
return fmt.Errorf("Status %d: %s", res.StatusCode, ERROR_AUTHENTICATION_FAILURE)
115117
}
116118

117119
defer res.Body.Close()

client/integrations.go

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
package client
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"io"
7+
"net/http"
8+
"net/url"
9+
)
10+
11+
const CONTENT_TYPE_INTEGRATION = "application/vnd.meshcloud.api.meshintegration.v1-preview.hal+json"
12+
13+
type MeshIntegration struct {
14+
ApiVersion string `json:"apiVersion" tfsdk:"api_version"`
15+
Kind string `json:"kind" tfsdk:"kind"`
16+
Metadata MeshIntegrationMetadata `json:"metadata" tfsdk:"metadata"`
17+
Spec MeshIntegrationSpec `json:"spec" tfsdk:"spec"`
18+
Status *MeshIntegrationStatus `json:"status,omitempty" tfsdk:"status"`
19+
}
20+
21+
type MeshIntegrationMetadata struct {
22+
UUID *string `json:"uuid,omitempty" tfsdk:"uuid"`
23+
OwnedByWorkspace string `json:"ownedByWorkspace" tfsdk:"owned_by_workspace"`
24+
CreatedOn *string `json:"createdOn,omitempty" tfsdk:"created_on"`
25+
}
26+
27+
type MeshIntegrationSpec struct {
28+
DisplayName string `json:"displayName" tfsdk:"display_name"`
29+
Config MeshIntegrationConfig `json:"config" tfsdk:"config"`
30+
}
31+
32+
type MeshIntegrationStatus struct {
33+
IsBuiltIn bool `json:"isBuiltIn" tfsdk:"is_built_in"`
34+
WorkloadIdentityFederation *MeshWorkloadIdentityFederation `json:"workloadIdentityFederation,omitempty" tfsdk:"workload_identity_federation"`
35+
}
36+
37+
// Integration Config wrapper with type discrimination
38+
type MeshIntegrationConfig struct {
39+
Type string `json:"type" tfsdk:"type"`
40+
Github *MeshGithubIntegrationProperties `json:"github,omitempty" tfsdk:"github"`
41+
Gitlab *MeshGitlabIntegrationProperties `json:"gitlab,omitempty" tfsdk:"gitlab"`
42+
AzureDevops *MeshAzureDevopsIntegrationProperties `json:"azuredevops,omitempty" tfsdk:"azuredevops"`
43+
}
44+
45+
// GitHub Integration
46+
type MeshGithubIntegrationProperties struct {
47+
Owner string `json:"owner" tfsdk:"owner"`
48+
BaseUrl string `json:"baseUrl" tfsdk:"base_url"`
49+
AppId string `json:"appId" tfsdk:"app_id"`
50+
AppPrivateKey string `json:"appPrivateKey" tfsdk:"app_private_key"`
51+
RunnerRef BuildingBlockRunnerRef `json:"runnerRef" tfsdk:"runner_ref"`
52+
}
53+
54+
// GitLab Integration
55+
type MeshGitlabIntegrationProperties struct {
56+
BaseUrl string `json:"baseUrl" tfsdk:"base_url"`
57+
RunnerRef BuildingBlockRunnerRef `json:"runnerRef" tfsdk:"runner_ref"`
58+
}
59+
60+
// Azure DevOps Integration
61+
type MeshAzureDevopsIntegrationProperties struct {
62+
BaseUrl string `json:"baseUrl" tfsdk:"base_url"`
63+
Organization string `json:"organization" tfsdk:"organization"`
64+
PersonalAccessToken string `json:"personalAccessToken" tfsdk:"personal_access_token"`
65+
RunnerRef BuildingBlockRunnerRef `json:"runnerRef" tfsdk:"runner_ref"`
66+
}
67+
68+
// Building Block Runner Reference
69+
type BuildingBlockRunnerRef struct {
70+
UUID string `json:"uuid" tfsdk:"uuid"`
71+
}
72+
73+
// Workload Identity Federation
74+
type MeshWorkloadIdentityFederation struct {
75+
Issuer string `json:"issuer" tfsdk:"issuer"`
76+
Subject string `json:"subject" tfsdk:"subject"`
77+
Gcp *MeshWifProvider `json:"gcp,omitempty" tfsdk:"gcp"`
78+
Aws *MeshAwsWifProvider `json:"aws,omitempty" tfsdk:"aws"`
79+
Azure *MeshWifProvider `json:"azure,omitempty" tfsdk:"azure"`
80+
}
81+
82+
type MeshWifProvider struct {
83+
Audience string `json:"audience" tfsdk:"audience"`
84+
}
85+
86+
type MeshAwsWifProvider struct {
87+
Audience string `json:"audience" tfsdk:"audience"`
88+
Thumbprint string `json:"thumbprint" tfsdk:"thumbprint"`
89+
}
90+
91+
func (c *MeshStackProviderClient) urlForIntegration(workspace string, uuid string) *url.URL {
92+
return c.endpoints.Integrations.JoinPath(workspace, uuid)
93+
}
94+
95+
func (c *MeshStackProviderClient) ReadIntegration(workspace string, uuid string) (*MeshIntegration, error) {
96+
targetUrl := c.urlForIntegration(workspace, uuid)
97+
req, err := http.NewRequest("GET", targetUrl.String(), nil)
98+
if err != nil {
99+
return nil, err
100+
}
101+
req.Header.Set("Accept", CONTENT_TYPE_INTEGRATION)
102+
103+
res, err := c.doAuthenticatedRequest(req)
104+
if err != nil {
105+
return nil, err
106+
}
107+
108+
defer res.Body.Close()
109+
110+
data, err := io.ReadAll(res.Body)
111+
if err != nil {
112+
return nil, err
113+
}
114+
115+
if res.StatusCode == http.StatusNotFound {
116+
return nil, nil
117+
}
118+
119+
if !isSuccessHTTPStatus(res) {
120+
return nil, fmt.Errorf("unexpected status code: %d, %s", res.StatusCode, data)
121+
}
122+
123+
var integration MeshIntegration
124+
err = json.Unmarshal(data, &integration)
125+
if err != nil {
126+
return nil, err
127+
}
128+
129+
return &integration, nil
130+
}
131+
132+
func (c *MeshStackProviderClient) ReadIntegrations(workspaceIdentifier string) (*[]MeshIntegration, error) {
133+
var allIntegrations []MeshIntegration
134+
135+
pageNumber := 0
136+
targetUrl := c.endpoints.Integrations
137+
query := targetUrl.Query()
138+
query.Set("workspaceIdentifier", workspaceIdentifier)
139+
140+
for {
141+
query.Set("page", fmt.Sprintf("%d", pageNumber))
142+
targetUrl.RawQuery = query.Encode()
143+
144+
req, err := http.NewRequest("GET", targetUrl.String(), nil)
145+
if err != nil {
146+
return nil, err
147+
}
148+
149+
req.Header.Set("Accept", CONTENT_TYPE_INTEGRATION)
150+
151+
res, err := c.doAuthenticatedRequest(req)
152+
if err != nil {
153+
return nil, err
154+
}
155+
156+
defer res.Body.Close()
157+
158+
data, err := io.ReadAll(res.Body)
159+
if err != nil {
160+
return nil, fmt.Errorf("failed to read response body: %w", err)
161+
}
162+
163+
if !isSuccessHTTPStatus(res) {
164+
return nil, fmt.Errorf("unexpected status code: %d, %s", res.StatusCode, data)
165+
}
166+
167+
var response struct {
168+
Embedded struct {
169+
MeshIntegrations []MeshIntegration `json:"meshIntegrations"`
170+
} `json:"_embedded"`
171+
Page struct {
172+
Size int `json:"size"`
173+
TotalElements int `json:"totalElements"`
174+
TotalPages int `json:"totalPages"`
175+
Number int `json:"number"`
176+
} `json:"page"`
177+
}
178+
179+
err = json.Unmarshal(data, &response)
180+
if err != nil {
181+
return nil, err
182+
}
183+
184+
allIntegrations = append(allIntegrations, response.Embedded.MeshIntegrations...)
185+
186+
// Check if there are more pages
187+
if response.Page.Number >= response.Page.TotalPages-1 {
188+
break
189+
}
190+
191+
pageNumber++
192+
}
193+
194+
return &allIntegrations, nil
195+
}

0 commit comments

Comments
 (0)