Introduce service accounts and bootstrap tokens (#22)

This commit is contained in:
Nikolay Edigaryev
2023-02-21 11:34:12 -05:00
committed by GitHub
parent edb9b3d693
commit 8df31f7c2d
37 changed files with 1245 additions and 40 deletions
+18 -5
View File
@@ -23,6 +23,9 @@ type Client struct {
httpClient *http.Client
baseURL *url.URL
serviceAccountName string
serviceAccountToken string
}
type Config struct {
@@ -51,6 +54,8 @@ func New(opts ...Option) (*Client, error) {
}
client.address = defaultContext.URL
client.serviceAccountName = defaultContext.ServiceAccountName
client.serviceAccountToken = defaultContext.ServiceAccountToken
tlsConfig, err := defaultContext.TLSConfig()
if err != nil {
@@ -60,7 +65,7 @@ func New(opts ...Option) (*Client, error) {
}
// Instantiate client
httpClient := &http.Client{
client.httpClient = &http.Client{
Transport: &http.Transport{
TLSClientConfig: client.tlsConfig,
},
@@ -70,11 +75,9 @@ func New(opts ...Option) (*Client, error) {
if err != nil {
return nil, err
}
client.baseURL = url
return &Client{
httpClient: httpClient,
baseURL: url,
}, nil
return client, nil
}
func (client *Client) request(
@@ -120,6 +123,10 @@ func (client *Client) request(
return fmt.Errorf("%w instantiate a request: %v", ErrFailed, err)
}
if client.serviceAccountName != "" && client.serviceAccountToken != "" {
request.SetBasicAuth(client.serviceAccountName, client.serviceAccountToken)
}
response, err := client.httpClient.Do(request)
if err != nil {
return fmt.Errorf("%w to make a request: %v", ErrFailed, err)
@@ -162,3 +169,9 @@ func (client *Client) VMs() *VMsService {
client: client,
}
}
func (client *Client) ServiceAccounts() *ServiceAccountsService {
return &ServiceAccountsService{
client: client,
}
}
+7
View File
@@ -15,3 +15,10 @@ func WithTLSConfig(tlsConfig *tls.Config) Option {
client.tlsConfig = tlsConfig
}
}
func WithCredentials(serviceAccountName string, serviceAccountToken string) Option {
return func(client *Client) {
client.serviceAccountName = serviceAccountName
client.serviceAccountToken = serviceAccountToken
}
}
+73
View File
@@ -0,0 +1,73 @@
//nolint:dupl // maybe we'll figure out how to make client API accessors generic in the future
package client
import (
"context"
"fmt"
"github.com/cirruslabs/orchard/pkg/resource/v1"
"net/http"
)
type ServiceAccountsService struct {
client *Client
}
func (service *ServiceAccountsService) Create(ctx context.Context, serviceAccount *v1.ServiceAccount) error {
err := service.client.request(ctx, http.MethodPost, "service-accounts",
serviceAccount, nil, nil)
if err != nil {
return err
}
return nil
}
func (service *ServiceAccountsService) List(ctx context.Context) ([]v1.ServiceAccount, error) {
var serviceAccounts []v1.ServiceAccount
err := service.client.request(ctx, http.MethodGet, "service-accounts",
nil, &serviceAccounts, nil)
if err != nil {
return nil, err
}
return serviceAccounts, nil
}
func (service *ServiceAccountsService) Get(ctx context.Context, name string) (*v1.ServiceAccount, error) {
var serviceAccount v1.ServiceAccount
err := service.client.request(ctx, http.MethodGet, fmt.Sprintf("service-accounts/%s", name),
nil, &serviceAccount, nil)
if err != nil {
return nil, err
}
return &serviceAccount, nil
}
func (service *ServiceAccountsService) Update(ctx context.Context, serviceAccount *v1.ServiceAccount) error {
err := service.client.request(ctx, http.MethodPut, fmt.Sprintf("service-accounts/%s", serviceAccount.Name),
serviceAccount, nil, nil)
if err != nil {
return err
}
return nil
}
func (service *ServiceAccountsService) Delete(ctx context.Context, name string, force bool) error {
params := map[string]string{}
if force {
params["force"] = "true"
}
err := service.client.request(ctx, http.MethodDelete, fmt.Sprintf("service-accounts/%s", name),
nil, nil, params)
if err != nil {
return err
}
return nil
}
+1
View File
@@ -1,3 +1,4 @@
//nolint:dupl // maybe we'll figure out how to make client API accessors generic in the future
package client
import (
+8
View File
@@ -0,0 +1,8 @@
package v1
type ServiceAccount struct {
Token string
Roles []ServiceAccountRole
Meta
}
+45
View File
@@ -0,0 +1,45 @@
package v1
import (
"errors"
"fmt"
)
var ErrUnsupportedServiceAccountRole = errors.New("unsupported service account role")
type ServiceAccountRole string
const (
ServiceAccountRoleWorker ServiceAccountRole = "worker"
ServiceAccountRoleComputeRead ServiceAccountRole = "compute:read"
ServiceAccountRoleComputeWrite ServiceAccountRole = "compute:write"
ServiceAccountRoleAdminRead ServiceAccountRole = "admin:read"
ServiceAccountRoleAdminWrite ServiceAccountRole = "admin:write"
)
func NewServiceAccountRole(name string) (ServiceAccountRole, error) {
switch name {
case string(ServiceAccountRoleWorker):
return ServiceAccountRoleWorker, nil
case string(ServiceAccountRoleComputeRead):
return ServiceAccountRoleComputeRead, nil
case string(ServiceAccountRoleComputeWrite):
return ServiceAccountRoleComputeWrite, nil
case string(ServiceAccountRoleAdminRead):
return ServiceAccountRoleAdminRead, nil
case string(ServiceAccountRoleAdminWrite):
return ServiceAccountRoleAdminWrite, nil
default:
return "", fmt.Errorf("%w: %s", ErrUnsupportedServiceAccountRole, name)
}
}
func AllServiceAccountRoles() []ServiceAccountRole {
return []ServiceAccountRole{
ServiceAccountRoleWorker,
ServiceAccountRoleComputeRead,
ServiceAccountRoleComputeWrite,
ServiceAccountRoleAdminRead,
ServiceAccountRoleAdminWrite,
}
}