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 }