ots

package module
v0.0.6 Latest Latest
Warning

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

Go to latest
Published: Jun 21, 2021 License: MPL-2.0 Imports: 11 Imported by: 0

README

OTS: Open Terraforming Server

A prototype open source alternative to terraform enterprise.

Functionality is currently limited:

  • State backend (state stored in a sqlite database)
  • Workspace management (supports terraform workspace commands)
  • Local execution mode (plans and applies run locally)

Getting Started

These steps will get you started with running everything on your local system. You'll setup the server, configure SSL so that terraform trusts the server, and then configure terraform. You'll then be able to run terraform commands using the server as a remote backend.

demo

  1. Download a release. The zip file contains two binaries: a daemon and a client, otsd and ots. Extract them to a directory in your PATH, e.g. /usr/local/bin.

  2. Generate SSL cert and key. For example, to generate a self-signed cert and key for localhost:

    openssl req -x509 -newkey rsa:4096 -sha256 -keyout key.pem -out cert.crt -days 365 -nodes -subj '/CN=localhost' -addext 'subjectAltName=DNS:localhost'
    
  3. Ensure your system trusts the generated cert. For example, on Linux:

    sudo cp cert.crt /usr/local/share/ca-certificates
    sudo update-ca-certificates
    
  4. Run the OTS daemon:

    otsd --ssl --cert-file=cert.crt --key-file=key.pem
    

    The daemon runs in the foreground and can be left to run.

  5. Login to your OTS server (this merely adds some dummy credentials to ~/.terraform.d/credentials.tfrc.json):

    ots login
    
  6. In another terminal create an organization:

    ots organizations new mycorp --email=sysadmin@mycorp.co
    
  7. Configure the terraform backend and define a resource:

    cat > main.tf <<EOF
    terraform {
      backend "remote" {
        hostname = "localhost:8080"
        organization = "mycorp"
    
        workspaces {
          name = "dev"
        }
      }
    }
    
    resource "null_resource" "e2e" {}
    EOF
    
  8. Run terraform!:

    terraform init
    terraform plan
    terraform apply
    

Next Steps

OTS is a mere prototype but a roadmap of further features could be:

  • User AuthN/Z
  • Remote execution mode
  • Agents
  • Github integration
  • Policies (OPA?)
  • Web frontend

Building

You'll need Go installed.

Clone the repo, and then build and install the binary using the make task:

git clone https://github.com/leg100/ots
cd ots
make install

That'll create a binary inside your go bins directory (defaults to $HOME/go/bin).

Documentation

Index

Constants

View Source
const (
	DefaultSessionTimeout         = 20160
	DefaultSessionExpiration      = 20160
	DefaultCollaboratorAuthPolicy = "password"
	DefaultCostEstimationEnabled  = true
)
View Source
const (
	DefaultPageNumber = 1
	DefaultPageSize   = 20
	MaxPageSize       = 100
)
View Source
const (
	DefaultAllowDestroyPlan    = true
	DefaultFileTriggersEnabled = true
	DefaultTerraformVersion    = "0.15.4"
)

Variables

View Source
var (
	Version = "unknown"
	Commit  = "unknown"
)
View Source
var (
	ErrWorkspaceAlreadyLocked   = errors.New("workspace already locked")
	ErrWorkspaceAlreadyUnlocked = errors.New("workspace already unlocked")
)

Functions

func GenerateRandomString

func GenerateRandomString(size int) string

func Int

func Int(i int) *int

func NewStateVersionID

func NewStateVersionID() string

func NewStateVersionOutputID

func NewStateVersionOutputID() string

func NewWorkspaceID

func NewWorkspaceID() string

func String

func String(str string) *string

func UpdateOrganizationFromOptions

func UpdateOrganizationFromOptions(org *Organization, opts *tfe.OrganizationUpdateOptions) error

Types

type AgentPool

type AgentPool struct {
	ID   string `jsonapi:"primary,agent-pools"`
	Name string `jsonapi:"attr,name"`

	// Relations
	Organization *Organization `jsonapi:"relation,organization"`
}

AgentPool represents a Terraform Cloud agent pool.

type Entitlements

type Entitlements struct {
	ID                    string `jsonapi:"primary,entitlement-sets"`
	Agents                bool   `jsonapi:"attr,agents"`
	AuditLogging          bool   `jsonapi:"attr,audit-logging"`
	CostEstimation        bool   `jsonapi:"attr,cost-estimation"`
	Operations            bool   `jsonapi:"attr,operations"`
	PrivateModuleRegistry bool   `jsonapi:"attr,private-module-registry"`
	SSO                   bool   `jsonapi:"attr,sso"`
	Sentinel              bool   `jsonapi:"attr,sentinel"`
	StateStorage          bool   `jsonapi:"attr,state-storage"`
	Teams                 bool   `jsonapi:"attr,teams"`
	VCSIntegrations       bool   `jsonapi:"attr,vcs-integrations"`
}

Entitlements represents the entitlements of an organization.

func NewEntitlements

func NewEntitlements(orgName string) *Entitlements
func (e *Entitlements) JSONAPILinks() *jsonapi.Links

type ListOptions

type ListOptions struct {
	// The page number to request. The results vary based on the PageSize.
	PageNumber int `schema:"page[number]"`

	// The number of elements returned in a single page.
	PageSize int `schema:"page[size]"`
}

ListOptions is used to specify pagination options when making API requests. Pagination allows breaking up large result sets into chunks, or "pages".

func (*ListOptions) Sanitize

func (o *ListOptions) Sanitize()

Sanitize list options' values, setting defaults and ensuring they adhere to mins/maxs.

type Organization

type Organization struct {
	Name                   string                   `jsonapi:"primary,organizations"`
	CollaboratorAuthPolicy tfe.AuthPolicyType       `jsonapi:"attr,collaborator-auth-policy"`
	CostEstimationEnabled  bool                     `jsonapi:"attr,cost-estimation-enabled"`
	CreatedAt              time.Time                `jsonapi:"attr,created-at,iso8601"`
	Email                  string                   `jsonapi:"attr,email"`
	EnterprisePlan         tfe.EnterprisePlanType   `jsonapi:"attr,enterprise-plan"`
	ExternalID             string                   `jsonapi:"attr,external-id"`
	OwnersTeamSAMLRoleID   string                   `jsonapi:"attr,owners-team-saml-role-id"`
	Permissions            *OrganizationPermissions `jsonapi:"attr,permissions"`
	SAMLEnabled            bool                     `jsonapi:"attr,saml-enabled"`
	SessionRemember        int                      `jsonapi:"attr,session-remember"`
	SessionTimeout         int                      `jsonapi:"attr,session-timeout"`
	TrialExpiresAt         time.Time                `jsonapi:"attr,trial-expires-at,iso8601"`
	TwoFactorConformant    bool                     `jsonapi:"attr,two-factor-conformant"`
}

Organization represents a Terraform Enterprise organization.

func NewOrganizationFromOptions

func NewOrganizationFromOptions(opts *tfe.OrganizationCreateOptions, overrides ...func(*Organization)) (*Organization, error)
func (org *Organization) JSONAPILinks() *jsonapi.Links

type OrganizationList

type OrganizationList struct {
	Items []*Organization
	OrganizationListOptions
}

func (*OrganizationList) GetItems

func (l *OrganizationList) GetItems() interface{}

func (*OrganizationList) GetListOptions

func (l *OrganizationList) GetListOptions() ListOptions

func (*OrganizationList) GetPath

func (l *OrganizationList) GetPath() string

type OrganizationListOptions

type OrganizationListOptions struct {
	ListOptions
}

OrganizationListOptions represents the options for listing organizations.

type OrganizationPermissions

type OrganizationPermissions struct {
	CanCreateTeam               bool `json:"can-create-team"`
	CanCreateWorkspace          bool `json:"can-create-workspace"`
	CanCreateWorkspaceMigration bool `json:"can-create-workspace-migration"`
	CanDestroy                  bool `json:"can-destroy"`
	CanTraverse                 bool `json:"can-traverse"`
	CanUpdate                   bool `json:"can-update"`
	CanUpdateAPIToken           bool `json:"can-update-api-token"`
	CanUpdateOAuth              bool `json:"can-update-oauth"`
	CanUpdateSentinel           bool `json:"can-update-sentinel"`
}

OrganizationPermissions represents the organization permissions.

type OrganizationService

type OrganizationService interface {
	CreateOrganization(opts *tfe.OrganizationCreateOptions) (*Organization, error)
	GetOrganization(name string) (*Organization, error)
	ListOrganizations(opts OrganizationListOptions) (*OrganizationList, error)
	UpdateOrganization(name string, opts *tfe.OrganizationUpdateOptions) (*Organization, error)
	DeleteOrganization(name string) error
	GetEntitlements(name string) (*Entitlements, error)
}

type Paginated

type Paginated interface {
	GetItems() interface{}
	GetListOptions() ListOptions
	GetPath() string
}

type PaginatedMock

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

func NewPaginatedMock

func NewPaginatedMock(path string, items, current, size int) *PaginatedMock

func (*PaginatedMock) GetItems

func (p *PaginatedMock) GetItems() interface{}

func (*PaginatedMock) GetListOptions

func (p *PaginatedMock) GetListOptions() ListOptions

func (*PaginatedMock) GetPath

func (p *PaginatedMock) GetPath() string

type Pagination

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

Pagination is used to return the pagination details of an API request.

func NewPagination

func NewPagination(p Paginated) *Pagination

NewPagination constructs a Pagination obj.

func (p *Pagination) JSONAPIPaginationLinks() *jsonapi.Links

func (*Pagination) JSONAPIPaginationMeta

func (p *Pagination) JSONAPIPaginationMeta() *jsonapi.Meta

type StateVersion

type StateVersion struct {
	ID           string    `jsonapi:"primary,state-versions"`
	CreatedAt    time.Time `jsonapi:"attr,created-at,iso8601"`
	DownloadURL  string    `jsonapi:"attr,hosted-state-download-url"`
	Serial       int64     `jsonapi:"attr,serial"`
	VCSCommitSHA string    `jsonapi:"attr,vcs-commit-sha"`
	VCSCommitURL string    `jsonapi:"attr,vcs-commit-url"`

	// Relations
	// Run     *Run                  `jsonapi:"relation,run"`
	Outputs []*StateVersionOutput `jsonapi:"relation,outputs"`
}

StateVersion represents a Terraform Enterprise state version.

func (sv *StateVersion) JSONAPILinks() *jsonapi.Links

type StateVersionCreateOptions

type StateVersionCreateOptions struct {
	// Type is a public field utilized by JSON:API to
	// set the resource type via the field tag.
	// It is not a user-defined value and does not need to be set.
	// https://jsonapi.org/format/#crud-creating
	Type string `jsonapi:"primary,state-versions"`

	// The lineage of the state.
	Lineage *string `jsonapi:"attr,lineage,omitempty"`

	// The MD5 hash of the state version.
	MD5 *string `jsonapi:"attr,md5"`

	// The serial of the state.
	Serial *int64 `jsonapi:"attr,serial"`

	// The base64 encoded state.
	State *string `jsonapi:"attr,state"`

	// Force can be set to skip certain validations. Wrong use
	// of this flag can cause data loss, so USE WITH CAUTION!
	Force *bool `jsonapi:"attr,force"`
}

StateVersionCreateOptions represents the options for creating a state version.

type StateVersionList

type StateVersionList struct {
	Items []*StateVersion
	StateVersionListOptions
}

func (*StateVersionList) GetItems

func (l *StateVersionList) GetItems() interface{}

func (*StateVersionList) GetListOptions

func (l *StateVersionList) GetListOptions() ListOptions

func (*StateVersionList) GetPath

func (l *StateVersionList) GetPath() string

type StateVersionListFilters

type StateVersionListFilters struct {
	Organization *string `schema:"filter[organization][name],required"`
	Workspace    *string `schema:"filter[workspace][name],required"`
}

StateVersionListFilters filters state version list by org and workspace

type StateVersionListOptions

type StateVersionListOptions struct {
	ListOptions
	StateVersionListFilters
}

StateVersionListOptions represents the options for listing state versions.

type StateVersionOutput

type StateVersionOutput struct {
	ID        string `jsonapi:"primary,state-version-outputs"`
	Name      string `jsonapi:"attr,name"`
	Sensitive bool   `jsonapi:"attr,sensitive"`
	Type      string `jsonapi:"attr,type"`
	Value     string `jsonapi:"attr,value"`
}
func (svo *StateVersionOutput) JSONAPILinks() *jsonapi.Links

type StateVersionOutputService

type StateVersionOutputService interface {
	GetStateVersionOutput(id string) (*StateVersionOutput, error)
}

type StateVersionService

type StateVersionService interface {
	CreateStateVersion(workspaceID string, opts *StateVersionCreateOptions) (*StateVersion, error)
	ListStateVersions(orgName, workspaceName string, opts StateVersionListOptions) (*StateVersionList, error)
	CurrentStateVersion(workspaceID string) (*StateVersion, error)
	GetStateVersion(id string) (*StateVersion, error)
	DownloadStateVersion(id string) ([]byte, error)
}

type VCSRepo

type VCSRepo struct {
	Branch            string `json:"branch"`
	DisplayIdentifier string `json:"display-identifier"`
	Identifier        string `json:"identifier"`
	IngressSubmodules bool   `json:"ingress-submodules"`
	OAuthTokenID      string `json:"oauth-token-id"`
	RepositoryHTTPURL string `json:"repository-http-url"`
	ServiceProvider   string `json:"service-provider"`
}

VCSRepo contains the configuration of a VCS integration.

type Workspace

type Workspace struct {
	ID                   string                `jsonapi:"primary,workspaces"`
	Actions              *WorkspaceActions     `jsonapi:"attr,actions"`
	AgentPoolID          string                `jsonapi:"attr,agent-pool-id"`
	AllowDestroyPlan     bool                  `jsonapi:"attr,allow-destroy-plan"`
	AutoApply            bool                  `jsonapi:"attr,auto-apply"`
	CanQueueDestroyPlan  bool                  `jsonapi:"attr,can-queue-destroy-plan"`
	CreatedAt            time.Time             `jsonapi:"attr,created-at,iso8601"`
	Description          string                `jsonapi:"attr,description"`
	Environment          string                `jsonapi:"attr,environment"`
	ExecutionMode        string                `jsonapi:"attr,execution-mode"`
	FileTriggersEnabled  bool                  `jsonapi:"attr,file-triggers-enabled"`
	GlobalRemoteState    bool                  `jsonapi:"attr,global-remote-state"`
	Locked               bool                  `jsonapi:"attr,locked"`
	MigrationEnvironment string                `jsonapi:"attr,migration-environment"`
	Name                 string                `jsonapi:"attr,name"`
	Operations           bool                  `jsonapi:"attr,operations"`
	Permissions          *WorkspacePermissions `jsonapi:"attr,permissions"`
	QueueAllRuns         bool                  `jsonapi:"attr,queue-all-runs"`
	SpeculativeEnabled   bool                  `jsonapi:"attr,speculative-enabled"`
	TerraformVersion     string                `jsonapi:"attr,terraform-version"`
	TriggerPrefixes      []string              `jsonapi:"attr,trigger-prefixes"`
	VCSRepo              *VCSRepo              `jsonapi:"attr,vcs-repo"`
	WorkingDirectory     string                `jsonapi:"attr,working-directory"`
	UpdatedAt            time.Time             `jsonapi:"attr,updated-at,iso8601"`
	ResourceCount        int                   `jsonapi:"attr,resource-count"`
	ApplyDurationAverage time.Duration         `jsonapi:"attr,apply-duration-average"`
	PlanDurationAverage  time.Duration         `jsonapi:"attr,plan-duration-average"`
	PolicyCheckFailures  int                   `jsonapi:"attr,policy-check-failures"`
	RunFailures          int                   `jsonapi:"attr,run-failures"`
	RunsCount            int                   `jsonapi:"attr,workspace-kpis-runs-count"`

	// Relations
	Organization *Organization `jsonapi:"relation,organization"`
}

Workspace represents a Terraform Enterprise workspace.

func (ws *Workspace) JSONAPILinks() *jsonapi.Links

type WorkspaceActions

type WorkspaceActions struct {
	IsDestroyable bool `json:"is-destroyable"`
}

WorkspaceActions represents the workspace actions.

type WorkspaceCreateOptions

type WorkspaceCreateOptions struct {
	// Type is a public field utilized by JSON:API to
	// set the resource type via the field tag.
	// It is not a user-defined value and does not need to be set.
	// https://jsonapi.org/format/#crud-creating
	Type string `jsonapi:"primary,workspaces"`

	// Required when execution-mode is set to agent. The ID of the agent pool
	// belonging to the workspace's organization. This value must not be specified
	// if execution-mode is set to remote or local or if operations is set to true.
	AgentPoolID *string `jsonapi:"attr,agent-pool-id,omitempty"`

	// Whether destroy plans can be queued on the workspace.
	AllowDestroyPlan *bool `jsonapi:"attr,allow-destroy-plan,omitempty"`

	// Whether to automatically apply changes when a Terraform plan is successful.
	AutoApply *bool `jsonapi:"attr,auto-apply,omitempty"`

	// A description for the workspace.
	Description *string `jsonapi:"attr,description,omitempty"`

	// Which execution mode to use. Valid values are remote, local, and agent.
	// When set to local, the workspace will be used for state storage only.
	// This value must not be specified if operations is specified.
	// 'agent' execution mode is not available in Terraform Enterprise.
	ExecutionMode *string `jsonapi:"attr,execution-mode,omitempty"`

	// Whether to filter runs based on the changed files in a VCS push. If
	// enabled, the working directory and trigger prefixes describe a set of
	// paths which must contain changes for a VCS push to trigger a run. If
	// disabled, any push will trigger a run.
	FileTriggersEnabled *bool `jsonapi:"attr,file-triggers-enabled,omitempty"`

	GlobalRemoteState *bool `jsonapi:"attr,global-remote-state,omitempty"`

	// The legacy TFE environment to use as the source of the migration, in the
	// form organization/environment. Omit this unless you are migrating a legacy
	// environment.
	MigrationEnvironment *string `jsonapi:"attr,migration-environment,omitempty"`

	// The name of the workspace, which can only include letters, numbers, -,
	// and _. This will be used as an identifier and must be unique in the
	// organization.
	Name *string `jsonapi:"attr,name"`

	// DEPRECATED. Whether the workspace will use remote or local execution mode.
	// Use ExecutionMode instead.
	Operations *bool `jsonapi:"attr,operations,omitempty"`

	// Whether to queue all runs. Unless this is set to true, runs triggered by
	// a webhook will not be queued until at least one run is manually queued.
	QueueAllRuns *bool `jsonapi:"attr,queue-all-runs,omitempty"`

	// Whether this workspace allows speculative plans. Setting this to false
	// prevents Terraform Cloud or the Terraform Enterprise instance from
	// running plans on pull requests, which can improve security if the VCS
	// repository is public or includes untrusted contributors.
	SpeculativeEnabled *bool `jsonapi:"attr,speculative-enabled,omitempty"`

	// The version of Terraform to use for this workspace. Upon creating a
	// workspace, the latest version is selected unless otherwise specified.
	TerraformVersion *string `jsonapi:"attr,terraform-version,omitempty"`

	// List of repository-root-relative paths which list all locations to be
	// tracked for changes. See FileTriggersEnabled above for more details.
	TriggerPrefixes []string `jsonapi:"attr,trigger-prefixes,omitempty"`

	// Settings for the workspace's VCS repository. If omitted, the workspace is
	// created without a VCS repo. If included, you must specify at least the
	// oauth-token-id and identifier keys below.
	VCSRepo *tfe.VCSRepoOptions `jsonapi:"attr,vcs-repo,omitempty"`

	// A relative path that Terraform will execute within. This defaults to the
	// root of your repository and is typically set to a subdirectory matching the
	// environment when multiple environments exist within the same repository.
	WorkingDirectory *string `jsonapi:"attr,working-directory,omitempty"`
}

WorkspaceCreateOptions represents the options for creating a new workspace.

func (*WorkspaceCreateOptions) Validate

func (opts *WorkspaceCreateOptions) Validate() error

type WorkspaceList

type WorkspaceList struct {
	Items        []*Workspace
	Organization string
	WorkspaceListOptions
}

func (*WorkspaceList) GetItems

func (l *WorkspaceList) GetItems() interface{}

func (*WorkspaceList) GetListOptions

func (l *WorkspaceList) GetListOptions() ListOptions

func (*WorkspaceList) GetPath

func (l *WorkspaceList) GetPath() string

type WorkspaceListOptions

type WorkspaceListOptions struct {
	ListOptions

	// A search string (partial workspace name) used to filter the results.
	Search *string `schema:"search[name]"`

	// A list of relations to include. See available resources https://www.terraform.io/docs/cloud/api/workspaces.html#available-related-resources
	Include *string `schema:"include"`
}

WorkspaceListOptions represents the options for listing workspaces.

type WorkspaceLockOptions

type WorkspaceLockOptions struct {
	// Specifies the reason for locking the workspace.
	Reason *string `jsonapi:"attr,reason,omitempty"`
}

WorkspaceLockOptions represents the options for locking a workspace.

type WorkspacePermissions

type WorkspacePermissions struct {
	CanDestroy        bool `json:"can-destroy"`
	CanForceUnlock    bool `json:"can-force-unlock"`
	CanLock           bool `json:"can-lock"`
	CanQueueApply     bool `json:"can-queue-apply"`
	CanQueueDestroy   bool `json:"can-queue-destroy"`
	CanQueueRun       bool `json:"can-queue-run"`
	CanReadSettings   bool `json:"can-read-settings"`
	CanUnlock         bool `json:"can-unlock"`
	CanUpdate         bool `json:"can-update"`
	CanUpdateVariable bool `json:"can-update-variable"`
}

WorkspacePermissions represents the workspace permissions.

type WorkspaceService

type WorkspaceService interface {
	CreateWorkspace(org string, opts *WorkspaceCreateOptions) (*Workspace, error)
	GetWorkspace(name, org string) (*Workspace, error)
	GetWorkspaceByID(id string) (*Workspace, error)
	ListWorkspaces(org string, opts WorkspaceListOptions) (*WorkspaceList, error)
	UpdateWorkspace(name, org string, opts *tfe.WorkspaceUpdateOptions) (*Workspace, error)
	UpdateWorkspaceByID(id string, opts *tfe.WorkspaceUpdateOptions) (*Workspace, error)
	DeleteWorkspace(name, org string) error
	DeleteWorkspaceByID(id string) error
	LockWorkspace(id string, opts WorkspaceLockOptions) (*Workspace, error)
	UnlockWorkspace(id string) (*Workspace, error)
}

Directories

Path Synopsis
cmd
ots

Jump to

Keyboard shortcuts

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