Skip to content

Commit

Permalink
feat: project group bindings
Browse files Browse the repository at this point in the history
  • Loading branch information
henryde committed Jun 21, 2024
1 parent 8e9bcae commit 7d20341
Show file tree
Hide file tree
Showing 18 changed files with 723 additions and 128 deletions.
23 changes: 10 additions & 13 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,6 @@ const (
ERROR_GENERIC_API_ERROR = "api error"
ERROR_AUTHENTICATION_FAILURE = "Not authorized. Check api key and secret."
ERROR_ENDPOINT_LOOKUP = "Could not fetch endpoints for meshStack."

CONTENT_TYPE_PROJECT = "application/vnd.meshcloud.api.meshproject.v2.hal+json"
CONTENT_TYPE_TENANT = "application/vnd.meshcloud.api.meshtenant.v3.hal+json"
CONTENT_TYPE_PROJECT_USER_BINDINGS = "application/vnd.meshcloud.api.meshprojectuserbinding.v1.hal+json"
CONTENT_TYPE_PROJECT_USER_BINDING = "application/vnd.meshcloud.api.meshprojectuserbinding.v3.hal+json"
)

type MeshStackProviderClient struct {
Expand All @@ -38,10 +33,11 @@ type MeshStackProviderClient struct {
}

type endpoints struct {
BuildingBlocks *url.URL `json:"meshbuildingblocks"`
Projects *url.URL `json:"meshprojects"`
ProjectUserBindings *url.URL `json:"meshprojectuserbindings"`
Tenants *url.URL `json:"meshtenants"`
BuildingBlocks *url.URL `json:"meshbuildingblocks"`
Projects *url.URL `json:"meshprojects"`
ProjectUserBindings *url.URL `json:"meshprojectuserbindings"`
ProjectGroupBindings *url.URL `json:"meshprojectgroupbindings"`
Tenants *url.URL `json:"meshtenants"`
}

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

// TODO: lookup endpoints
client.endpoints = endpoints{
BuildingBlocks: rootUrl.JoinPath(apiMeshObjectsRoot, "meshbuildingblocks"),
Projects: rootUrl.JoinPath(apiMeshObjectsRoot, "meshprojects"),
ProjectUserBindings: rootUrl.JoinPath(apiMeshObjectsRoot, "meshprojectbindings", "userbindings"),
Tenants: rootUrl.JoinPath(apiMeshObjectsRoot, "meshtenants"),
BuildingBlocks: rootUrl.JoinPath(apiMeshObjectsRoot, "meshbuildingblocks"),
Projects: rootUrl.JoinPath(apiMeshObjectsRoot, "meshprojects"),
ProjectUserBindings: rootUrl.JoinPath(apiMeshObjectsRoot, "meshprojectbindings", "userbindings"),
ProjectGroupBindings: rootUrl.JoinPath(apiMeshObjectsRoot, "meshprojectbindings", "groupbindings"),
Tenants: rootUrl.JoinPath(apiMeshObjectsRoot, "meshtenants"),
}

return client, nil
Expand Down
2 changes: 2 additions & 0 deletions client/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"net/url"
)

const CONTENT_TYPE_PROJECT = "application/vnd.meshcloud.api.meshproject.v2.hal+json"

type MeshProject struct {
ApiVersion string `json:"apiVersion" tfsdk:"api_version"`
Kind string `json:"kind" tfsdk:"kind"`
Expand Down
134 changes: 134 additions & 0 deletions client/project_binding.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package client

import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
)

type MeshProjectBinding struct {
ApiVersion string `json:"apiVersion" tfsdk:"api_version"`
Kind string `json:"kind" tfsdk:"kind"`
Metadata MeshProjectBindingMetadata `json:"metadata" tfsdk:"metadata"`
RoleRef MeshProjectRoleRef `json:"roleRef" tfsdk:"role_ref"`
TargetRef MeshProjectTargetRef `json:"targetRef" tfsdk:"target_ref"`
Subject MeshSubject `json:"subject" tfsdk:"subject"`
}

type MeshProjectBindingMetadata struct {
Name string `json:"name" tfsdk:"name"`
}

type MeshProjectRoleRef struct {
Name string `json:"name" tfsdk:"name"`
}

type MeshProjectTargetRef struct {
Name string `json:"name" tfsdk:"name"`
OwnedByWorkspace string `json:"ownedByWorkspace" tfsdk:"owned_by_workspace"`
}

type MeshSubject struct {
Name string `json:"name" tfsdk:"name"`
}

func (c *MeshStackProviderClient) readProjectBinding(name string, contentType string) (*MeshProjectBinding, error) {
var targetUrl *url.URL
switch contentType {
case CONTENT_TYPE_PROJECT_USER_BINDING:
targetUrl = c.urlForPojectUserBinding(name)

case CONTENT_TYPE_PROJECT_GROUP_BINDING:
targetUrl = c.urlForPojectGroupBinding(name)

default:
return nil, fmt.Errorf("Unexpected content type: %s", contentType)
}

req, err := http.NewRequest("GET", targetUrl.String(), nil)
if err != nil {
return nil, err
}
req.Header.Set("Accept", contentType)

res, err := c.doAuthenticatedRequest(req)
if err != nil {
return nil, err
}

defer res.Body.Close()

data, err := io.ReadAll(res.Body)
if err != nil {
return nil, err
}

if res.StatusCode == 404 {
return nil, nil
}

if res.StatusCode != 200 {
return nil, fmt.Errorf("unexpected status code: %d, %s", res.StatusCode, data)
}

var binding MeshProjectBinding
err = json.Unmarshal(data, &binding)
if err != nil {
return nil, err
}

return &binding, nil
}

func (c *MeshStackProviderClient) createProjectBinding(binding *MeshProjectBinding, contentType string) (*MeshProjectBinding, error) {
var targetUrl *url.URL
switch contentType {
case CONTENT_TYPE_PROJECT_USER_BINDING:
targetUrl = c.endpoints.ProjectUserBindings

case CONTENT_TYPE_PROJECT_GROUP_BINDING:
targetUrl = c.endpoints.ProjectGroupBindings

default:
return nil, fmt.Errorf("Unexpected content type: %s", contentType)
}

payload, err := json.Marshal(binding)
if err != nil {
return nil, err
}

req, err := http.NewRequest("POST", targetUrl.String(), bytes.NewBuffer(payload))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", CONTENT_TYPE_PROJECT_GROUP_BINDING)
req.Header.Set("Accept", CONTENT_TYPE_PROJECT_GROUP_BINDING)

res, err := c.doAuthenticatedRequest(req)
if err != nil {
return nil, err
}

defer res.Body.Close()

data, err := io.ReadAll(res.Body)
if err != nil {
return nil, err
}

if res.StatusCode != 200 {
return nil, fmt.Errorf("unexpected status code: %d, %s", res.StatusCode, data)
}

var createdBinding MeshProjectBinding
err = json.Unmarshal(data, &createdBinding)
if err != nil {
return nil, err
}

return &createdBinding, nil
}
26 changes: 26 additions & 0 deletions client/project_group_binding.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package client

import (
"net/url"
)

const CONTENT_TYPE_PROJECT_GROUP_BINDING = "application/vnd.meshcloud.api.meshprojectgroupbinding.v3.hal+json"

type MeshProjectGroupBinding = MeshProjectBinding

func (c *MeshStackProviderClient) urlForPojectGroupBinding(name string) *url.URL {
return c.endpoints.ProjectGroupBindings.JoinPath(name)
}

func (c *MeshStackProviderClient) ReadProjectGroupBinding(name string) (*MeshProjectGroupBinding, error) {
return c.readProjectBinding(name, CONTENT_TYPE_PROJECT_GROUP_BINDING)
}

func (c *MeshStackProviderClient) CreateProjectGroupBinding(binding *MeshProjectGroupBinding) (*MeshProjectGroupBinding, error) {
return c.createProjectBinding(binding, CONTENT_TYPE_PROJECT_GROUP_BINDING)
}

func (c *MeshStackProviderClient) DeleteProjecGroupBinding(name string) error {
targetUrl := c.urlForPojectGroupBinding(name)
return c.deleteMeshObject(*targetUrl, 204)
}
102 changes: 4 additions & 98 deletions client/project_user_binding.go
Original file line number Diff line number Diff line change
@@ -1,117 +1,23 @@
package client

import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
)

type MeshProjectUserBinding struct {
ApiVersion string `json:"apiVersion" tfsdk:"api_version"`
Kind string `json:"kind" tfsdk:"kind"`
Metadata MeshProjectUserBindingMetadata `json:"metadata" tfsdk:"metadata"`
RoleRef MeshProjectRoleRef `json:"roleRef" tfsdk:"role_ref"`
TargetRef MeshProjectTargetRef `json:"targetRef" tfsdk:"target_ref"`
Subject MeshSubject `json:"subject" tfsdk:"subject"`
}

type MeshProjectUserBindingMetadata struct {
Name string `json:"name" tfsdk:"name"`
}

type MeshProjectRoleRef struct {
Name string `json:"name" tfsdk:"name"`
}

type MeshProjectTargetRef struct {
Name string `json:"name" tfsdk:"name"`
OwnedByWorkspace string `json:"ownedByWorkspace" tfsdk:"owned_by_workspace"`
}
const CONTENT_TYPE_PROJECT_USER_BINDING = "application/vnd.meshcloud.api.meshprojectuserbinding.v3.hal+json"

type MeshSubject struct {
Name string `json:"name" tfsdk:"name"`
}
type MeshProjectUserBinding = MeshProjectBinding

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

func (c *MeshStackProviderClient) ReadProjectUserBinding(name string) (*MeshProjectUserBinding, error) {
targetUrl := c.urlForPojectUserBinding(name)
req, err := http.NewRequest("GET", targetUrl.String(), nil)
if err != nil {
return nil, err
}
req.Header.Set("Accept", CONTENT_TYPE_PROJECT_USER_BINDING)

res, err := c.doAuthenticatedRequest(req)
if err != nil {
return nil, err
}

defer res.Body.Close()

data, err := io.ReadAll(res.Body)
if err != nil {
return nil, err
}

if res.StatusCode == 404 {
return nil, nil
}

if res.StatusCode != 200 {
return nil, fmt.Errorf("unexpected status code: %d, %s", res.StatusCode, data)
}

var binding MeshProjectUserBinding
err = json.Unmarshal(data, &binding)
if err != nil {
return nil, err
}

return &binding, nil
return c.readProjectBinding(name, CONTENT_TYPE_PROJECT_USER_BINDING)
}

func (c *MeshStackProviderClient) CreateProjectUserBinding(binding *MeshProjectUserBinding) (*MeshProjectUserBinding, error) {
payload, err := json.Marshal(binding)
if err != nil {
return nil, err
}

req, err := http.NewRequest("POST", c.endpoints.ProjectUserBindings.String(), bytes.NewBuffer(payload))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", CONTENT_TYPE_PROJECT_USER_BINDING)
req.Header.Set("Accept", CONTENT_TYPE_PROJECT_USER_BINDING)

res, err := c.doAuthenticatedRequest(req)
if err != nil {
return nil, err
}

defer res.Body.Close()

data, err := io.ReadAll(res.Body)
if err != nil {
return nil, err
}

if res.StatusCode != 200 {
return nil, fmt.Errorf("unexpected status code: %d, %s", res.StatusCode, data)
}

var createdBinding MeshProjectUserBinding
err = json.Unmarshal(data, &createdBinding)
if err != nil {
return nil, err
}

return &createdBinding, nil
return c.createProjectBinding(binding, CONTENT_TYPE_PROJECT_USER_BINDING)
}

func (c *MeshStackProviderClient) DeleteProjecUserBinding(name string) error {
Expand Down
2 changes: 2 additions & 0 deletions client/tenant.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"net/url"
)

const CONTENT_TYPE_TENANT = "application/vnd.meshcloud.api.meshtenant.v3.hal+json"

type MeshTenant struct {
ApiVersion string `json:"apiVersion" tfsdk:"api_version"`
Kind string `json:"kind" tfsdk:"kind"`
Expand Down
Loading

0 comments on commit 7d20341

Please sign in to comment.