-
Notifications
You must be signed in to change notification settings - Fork 11
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
Resource: service #219
Merged
ekampf
merged 68 commits into
Twingate:main
from
vmanilo:feature/service-account-resource
Dec 8, 2022
Merged
Resource: service #219
Changes from all commits
Commits
Show all changes
68 commits
Select commit
Hold shift + click to select a range
f6c08a5
WIP
vmanilo e1d4695
updated project layout
vmanilo 8dd6619
fix linter
vmanilo 3f23300
ignore sec warn
vmanilo 29a7fdd
Merge branch 'main' into restructure-layout
vmanilo 1e0b57c
fix: re-generated docs
vmanilo 5630e22
fix users test
vmanilo b0148a7
added connector model
vmanilo ff7fea3
fix convertion graphql.ID to string
vmanilo d5e6a9e
added connector tokens model
vmanilo 621e396
added group model
vmanilo c1803dd
added remote-network model
vmanilo f940fec
fix fmt
vmanilo 9caeb87
added user model
vmanilo c419c4b
fix fmt
vmanilo 2d2767d
WIP
vmanilo 14fc36c
added connectors pages
vmanilo 531ffcf
Merge remote-tracking branch 'upstream/main' into feature/datasource-…
vmanilo 1e24caf
added featching all pages for groups
vmanilo 091108d
Merge remote-tracking branch 'upstream/main' into feature/datasource-…
vmanilo d52af8f
added featching all pages for resources
vmanilo d6a292c
added featching all pages for users
vmanilo 1b5f6a8
Merge branch 'main' into feature/datasource-load-all-pages
vmanilo 0480bbc
Merge branch 'main' into restructure-layout
vmanilo fc4e5c0
Merge branch 'feature/datasource-load-all-pages' into restructure-layout
vmanilo d25a954
updated test results location
vmanilo 2893d74
wip: fixing tests
vmanilo 0d0b123
added generic paginated resource
vmanilo 2ef2789
added tests
vmanilo 3e7777c
Merge branch 'feature/datasource-load-all-pages' into restructure-layout
vmanilo 62269e2
Merge branch 'main' into feature/datasource-load-all-pages
vmanilo 99c0d99
Merge remote-tracking branch 'origin/feature/datasource-load-all-page…
vmanilo bb243b0
renamed transport pkg to client
vmanilo 2ea5508
fixed tests
vmanilo aa89c02
fix path to generated test coverage report
vmanilo 71ec3a1
fix read resources
vmanilo dd5664b
remove parallel resource tests
vmanilo e7263b7
added debug log
vmanilo b380e58
debug error
vmanilo 2c0a2dd
debug error
vmanilo 96f0b70
fix test
vmanilo a7e2d7a
remove logs
vmanilo 21005c3
Merge remote-tracking branch 'upstream/main' into restructure-layout
vmanilo 0165eb3
revert changes in ci.yml
vmanilo 1bfafad
simplify converters
vmanilo be04a4f
added tests
vmanilo 3810400
added tests for models
vmanilo 447484c
fix fmt
vmanilo fef2ede
added test coverage
vmanilo d718edd
added test coverage
vmanilo 7843068
added test coverage
vmanilo b8aa0ae
fix test
vmanilo 1fffa30
added test coverage
vmanilo 16bbb33
run acc test
vmanilo 63f2d0a
revert changes
vmanilo 595d82c
added service-account resource
vmanilo a7348c1
refactor acc tests
vmanilo 87c6337
Merge branch 'restructure-layout' into feature/service-account-resource
vmanilo 3882988
Fix http_max_retry doc
ekampf 62f8011
regenerated docs
vmanilo ce44a5a
Merge branch 'restructure-layout' into feature/service-account-resource
vmanilo 9705524
renamed resource: service-account -> service
vmanilo b58eba7
fix acctest
vmanilo add7a8b
Merge branch 'main' into feature/service-account-resource
vmanilo bbf40ca
renamed resource to twingate_service_account
vmanilo 07624e2
added test coverage
vmanilo ad360b3
added test coverage
vmanilo 84de94b
updated doc description
vmanilo File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
--- | ||
# generated by https://github.com/hashicorp/terraform-plugin-docs | ||
page_title: "twingate_service_account Resource - terraform-provider-twingate" | ||
subcategory: "" | ||
description: |- | ||
Service Accounts offer a way to provide programmatic, centrally-controlled, and consistent access controls. | ||
--- | ||
|
||
# twingate_service_account (Resource) | ||
|
||
Service Accounts offer a way to provide programmatic, centrally-controlled, and consistent access controls. | ||
|
||
## Example Usage | ||
|
||
```terraform | ||
provider "twingate" { | ||
api_token = "1234567890abcdef" | ||
network = "mynetwork" | ||
} | ||
|
||
resource "twingate_service_account" "github_actions_prod" { | ||
name = "Github Actions PROD" | ||
} | ||
``` | ||
|
||
<!-- schema generated by tfplugindocs --> | ||
## Schema | ||
|
||
### Required | ||
|
||
- `name` (String) The name of the Service Account in Twingate | ||
|
||
### Read-Only | ||
|
||
- `id` (String) Autogenerated ID of the Service Account | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
provider "twingate" { | ||
api_token = "1234567890abcdef" | ||
network = "mynetwork" | ||
} | ||
|
||
resource "twingate_service_account" "github_actions_prod" { | ||
name = "Github Actions PROD" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
package client | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this here and not in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. here I'm testing private func |
||
|
||
import ( | ||
"context" | ||
"errors" | ||
"fmt" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/twingate/go-graphql-client" | ||
) | ||
|
||
func TestPagination(t *testing.T) { | ||
badError := errors.New("bad error") | ||
|
||
cases := []struct { | ||
resource *PaginatedResource[int] | ||
nextPage nextPageFunc[int] | ||
|
||
expected *PaginatedResource[int] | ||
expectedErr error | ||
}{ | ||
{}, | ||
{ | ||
resource: &PaginatedResource[int]{ | ||
PageInfo: PageInfo{ | ||
HasNextPage: false, | ||
}, | ||
}, | ||
expected: &PaginatedResource[int]{ | ||
PageInfo: PageInfo{ | ||
HasNextPage: false, | ||
}, | ||
}, | ||
}, | ||
{ | ||
resource: &PaginatedResource[int]{ | ||
PageInfo: PageInfo{ | ||
HasNextPage: true, | ||
}, | ||
}, | ||
nextPage: func(ctx context.Context, variables map[string]interface{}, cursor graphql.String) (*PaginatedResource[int], error) { | ||
return nil, badError | ||
}, | ||
expected: &PaginatedResource[int]{ | ||
PageInfo: PageInfo{ | ||
HasNextPage: true, | ||
}, | ||
}, | ||
expectedErr: badError, | ||
}, | ||
{ | ||
resource: &PaginatedResource[int]{ | ||
PageInfo: PageInfo{ | ||
HasNextPage: true, | ||
}, | ||
Edges: []int{1, 2}, | ||
}, | ||
nextPage: func(ctx context.Context, variables map[string]interface{}, cursor graphql.String) (*PaginatedResource[int], error) { | ||
return &PaginatedResource[int]{ | ||
PageInfo: PageInfo{ | ||
HasNextPage: false, | ||
}, | ||
Edges: []int{3, 4}, | ||
}, nil | ||
}, | ||
expected: &PaginatedResource[int]{ | ||
PageInfo: PageInfo{ | ||
HasNextPage: true, | ||
}, | ||
Edges: []int{1, 2, 3, 4}, | ||
}, | ||
}, | ||
} | ||
|
||
for n, c := range cases { | ||
t.Run(fmt.Sprintf("case_%d", n), func(t *testing.T) { | ||
err := c.resource.fetchPages(context.TODO(), c.nextPage, map[string]interface{}{}) | ||
|
||
assert.Equal(t, c.expected, c.resource) | ||
assert.Equal(t, c.expectedErr, err) | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,186 @@ | ||
package client | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/Twingate/terraform-provider-twingate/twingate/internal/model" | ||
"github.com/twingate/go-graphql-client" | ||
) | ||
|
||
const serviceAccountResourceName = "service account" | ||
|
||
type gqlServiceAccount struct { | ||
IDName | ||
} | ||
|
||
type createServiceAccountQuery struct { | ||
ServiceAccountCreate struct { | ||
Entity IDName | ||
OkError | ||
} `graphql:"serviceAccountCreate(name: $name)"` | ||
} | ||
|
||
func (client *Client) CreateServiceAccount(ctx context.Context, serviceAccountName string) (*model.ServiceAccount, error) { | ||
if serviceAccountName == "" { | ||
return nil, NewAPIError(ErrGraphqlNameIsEmpty, "create", serviceAccountResourceName) | ||
} | ||
|
||
variables := newVars(gqlField(serviceAccountName, "name")) | ||
response := createServiceAccountQuery{} | ||
|
||
err := client.GraphqlClient.NamedMutate(ctx, "createServiceAccount", &response, variables) | ||
if err != nil { | ||
return nil, NewAPIError(err, "create", serviceAccountResourceName) | ||
} | ||
|
||
if !response.ServiceAccountCreate.Ok { | ||
message := response.ServiceAccountCreate.Error | ||
|
||
return nil, NewAPIError(NewMutationError(message), "create", serviceAccountResourceName) | ||
} | ||
|
||
return response.ToModel(), nil | ||
} | ||
|
||
type readServiceAccountQuery struct { | ||
ServiceAccount *gqlServiceAccount `graphql:"serviceAccount(id: $id)"` | ||
} | ||
|
||
func (client *Client) ReadServiceAccount(ctx context.Context, serviceAccountID string) (*model.ServiceAccount, error) { | ||
if serviceAccountID == "" { | ||
return nil, NewAPIError(ErrGraphqlIDIsEmpty, "read", serviceAccountResourceName) | ||
} | ||
|
||
variables := newVars(gqlID(serviceAccountID)) | ||
response := readServiceAccountQuery{} | ||
|
||
err := client.GraphqlClient.NamedQuery(ctx, "readServiceAccount", &response, variables) | ||
if err != nil { | ||
return nil, NewAPIErrorWithID(err, "read", serviceAccountResourceName, serviceAccountID) | ||
} | ||
|
||
if response.ServiceAccount == nil { | ||
return nil, NewAPIErrorWithID(ErrGraphqlResultIsEmpty, "read", serviceAccountResourceName, serviceAccountID) | ||
} | ||
|
||
return response.ToModel(), nil | ||
} | ||
|
||
type updateServiceAccountQuery struct { | ||
ServiceAccountUpdate struct { | ||
Entity *gqlServiceAccount | ||
OkError | ||
} `graphql:"serviceAccountUpdate(id: $id, name: $name)"` | ||
} | ||
|
||
func (client *Client) UpdateServiceAccount(ctx context.Context, serviceAccount *model.ServiceAccount) (*model.ServiceAccount, error) { | ||
if serviceAccount == nil || serviceAccount.ID == "" { | ||
return nil, NewAPIError(ErrGraphqlIDIsEmpty, "update", serviceAccountResourceName) | ||
} | ||
|
||
if serviceAccount.Name == "" { | ||
return nil, NewAPIError(ErrGraphqlNameIsEmpty, "update", serviceAccountResourceName) | ||
} | ||
|
||
variables := newVars( | ||
gqlID(serviceAccount.ID), | ||
gqlField(serviceAccount.Name, "name"), | ||
) | ||
|
||
response := updateServiceAccountQuery{} | ||
|
||
err := client.GraphqlClient.NamedMutate(ctx, "updateServiceAccount", &response, variables) | ||
if err != nil { | ||
return nil, NewAPIErrorWithID(err, "update", serviceAccountResourceName, serviceAccount.ID) | ||
} | ||
|
||
if !response.ServiceAccountUpdate.Ok { | ||
return nil, NewAPIErrorWithID(NewMutationError(response.ServiceAccountUpdate.Error), "update", serviceAccountResourceName, serviceAccount.ID) | ||
} | ||
|
||
if response.ServiceAccountUpdate.Entity == nil { | ||
return nil, NewAPIErrorWithID(ErrGraphqlResultIsEmpty, "update", serviceAccountResourceName, serviceAccount.ID) | ||
} | ||
|
||
return response.ServiceAccountUpdate.Entity.ToModel(), nil | ||
} | ||
|
||
type deleteServiceAccountQuery struct { | ||
ServiceAccountDelete *OkError `graphql:"serviceAccountDelete(id: $id)"` | ||
} | ||
|
||
func (client *Client) DeleteServiceAccount(ctx context.Context, serviceAccountID string) error { | ||
if serviceAccountID == "" { | ||
return NewAPIError(ErrGraphqlIDIsEmpty, "delete", serviceAccountResourceName) | ||
} | ||
|
||
variables := newVars(gqlID(serviceAccountID)) | ||
response := deleteServiceAccountQuery{} | ||
|
||
err := client.GraphqlClient.NamedMutate(ctx, "deleteServiceAccount", &response, variables) | ||
if err != nil { | ||
return NewAPIErrorWithID(err, "delete", serviceAccountResourceName, serviceAccountID) | ||
} | ||
|
||
if !response.ServiceAccountDelete.Ok { | ||
return NewAPIErrorWithID(NewMutationError(response.ServiceAccountDelete.Error), "delete", serviceAccountResourceName, serviceAccountID) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
type ServiceAccountEdge struct { | ||
Node *gqlServiceAccount | ||
} | ||
|
||
type ServiceAccounts struct { | ||
PaginatedResource[*ServiceAccountEdge] | ||
} | ||
|
||
type readServiceAccountsQuery struct { | ||
ServiceAccounts ServiceAccounts | ||
} | ||
|
||
func (client *Client) ReadServiceAccounts(ctx context.Context) ([]*model.ServiceAccount, error) { | ||
response := readServiceAccountsQuery{} | ||
|
||
err := client.GraphqlClient.NamedQuery(ctx, "readServiceAccounts", &response, nil) | ||
if err != nil { | ||
return nil, NewAPIErrorWithID(err, "read", serviceAccountResourceName, "All") | ||
} | ||
|
||
if len(response.ServiceAccounts.Edges) == 0 { | ||
return nil, NewAPIErrorWithID(ErrGraphqlResultIsEmpty, "read", serviceAccountResourceName, "All") | ||
} | ||
|
||
err = response.ServiceAccounts.fetchPages(ctx, client.readServiceAccountsAfter, nil) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return response.ServiceAccounts.ToModel(), nil | ||
} | ||
|
||
type readServiceAccountsAfter struct { | ||
ServiceAccounts ServiceAccounts `graphql:"serviceAccounts(after: $serviceAccountsEndCursor)"` | ||
} | ||
|
||
func (client *Client) readServiceAccountsAfter(ctx context.Context, variables map[string]interface{}, cursor graphql.String) (*PaginatedResource[*ServiceAccountEdge], error) { | ||
if variables == nil { | ||
variables = make(map[string]interface{}) | ||
} | ||
|
||
variables["serviceAccountsEndCursor"] = cursor | ||
response := readServiceAccountsAfter{} | ||
|
||
err := client.GraphqlClient.NamedQuery(ctx, "readServiceAccounts", &response, variables) | ||
if err != nil { | ||
return nil, NewAPIErrorWithID(err, "read", serviceAccountResourceName, "All") | ||
} | ||
|
||
if len(response.ServiceAccounts.Edges) == 0 { | ||
return nil, NewAPIErrorWithID(ErrGraphqlResultIsEmpty, "read", serviceAccountResourceName, "All") | ||
} | ||
|
||
return &response.ServiceAccounts.PaginatedResource, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package model | ||
|
||
type ServiceAccount struct { | ||
ID string | ||
Name string | ||
} | ||
|
||
func (s ServiceAccount) GetName() string { | ||
return s.Name | ||
} | ||
|
||
func (s ServiceAccount) GetID() string { | ||
return s.ID | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Its something I missed in the restructure review but Im not sure I understand the purpose of
converter.go
- we definecreateServiceAccountQuery
inservice-account.go
why cant its methods be there?(same for all the other structs that their methods are here)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or maybe the struct defintion should be here too?
or maybe we need
queries/createServiceAccountQuery.go
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here in
converter.go
I've collected simple utilities functions which converts queries objects to modelsI think in
service-account.go
would be better to have only code related to API request, and this object conversions like lower layer detailsI like the idea with separate package for
queries
, I think this can help organise code better :)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok so lets merge this and refactor to
queries
on a separate PR