model

package
v0.9.0 Latest Latest
Warning

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

Go to latest
Published: Sep 5, 2016 License: Apache-2.0 Imports: 10 Imported by: 15

Documentation

Index

Constants

View Source
const (
	UserRoleAdmin = "admin"
	UserRoleUser  = "user"
)

Variables

This section is empty.

Functions

func ZeroPrivateFields

func ZeroPrivateFields(r Model)

ZeroPrivateFields takes a Model with pointer, and zeroes any fields with the tag sg:"private".

func ZeroReadonlyFields

func ZeroReadonlyFields(r Model)

ZeroReadonlyFields takes a Model with pointer, and zeroes any fields with the tag sg:"readonly".

Types

type AWSKubeConfig

type AWSKubeConfig struct {
	Region              string `json:"region" validate:"nonzero,regexp=^[a-z]{2}-[a-z]+-[0-9]$"`
	AvailabilityZone    string `json:"availability_zone" validate:"nonzero,regexp=^[a-z]{2}-[a-z]+-[0-9][a-z]$"`
	VPCIPRange          string `json:"vpc_ip_range" validate:"nonzero" sg:"default=172.20.0.0/16"`
	PublicSubnetIPRange string `json:"public_subnet_ip_range" validate:"nonzero" sg:"default=172.20.0.0/24"`
	MasterPrivateIP     string `json:"master_private_ip" validate:"nonzero" sg:"default=172.20.0.9"`

	PrivateKey                    string `json:"private_key,omitempty" sg:"readonly,private"`
	VPCID                         string `json:"vpc_id" sg:"readonly"`
	InternetGatewayID             string `json:"internet_gateway_id" sg:"readonly"`
	PublicSubnetID                string `json:"public_subnet_id" sg:"readonly"`
	RouteTableID                  string `json:"route_table_id" sg:"readonly"`
	RouteTableSubnetAssociationID string `json:"route_table_subnet_association_id" sg:"readonly"`
	ELBSecurityGroupID            string `json:"elb_security_group_id" sg:"readonly"`
	NodeSecurityGroupID           string `json:"node_security_group_id" sg:"readonly"`
	MasterID                      string `json:"master_id" sg:"readonly"`
}

type ActionStatus

type ActionStatus struct {
	Description string `json:"description"`
	MaxRetries  int    `json:"max_retries"`
	Retries     int    `json:"retries"`
	Error       string `json:"error,omitempty"`
	Cancelled   bool   `json:"cancelled,omitempty"`
}

type Addresses

type Addresses struct {
	External []*PortAddress `json:"external"`
	Internal []*PortAddress `json:"internal"`
}

type App

type App struct {
	BaseModel
	Name string `json:"name" validate:"nonzero,max=24,regexp=^[a-z]([-a-z0-9]*[a-z0-9])?$" gorm:"not null;unique_index:name_within_kube"`

	// belongs_to Kube
	Kube   *Kube  `json:"kube,omitempty"`
	KubeID *int64 `json:"kube_id" gorm:"not null;index;unique_index:name_within_kube"`

	// has_many Components
	Components []*Component `json:"components,omitempty"`
}

type BaseModel

type BaseModel struct {
	ID        *int64        `gorm:"primary_key" json:"id,omitempty" sg:"readonly"`
	UUID      string        `json:"uuid,omitempty" sg:"readonly"`
	CreatedAt time.Time     `json:"created_at,omitempty" sg:"readonly"` // TODO won't be omitted cuz not *time.Time
	UpdatedAt time.Time     `json:"updated_at,omitempty" sg:"readonly"`
	Status    *ActionStatus `gorm:"-" json:"status,omitempty"`
}

func (*BaseModel) GetID

func (m *BaseModel) GetID() interface{}

func (*BaseModel) GetUUID

func (m *BaseModel) GetUUID() string

func (*BaseModel) SetActionStatus

func (m *BaseModel) SetActionStatus(status *ActionStatus)

func (*BaseModel) SetUUID

func (m *BaseModel) SetUUID()

type BelongsToField

type BelongsToField struct {
	Field reflect.StructField
	Value reflect.Value
}

type BytesValue

type BytesValue struct {
	Bytes int64
}

func BytesFromString

func BytesFromString(str string) *BytesValue

func (*BytesValue) Gibibytes

func (v *BytesValue) Gibibytes() float64

func (*BytesValue) MarshalJSON

func (b *BytesValue) MarshalJSON() ([]byte, error)

func (*BytesValue) Mebibytes

func (v *BytesValue) Mebibytes() float64

func (*BytesValue) ToKubeMebibytes

func (v *BytesValue) ToKubeMebibytes() string

func (*BytesValue) UnmarshalJSON

func (b *BytesValue) UnmarshalJSON(raw []byte) error

type CloudAccount

type CloudAccount struct {
	BaseModel

	// has_many Kubes
	Kubes []*Kube `json:"kubes,omitempty"`

	Name string `json:"name" validate:"nonzero" gorm:"not null;unique_index"`

	Provider string `json:"provider" validate:"regexp=^(aws)$" gorm:"not null"`

	// NOTE this is loose map to allow for multiple clouds (eventually)
	Credentials     map[string]string `json:"credentials,omitempty" gorm:"-" sg:"store_as_json_in=CredentialsJSON,private"`
	CredentialsJSON []byte            `json:"-" gorm:"not null"`
}

type Component

type Component struct {
	BaseModel

	// belongs_to App
	App   *App   `json:"app,omitempty"`
	AppID *int64 `json:"app_id" gorm:"not null;index;unique_index:name_within_app"`

	Name string `json:"name" validate:"nonzero,max=17,regexp=^[a-z]([-a-z0-9]*[a-z0-9])?$" gorm:"not null;unique_index:name_within_app"`

	// CustomDeployScript is stored as JSON (like an embed in Mongo)
	CustomDeployScript     *CustomDeployScript `json:"custom_deploy_script,omitempty" gorm:"-" sg:"store_as_json_in=CustomDeployScriptJSON"`
	CustomDeployScriptJSON []byte              `json:"-"`

	// has_many Releases (for preloading)
	Releases []*Release `json:"releases,omitempty"`

	// has_many Instances (for preloading)
	Instances []*Instance `json:"instances,omitempty"`

	// has_one CurrentRelease
	CurrentRelease   *Release `json:"current_release,omitempty" gorm:"ForeignKey:CurrentReleaseID"`
	CurrentReleaseID *int64   `json:"current_release_id" sg:"readonly"`

	// has_one TargetRelease
	TargetRelease   *Release `json:"target_release,omitempty" gorm:"ForeignKey:TargetReleaseID"`
	TargetReleaseID *int64   `json:"target_release_id" sg:"readonly"`

	Addresses     *Addresses `json:"addresses,omitempty" gorm:"-" sg:"store_as_json_in=AddressesJSON"`
	AddressesJSON []byte     `json:"-"`

	// has_many ComponentPrivateImageKeys (really a many2many with PrivateImageKeys)
	PrivateImageKeys []*ComponentPrivateImageKey `json:"private_image_keys"`
}

func (*Component) InstanceByNum

func (m *Component) InstanceByNum(num int) *Instance

func (*Component) InstanceCount

func (m *Component) InstanceCount() int

returns max of the 2 releases

type ComponentConfig

type ComponentConfig struct {
	// These attributes, when changed from last Release, indicate a restart is
	// needed (or just new instances through other means).
	Volumes                []*VolumeBlueprint    `json:"volumes"`
	Containers             []*ContainerBlueprint `json:"containers" validate:"min=1"`
	TerminationGracePeriod int                   `json:"termination_grace_period" validate:"min=0" sg:"default=10"`
}

type ComponentPrivateImageKey

type ComponentPrivateImageKey struct {
	BaseModel
	// belongs_to Component
	Component   *Component `json:"component,omitempty"`
	ComponentID *int64     `json:"component_id" gorm:"not null;index"`
	// belongs_to PrivateImageKey
	Key   *PrivateImageKey `json:"key,omitempty" gorm:"ForeignKey:KeyID"`
	KeyID *int64           `json:"key_id" gorm:"not null;index"`
}

Join model

type ContainerBlueprint

type ContainerBlueprint struct {
	Image      string      `json:"image" validate:"nonzero,regexp=^[-\\w\\.\\/]+(:[-\\w\\.]+)?$"`
	Name       string      `json:"name,omitempty" validate:"regexp=^[-\\w\\.\\/]+(:[-\\w\\.]+)?$"`
	Command    []string    `json:"command,omitempty"`
	Ports      []*Port     `json:"ports,omitempty"`
	Env        []*EnvVar   `json:"env,omitempty"`
	CPURequest *CoresValue `json:"cpu_request"`
	CPULimit   *CoresValue `json:"cpu_limit"`
	RAMRequest *BytesValue `json:"ram_request"`
	RAMLimit   *BytesValue `json:"ram_limit"`
	Mounts     []*Mount    `json:"mounts,omitempty"`
}

func (*ContainerBlueprint) NameOrDefault

func (c *ContainerBlueprint) NameOrDefault() string

type CoresValue

type CoresValue struct {
	Millicores int
}

func CoresFromString

func CoresFromString(str string) *CoresValue

func (*CoresValue) Cores

func (v *CoresValue) Cores() float64

func (*CoresValue) MarshalJSON

func (c *CoresValue) MarshalJSON() ([]byte, error)

func (*CoresValue) ToKubeMillicores

func (v *CoresValue) ToKubeMillicores() string

func (*CoresValue) UnmarshalJSON

func (c *CoresValue) UnmarshalJSON(raw []byte) error

type CustomDeployScript

type CustomDeployScript struct {
	Image   string   `json:"image" validate:"nonzero,regexp=^[-\\w\\.\\/]+(:[-\\w\\.]+)?$"`
	Command []string `json:"command"` // TODO need validation here, I think we need to reqire command
	Timeout int      `json:"timeout" sg:"default=1800"`
}

type Entrypoint

type Entrypoint struct {
	BaseModel

	// belongs_to Kube
	Kube   *Kube  `json:"kube,omitempty"`
	KubeID *int64 `json:"kube_id" gorm:"not null;index"`

	Name string `json:"name" validate:"nonzero,max=21,regexp=^[\\w-]+$" gorm:"not null;unique_index"`

	ProviderID string `json:"provider_id" sg:"readonly"`

	// the ELB address
	Address string `json:"address,omitempty" sg:"readonly"`
}

func (*Entrypoint) BeforeCreate

func (m *Entrypoint) BeforeCreate() error

type EnvVar

type EnvVar struct {
	Name  string `json:"name" validate:"nonzero"`
	Value string `json:"value" validate:"nonzero"` // this may be templated, "something_{{ instance_id }}"
}

type Error

type Error struct {
	Status  int    `json:"status"`
	Message string `json:"message"`
}

func (*Error) Error

func (e *Error) Error() string

type IndexedModelField

type IndexedModelField struct {
	JSONName string
	Kind     reflect.Kind
}

func IndexedFields

func IndexedFields(m Model) (fields []*IndexedModelField)

type Instance

type Instance struct {
	BaseModel

	// belongs_to Component (we could simply get by current or target ID off of Component, but this makes it simpler for Component-based lookup)
	Component   *Component `json:"component,omitempty"`
	ComponentID *int64     `json:"component_id" gorm:"not null;index"`

	// belongs_to Release (this can be changed)
	Release   *Release `json:"release,omitempty"`
	ReleaseID *int64   `json:"release_id" gorm:"not null;index"`

	// has_many Volumes (for preloading)
	Volumes []*Volume `json:"volumes,omitempty"`

	Num int `json:"num"`

	Name string `json:"name"`

	Started bool `json:"started" gorm:"index"`

	ResourceMetrics

	Addresses     *Addresses `json:"addresses,omitempty" gorm:"-" sg:"store_as_json_in=AddressesJSON"`
	AddressesJSON []byte     `json:"-"`
}

type Kube

type Kube struct {
	BaseModel

	// belongs_to CloudAccount
	CloudAccount   *CloudAccount `json:"cloud_account,omitempty"`
	CloudAccountID *int64        `json:"cloud_account_id" gorm:"not null;index"`

	// has_many Nodes
	Nodes []*Node `json:"nodes,omitempty"`

	// has_many Apps
	Apps []*App `json:"apps,omitempty"`

	// has_many Entrypoints
	Entrypoints []*Entrypoint `json:"entrypoints,omitempty"`

	// has_many Volumes
	Volumes []*Volume `json:"volumes,omitempty"`

	Name string `json:"name" validate:"nonzero,max=12,regexp=^[a-z]([-a-z0-9]*[a-z0-9])?$" gorm:"not null;unique_index"`

	MasterNodeSize string `json:"master_node_size" validate:"nonzero"`

	NodeSizes     []string `json:"node_sizes" gorm:"-" validate:"min=1" sg:"store_as_json_in=NodeSizesJSON"`
	NodeSizesJSON []byte   `json:"-" gorm:"not null"`

	Username string `json:"username" validate:"nonzero"`
	Password string `json:"password" validate:"nonzero"`

	// NOTE due to how we marshal this as JSON, it's difficult to have this stored
	// as an interface, because unmarshalling causes us to lose the underlying
	// type. So, this is kindof like a whacky form of single-table inheritance.
	AWSConfig     *AWSKubeConfig `json:"aws_config,omitempty" gorm:"-" sg:"store_as_json_in=AWSConfigJSON"`
	AWSConfigJSON []byte         `json:"-"`

	MasterPublicIP string `json:"master_public_ip" sg:"readonly"`

	Ready bool `json:"ready" sg:"readonly" gorm:"index"`
}

type Model

type Model interface {
	GetID() interface{}
	GetUUID() string
	SetUUID()
	SetActionStatus(*ActionStatus)
}

type Mount

type Mount struct {
	Volume string `json:"volume" validate:"nonzero"` // TODO should be VolumeName
	Path   string `json:"path" validate:"nonzero"`
}

type Node

type Node struct {
	BaseModel

	// belongs_to Kube
	Kube   *Kube  `json:"kube,omitempty"`
	KubeID *int64 `json:"kube_id" gorm:"not null;index"`

	// This is the only input for Node
	Size string `json:"size" validate:"nonzero"`

	ProviderID                string    `json:"provider_id" sg:"readonly" gorm:"index"`
	Name                      string    `json:"name" sg:"readonly" gorm:"index"`
	ExternalIP                string    `json:"external_ip" sg:"readonly"`
	ProviderCreationTimestamp time.Time `json:"provider_creation_timestamp" sg:"readonly"`

	OutOfDisk bool `json:"out_of_disk" sg:"readonly"`
	Ready     bool `json:"ready" sg:"readonly"`

	ResourceMetrics
}

type Port

type Port struct {
	// TODO Kube only accepts TCP|UDP for protocol values, but we accept values
	// like HTTP, which are used to display component addresses. We should either
	// build a map defining the accepted application protocols on top of TCP|UDP,
	// or make a sep. field.
	Protocol string `json:"protocol" validate:"nonzero" sg:"default=TCP"`

	// Number is the port number used by the container. If your application runs
	// on port 80, for example, use that.
	Number int `json:"number" validate:"nonzero,max=40000"`

	// Public determines whether the port can be accessed ONLY from other
	// Components within Supergiant (false), or from BOTH inside and outside of
	// Supergiant (true). When true, the port can be accessed from external Node
	// IPs. When true, and with an EntrypointDomain provided, the port will be
	// exposed on an external load balancer.
	Public bool `json:"public"`

	// PerInstance, when true, provides each Instance of a Component with its own
	// addressable endpoint (in addition to the normal Component-wide endpoints).
	// When false, Instances can not be reached directly, as traffic to the port
	// is load balanced randomly across all Instances.
	PerInstance bool `json:"per_instance"`

	// EntrypointDomain specifies which Entrypoint this Port is added to. Does not
	// apply when Public is false.
	EntrypointID *int64 `json:"entrypoint_id,omitempty"`

	// ExternalNumber instructs the Entrypoint to set the actual Port number
	// specified as the external load balancer port.
	//
	// TODO validation needed just like on Number, but it can't be nonzero since
	// the value provided can be 0.
	//
	// NOTE Does not apply when EntrypointDomain is nil.
	//      Does not apply to PerInstance ports.
	ExternalNumber int `json:"external_number"`
}

type PortAddress

type PortAddress struct {
	Port    string `json:"port"` // TODO really this should be the name of the port, which currently is the string of the number
	Address string `json:"address"`
}

type PrivateImageKey

type PrivateImageKey struct {
	BaseModel

	// SSL  bool   `json:"ssl"`
	Host string `json:"host" validate:"nonzero,regexp=^[^/]+$"`

	Username string `json:"username" validate:"nonzero" gorm:"not null;index"` // Not unique, because maybe multiple registries

	// NOTE these are not stored in database
	Email    string `json:"email" validate:"nonzero" sg:"private" gorm:"-"`
	Password string `json:"password" validate:"nonzero" sg:"private" gorm:"-"`

	// Used for K8S Secret
	Key string `json:"key" validate:"nonzero" sg:"private,readonly"`
}

func (*PrivateImageKey) MakeKey

func (m *PrivateImageKey) MakeKey()

func (*PrivateImageKey) RegistryURL

func (m *PrivateImageKey) RegistryURL() string

type Release

type Release struct {
	BaseModel

	// belongs_to Component
	Component   *Component `json:"component,omitempty"`
	ComponentID *int64     `json:"component_id" gorm:"not null;index"`

	// TODO
	// InstanceGroup is used as a labeling mechanism for instances. If nil,
	// InstanceGroup is set equal to the release's Timestamp. If a value is
	// supplied by the user, it MUST be the current (previous) Release's
	// Timestamp.
	//
	// The purpose of InstanceGroup is to prevent restarting between Releases.
	// I'm pretty sure the ONLY scenario in which this value makes sense is when
	// changing InstanceCount, and the value supplied in such a scenario must be
	// the previous Release's timestamp.
	//
	// It seems as though we need to break deploys up into:
	//   - config changes
	//	 - adding/removing instances
	//
	// It might still makes sense to have Release as a grouping mechanism, though,
	// because it could allow for grouping metrics recorded per-Release. However,
	// you may be able to separate the operations, but have every operation create
	// a new record that records the config / instance count at that time.
	InstanceGroup *int64 `json:"instance_group,omitempty"`

	InstanceCount int `json:"instance_count" validate:"min=1" sg:"default=1"`

	// Config is stored as JSON (like an embed in Mongo)
	Config     *ComponentConfig `json:"config" gorm:"-" sg:"store_as_json_in=ConfigJSON"`
	ConfigJSON []byte           `json:"-" gorm:"not null"`

	InUse bool `json:"in_use" sg:"readonly"`
}

NOTE the word Blueprint is used for Volumes and Containers, since they are both "definitions" that create "instances" of the real thing

type ResourceMetrics

type ResourceMetrics struct {
	CPUUsage int64 `json:"cpu_usage" sg:"readonly"`
	CPULimit int64 `json:"cpu_limit" sg:"readonly"`
	RAMUsage int64 `json:"ram_usage" sg:"readonly"`
	RAMLimit int64 `json:"ram_limit" sg:"readonly"`
}

NOTE this is not to be confused with our concept of Resources like Apps and Components -- this is for CPU / RAM / disk.

type Session

type Session struct {
	ID        string    `json:"id"`
	UserID    *int64    `json:"user_id"`
	CreatedAt time.Time `json:"created_at"`

	User *User `json:"user"`
}

func (*Session) Description

func (m *Session) Description() string

func (*Session) GetID

func (m *Session) GetID() interface{}

func (*Session) GetUUID

func (m *Session) GetUUID() string

func (*Session) SetActionStatus

func (m *Session) SetActionStatus(status *ActionStatus)

func (*Session) SetUUID

func (m *Session) SetUUID()

type TaggedModelField

type TaggedModelField struct {
	Field         reflect.Value
	Readonly      bool
	Private       bool
	Default       interface{}
	StoreAsJsonIn *reflect.Value
	ForeignKeyOf  *BelongsToField
}

func TaggedModelFieldsOf

func TaggedModelFieldsOf(r Model) (taggedFields []*TaggedModelField)

type User

type User struct {
	BaseModel

	Username string `json:"username" validate:"nonzero,max=24,regexp=^[A-Za-z0-9_-]+$" gorm:"not null;unique_index"`
	Password string `json:"password,omitempty" validate:"nonzero,min=8,max=32" gorm:"-" sg:"private"`
	Role     string `json:"role" validate:"nonzero" gorm:"not null" sg:"default=user"`

	EncryptedPassword []byte `json:"-" gorm:"not null"`

	APIToken string `json:"api_token" gorm:"not null;index" sg:"readonly"`
}

func (*User) BeforeCreate

func (m *User) BeforeCreate() error

func (*User) BeforeSave

func (m *User) BeforeSave() error

func (*User) GenerateAPIToken

func (m *User) GenerateAPIToken()

type Volume

type Volume struct {
	BaseModel

	// belongs_to Instance
	Instance   *Instance `json:"instance"`
	InstanceID *int64    `json:"instance_id" gorm:"not null;index"`

	// belongs_to Kube
	Kube   *Kube  `json:"kube"`
	KubeID *int64 `json:"kube_id" gorm:"not null;index"`

	// NOTE these are the same as VolumeBlueprint (we may want to repeat valiations)
	Name string `json:"name"`
	Type string `json:"type"`
	Size int    `json:"size"`

	ProviderID string `json:"provider_id" sg:"readonly"`
}

type VolumeBlueprint

type VolumeBlueprint struct {
	Name string `json:"name" validate:"nonzero,regexp=^\\w[-\\w\\.]*$/"` // TODO max length
	Type string `json:"type" validate:"regexp=^(gp2)$" sg:"default=gp2"` // TODO support other vol types
	Size int    `json:"size" validate:"min=1"`
}

Jump to

Keyboard shortcuts

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