github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/caas/kubernetes/provider/k8stypes.go (about)

     1  // Copyright 2018 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package provider
     5  
     6  import (
     7  	"fmt"
     8  	"strings"
     9  
    10  	"github.com/juju/collections/set"
    11  	"github.com/juju/errors"
    12  	"gopkg.in/yaml.v2"
    13  	core "k8s.io/api/core/v1"
    14  	k8syaml "k8s.io/apimachinery/pkg/util/yaml"
    15  
    16  	"github.com/juju/juju/caas"
    17  )
    18  
    19  type caasContainerSpec caas.ContainerSpec
    20  
    21  type k8sContainer struct {
    22  	caasContainerSpec `json:",inline"`
    23  	*K8sContainerSpec `json:",inline"`
    24  }
    25  
    26  type k8sContainers struct {
    27  	Containers []k8sContainer `json:"containers"`
    28  }
    29  
    30  // K8sContainerSpec is a subset of v1.Container which defines
    31  // attributes we expose for charms to set.
    32  type K8sContainerSpec struct {
    33  	LivenessProbe   *core.Probe     `json:"livenessProbe,omitempty"`
    34  	ReadinessProbe  *core.Probe     `json:"readinessProbe,omitempty"`
    35  	ImagePullPolicy core.PullPolicy `json:"imagePullPolicy,omitempty"`
    36  }
    37  
    38  // Validate is defined on ProviderContainer.
    39  func (*K8sContainerSpec) Validate() error {
    40  	return nil
    41  }
    42  
    43  type caasPodSpec caas.PodSpec
    44  
    45  type k8sPod struct {
    46  	caasPodSpec `json:",inline"`
    47  	*K8sPodSpec `json:",inline"`
    48  }
    49  
    50  // K8sPodSpec is a subset of v1.PodSpec which defines
    51  // attributes we expose for charms to set.
    52  type K8sPodSpec struct {
    53  	ServiceAccountName            string                   `json:"serviceAccountName,omitempty"`
    54  	RestartPolicy                 core.RestartPolicy       `json:"restartPolicy,omitempty"`
    55  	TerminationGracePeriodSeconds *int64                   `json:"terminationGracePeriodSeconds,omitempty"`
    56  	ActiveDeadlineSeconds         *int64                   `json:"activeDeadlineSeconds,omitempty"`
    57  	DNSPolicy                     core.DNSPolicy           `json:"dnsPolicy,omitempty"`
    58  	AutomountServiceAccountToken  *bool                    `json:"automountServiceAccountToken,omitempty"`
    59  	SecurityContext               *core.PodSecurityContext `json:"securityContext,omitempty"`
    60  	Hostname                      string                   `json:"hostname,omitempty"`
    61  	Subdomain                     string                   `json:"subdomain,omitempty"`
    62  	PriorityClassName             string                   `json:"priorityClassName,omitempty"`
    63  	Priority                      *int32                   `json:"priority,omitempty"`
    64  	DNSConfig                     *core.PodDNSConfig       `json:"dnsConfig,omitempty"`
    65  	ReadinessGates                []core.PodReadinessGate  `json:"readinessGates,omitempty"`
    66  }
    67  
    68  // Validate is defined on ProviderPod.
    69  func (*K8sPodSpec) Validate() error {
    70  	return nil
    71  }
    72  
    73  var boolValues = set.NewStrings(
    74  	strings.Split("y|Y|yes|Yes|YES|n|N|no|No|NO|true|True|TRUE|false|False|FALSE|on|On|ON|off|Off|OFF", "|")...)
    75  
    76  // parseK8sPodSpec parses a YAML file which defines how to
    77  // configure a CAAS pod. We allow for generic container
    78  // set up plus k8s select specific features.
    79  func parseK8sPodSpec(in string) (*caas.PodSpec, error) {
    80  	// Do the common fields.
    81  	var spec caas.PodSpec
    82  	if err := yaml.Unmarshal([]byte(in), &spec); err != nil {
    83  		return nil, errors.Trace(err)
    84  	}
    85  
    86  	// Do the k8s pod attributes.
    87  	var pod k8sPod
    88  	decoder := k8syaml.NewYAMLOrJSONDecoder(strings.NewReader(in), len(in))
    89  	if err := decoder.Decode(&pod); err != nil {
    90  		return nil, errors.Trace(err)
    91  	}
    92  	if pod.K8sPodSpec != nil {
    93  		spec.ProviderPod = pod.K8sPodSpec
    94  	}
    95  
    96  	// Do the k8s containers.
    97  	var containers k8sContainers
    98  	decoder = k8syaml.NewYAMLOrJSONDecoder(strings.NewReader(in), len(in))
    99  	if err := decoder.Decode(&containers); err != nil {
   100  		return nil, errors.Trace(err)
   101  	}
   102  
   103  	if len(containers.Containers) == 0 {
   104  		return nil, errors.New("require at least one container spec")
   105  	}
   106  
   107  	// Any string config values that could be interpreted as bools need to be quoted.
   108  	for _, container := range containers.Containers {
   109  		for k, v := range container.Config {
   110  			strValue, ok := v.(string)
   111  			if !ok {
   112  				continue
   113  			}
   114  			if boolValues.Contains(strValue) {
   115  				container.Config[k] = fmt.Sprintf("'%s'", strValue)
   116  			}
   117  		}
   118  	}
   119  
   120  	// Compose the result.
   121  	spec.Containers = make([]caas.ContainerSpec, len(containers.Containers))
   122  	for i, c := range containers.Containers {
   123  		if err := c.Validate(); err != nil {
   124  			return nil, errors.Trace(err)
   125  		}
   126  		spec.Containers[i] = caas.ContainerSpec{
   127  			ImageDetails: c.ImageDetails,
   128  			Name:         c.Name,
   129  			Image:        c.Image,
   130  			Ports:        c.Ports,
   131  			Command:      c.Command,
   132  			Args:         c.Args,
   133  			WorkingDir:   c.WorkingDir,
   134  			Config:       c.Config,
   135  			Files:        c.Files,
   136  		}
   137  		if c.K8sContainerSpec != nil {
   138  			spec.Containers[i].ProviderContainer = c.K8sContainerSpec
   139  		}
   140  	}
   141  	return &spec, nil
   142  }