2016-12-28 02:54:55 +00:00
|
|
|
package services
|
|
|
|
|
|
|
|
import (
|
2016-12-28 22:07:03 +00:00
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"sort"
|
|
|
|
"strings"
|
2016-12-28 02:54:55 +00:00
|
|
|
"time"
|
2016-12-28 22:07:03 +00:00
|
|
|
|
|
|
|
"github.com/gravitational/teleport/lib/utils"
|
2017-04-07 23:51:31 +00:00
|
|
|
|
2016-12-28 22:07:03 +00:00
|
|
|
"github.com/gravitational/trace"
|
2017-04-07 23:51:31 +00:00
|
|
|
"github.com/jonboulle/clockwork"
|
2016-12-28 02:54:55 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Server represents a Node, Proxy or Auth server in a Teleport cluster
|
|
|
|
type Server interface {
|
2017-04-07 23:51:31 +00:00
|
|
|
// Resource provides common resource headers
|
|
|
|
Resource
|
2016-12-28 02:54:55 +00:00
|
|
|
// GetAddr return server address
|
|
|
|
GetAddr() string
|
|
|
|
// GetHostname returns server hostname
|
|
|
|
GetHostname() string
|
|
|
|
// GetNamespace returns server namespace
|
|
|
|
GetNamespace() string
|
|
|
|
// GetAllLabels returns server's static and dynamic label values merged together
|
|
|
|
GetAllLabels() map[string]string
|
|
|
|
// GetLabels returns server's static label key pairs
|
|
|
|
GetLabels() map[string]string
|
|
|
|
// GetCmdLabels returns command labels
|
|
|
|
GetCmdLabels() map[string]CommandLabel
|
2017-03-17 01:22:27 +00:00
|
|
|
// GetPublicAddr is an optional field that returns the public address this cluster can be reached at.
|
|
|
|
GetPublicAddr() string
|
2016-12-28 02:54:55 +00:00
|
|
|
// String returns string representation of the server
|
|
|
|
String() string
|
2016-12-29 19:36:57 +00:00
|
|
|
// SetAddr sets server address
|
|
|
|
SetAddr(addr string)
|
2017-03-17 01:22:27 +00:00
|
|
|
// SetPublicAddr sets the public address this cluster can be reached at.
|
|
|
|
SetPublicAddr(string)
|
2016-12-29 19:36:57 +00:00
|
|
|
// SetNamespace sets server namespace
|
|
|
|
SetNamespace(namespace string)
|
2016-12-30 21:25:35 +00:00
|
|
|
// V1 returns V1 version for backwards compatibility
|
|
|
|
V1() *ServerV1
|
2016-12-30 22:47:52 +00:00
|
|
|
// MatchAgainst takes a map of labels and returns True if this server
|
|
|
|
// has ALL of them
|
|
|
|
//
|
|
|
|
// Any server matches against an empty label set
|
|
|
|
MatchAgainst(labels map[string]string) bool
|
2016-12-30 23:13:45 +00:00
|
|
|
// LabelsString returns a comma separated string with all node's labels
|
|
|
|
LabelsString() string
|
2016-12-30 21:25:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ServersToV1 converts list of servers to slice of V1 style ones
|
|
|
|
func ServersToV1(in []Server) []ServerV1 {
|
|
|
|
out := make([]ServerV1, len(in))
|
|
|
|
for i := range in {
|
|
|
|
out[i] = *(in[i].V1())
|
|
|
|
}
|
|
|
|
return out
|
2016-12-28 02:54:55 +00:00
|
|
|
}
|
|
|
|
|
2016-12-29 20:23:58 +00:00
|
|
|
// ServerV2 is version1 resource spec of the server
|
|
|
|
type ServerV2 struct {
|
2016-12-28 02:54:55 +00:00
|
|
|
// Kind is a resource kind
|
|
|
|
Kind string `json:"kind"`
|
|
|
|
// Version is version
|
|
|
|
Version string `json:"version"`
|
|
|
|
// Metadata is User metadata
|
|
|
|
Metadata Metadata `json:"metadata"`
|
|
|
|
// Spec contains user specification
|
2016-12-29 20:23:58 +00:00
|
|
|
Spec ServerSpecV2 `json:"spec"`
|
2016-12-28 02:54:55 +00:00
|
|
|
}
|
|
|
|
|
2017-04-07 23:51:31 +00:00
|
|
|
// GetMetadata returns metadata
|
|
|
|
func (s *ServerV2) GetMetadata() Metadata {
|
|
|
|
return s.Metadata
|
|
|
|
}
|
|
|
|
|
2016-12-29 23:16:42 +00:00
|
|
|
// V2 returns version 2 of the resource, itself
|
|
|
|
func (s *ServerV2) V2() *ServerV2 {
|
|
|
|
return s
|
|
|
|
}
|
|
|
|
|
|
|
|
// V1 returns V1 version of the resource
|
|
|
|
func (s *ServerV2) V1() *ServerV1 {
|
|
|
|
labels := make(map[string]CommandLabelV1, len(s.Spec.CmdLabels))
|
|
|
|
for key := range s.Spec.CmdLabels {
|
|
|
|
val := s.Spec.CmdLabels[key]
|
|
|
|
labels[key] = CommandLabelV1{
|
|
|
|
Period: val.Period.Duration,
|
|
|
|
Result: val.Result,
|
|
|
|
Command: val.Command,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return &ServerV1{
|
|
|
|
ID: s.Metadata.Name,
|
|
|
|
Kind: s.Kind,
|
|
|
|
Namespace: ProcessNamespace(s.Metadata.Namespace),
|
|
|
|
Addr: s.Spec.Addr,
|
|
|
|
Hostname: s.Spec.Hostname,
|
2016-12-29 23:33:23 +00:00
|
|
|
Labels: s.Metadata.Labels,
|
2016-12-29 23:16:42 +00:00
|
|
|
CmdLabels: labels,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-29 19:36:57 +00:00
|
|
|
// SetNamespace sets server namespace
|
2016-12-29 20:23:58 +00:00
|
|
|
func (s *ServerV2) SetNamespace(namespace string) {
|
2016-12-29 19:36:57 +00:00
|
|
|
s.Metadata.Namespace = namespace
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetAddr sets server address
|
2016-12-29 20:23:58 +00:00
|
|
|
func (s *ServerV2) SetAddr(addr string) {
|
2016-12-29 19:36:57 +00:00
|
|
|
s.Spec.Addr = addr
|
|
|
|
}
|
|
|
|
|
2017-04-07 23:51:31 +00:00
|
|
|
// SetExpiry sets expiry time for the object
|
|
|
|
func (s *ServerV2) SetExpiry(expires time.Time) {
|
|
|
|
s.Metadata.SetExpiry(expires)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Expires retuns object expiry setting
|
|
|
|
func (s *ServerV2) Expiry() time.Time {
|
|
|
|
return s.Metadata.Expiry()
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetTTL sets Expires header using realtime clock
|
|
|
|
func (s *ServerV2) SetTTL(clock clockwork.Clock, ttl time.Duration) {
|
|
|
|
s.Metadata.SetTTL(clock, ttl)
|
|
|
|
}
|
|
|
|
|
2017-03-17 01:22:27 +00:00
|
|
|
// SetPublicAddr sets the public address this cluster can be reached at.
|
|
|
|
func (s *ServerV2) SetPublicAddr(addr string) {
|
|
|
|
s.Spec.PublicAddr = addr
|
|
|
|
}
|
|
|
|
|
2016-12-28 02:54:55 +00:00
|
|
|
// GetName returns server name
|
2016-12-29 20:23:58 +00:00
|
|
|
func (s *ServerV2) GetName() string {
|
2016-12-28 02:54:55 +00:00
|
|
|
return s.Metadata.Name
|
|
|
|
}
|
|
|
|
|
2017-04-07 23:51:31 +00:00
|
|
|
// SetName sets the name of the TrustedCluster.
|
|
|
|
func (s *ServerV2) SetName(e string) {
|
|
|
|
s.Metadata.Name = e
|
|
|
|
}
|
|
|
|
|
2016-12-28 02:54:55 +00:00
|
|
|
// GetAddr return server address
|
2016-12-29 20:23:58 +00:00
|
|
|
func (s *ServerV2) GetAddr() string {
|
2016-12-28 02:54:55 +00:00
|
|
|
return s.Spec.Addr
|
|
|
|
}
|
|
|
|
|
2017-03-17 01:22:27 +00:00
|
|
|
// GetPublicAddr is an optional field that returns the public address this cluster can be reached at.
|
|
|
|
func (s *ServerV2) GetPublicAddr() string {
|
|
|
|
return s.Spec.PublicAddr
|
|
|
|
}
|
|
|
|
|
2016-12-28 02:54:55 +00:00
|
|
|
// GetHostname returns server hostname
|
2016-12-29 20:23:58 +00:00
|
|
|
func (s *ServerV2) GetHostname() string {
|
2016-12-28 02:54:55 +00:00
|
|
|
return s.Spec.Hostname
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetLabels returns server's static label key pairs
|
2016-12-29 20:23:58 +00:00
|
|
|
func (s *ServerV2) GetLabels() map[string]string {
|
2016-12-28 22:07:03 +00:00
|
|
|
return s.Metadata.Labels
|
2016-12-28 02:54:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetCmdLabels returns command labels
|
2016-12-29 20:23:58 +00:00
|
|
|
func (s *ServerV2) GetCmdLabels() map[string]CommandLabel {
|
2016-12-28 02:54:55 +00:00
|
|
|
if s.Spec.CmdLabels == nil {
|
|
|
|
return nil
|
|
|
|
}
|
2016-12-28 22:07:03 +00:00
|
|
|
out := make(map[string]CommandLabel, len(s.Spec.CmdLabels))
|
2016-12-28 02:54:55 +00:00
|
|
|
for key := range s.Spec.CmdLabels {
|
|
|
|
val := s.Spec.CmdLabels[key]
|
|
|
|
out[key] = &val
|
|
|
|
}
|
|
|
|
return out
|
|
|
|
}
|
|
|
|
|
2016-12-29 20:23:58 +00:00
|
|
|
func (s *ServerV2) String() string {
|
2016-12-28 22:07:03 +00:00
|
|
|
return fmt.Sprintf("Server(name=%v, namespace=%v, addr=%v, labels=%v)", s.Metadata.Name, s.Metadata.Namespace, s.Spec.Addr, s.Metadata.Labels)
|
2016-12-28 02:54:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetNamespace returns server namespace
|
2016-12-29 20:23:58 +00:00
|
|
|
func (s *ServerV2) GetNamespace() string {
|
2016-12-28 02:54:55 +00:00
|
|
|
return ProcessNamespace(s.Metadata.Namespace)
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetAllLabels returns the full key:value map of both static labels and
|
|
|
|
// "command labels"
|
2016-12-29 20:23:58 +00:00
|
|
|
func (s *ServerV2) GetAllLabels() map[string]string {
|
2016-12-28 02:54:55 +00:00
|
|
|
lmap := make(map[string]string)
|
2016-12-28 22:07:03 +00:00
|
|
|
for key, value := range s.Metadata.Labels {
|
2016-12-28 02:54:55 +00:00
|
|
|
lmap[key] = value
|
|
|
|
}
|
2016-12-28 22:07:03 +00:00
|
|
|
for key, cmd := range s.Spec.CmdLabels {
|
2016-12-28 02:54:55 +00:00
|
|
|
lmap[key] = cmd.Result
|
|
|
|
}
|
|
|
|
return lmap
|
|
|
|
}
|
|
|
|
|
|
|
|
// MatchAgainst takes a map of labels and returns True if this server
|
|
|
|
// has ALL of them
|
|
|
|
//
|
|
|
|
// Any server matches against an empty label set
|
2016-12-29 20:23:58 +00:00
|
|
|
func (s *ServerV2) MatchAgainst(labels map[string]string) bool {
|
2016-12-28 02:54:55 +00:00
|
|
|
if labels != nil {
|
2016-12-28 22:07:03 +00:00
|
|
|
myLabels := s.GetAllLabels()
|
2016-12-28 02:54:55 +00:00
|
|
|
for key, value := range labels {
|
|
|
|
if myLabels[key] != value {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
// LabelsString returns a comma separated string with all node's labels
|
2016-12-29 20:23:58 +00:00
|
|
|
func (s *ServerV2) LabelsString() string {
|
2016-12-28 02:54:55 +00:00
|
|
|
labels := []string{}
|
2016-12-28 22:07:03 +00:00
|
|
|
for key, val := range s.Metadata.Labels {
|
2016-12-28 02:54:55 +00:00
|
|
|
labels = append(labels, fmt.Sprintf("%s=%s", key, val))
|
|
|
|
}
|
2016-12-28 22:07:03 +00:00
|
|
|
for key, val := range s.Spec.CmdLabels {
|
2016-12-28 02:54:55 +00:00
|
|
|
labels = append(labels, fmt.Sprintf("%s=%s", key, val.Result))
|
|
|
|
}
|
|
|
|
sort.Strings(labels)
|
|
|
|
return strings.Join(labels, ",")
|
|
|
|
}
|
|
|
|
|
2016-12-29 20:23:58 +00:00
|
|
|
// ServerSpecV2 is a specification for V2 Server
|
|
|
|
type ServerSpecV2 struct {
|
2016-12-28 02:54:55 +00:00
|
|
|
// Addr is server host:port address
|
|
|
|
Addr string `json:"addr"`
|
2017-03-17 01:22:27 +00:00
|
|
|
// PublicAddr is the public address this cluster can be reached at.
|
|
|
|
PublicAddr string `json:"public_addr,omitempty"`
|
2016-12-28 02:54:55 +00:00
|
|
|
// Hostname is server hostname
|
|
|
|
Hostname string `json:"hostname"`
|
|
|
|
// CmdLabels is server dynamic labels
|
2016-12-29 20:23:58 +00:00
|
|
|
CmdLabels map[string]CommandLabelV2 `json:"cmd_labels,omitempty"`
|
2016-12-28 02:54:55 +00:00
|
|
|
}
|
|
|
|
|
2016-12-29 20:23:58 +00:00
|
|
|
// ServerSpecV2Schema is JSON schema for server
|
|
|
|
const ServerSpecV2Schema = `{
|
2016-12-28 02:54:55 +00:00
|
|
|
"type": "object",
|
|
|
|
"additionalProperties": false,
|
|
|
|
"properties": {
|
|
|
|
"addr": {"type": "string"},
|
2017-03-17 01:22:27 +00:00
|
|
|
"public_addr": {"type": "string"},
|
2016-12-28 02:54:55 +00:00
|
|
|
"hostname": {"type": "string"},
|
|
|
|
"labels": {
|
2016-12-29 02:47:33 +00:00
|
|
|
"type": "object",
|
2016-12-28 02:54:55 +00:00
|
|
|
"patternProperties": {
|
|
|
|
"^.*$": { "type": "string" }
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"cmd_labels": {
|
2016-12-29 02:47:33 +00:00
|
|
|
"type": "object",
|
|
|
|
"patternProperties": {
|
|
|
|
"^.*$": {
|
|
|
|
"type": "object",
|
|
|
|
"additionalProperties": false,
|
|
|
|
"required": ["command"],
|
|
|
|
"properties": {
|
|
|
|
"command": {"type": "array", "items": {"type": "string"}},
|
|
|
|
"period": {"type": "string"},
|
|
|
|
"result": {"type": "string"}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-12-28 02:54:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}`
|
|
|
|
|
2016-12-29 23:16:42 +00:00
|
|
|
// ServerV1 represents V1 spec of the server
|
|
|
|
type ServerV1 struct {
|
2016-12-28 02:54:55 +00:00
|
|
|
Kind string `json:"kind"`
|
|
|
|
ID string `json:"id"`
|
|
|
|
Addr string `json:"addr"`
|
|
|
|
Hostname string `json:"hostname"`
|
|
|
|
Namespace string `json:"namespace"`
|
|
|
|
Labels map[string]string `json:"labels"`
|
2016-12-29 23:16:42 +00:00
|
|
|
CmdLabels map[string]CommandLabelV1 `json:"cmd_labels"`
|
2016-12-28 02:54:55 +00:00
|
|
|
}
|
|
|
|
|
2016-12-29 23:16:42 +00:00
|
|
|
// V1 returns V1 version of the resource
|
|
|
|
func (s *ServerV1) V1() *ServerV1 {
|
|
|
|
return s
|
|
|
|
}
|
|
|
|
|
|
|
|
// V2 returns V2 version of the resource
|
|
|
|
func (s *ServerV1) V2() *ServerV2 {
|
2016-12-29 20:23:58 +00:00
|
|
|
labels := make(map[string]CommandLabelV2, len(s.CmdLabels))
|
2016-12-28 02:54:55 +00:00
|
|
|
for key := range s.CmdLabels {
|
|
|
|
val := s.CmdLabels[key]
|
2016-12-29 20:23:58 +00:00
|
|
|
labels[key] = CommandLabelV2{
|
2016-12-28 02:54:55 +00:00
|
|
|
Period: Duration{Duration: val.Period},
|
|
|
|
Result: val.Result,
|
|
|
|
Command: val.Command,
|
|
|
|
}
|
|
|
|
}
|
2016-12-29 20:23:58 +00:00
|
|
|
return &ServerV2{
|
2016-12-28 02:54:55 +00:00
|
|
|
Kind: s.Kind,
|
2016-12-29 20:23:58 +00:00
|
|
|
Version: V2,
|
2016-12-28 02:54:55 +00:00
|
|
|
Metadata: Metadata{
|
|
|
|
Name: s.ID,
|
2016-12-28 23:50:32 +00:00
|
|
|
Namespace: ProcessNamespace(s.Namespace),
|
2016-12-28 22:07:03 +00:00
|
|
|
Labels: s.Labels,
|
2016-12-28 02:54:55 +00:00
|
|
|
},
|
2016-12-29 20:23:58 +00:00
|
|
|
Spec: ServerSpecV2{
|
2016-12-28 22:07:03 +00:00
|
|
|
Addr: s.Addr,
|
|
|
|
Hostname: s.Hostname,
|
|
|
|
CmdLabels: labels,
|
2016-12-28 02:54:55 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-30 20:20:48 +00:00
|
|
|
// LabelsToV2 converts labels from interface to V2 spec
|
|
|
|
func LabelsToV2(labels map[string]CommandLabel) map[string]CommandLabelV2 {
|
|
|
|
out := make(map[string]CommandLabelV2, len(labels))
|
|
|
|
for key, val := range labels {
|
|
|
|
out[key] = CommandLabelV2{
|
|
|
|
Period: NewDuration(val.GetPeriod()),
|
|
|
|
Result: val.GetResult(),
|
|
|
|
Command: val.GetCommand(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return out
|
|
|
|
}
|
|
|
|
|
2016-12-29 20:23:58 +00:00
|
|
|
// CommandLabelV2 is a label that has a value as a result of the
|
2016-12-28 02:54:55 +00:00
|
|
|
// output generated by running command, e.g. hostname
|
|
|
|
type CommandLabel interface {
|
|
|
|
// GetPeriod returns label period
|
|
|
|
GetPeriod() time.Duration
|
2016-12-30 20:20:48 +00:00
|
|
|
// SetPeriod sets label period
|
|
|
|
SetPeriod(time.Duration)
|
2016-12-28 02:54:55 +00:00
|
|
|
// GetResult returns label result
|
|
|
|
GetResult() string
|
2016-12-30 20:20:48 +00:00
|
|
|
// SetResult sets label result
|
|
|
|
SetResult(string)
|
2016-12-28 02:54:55 +00:00
|
|
|
// GetCommand returns to execute and set as a label result
|
|
|
|
GetCommand() []string
|
2016-12-31 01:07:54 +00:00
|
|
|
// Clone returns label copy
|
|
|
|
Clone() CommandLabel
|
2016-12-28 02:54:55 +00:00
|
|
|
}
|
|
|
|
|
2016-12-29 20:23:58 +00:00
|
|
|
// CommandLabelV2 is a label that has a value as a result of the
|
2016-12-28 02:54:55 +00:00
|
|
|
// output generated by running command, e.g. hostname
|
2016-12-29 20:23:58 +00:00
|
|
|
type CommandLabelV2 struct {
|
2016-12-28 02:54:55 +00:00
|
|
|
// Period is a time between command runs
|
|
|
|
Period Duration `json:"period"`
|
|
|
|
// Command is a command to run
|
|
|
|
Command []string `json:"command"` //["/usr/bin/hostname", "--long"]
|
|
|
|
// Result captures standard output
|
|
|
|
Result string `json:"result"`
|
|
|
|
}
|
|
|
|
|
2016-12-31 01:07:54 +00:00
|
|
|
// Clone returns label copy
|
|
|
|
func (c *CommandLabelV2) Clone() CommandLabel {
|
|
|
|
cp := *c
|
|
|
|
return &cp
|
|
|
|
}
|
|
|
|
|
2016-12-30 20:20:48 +00:00
|
|
|
// SetResult sets label result
|
|
|
|
func (c *CommandLabelV2) SetResult(r string) {
|
|
|
|
c.Result = r
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetPeriod sets label period
|
|
|
|
func (c *CommandLabelV2) SetPeriod(p time.Duration) {
|
|
|
|
c.Period.Duration = p
|
|
|
|
}
|
|
|
|
|
2016-12-28 02:54:55 +00:00
|
|
|
// GetPeriod returns label period
|
2016-12-29 20:23:58 +00:00
|
|
|
func (c *CommandLabelV2) GetPeriod() time.Duration {
|
2016-12-28 02:54:55 +00:00
|
|
|
return c.Period.Duration
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetResult returns label result
|
2016-12-29 20:23:58 +00:00
|
|
|
func (c *CommandLabelV2) GetResult() string {
|
2016-12-28 02:54:55 +00:00
|
|
|
return c.Result
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetCommand returns to execute and set as a label result
|
2016-12-29 20:23:58 +00:00
|
|
|
func (c *CommandLabelV2) GetCommand() []string {
|
2016-12-28 02:54:55 +00:00
|
|
|
return c.Command
|
|
|
|
}
|
|
|
|
|
2016-12-29 23:16:42 +00:00
|
|
|
// CommandLabelV1 is a label that has a value as a result of the
|
2016-12-28 02:54:55 +00:00
|
|
|
// output generated by running command, e.g. hostname
|
2016-12-29 23:16:42 +00:00
|
|
|
type CommandLabelV1 struct {
|
2016-12-28 02:54:55 +00:00
|
|
|
// Period is a time between command runs
|
|
|
|
Period time.Duration `json:"period"`
|
|
|
|
// Command is a command to run
|
|
|
|
Command []string `json:"command"` //["/usr/bin/hostname", "--long"]
|
|
|
|
// Result captures standard output
|
|
|
|
Result string `json:"result"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// CommandLabels is a set of command labels
|
|
|
|
type CommandLabels map[string]CommandLabel
|
|
|
|
|
|
|
|
// SetEnv sets the value of the label from environment variable
|
|
|
|
func (c *CommandLabels) SetEnv(v string) error {
|
|
|
|
if err := json.Unmarshal([]byte(v), c); err != nil {
|
|
|
|
return trace.Wrap(err, "can not parse Command Labels")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2016-12-28 03:54:02 +00:00
|
|
|
|
|
|
|
// GetServerSchema returns role schema with optionally injected
|
|
|
|
// schema for extensions
|
|
|
|
func GetServerSchema() string {
|
2016-12-29 20:23:58 +00:00
|
|
|
return fmt.Sprintf(V2SchemaTemplate, MetadataSchema, ServerSpecV2Schema)
|
2016-12-28 03:54:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// UnmarshalServerResource unmarshals role from JSON or YAML,
|
|
|
|
// sets defaults and checks the schema
|
|
|
|
func UnmarshalServerResource(data []byte, kind string) (Server, error) {
|
|
|
|
if len(data) == 0 {
|
|
|
|
return nil, trace.BadParameter("missing server data")
|
|
|
|
}
|
|
|
|
var h ResourceHeader
|
2016-12-28 22:07:03 +00:00
|
|
|
err := json.Unmarshal(data, &h)
|
2016-12-28 03:54:02 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, trace.Wrap(err)
|
|
|
|
}
|
|
|
|
switch h.Version {
|
|
|
|
case "":
|
2016-12-29 23:16:42 +00:00
|
|
|
var s ServerV1
|
2016-12-28 22:07:03 +00:00
|
|
|
err := json.Unmarshal(data, &s)
|
2016-12-28 03:54:02 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, trace.Wrap(err)
|
|
|
|
}
|
|
|
|
s.Kind = kind
|
2016-12-29 20:23:58 +00:00
|
|
|
return s.V2(), nil
|
|
|
|
case V2:
|
|
|
|
var s ServerV2
|
2016-12-28 22:07:03 +00:00
|
|
|
if err := utils.UnmarshalWithSchema(GetServerSchema(), &s, data); err != nil {
|
2016-12-28 03:54:02 +00:00
|
|
|
return nil, trace.BadParameter(err.Error())
|
|
|
|
}
|
2017-04-07 23:51:31 +00:00
|
|
|
utils.UTC(&s.Metadata.Expires)
|
2016-12-28 22:07:03 +00:00
|
|
|
return &s, nil
|
2016-12-28 03:54:02 +00:00
|
|
|
}
|
|
|
|
return nil, trace.BadParameter("server resource version %v is not supported", h.Version)
|
|
|
|
}
|
|
|
|
|
|
|
|
var serverMarshaler ServerMarshaler = &TeleportServerMarshaler{}
|
|
|
|
|
|
|
|
func SetServerMarshaler(m ServerMarshaler) {
|
|
|
|
marshalerMutex.Lock()
|
|
|
|
defer marshalerMutex.Unlock()
|
|
|
|
serverMarshaler = m
|
|
|
|
}
|
|
|
|
|
|
|
|
func GetServerMarshaler() ServerMarshaler {
|
|
|
|
marshalerMutex.Lock()
|
|
|
|
defer marshalerMutex.Unlock()
|
|
|
|
return serverMarshaler
|
|
|
|
}
|
|
|
|
|
|
|
|
// ServerMarshaler implements marshal/unmarshal of Role implementations
|
|
|
|
// mostly adds support for extended versions
|
|
|
|
type ServerMarshaler interface {
|
|
|
|
// UnmarshalServer from binary representation
|
|
|
|
UnmarshalServer(bytes []byte, kind string) (Server, error)
|
|
|
|
// MarshalServer to binary representation
|
2016-12-29 23:16:42 +00:00
|
|
|
MarshalServer(Server, ...MarshalOption) ([]byte, error)
|
2016-12-28 03:54:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type TeleportServerMarshaler struct{}
|
|
|
|
|
|
|
|
// UnmarshalServer unmarshals server from JSON
|
|
|
|
func (*TeleportServerMarshaler) UnmarshalServer(bytes []byte, kind string) (Server, error) {
|
|
|
|
return UnmarshalServerResource(bytes, kind)
|
|
|
|
}
|
|
|
|
|
2016-12-29 23:16:42 +00:00
|
|
|
// MarshalServer marshals server into JSON
|
|
|
|
func (*TeleportServerMarshaler) MarshalServer(s Server, opts ...MarshalOption) ([]byte, error) {
|
|
|
|
cfg, err := collectOptions(opts)
|
|
|
|
if err != nil {
|
|
|
|
return nil, trace.Wrap(err)
|
|
|
|
}
|
|
|
|
type serverv1 interface {
|
|
|
|
V1() *ServerV1
|
|
|
|
}
|
|
|
|
|
|
|
|
type serverv2 interface {
|
|
|
|
V2() *ServerV2
|
|
|
|
}
|
|
|
|
version := cfg.GetVersion()
|
|
|
|
switch version {
|
|
|
|
case V1:
|
|
|
|
v, ok := s.(serverv1)
|
|
|
|
if !ok {
|
|
|
|
return nil, trace.BadParameter("don't know how to marshal %v", V1)
|
|
|
|
}
|
|
|
|
return json.Marshal(v.V1())
|
|
|
|
case V2:
|
|
|
|
v, ok := s.(serverv2)
|
|
|
|
if !ok {
|
|
|
|
return nil, trace.BadParameter("don't know how to marshal %v", V2)
|
|
|
|
}
|
|
|
|
return json.Marshal(v.V2())
|
|
|
|
default:
|
|
|
|
return nil, trace.BadParameter("version %v is not supported", version)
|
|
|
|
}
|
2016-12-28 03:54:02 +00:00
|
|
|
}
|
2016-12-29 02:47:33 +00:00
|
|
|
|
|
|
|
// SortedServers is a sort wrapper that sorts servers by name
|
|
|
|
type SortedServers []Server
|
|
|
|
|
|
|
|
func (s SortedServers) Len() int {
|
|
|
|
return len(s)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s SortedServers) Less(i, j int) bool {
|
|
|
|
return s[i].GetName() < s[j].GetName()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s SortedServers) Swap(i, j int) {
|
|
|
|
s[i], s[j] = s[j], s[i]
|
|
|
|
}
|
|
|
|
|
|
|
|
// SortedReverseTunnels sorts reverse tunnels by cluster name
|
|
|
|
type SortedReverseTunnels []ReverseTunnel
|
|
|
|
|
|
|
|
func (s SortedReverseTunnels) Len() int {
|
|
|
|
return len(s)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s SortedReverseTunnels) Less(i, j int) bool {
|
|
|
|
return s[i].GetClusterName() < s[j].GetClusterName()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s SortedReverseTunnels) Swap(i, j int) {
|
|
|
|
s[i], s[j] = s[j], s[i]
|
|
|
|
}
|