Skip to content

Commit e287df7

Browse files
committed
feat: project group bindings
1 parent 0778b43 commit e287df7

18 files changed

+723
-128
lines changed

client/client.go

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,6 @@ const (
2020
ERROR_GENERIC_API_ERROR = "api error"
2121
ERROR_AUTHENTICATION_FAILURE = "Not authorized. Check api key and secret."
2222
ERROR_ENDPOINT_LOOKUP = "Could not fetch endpoints for meshStack."
23-
24-
CONTENT_TYPE_PROJECT = "application/vnd.meshcloud.api.meshproject.v2.hal+json"
25-
CONTENT_TYPE_TENANT = "application/vnd.meshcloud.api.meshtenant.v3.hal+json"
26-
CONTENT_TYPE_PROJECT_USER_BINDINGS = "application/vnd.meshcloud.api.meshprojectuserbinding.v1.hal+json"
27-
CONTENT_TYPE_PROJECT_USER_BINDING = "application/vnd.meshcloud.api.meshprojectuserbinding.v3.hal+json"
2823
)
2924

3025
type MeshStackProviderClient struct {
@@ -38,10 +33,11 @@ type MeshStackProviderClient struct {
3833
}
3934

4035
type endpoints struct {
41-
BuildingBlocks *url.URL `json:"meshbuildingblocks"`
42-
Projects *url.URL `json:"meshprojects"`
43-
ProjectUserBindings *url.URL `json:"meshprojectuserbindings"`
44-
Tenants *url.URL `json:"meshtenants"`
36+
BuildingBlocks *url.URL `json:"meshbuildingblocks"`
37+
Projects *url.URL `json:"meshprojects"`
38+
ProjectUserBindings *url.URL `json:"meshprojectuserbindings"`
39+
ProjectGroupBindings *url.URL `json:"meshprojectgroupbindings"`
40+
Tenants *url.URL `json:"meshtenants"`
4541
}
4642

4743
type loginResponse struct {
@@ -62,10 +58,11 @@ func NewClient(rootUrl *url.URL, apiKey string, apiSecret string) (*MeshStackPro
6258

6359
// TODO: lookup endpoints
6460
client.endpoints = endpoints{
65-
BuildingBlocks: rootUrl.JoinPath(apiMeshObjectsRoot, "meshbuildingblocks"),
66-
Projects: rootUrl.JoinPath(apiMeshObjectsRoot, "meshprojects"),
67-
ProjectUserBindings: rootUrl.JoinPath(apiMeshObjectsRoot, "meshprojectbindings", "userbindings"),
68-
Tenants: rootUrl.JoinPath(apiMeshObjectsRoot, "meshtenants"),
61+
BuildingBlocks: rootUrl.JoinPath(apiMeshObjectsRoot, "meshbuildingblocks"),
62+
Projects: rootUrl.JoinPath(apiMeshObjectsRoot, "meshprojects"),
63+
ProjectUserBindings: rootUrl.JoinPath(apiMeshObjectsRoot, "meshprojectbindings", "userbindings"),
64+
ProjectGroupBindings: rootUrl.JoinPath(apiMeshObjectsRoot, "meshprojectbindings", "groupbindings"),
65+
Tenants: rootUrl.JoinPath(apiMeshObjectsRoot, "meshtenants"),
6966
}
7067

7168
return client, nil

client/project.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import (
99
"net/url"
1010
)
1111

12+
const CONTENT_TYPE_PROJECT = "application/vnd.meshcloud.api.meshproject.v2.hal+json"
13+
1214
type MeshProject struct {
1315
ApiVersion string `json:"apiVersion" tfsdk:"api_version"`
1416
Kind string `json:"kind" tfsdk:"kind"`

client/project_binding.go

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
package client
2+
3+
import (
4+
"bytes"
5+
"encoding/json"
6+
"fmt"
7+
"io"
8+
"net/http"
9+
"net/url"
10+
)
11+
12+
type MeshProjectBinding struct {
13+
ApiVersion string `json:"apiVersion" tfsdk:"api_version"`
14+
Kind string `json:"kind" tfsdk:"kind"`
15+
Metadata MeshProjectBindingMetadata `json:"metadata" tfsdk:"metadata"`
16+
RoleRef MeshProjectRoleRef `json:"roleRef" tfsdk:"role_ref"`
17+
TargetRef MeshProjectTargetRef `json:"targetRef" tfsdk:"target_ref"`
18+
Subject MeshSubject `json:"subject" tfsdk:"subject"`
19+
}
20+
21+
type MeshProjectBindingMetadata struct {
22+
Name string `json:"name" tfsdk:"name"`
23+
}
24+
25+
type MeshProjectRoleRef struct {
26+
Name string `json:"name" tfsdk:"name"`
27+
}
28+
29+
type MeshProjectTargetRef struct {
30+
Name string `json:"name" tfsdk:"name"`
31+
OwnedByWorkspace string `json:"ownedByWorkspace" tfsdk:"owned_by_workspace"`
32+
}
33+
34+
type MeshSubject struct {
35+
Name string `json:"name" tfsdk:"name"`
36+
}
37+
38+
func (c *MeshStackProviderClient) readProjectBinding(name string, contentType string) (*MeshProjectBinding, error) {
39+
var targetUrl *url.URL
40+
switch contentType {
41+
case CONTENT_TYPE_PROJECT_USER_BINDING:
42+
targetUrl = c.urlForPojectUserBinding(name)
43+
44+
case CONTENT_TYPE_PROJECT_GROUP_BINDING:
45+
targetUrl = c.urlForPojectGroupBinding(name)
46+
47+
default:
48+
return nil, fmt.Errorf("Unexpected content type: %s", contentType)
49+
}
50+
51+
req, err := http.NewRequest("GET", targetUrl.String(), nil)
52+
if err != nil {
53+
return nil, err
54+
}
55+
req.Header.Set("Accept", contentType)
56+
57+
res, err := c.doAuthenticatedRequest(req)
58+
if err != nil {
59+
return nil, err
60+
}
61+
62+
defer res.Body.Close()
63+
64+
data, err := io.ReadAll(res.Body)
65+
if err != nil {
66+
return nil, err
67+
}
68+
69+
if res.StatusCode == 404 {
70+
return nil, nil
71+
}
72+
73+
if res.StatusCode != 200 {
74+
return nil, fmt.Errorf("unexpected status code: %d, %s", res.StatusCode, data)
75+
}
76+
77+
var binding MeshProjectBinding
78+
err = json.Unmarshal(data, &binding)
79+
if err != nil {
80+
return nil, err
81+
}
82+
83+
return &binding, nil
84+
}
85+
86+
func (c *MeshStackProviderClient) createProjectBinding(binding *MeshProjectBinding, contentType string) (*MeshProjectBinding, error) {
87+
var targetUrl *url.URL
88+
switch contentType {
89+
case CONTENT_TYPE_PROJECT_USER_BINDING:
90+
targetUrl = c.endpoints.ProjectUserBindings
91+
92+
case CONTENT_TYPE_PROJECT_GROUP_BINDING:
93+
targetUrl = c.endpoints.ProjectGroupBindings
94+
95+
default:
96+
return nil, fmt.Errorf("Unexpected content type: %s", contentType)
97+
}
98+
99+
payload, err := json.Marshal(binding)
100+
if err != nil {
101+
return nil, err
102+
}
103+
104+
req, err := http.NewRequest("POST", targetUrl.String(), bytes.NewBuffer(payload))
105+
if err != nil {
106+
return nil, err
107+
}
108+
req.Header.Set("Content-Type", CONTENT_TYPE_PROJECT_GROUP_BINDING)
109+
req.Header.Set("Accept", CONTENT_TYPE_PROJECT_GROUP_BINDING)
110+
111+
res, err := c.doAuthenticatedRequest(req)
112+
if err != nil {
113+
return nil, err
114+
}
115+
116+
defer res.Body.Close()
117+
118+
data, err := io.ReadAll(res.Body)
119+
if err != nil {
120+
return nil, err
121+
}
122+
123+
if res.StatusCode != 200 {
124+
return nil, fmt.Errorf("unexpected status code: %d, %s", res.StatusCode, data)
125+
}
126+
127+
var createdBinding MeshProjectBinding
128+
err = json.Unmarshal(data, &createdBinding)
129+
if err != nil {
130+
return nil, err
131+
}
132+
133+
return &createdBinding, nil
134+
}

client/project_group_binding.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package client
2+
3+
import (
4+
"net/url"
5+
)
6+
7+
const CONTENT_TYPE_PROJECT_GROUP_BINDING = "application/vnd.meshcloud.api.meshprojectgroupbinding.v3.hal+json"
8+
9+
type MeshProjectGroupBinding = MeshProjectBinding
10+
11+
func (c *MeshStackProviderClient) urlForPojectGroupBinding(name string) *url.URL {
12+
return c.endpoints.ProjectGroupBindings.JoinPath(name)
13+
}
14+
15+
func (c *MeshStackProviderClient) ReadProjectGroupBinding(name string) (*MeshProjectGroupBinding, error) {
16+
return c.readProjectBinding(name, CONTENT_TYPE_PROJECT_GROUP_BINDING)
17+
}
18+
19+
func (c *MeshStackProviderClient) CreateProjectGroupBinding(binding *MeshProjectGroupBinding) (*MeshProjectGroupBinding, error) {
20+
return c.createProjectBinding(binding, CONTENT_TYPE_PROJECT_GROUP_BINDING)
21+
}
22+
23+
func (c *MeshStackProviderClient) DeleteProjecGroupBinding(name string) error {
24+
targetUrl := c.urlForPojectGroupBinding(name)
25+
return c.deleteMeshObject(*targetUrl, 204)
26+
}

client/project_user_binding.go

Lines changed: 4 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,117 +1,23 @@
11
package client
22

33
import (
4-
"bytes"
5-
"encoding/json"
6-
"fmt"
7-
"io"
8-
"net/http"
94
"net/url"
105
)
116

12-
type MeshProjectUserBinding struct {
13-
ApiVersion string `json:"apiVersion" tfsdk:"api_version"`
14-
Kind string `json:"kind" tfsdk:"kind"`
15-
Metadata MeshProjectUserBindingMetadata `json:"metadata" tfsdk:"metadata"`
16-
RoleRef MeshProjectRoleRef `json:"roleRef" tfsdk:"role_ref"`
17-
TargetRef MeshProjectTargetRef `json:"targetRef" tfsdk:"target_ref"`
18-
Subject MeshSubject `json:"subject" tfsdk:"subject"`
19-
}
20-
21-
type MeshProjectUserBindingMetadata struct {
22-
Name string `json:"name" tfsdk:"name"`
23-
}
24-
25-
type MeshProjectRoleRef struct {
26-
Name string `json:"name" tfsdk:"name"`
27-
}
28-
29-
type MeshProjectTargetRef struct {
30-
Name string `json:"name" tfsdk:"name"`
31-
OwnedByWorkspace string `json:"ownedByWorkspace" tfsdk:"owned_by_workspace"`
32-
}
7+
const CONTENT_TYPE_PROJECT_USER_BINDING = "application/vnd.meshcloud.api.meshprojectuserbinding.v3.hal+json"
338

34-
type MeshSubject struct {
35-
Name string `json:"name" tfsdk:"name"`
36-
}
9+
type MeshProjectUserBinding = MeshProjectBinding
3710

3811
func (c *MeshStackProviderClient) urlForPojectUserBinding(name string) *url.URL {
3912
return c.endpoints.ProjectUserBindings.JoinPath(name)
4013
}
4114

4215
func (c *MeshStackProviderClient) ReadProjectUserBinding(name string) (*MeshProjectUserBinding, error) {
43-
targetUrl := c.urlForPojectUserBinding(name)
44-
req, err := http.NewRequest("GET", targetUrl.String(), nil)
45-
if err != nil {
46-
return nil, err
47-
}
48-
req.Header.Set("Accept", CONTENT_TYPE_PROJECT_USER_BINDING)
49-
50-
res, err := c.doAuthenticatedRequest(req)
51-
if err != nil {
52-
return nil, err
53-
}
54-
55-
defer res.Body.Close()
56-
57-
data, err := io.ReadAll(res.Body)
58-
if err != nil {
59-
return nil, err
60-
}
61-
62-
if res.StatusCode == 404 {
63-
return nil, nil
64-
}
65-
66-
if res.StatusCode != 200 {
67-
return nil, fmt.Errorf("unexpected status code: %d, %s", res.StatusCode, data)
68-
}
69-
70-
var binding MeshProjectUserBinding
71-
err = json.Unmarshal(data, &binding)
72-
if err != nil {
73-
return nil, err
74-
}
75-
76-
return &binding, nil
16+
return c.readProjectBinding(name, CONTENT_TYPE_PROJECT_USER_BINDING)
7717
}
7818

7919
func (c *MeshStackProviderClient) CreateProjectUserBinding(binding *MeshProjectUserBinding) (*MeshProjectUserBinding, error) {
80-
payload, err := json.Marshal(binding)
81-
if err != nil {
82-
return nil, err
83-
}
84-
85-
req, err := http.NewRequest("POST", c.endpoints.ProjectUserBindings.String(), bytes.NewBuffer(payload))
86-
if err != nil {
87-
return nil, err
88-
}
89-
req.Header.Set("Content-Type", CONTENT_TYPE_PROJECT_USER_BINDING)
90-
req.Header.Set("Accept", CONTENT_TYPE_PROJECT_USER_BINDING)
91-
92-
res, err := c.doAuthenticatedRequest(req)
93-
if err != nil {
94-
return nil, err
95-
}
96-
97-
defer res.Body.Close()
98-
99-
data, err := io.ReadAll(res.Body)
100-
if err != nil {
101-
return nil, err
102-
}
103-
104-
if res.StatusCode != 200 {
105-
return nil, fmt.Errorf("unexpected status code: %d, %s", res.StatusCode, data)
106-
}
107-
108-
var createdBinding MeshProjectUserBinding
109-
err = json.Unmarshal(data, &createdBinding)
110-
if err != nil {
111-
return nil, err
112-
}
113-
114-
return &createdBinding, nil
20+
return c.createProjectBinding(binding, CONTENT_TYPE_PROJECT_USER_BINDING)
11521
}
11622

11723
func (c *MeshStackProviderClient) DeleteProjecUserBinding(name string) error {

client/tenant.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import (
99
"net/url"
1010
)
1111

12+
const CONTENT_TYPE_TENANT = "application/vnd.meshcloud.api.meshtenant.v3.hal+json"
13+
1214
type MeshTenant struct {
1315
ApiVersion string `json:"apiVersion" tfsdk:"api_version"`
1416
Kind string `json:"kind" tfsdk:"kind"`

0 commit comments

Comments
 (0)