terraform/builtin/providers/kubernetes/provider.go

201 lines
6.4 KiB
Go

package kubernetes
import (
"bytes"
"fmt"
"log"
"os"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/terraform"
"github.com/mitchellh/go-homedir"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
kubernetes "k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
)
func Provider() terraform.ResourceProvider {
return &schema.Provider{
Schema: map[string]*schema.Schema{
"host": {
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("KUBE_HOST", ""),
Description: "The hostname (in form of URI) of Kubernetes master.",
},
"username": {
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("KUBE_USER", ""),
Description: "The username to use for HTTP basic authentication when accessing the Kubernetes master endpoint.",
},
"password": {
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("KUBE_PASSWORD", ""),
Description: "The password to use for HTTP basic authentication when accessing the Kubernetes master endpoint.",
},
"insecure": {
Type: schema.TypeBool,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("KUBE_INSECURE", false),
Description: "Whether server should be accessed without verifying the TLS certificate.",
},
"client_certificate": {
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("KUBE_CLIENT_CERT_DATA", ""),
Description: "PEM-encoded client certificate for TLS authentication.",
},
"client_key": {
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("KUBE_CLIENT_KEY_DATA", ""),
Description: "PEM-encoded client certificate key for TLS authentication.",
},
"cluster_ca_certificate": {
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("KUBE_CLUSTER_CA_CERT_DATA", ""),
Description: "PEM-encoded root certificates bundle for TLS authentication.",
},
"config_path": {
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.MultiEnvDefaultFunc(
[]string{
"KUBE_CONFIG",
"KUBECONFIG",
},
"~/.kube/config"),
Description: "Path to the kube config file, defaults to ~/.kube/config",
},
"config_context": {
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("KUBE_CTX", ""),
},
"config_context_auth_info": {
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("KUBE_CTX_AUTH_INFO", ""),
Description: "",
},
"config_context_cluster": {
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("KUBE_CTX_CLUSTER", ""),
Description: "",
},
},
ResourcesMap: map[string]*schema.Resource{
"kubernetes_config_map": resourceKubernetesConfigMap(),
"kubernetes_horizontal_pod_autoscaler": resourceKubernetesHorizontalPodAutoscaler(),
"kubernetes_limit_range": resourceKubernetesLimitRange(),
"kubernetes_namespace": resourceKubernetesNamespace(),
"kubernetes_persistent_volume": resourceKubernetesPersistentVolume(),
"kubernetes_persistent_volume_claim": resourceKubernetesPersistentVolumeClaim(),
"kubernetes_pod": resourceKubernetesPod(),
"kubernetes_resource_quota": resourceKubernetesResourceQuota(),
"kubernetes_secret": resourceKubernetesSecret(),
"kubernetes_service": resourceKubernetesService(),
},
ConfigureFunc: providerConfigure,
}
}
func providerConfigure(d *schema.ResourceData) (interface{}, error) {
// Config file loading
cfg, err := tryLoadingConfigFile(d)
if err != nil {
return nil, err
}
if cfg == nil {
cfg = &restclient.Config{}
}
// Overriding with static configuration
cfg.UserAgent = fmt.Sprintf("HashiCorp/1.0 Terraform/%s", terraform.VersionString())
if v, ok := d.GetOk("host"); ok {
cfg.Host = v.(string)
}
if v, ok := d.GetOk("username"); ok {
cfg.Username = v.(string)
}
if v, ok := d.GetOk("password"); ok {
cfg.Password = v.(string)
}
if v, ok := d.GetOk("insecure"); ok {
cfg.Insecure = v.(bool)
}
if v, ok := d.GetOk("cluster_ca_certificate"); ok {
cfg.CAData = bytes.NewBufferString(v.(string)).Bytes()
}
if v, ok := d.GetOk("client_certificate"); ok {
cfg.CertData = bytes.NewBufferString(v.(string)).Bytes()
}
if v, ok := d.GetOk("client_key"); ok {
cfg.KeyData = bytes.NewBufferString(v.(string)).Bytes()
}
k, err := kubernetes.NewForConfig(cfg)
if err != nil {
return nil, fmt.Errorf("Failed to configure: %s", err)
}
return k, nil
}
func tryLoadingConfigFile(d *schema.ResourceData) (*restclient.Config, error) {
path, err := homedir.Expand(d.Get("config_path").(string))
if err != nil {
return nil, err
}
loader := &clientcmd.ClientConfigLoadingRules{
ExplicitPath: path,
}
overrides := &clientcmd.ConfigOverrides{}
ctxSuffix := "; default context"
ctx, ctxOk := d.GetOk("config_context")
authInfo, authInfoOk := d.GetOk("config_context_auth_info")
cluster, clusterOk := d.GetOk("config_context_cluster")
if ctxOk || authInfoOk || clusterOk {
ctxSuffix = "; overriden context"
if ctxOk {
overrides.CurrentContext = ctx.(string)
ctxSuffix += fmt.Sprintf("; config ctx: %s", overrides.CurrentContext)
log.Printf("[DEBUG] Using custom current context: %q", overrides.CurrentContext)
}
overrides.Context = clientcmdapi.Context{}
if authInfoOk {
overrides.Context.AuthInfo = authInfo.(string)
ctxSuffix += fmt.Sprintf("; auth_info: %s", overrides.Context.AuthInfo)
}
if clusterOk {
overrides.Context.Cluster = cluster.(string)
ctxSuffix += fmt.Sprintf("; cluster: %s", overrides.Context.Cluster)
}
log.Printf("[DEBUG] Using overidden context: %#v", overrides.Context)
}
cc := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loader, overrides)
cfg, err := cc.ClientConfig()
if err != nil {
if pathErr, ok := err.(*os.PathError); ok && os.IsNotExist(pathErr.Err) {
log.Printf("[INFO] Unable to load config file as it doesn't exist at %q", path)
return nil, nil
}
return nil, fmt.Errorf("Failed to load config (%s%s): %s", path, ctxSuffix, err)
}
log.Printf("[INFO] Successfully loaded config file (%s%s)", path, ctxSuffix)
return cfg, nil
}