Skip to content

Commit

Permalink
PRODENG-2237 Added pruning policy resource
Browse files Browse the repository at this point in the history
Signed-off-by: Dimitar Dimitrov <[email protected]>
  • Loading branch information
cranzy committed Sep 14, 2023
1 parent 913d62b commit 13868b6
Show file tree
Hide file tree
Showing 8 changed files with 716 additions and 50 deletions.
39 changes: 39 additions & 0 deletions docs/resources/pruning_policy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "msr_pruning_policy Resource - terraform-provider-msr"
subcategory: ""
description: |-
Pruning policy resource
---

# msr_pruning_policy (Resource)

Pruning policy resource



<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `org_name` (String) The organization that contains the repo
- `repo_name` (String) The repository to apply the pruning policy on

### Optional

- `enabled` (Boolean) Is the pruning policy enabled
- `rule` (Block List) The rules of the pruning policy (see [below for nested schema](#nestedblock--rule))

### Read-Only

- `id` (String) Identifier

<a id="nestedblock--rule"></a>
### Nested Schema for `rule`

Required:

- `field` (String) The field for the rule
- `operator` (String) The operator for the particular field
- `values` (List of String) The regex values for the rule
118 changes: 118 additions & 0 deletions internal/client/pruning_policy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package client

import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"

"github.com/hashicorp/terraform-plugin-framework/types"
)

type PruningPolicyRuleAPI struct {
Field string `tfsdk:"field" json:"field"`
Operator string `tfsdk:"operator" json:"operator"`
Values []string `tfsdk:"values" json:"values"`
}

type PruningPolicyRuleTFSDK struct {
Field types.String `tfsdk:"field" json:"field"`
Operator types.String `tfsdk:"operator" json:"operator"`
Values []types.String `tfsdk:"values" json:"values"`
}

type CreatePruningPolicy struct {
Enabled bool `json:"enabled"`
Rules []PruningPolicyRuleAPI `json:"rules"`
}

type ResponsePruningPolicy struct {
ID string `json:"id"`
Enabled bool `json:"enabled"`
Rules []PruningPolicyRuleAPI `json:"rules"`
}

// CreatePruningPolicy creates a repo in MSR.
func (c *Client) CreatePruningPolicy(ctx context.Context, orgName string, repoName string, policy CreatePruningPolicy) (ResponsePruningPolicy, error) {
body, err := json.Marshal(policy)
if err != nil {
return ResponsePruningPolicy{}, fmt.Errorf("creating pruning policy %+v failed. %w: %s", policy, ErrMarshaling, err)
}
url := fmt.Sprintf("%s/%s/%s/pruningPolicies?initialEvaluation=true", c.createMsrUrl("repositories"), orgName, repoName)
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewBuffer(body))
if err != nil {
return ResponsePruningPolicy{}, fmt.Errorf("creating pruning policy %+v failed. %w: %s", policy, ErrRequestCreation, err)
}
req.Header.Set("Content-Type", "application/json")
resBody, err := c.doRequest(req)
if err != nil {
return ResponsePruningPolicy{}, fmt.Errorf("creating pruning policy %+v failed. %w", policy, err)
}

resPolicy := ResponsePruningPolicy{}
if err := json.Unmarshal(resBody, &resPolicy); err != nil {
return ResponsePruningPolicy{}, fmt.Errorf("creating pruning policy %+v failed. %w: %s", policy, ErrUnmarshaling, err)
}

return resPolicy, nil
}

// ReadPruningPolicy creates a repo in MSR.
func (c *Client) ReadPruningPolicy(ctx context.Context, orgName string, repoName string, policyId string) (ResponsePruningPolicy, error) {
url := fmt.Sprintf("%s/%s/%s/pruningPolicies/%s", c.createMsrUrl("repositories"), orgName, repoName, policyId)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return ResponsePruningPolicy{}, fmt.Errorf("reading pruning policy for %s/%s failed. %w: %s", orgName, repoName, ErrRequestCreation, err)
}
resBody, err := c.doRequest(req)
if err != nil {
return ResponsePruningPolicy{}, fmt.Errorf("reading pruning policy for %s/%s failed. %w", orgName, repoName, err)
}

resPolicy := ResponsePruningPolicy{}
if err := json.Unmarshal(resBody, &resPolicy); err != nil {
return ResponsePruningPolicy{}, fmt.Errorf("reading pruning policy for %s/%s failed. %w: %s", orgName, repoName, ErrUnmarshaling, err)
}

return resPolicy, nil
}

// DeletePruningPolicy creates a repo in MSR.
func (c *Client) DeletePruningPolicy(ctx context.Context, orgName string, repoName string, policyId string) error {
url := fmt.Sprintf("%s/%s/%s/pruningPolicies/%s", c.createMsrUrl("repositories"), orgName, repoName, policyId)
req, err := http.NewRequestWithContext(ctx, http.MethodDelete, url, nil)
if err != nil {
return fmt.Errorf("deleting pruning policy for %s/%s failed. %w: %s", orgName, repoName, ErrRequestCreation, err)
}
if _, err = c.doRequest(req); err != nil {
return fmt.Errorf("deleting pruning policy for %s/%s failed. %w", orgName, repoName, err)
}

return err
}

// UpdatePruningPolicy creates a repo in MSR.
func (c *Client) UpdatePruningPolicy(ctx context.Context, orgName string, repoName string, policy CreatePruningPolicy, policyId string) (ResponsePruningPolicy, error) {
body, err := json.Marshal(policy)
if err != nil {
return ResponsePruningPolicy{}, fmt.Errorf("creating pruning policy %+v failed. %w: %s", policy, ErrMarshaling, err)
}
url := fmt.Sprintf("%s/%s/%s/pruningPolicies/%s?initialEvaluation=true", c.createMsrUrl("repositories"), orgName, repoName, policyId)
req, err := http.NewRequestWithContext(ctx, http.MethodPut, url, bytes.NewBuffer(body))
if err != nil {
return ResponsePruningPolicy{}, fmt.Errorf("updating pruning policy for %s/%s failed. %w: %s", orgName, repoName, ErrRequestCreation, err)
}
req.Header.Set("Content-Type", "application/json")
resBody, err := c.doRequest(req)
if err != nil {
return ResponsePruningPolicy{}, fmt.Errorf("updating pruning policy for %s/%s failed. %w", orgName, repoName, err)
}

resPolicy := ResponsePruningPolicy{}
if err := json.Unmarshal(resBody, &resPolicy); err != nil {
return ResponsePruningPolicy{}, fmt.Errorf("updating pruning policy for %s/%s failed. %w: %s", orgName, repoName, ErrUnmarshaling, err)
}

return resPolicy, nil
}
170 changes: 170 additions & 0 deletions internal/client/pruning_policy_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
package client_test

import (
"context"
"encoding/json"
"errors"
"net/http"
"net/http/httptest"
"reflect"
"testing"

"github.com/Mirantis/terraform-provider-msr/internal/client"
)

type testPruningPolicyStruct struct {
server *httptest.Server
expectedResponse client.ResponsePruningPolicy
expectedErr error
}

func TestCreateValidPruningPolicy(t *testing.T) {
testResPolicy := client.ResponsePruningPolicy{
ID: "fake-test-id",
Enabled: true,
Rules: []client.PruningPolicyRuleAPI{
{
Field: "tag",
Operator: "eq",
Values: []string{"test"},
},
},
}
mAccount, err := json.Marshal(testResPolicy)
if err != nil {
t.Error(err)
}
tc := testPruningPolicyStruct{
server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
if _, err := w.Write(mAccount); err != nil {
t.Error(err)
return
}
})),
expectedResponse: testResPolicy,
expectedErr: nil,
}
defer tc.server.Close()
testClient, err := client.NewDefaultClient(tc.server.URL, "fakeuser", "fakepass", true)
if err != nil {
t.Error("couldn't create test client")
}
ctx := context.Background()
resp, err := testClient.CreatePruningPolicy(ctx, "fake", "fake", client.CreatePruningPolicy{
Enabled: true,
Rules: []client.PruningPolicyRuleAPI{
{
Field: "tag",
Operator: "eq",
Values: []string{"test"},
},
},
})
if !reflect.DeepEqual(tc.expectedResponse, resp) {
t.Errorf("expected (%v), got (%v)", tc.expectedResponse, resp)
}
if !errors.Is(err, tc.expectedErr) {
t.Errorf("expected (%v), got (%v)", tc.expectedErr, err)
}
}

func TestCreateInvalidPruningPolicy(t *testing.T) {
testResPolicy := client.ResponsePruningPolicy{}
mAccount, err := json.Marshal(testResPolicy)
if err != nil {
t.Fatal(err)
}
tc := testPruningPolicyStruct{
server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusBadRequest)
if _, err := w.Write(mAccount); err != nil {
t.Error(err)
return
}
})),
expectedResponse: testResPolicy,
expectedErr: client.ErrEmptyResError,
}
defer tc.server.Close()
testClient, err := client.NewDefaultClient(tc.server.URL, "fakeuser", "fakepass", true)
if err != nil {
t.Error("couldn't create test client")
}
ctx := context.Background()

resp, err := testClient.CreatePruningPolicy(ctx, "fake", "fake", client.CreatePruningPolicy{
Enabled: true,
Rules: []client.PruningPolicyRuleAPI{
{
Field: "tag",
Operator: "eq",
Values: []string{"test"},
},
},
})

if !reflect.DeepEqual(tc.expectedResponse, resp) {
t.Errorf("expected resp: (%+v),\n got (%+v)", tc.expectedResponse, resp)
}
if !errors.Is(err, tc.expectedErr) {
t.Errorf("expected error: (%v),\n got (%v)", tc.expectedErr, err)
}
}

func TestCreatePruningPolicyErrUmarshaling(t *testing.T) {
tc := testPruningPolicyStruct{
server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusBadRequest)
if _, err := w.Write(nil); err != nil {
t.Error(err)
return
}
})),
expectedResponse: client.ResponsePruningPolicy{},
expectedErr: client.ErrUnmarshaling,
}
defer tc.server.Close()
testClient, err := client.NewDefaultClient(tc.server.URL, "fakeuser", "fakepass", true)
if err != nil {
t.Error("couldn't create test client")
}
ctx := context.Background()

resp, err := testClient.CreatePruningPolicy(ctx, "fake", "fake", client.CreatePruningPolicy{})

if !reflect.DeepEqual(tc.expectedResponse, resp) {
t.Errorf("expected resp: (%+v),\n got (%+v)", tc.expectedResponse, resp)
}
if !errors.Is(err, tc.expectedErr) {
t.Errorf("expected error: (%v),\n got (%v)", tc.expectedErr, err)
}
}

func TestUpdatePruningPolicyFailed(t *testing.T) {
tc := testPruningPolicyStruct{
server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
if _, err := w.Write(nil); err != nil {
t.Error(err)
return
}
})),
expectedResponse: client.ResponsePruningPolicy{},
expectedErr: client.ErrUnmarshaling,
}
defer tc.server.Close()
testClient, err := client.NewDefaultClient(tc.server.URL, "fakeuser", "fakepass", true)
if err != nil {
t.Error("couldn't create test client")
}
ctx := context.Background()
resp, err := testClient.UpdatePruningPolicy(ctx, "fakeid", "fakeid", client.CreatePruningPolicy{Enabled: true}, "fakeid")

if !reflect.DeepEqual(tc.expectedResponse, resp) {
t.Errorf("expected resp: (%+v),\n got (%+v)", tc.expectedResponse, resp)
}
if !errors.Is(err, tc.expectedErr) {
t.Errorf("expected error: (%v),\n got (%v)", tc.expectedErr, err)
}
}
Loading

0 comments on commit 13868b6

Please sign in to comment.