Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: project group bindings #20

Merged
merged 1 commit into from
Jul 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading