github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/caas/kubernetes/provider/provider.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  	"net/url"
     8  
     9  	jujuclock "github.com/juju/clock"
    10  	"github.com/juju/errors"
    11  	"github.com/juju/jsonschema"
    12  	apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
    13  	"k8s.io/client-go/kubernetes"
    14  	"k8s.io/client-go/rest"
    15  
    16  	"github.com/juju/juju/caas"
    17  	"github.com/juju/juju/cloud"
    18  	"github.com/juju/juju/environs"
    19  	"github.com/juju/juju/environs/config"
    20  	"github.com/juju/juju/environs/context"
    21  )
    22  
    23  type kubernetesEnvironProvider struct {
    24  	environProviderCredentials
    25  }
    26  
    27  var _ environs.EnvironProvider = (*kubernetesEnvironProvider)(nil)
    28  var providerInstance = kubernetesEnvironProvider{}
    29  
    30  // Version is part of the EnvironProvider interface.
    31  func (kubernetesEnvironProvider) Version() int {
    32  	return 0
    33  }
    34  
    35  func newK8sClient(c *rest.Config) (kubernetes.Interface, apiextensionsclientset.Interface, error) {
    36  	k8sClient, err := kubernetes.NewForConfig(c)
    37  	if err != nil {
    38  		return nil, nil, err
    39  	}
    40  	var apiextensionsclient *apiextensionsclientset.Clientset
    41  	apiextensionsclient, err = apiextensionsclientset.NewForConfig(c)
    42  	if err != nil {
    43  		return nil, nil, err
    44  	}
    45  	return k8sClient, apiextensionsclient, nil
    46  }
    47  
    48  func cloudSpecToK8sRestConfig(cloudSpec environs.CloudSpec) (*rest.Config, error) {
    49  	if cloudSpec.Credential == nil {
    50  		return nil, errors.Errorf("cloud %v has no credential", cloudSpec.Name)
    51  	}
    52  
    53  	var CAData []byte
    54  	for _, cacert := range cloudSpec.CACertificates {
    55  		CAData = append(CAData, cacert...)
    56  	}
    57  
    58  	credentialAttrs := cloudSpec.Credential.Attributes()
    59  	return &rest.Config{
    60  		Host:        cloudSpec.Endpoint,
    61  		Username:    credentialAttrs[CredAttrUsername],
    62  		Password:    credentialAttrs[CredAttrPassword],
    63  		BearerToken: credentialAttrs[CredAttrToken],
    64  		TLSClientConfig: rest.TLSClientConfig{
    65  			CertData: []byte(credentialAttrs[CredAttrClientCertificateData]),
    66  			KeyData:  []byte(credentialAttrs[CredAttrClientKeyData]),
    67  			CAData:   CAData,
    68  		},
    69  	}, nil
    70  }
    71  
    72  // Open is part of the ContainerEnvironProvider interface.
    73  func (p kubernetesEnvironProvider) Open(args environs.OpenParams) (caas.Broker, error) {
    74  	logger.Debugf("opening model %q.", args.Config.Name())
    75  	if err := p.validateCloudSpec(args.Cloud); err != nil {
    76  		return nil, errors.Annotate(err, "validating cloud spec")
    77  	}
    78  	k8sRestConfig, err := cloudSpecToK8sRestConfig(args.Cloud)
    79  	if err != nil {
    80  		return nil, errors.Trace(err)
    81  	}
    82  	broker, err := NewK8sBroker(k8sRestConfig, args.Config, newK8sClient, newKubernetesWatcher, jujuclock.WallClock)
    83  	if err != nil {
    84  		return nil, err
    85  	}
    86  	return broker, nil
    87  }
    88  
    89  // ParsePodSpec is part of the ContainerEnvironProvider interface.
    90  func (kubernetesEnvironProvider) ParsePodSpec(in string) (*caas.PodSpec, error) {
    91  	spec, err := parseK8sPodSpec(in)
    92  	if err != nil {
    93  		return nil, errors.Trace(err)
    94  	}
    95  	return spec, spec.Validate()
    96  }
    97  
    98  // CloudSchema returns the schema for adding new clouds of this type.
    99  func (p kubernetesEnvironProvider) CloudSchema() *jsonschema.Schema {
   100  	return nil
   101  }
   102  
   103  // Ping tests the connection to the cloud, to verify the endpoint is valid.
   104  func (p kubernetesEnvironProvider) Ping(ctx context.ProviderCallContext, endpoint string) error {
   105  	return errors.NotImplementedf("Ping")
   106  }
   107  
   108  // PrepareConfig is specified in the EnvironProvider interface.
   109  func (p kubernetesEnvironProvider) PrepareConfig(args environs.PrepareConfigParams) (*config.Config, error) {
   110  	if err := p.validateCloudSpec(args.Cloud); err != nil {
   111  		return nil, errors.Annotate(err, "validating cloud spec")
   112  	}
   113  	// Set the default storage sources.
   114  	attrs := make(map[string]interface{})
   115  	if _, ok := args.Config.StorageDefaultBlockSource(); !ok {
   116  		attrs[config.StorageDefaultBlockSourceKey] = K8s_ProviderType
   117  	}
   118  	if _, ok := args.Config.StorageDefaultFilesystemSource(); !ok {
   119  		attrs[config.StorageDefaultFilesystemSourceKey] = K8s_ProviderType
   120  	}
   121  	return args.Config.Apply(attrs)
   122  }
   123  
   124  // DetectRegions is specified in the environs.CloudRegionDetector interface.
   125  func (p kubernetesEnvironProvider) DetectRegions() ([]cloud.Region, error) {
   126  	return nil, errors.NotFoundf("regions")
   127  }
   128  
   129  func (p kubernetesEnvironProvider) Validate(cfg, old *config.Config) (*config.Config, error) {
   130  	if err := config.Validate(cfg, old); err != nil {
   131  		return nil, err
   132  	}
   133  	return cfg, nil
   134  }
   135  
   136  func (p kubernetesEnvironProvider) newConfig(cfg *config.Config) (*config.Config, error) {
   137  	valid, err := p.Validate(cfg, nil)
   138  	if err != nil {
   139  		return nil, err
   140  	}
   141  	return valid, nil
   142  }
   143  
   144  func (p kubernetesEnvironProvider) validateCloudSpec(spec environs.CloudSpec) error {
   145  
   146  	if err := spec.Validate(); err != nil {
   147  		return errors.Trace(err)
   148  	}
   149  	if _, err := url.Parse(spec.Endpoint); err != nil {
   150  		return errors.NotValidf("endpoint %q", spec.Endpoint)
   151  	}
   152  	if spec.Credential == nil {
   153  		return errors.NotValidf("missing credential")
   154  	}
   155  	if authType := spec.Credential.AuthType(); !p.supportedAuthTypes().Contains(authType) {
   156  		return errors.NotSupportedf("%q auth-type", authType)
   157  	}
   158  	return nil
   159  }