plank

package module
v4.2.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 2, 2023 License: Apache-2.0 Imports: 15 Imported by: 0

README

plank

Spinnaker SDK for Go.

Plank is a work in progress and will change drastically over the next few months.

What is it?

A package used by services that interact with Spinnaker's micro-services. It is not intended to be a client which interacts with Spinnaker's outward facing API.

Why is it named plank?

Because it's funny.

How do I use it?

Very carefully. 😃

Basic concept is that you instantiate a Plank client thusly:

client := plank.New()

If you'd like to supply your own http client (we use a pooled client by default):

client := plank.New(plank.WithClient(&http.Client{}))

To tune the maxiumum number of retries or set an exponential backoff value:

client := plank.New(plank.WithMaxRetries(5), plank.WithRetryIncrement(5 * time.Second))

You can (or may need to) replace the base URLs for the microservices by assign them to the keys in the client.URLs map:

client.URLs["orca"] = "http://my-orca:8083"
client.URLs["front50"] = config.Front50.BaseURL

After that, you just use the Plank functions to "do stuff":

app, err := client.GetApplication("myappname")
pipelines, err := client.GetPipelines(app.Name)
// etc...

Development

Build the project:

$ go build

Test the project:

$ go test
Cutting a New Release
  1. Update the [CHANGELOG.md]'s ##Unreleased section with the next version and today's date in YYYY-MM-DD format.
  • Don't forget to update the release URL so that it's easy to diff what was changed (look at the bottom of the CHANGELOG for existing examples).
  1. git tag vx.x.x where x.x.x is the version you're releasing, and git push --tags to make sure it's persisted to the project.

Documentation

Overview

  • Copyright 2019 Armory, Inc. *

  • Licensed under the Apache License, Version 2.0 (the "License")

  • you may not use this file except in compliance with the License.

  • You may obtain a copy of the License at *

  • http://www.apache.org/licenses/LICENSE-2.0 *

  • Unless required by applicable law or agreed to in writing, software

  • distributed under the License is distributed on an "AS IS" BASIS,

  • WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

  • See the License for the specific language governing permissions and

  • limitations under the License.

  • Copyright 2020 Armory, Inc. *

  • Licensed under the Apache License, Version 2.0 (the "License")

  • you may not use this file except in compliance with the License.

  • You may obtain a copy of the License at *

  • http://www.apache.org/licenses/LICENSE-2.0 *

  • Unless required by applicable law or agreed to in writing, software

  • distributed under the License is distributed on an "AS IS" BASIS,

  • WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

  • See the License for the specific language governing permissions and

  • limitations under the License.

  • Copyright 2020 Armory, Inc. *

  • Licensed under the Apache License, Version 2.0 (the "License")

  • you may not use this file except in compliance with the License.

  • You may obtain a copy of the License at *

  • http://www.apache.org/licenses/LICENSE-2.0 *

  • Unless required by applicable law or agreed to in writing, software

  • distributed under the License is distributed on an "AS IS" BASIS,

  • WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

  • See the License for the specific language governing permissions and

  • limitations under the License.

  • Copyright 2019 Armory, Inc. *

  • Licensed under the Apache License, Version 2.0 (the "License")

  • you may not use this file except in compliance with the License.

  • You may obtain a copy of the License at *

  • http://www.apache.org/licenses/LICENSE-2.0 *

  • Unless required by applicable law or agreed to in writing, software

  • distributed under the License is distributed on an "AS IS" BASIS,

  • WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

  • See the License for the specific language governing permissions and

  • limitations under the License.

  • Copyright 2019 Armory, Inc. *

  • Licensed under the Apache License, Version 2.0 (the "License")

  • you may not use this file except in compliance with the License.

  • You may obtain a copy of the License at *

  • http://www.apache.org/licenses/LICENSE-2.0 *

  • Unless required by applicable law or agreed to in writing, software

  • distributed under the License is distributed on an "AS IS" BASIS,

  • WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

  • See the License for the specific language governing permissions and

  • limitations under the License.

Package plank is a SDK for Spinnaker. It allows you to write Go code that interacts with Spinnaker's subservices.

  • Copyright 2019 Armory, Inc. *
  • Licensed under the Apache License, Version 2.0 (the "License")
  • you may not use this file except in compliance with the License.
  • You may obtain a copy of the License at *
  • http://www.apache.org/licenses/LICENSE-2.0 *
  • Unless required by applicable law or agreed to in writing, software
  • distributed under the License is distributed on an "AS IS" BASIS,
  • WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  • See the License for the specific language governing permissions and
  • limitations under the License.

Index

Constants

View Source
const (
	// SpinFiatUserHeader is the header name used for representing users.
	SpinFiatUserHeader string = "X-Spinnaker-User"
	// SpinFiatAccountHeader is the header name used for representing accounts.
	SpinFiatAccountHeader string = "X-Spinnaker-Accounts"

	ApplicationJson        ContentType = "application/json"
	ApplicationContextJson ContentType = "application/context+json"
)

Variables

View Source
var DefaultURLs = map[string]string{
	"orca":    "http://localhost:8083",
	"front50": "http://localhost:8080",
	"fiat":    "http://localhost:7003",
	"gate":    "http://localhost:8084",
}

DefaultURLs

Functions

This section is empty.

Types

type Application

type Application struct {
	Name           string                 `json:"name" mapstructure:"name" yaml:"name" hcl:"name"`
	Email          string                 `json:"email" mapstructure:"email" yaml:"email" hcl:"email"`
	Description    string                 `json:"description,omitempty" mapstructure:"description" yaml:"description,omitempty" hcl:"description,omitempty"`
	User           string                 `json:"user,omitempty" mapstructure:"user" yaml:"user,omitempty" hcl:"user,omitempty"`
	DataSources    *DataSourcesType       `json:"dataSources,omitempty" mapstructure:"dataSources" yaml:"datasources,omitempty" hcl:"datasources,omitempty"`
	Permissions    *PermissionsType       `json:"permissions,omitempty" mapstructure:"permissions" yaml:"permissions,omitempty" hcl:"permissions,omitempty"`
	Notifications  NotificationsType      `json:"notifications,omitempty" mapstructure:"notifications" yaml:"notifications,omitempty" hcl:"notifications,omitempty"`
	AppMetadata    map[string]interface{} `json:"appmetadata,omitempty" mapstructure:"appmetadata" yaml:"appmetadata,omitempty" hcl:"appmetadata,omitempty"`
	RepoSlug       string                 `json:"repoSlug,omitempty" mapstructure:"repoSlug" yaml:"repoSlug,omitempty" hcl:"repoSlug,omitempty"`
	RepoType       string                 `json:"repoType,omitempty" mapstructure:"repoType" yaml:"repoType,omitempty" hcl:"repoType,omitempty"`
	RepoProjectKey string                 `json:"repoProjectKey,omitempty" mapstructure:"repoProjectKey" yaml:"repoProjectKey,omitempty" hcl:"repoProjectKey,omitempty"`
}

Application as returned from the Spinnaker API.

func (Application) MarshalJSON

func (a Application) MarshalJSON() ([]byte, error)

All in Metadata will be in root

type Authorization

type Authorization struct {
	Name string `json:"name" yaml:"name" hcl:"name"`
	// Authorizations can be 'READ' 'WRITE'
	Authorizations []string `json:"authorizations" yaml:"authorizations" hcl:"authorizations"`
}

Authorization describes permissinos for an account or application.

type Client

type Client struct {
	URLs            map[string]string
	FiatUser        string
	ArmoryEndpoints bool
	UseGate         bool
	// contains filtered or unexported fields
}

Client for working with API servers that accept and return JSON payloads.

func New

func New(opts ...ClientOption) *Client

New constructs a Client using a default client and sane non-shared http transport

func (*Client) ArmoryEndpointsEnabled

func (c *Client) ArmoryEndpointsEnabled() bool

func (*Client) CreateApplication

func (c *Client) CreateApplication(a *Application, traceparent string) error

CreateApplication does what it says.

func (*Client) CreateTask

func (c *Client) CreateTask(app, desc, traceparent string, payload interface{}) (*TaskRefResponse, error)

Create task puts the payload into the Task wrapper.

func (*Client) Delete

func (c *Client) Delete(url, traceparent string) error

func (*Client) DeleteApplication

func (c *Client) DeleteApplication(name, traceparent string) error

DeleteApplication deletes an application from the configured front50 store.

func (*Client) DeletePipeline

func (c *Client) DeletePipeline(p Pipeline, traceparent string) error

DeletePipeline does what it says.

func (*Client) DeletePipelineByName

func (c *Client) DeletePipelineByName(app, pipeline, traceparent string) error

func (*Client) DeleteWithRetry

func (c *Client) DeleteWithRetry(url, traceparent string) error

func (*Client) DisableARmoryEndpoints

func (c *Client) DisableARmoryEndpoints()

func (*Client) EnableArmoryEndpoints

func (c *Client) EnableArmoryEndpoints()

func (*Client) Execute

func (c *Client) Execute(application, pipeline, traceparent string) (*PipelineRef, error)

Execute a pipeline by application and pipeline.

func (*Client) Get

func (c *Client) Get(url, traceparent string, dest interface{}) error

Get a JSON payload from the URL then decode it into the 'dest' arguement.

func (*Client) GetApplication

func (c *Client) GetApplication(name, traceparent string) (*Application, error)

GetApplication returns the Application data struct for the given application name.

func (*Client) GetApplicationNotifications

func (c *Client) GetApplicationNotifications(appName, traceparent string) (*NotificationsType, error)

GetApplicationNotifications returns all application notifications

func (*Client) GetApplications

func (c *Client) GetApplications(traceparent string) (*[]Application, error)

GetApplications returns all applications (you can see, at least)

func (*Client) GetPipelines

func (c *Client) GetPipelines(app, traceparent string) ([]Pipeline, error)

Get returns an array of all the Spinnaker pipelines configured for app

func (*Client) GetTask

func (c *Client) GetTask(refURL, traceparent string) (*ExecutionStatusResponse, error)

func (*Client) GetUser

func (c *Client) GetUser(name, traceparent string) (*User, error)

GetUser gets a user by name.

func (*Client) GetWithRetry

func (c *Client) GetWithRetry(url, traceparent string, dest interface{}) error

func (*Client) HasAppWriteAccess

func (c *Client) HasAppWriteAccess(username, app, traceparent string) (bool, error)

HasAppWriteAccess returns whether or not a user can write pipelines/configs/etc. for an app.

func (*Client) IsAdmin

func (c *Client) IsAdmin(username, traceparent string) (bool, error)

Admin returns whether or not a user is an admin.

func (*Client) Patch

func (c *Client) Patch(url, traceparent string, contentType ContentType, body interface{}, dest interface{}) error

Patch updates a resource for the target URL

func (*Client) PatchWithRetry

func (c *Client) PatchWithRetry(url, traceparent string, contentType ContentType, body interface{}, dest interface{}) error

PatchWithRetry updates a resource for the target URL

func (*Client) PollTaskStatus

func (c *Client) PollTaskStatus(refURL, traceparent string) (*ExecutionStatusResponse, error)

func (*Client) Post

func (c *Client) Post(url, traceparent string, contentType ContentType, body interface{}, dest interface{}) error

Post a JSON payload from the URL then decode it into the 'dest' arguement.

func (*Client) PostWithRetry

func (c *Client) PostWithRetry(url, traceparent string, contentType ContentType, body interface{}, dest interface{}) error

func (*Client) Put

func (c *Client) Put(url, traceparent string, contentType ContentType, body interface{}, dest interface{}) error

Post a JSON payload from the URL then decode it into the 'dest' arguement.

func (*Client) PutWithRetry

func (c *Client) PutWithRetry(url, traceparent string, contentType ContentType, body interface{}, dest interface{}) error

func (*Client) RequestWithRetry

func (c *Client) RequestWithRetry(f RequestFunction) error

func (*Client) ResyncFiat

func (c *Client) ResyncFiat(traceparent string) error

ResyncFiat calls to Fiat to tell it to resync its cache of applications and permissions. This uses an endpoint specific to Armory's distribution of Fiat; if ArmoryEndpoints is not set (it's false by default) this is a no-op.

func (*Client) UpdateApplication

func (c *Client) UpdateApplication(app Application, traceparent string) error

UpdateApplication updates an application in the configured front50 store.

func (*Client) UpdateApplicationNotifications

func (c *Client) UpdateApplicationNotifications(notifications NotificationsType, appName, traceparent string) error

UpdateApplicationNotifications updates notifications in the configured front50 store.

func (*Client) UpdatePermissions

func (c *Client) UpdatePermissions(appName, traceparent string, permissions *PermissionsType) error

UpdatePermissions updates an application permissions in the configured front50 store.

func (*Client) UpsertPipeline

func (c *Client) UpsertPipeline(p Pipeline, id, traceparent string) error

func (*Client) UpsertPipelineUsingOrca added in v4.1.2

func (c *Client) UpsertPipelineUsingOrca(p Pipeline, id, traceparent string) error

func (*Client) UseGateEndpoints

func (c *Client) UseGateEndpoints()

func (*Client) UseServiceEndpoints

func (c *Client) UseServiceEndpoints()

func (*Client) UserRoles

func (c *Client) UserRoles(username, traceparent string) ([]string, error)

type ClientOption

type ClientOption func(*Client)

func WithClient

func WithClient(client *http.Client) ClientOption

func WithFiatUser

func WithFiatUser(user string) ClientOption

func WithMaxRetries

func WithMaxRetries(retries int) ClientOption

func WithOverrideAllURLs

func WithOverrideAllURLs(urls map[string]string) ClientOption

func WithRetryIncrement

func WithRetryIncrement(t time.Duration) ClientOption

func WithTransport

func WithTransport(transport *http.Transport) ClientOption

type ContentType

type ContentType string

type DataSourcesType

type DataSourcesType struct {
	Enabled  []string `json:"enabled" mapstructure:"enabled" yaml:"enabled" hcl:"enabled"`
	Disabled []string `json:"disabled" mapstructure:"disabled" yaml:"disabled" hcl:"disabled"`
}

DataSourcesType creates this block:

"dataSources": {
  "disabled": [],
  "enabled": ["canaryConfigs"]
}

type ErrUnsupportedStatusCode

type ErrUnsupportedStatusCode struct {
	Code int
}

func (*ErrUnsupportedStatusCode) Error

func (e *ErrUnsupportedStatusCode) Error() string

type ExecutionStatusResponse

type ExecutionStatusResponse struct {
	ID      string `json:"id"`
	Status  string `json:"status"`
	EndTime int    `json:"endTime"`
}

type FailedResponse

type FailedResponse struct {
	Response   []byte
	StatusCode int
}

FailedResponse captures a 4xx/5xx response from the upstream Spinnaker service. It is expected that the caller destructures the response according to the structure they expect.

func (*FailedResponse) Error

func (e *FailedResponse) Error() string

type FiatClient

type FiatClient interface {
	UserRoles(username, traceparent string) ([]string, error)
}

type FiatClientFactory

type FiatClientFactory func(opts ...ClientOption) FiatClient

type FiatPermissionEvaluator

type FiatPermissionEvaluator struct {
	// contains filtered or unexported fields
}

func NewFiatPermissionEvaluator

func NewFiatPermissionEvaluator(opts ...PermissionEvaluatorOpt) *FiatPermissionEvaluator

func (*FiatPermissionEvaluator) HasReadPermission

func (f *FiatPermissionEvaluator) HasReadPermission(user, traceparent string, rp ReadPermissable) (bool, error)

type FiatRole

type FiatRole struct {
	Name   string `json:"name"`
	Source string `json:"source"`
}

type Front50Permissions

type Front50Permissions struct {
	Name        string           `json:"name" mapstructure:"name" yaml:"name" hcl:"name"`
	Permissions *PermissionsType `json:"permissions,omitempty" mapstructure:"permissions" yaml:"permissions,omitempty" hcl:"permissions,omitempty"`
}

Front50 needs this struct to update permissions

type Method

type Method string

Method represents a supported HTTP Method in Plank.

const (
	// Patch is a PATCH HTTP method
	Patch Method = http.MethodPatch
	// Post is a POST HTTP method
	Post Method = http.MethodPost
	// Put is a PUT HTTP method
	Put Method = http.MethodPut
	// Get is a GET HTTP method
	Get Method = http.MethodGet
)

type NotificationsType

type NotificationsType map[string]interface{}

func (*NotificationsType) FillAppNotificationFields

func (notifications *NotificationsType) FillAppNotificationFields(appName string)

func (*NotificationsType) ValidateAppNotification

func (notifications *NotificationsType) ValidateAppNotification() error

type PermissionEvaluatorOpt

type PermissionEvaluatorOpt func(fpe *FiatPermissionEvaluator)

func WithClientOptions

func WithClientOptions(opts ...ClientOption) PermissionEvaluatorOpt

func WithOrMode

func WithOrMode(orMode bool) PermissionEvaluatorOpt

type PermissionsEvaluator

type PermissionsEvaluator interface {
	HasReadPermission(user string, traceparent string, rp ReadPermissable) (bool, error)
}

type PermissionsType

type PermissionsType struct {
	Read    []string `json:"READ" mapstructure:"READ" yaml:"READ" hcl:"READ"`
	Write   []string `json:"WRITE" mapstructure:"WRITE" yaml:"WRITE" hcl:"WRITE"`
	Execute []string `json:"EXECUTE" mapstructure:"EXECUTE" yaml:"EXECUTE" hcl:"EXECUTE"`
}

PermissionsType creates this block:

"permissions": {
  "READ": ["armory-io", "core"],
  "WRITE": ["armory-io", "core"]
}

type Pipeline

type Pipeline struct {
	ID                   string                   `json:"id,omitempty" yaml:"id,omitempty" hcl:"id,omitempty"`
	Type                 string                   `json:"type,omitempty" yaml:"type,omitempty" hcl:"type,omitempty"`
	Name                 string                   `json:"name" yaml:"name" hcl:"name"`
	Application          string                   `json:"application" yaml:"application" hcl:"application"`
	Description          string                   `json:"description,omitempty" yaml:"description,omitempty" hcl:"description,omitempty"`
	ExecutionEngine      string                   `json:"executionEngine,omitempty" yaml:"executionEngine,omitempty" hcl:"executionEngine,omitempty"`
	Parallel             bool                     `json:"parallel" yaml:"parallel" hcl:"parallel"`
	LimitConcurrent      bool                     `json:"limitConcurrent" yaml:"limitConcurrent" hcl:"limitConcurrent"`
	KeepWaitingPipelines bool                     `json:"keepWaitingPipelines" yaml:"keepWaitingPipelines" hcl:"keepWaitingPipelines"`
	Roles                []string                 `json:"roles,omitempty" yaml:"roles,omitempty" hcl:"roles,omitempty"`
	Stages               []map[string]interface{} `json:"stages,omitempty" yaml:"stages,omitempty" hcl:"stages,omitempty"`
	Triggers             []map[string]interface{} `json:"triggers,omitempty" yaml:"triggers,omitempty" hcl:"triggers,omitempty"`
	Parameters           []map[string]interface{} `json:"parameterConfig,omitempty" yaml:"parameterConfig,omitempty" hcl:"parameterConfig,omitempty"`
	Notifications        []map[string]interface{} `json:"notifications,omitempty" yaml:"notifications,omitempty" hcl:"notifications,omitempty"`
	ExpectedArtifacts    []map[string]interface{} `json:"expectedArtifacts,omitempty" yaml:"expectedArtifacts,omitempty" hcl:"expectedArtifacts,omitempty"`
	LastModifiedBy       string                   `json:"lastModifiedBy" yaml:"lastModifiedBy" hcl:"lastModifiedBy"`
	Config               interface{}              `json:"config,omitempty" yaml:"config,omitempty" hcl:"config,omitempty"`
	UpdateTs             string                   `json:"updateTs" yaml:"updateTs" hcl:"updateTs"`
	Locked               *PipelineLockType        `json:"locked,omitempty" yaml:"locked,omitempty" hcl:"locked,omitempty"`
	SpelEvaluator        string                   `json:"spelEvaluator" yaml:"spelEvaluator" hcl:"spelEvaluator"`
}

Pipeline is the structure that comes back from Spinnaker representing a pipeline definition (different than an execution)

func (*Pipeline) Lock

func (p *Pipeline) Lock() *Pipeline

func (*Pipeline) ValidateRefIds

func (p *Pipeline) ValidateRefIds() ValidationResult

type PipelineLockType

type PipelineLockType struct {
	UI            bool `json:"ui" yaml:"ui" hcl:"ui"`
	AllowUnlockUI bool `json:"allowUnlockUi" yaml:"allowUnlockUi" hcl:"allowUnlockUi"`
}

type PipelineRef

type PipelineRef struct {
	// Ref is the path the the execution. Use it to get status updates.
	Ref string `json:"ref" yaml:"ref" hcl:"ref"`
}

type ReadPermissable

type ReadPermissable interface {
	GetName() string
	GetPermissions() []string
}

ReadPermissable is an interface for things that should be readable

type RequestFunction

type RequestFunction func() error

type Task

type Task struct {
	Application string        `json:"application"`
	Description string        `json:"description"`
	Job         []interface{} `json:"job,omitempty"`
}

type TaskRefResponse

type TaskRefResponse struct {
	Ref string `json:"ref"`
}

type User

type User struct {
	Name         string          `json:"name" yaml:"name" hcl:"name"`
	Admin        bool            `json:"admin" yaml:"admin" hcl:"admin"`
	Accounts     []Authorization `json:"accounts" yaml:"accounts" hcl:"accounts"`
	Applications []Authorization `json:"applications" yaml:"applications" hcl:"applications"`
}

User is returned by Fiat's /authorize endpoint.

func (*User) HasAppWriteAccess

func (u *User) HasAppWriteAccess(app string) bool

HasAppWriteAccess returns true if user has write access to given app.

func (*User) IsAdmin

func (u *User) IsAdmin() bool

IsAdmin returns true if the user has admin permissions

type ValidationResult

type ValidationResult struct {
	Errors   []error
	Warnings []string
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL