plank

package module
v3.4.5 Latest Latest
Warning

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

Go to latest
Published: Feb 16, 2021 License: Apache-2.0 Imports: 14 Imported by: 1

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"`
}

Application as returned from the Spinnaker API.

func (Application) MarshalJSON added in v3.4.4

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
	// 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) error

CreateApplication does what it says.

func (*Client) CreateTask

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

Create task puts the payload into the Task wrapper.

func (*Client) Delete

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

func (*Client) DeleteApplication

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

DeleteApplication deletes an application from the configured front50 store.

func (*Client) DeletePipeline

func (c *Client) DeletePipeline(p Pipeline) error

DeletePipeline does what it says.

func (*Client) DeletePipelineByName

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

func (*Client) DeleteWithRetry

func (c *Client) DeleteWithRetry(url 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 string) (*PipelineRef, error)

Execute a pipeline by application and pipeline.

func (*Client) Get

func (c *Client) Get(url 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 string) (*Application, error)

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

func (*Client) GetApplicationNotifications added in v3.4.0

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

GetApplicationNotifications returns all application notifications

func (*Client) GetApplications

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

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

func (*Client) GetPipelines

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

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

func (*Client) GetTask

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

func (*Client) GetUser

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

GetUser gets a user by name.

func (*Client) GetWithRetry

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

func (*Client) HasAppWriteAccess

func (c *Client) HasAppWriteAccess(username, app 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 string) (bool, error)

Admin returns whether or not a user is an admin.

func (*Client) Patch

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

Patch updates a resource for the target URL

func (*Client) PatchWithRetry

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

PatchWithRetry updates a resource for the target URL

func (*Client) PollTaskStatus

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

func (*Client) Post

func (c *Client) Post(url 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 string, contentType ContentType, body interface{}, dest interface{}) error

func (*Client) Put

func (c *Client) Put(url 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 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() 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) error

UpdateApplication updates an application in the configured front50 store.

func (*Client) UpdateApplicationNotifications added in v3.4.0

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

UpdateApplicationNotifications updates notifications in the configured front50 store.

func (*Client) UpdatePermissions added in v3.4.3

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

UpdatePermissions updates an application permissions in the configured front50 store.

func (*Client) UpsertPipeline

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

UpsertPipeline creates/updates a pipeline defined in the struct argument.

func (*Client) UserRoles added in v3.2.0

func (c *Client) UserRoles(username 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 added in v3.2.0

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

type FiatClientFactory added in v3.2.0

type FiatClientFactory func(opts ...ClientOption) FiatClient

type FiatPermissionEvaluator added in v3.2.0

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

func NewFiatPermissionEvaluator added in v3.2.0

func NewFiatPermissionEvaluator(opts ...PermissionEvaluatorOpt) *FiatPermissionEvaluator

func (*FiatPermissionEvaluator) HasReadPermission added in v3.2.0

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

type FiatRole added in v3.2.0

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

type Front50Permissions added in v3.4.3

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 added in v3.4.0

type NotificationsType map[string]interface{}

func (*NotificationsType) FillAppNotificationFields added in v3.4.0

func (notifications *NotificationsType) FillAppNotificationFields(appName string)

func (*NotificationsType) ValidateAppNotification added in v3.4.0

func (notifications *NotificationsType) ValidateAppNotification() error

type PermissionEvaluatorOpt added in v3.3.0

type PermissionEvaluatorOpt func(fpe *FiatPermissionEvaluator)

func WithClientOptions added in v3.3.0

func WithClientOptions(opts ...ClientOption) PermissionEvaluatorOpt

func WithOrMode added in v3.2.0

func WithOrMode(orMode bool) PermissionEvaluatorOpt

type PermissionsEvaluator added in v3.2.0

type PermissionsEvaluator interface {
	HasReadPermission(user 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"`
	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 added in v3.2.0

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