2018-07-23 10:06:37 -07:00
|
|
|
/*
|
|
|
|
|
Copyright 2018 The Kubernetes Authors.
|
|
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
|
limitations under the License.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
package cluster
|
|
|
|
|
|
|
|
|
|
import (
|
2020-02-19 15:06:46 -08:00
|
|
|
"os/exec"
|
2019-11-05 17:59:00 -08:00
|
|
|
"sort"
|
|
|
|
|
|
2019-02-28 16:23:48 -08:00
|
|
|
"sigs.k8s.io/kind/pkg/cluster/constants"
|
2018-11-09 17:33:53 -08:00
|
|
|
"sigs.k8s.io/kind/pkg/cluster/nodes"
|
2020-04-29 01:40:24 -07:00
|
|
|
"sigs.k8s.io/kind/pkg/cluster/nodeutils"
|
2019-11-05 17:59:00 -08:00
|
|
|
"sigs.k8s.io/kind/pkg/log"
|
2019-09-16 16:10:50 -07:00
|
|
|
|
2019-12-04 22:44:00 -08:00
|
|
|
internalcreate "sigs.k8s.io/kind/pkg/cluster/internal/create"
|
|
|
|
|
internaldelete "sigs.k8s.io/kind/pkg/cluster/internal/delete"
|
|
|
|
|
"sigs.k8s.io/kind/pkg/cluster/internal/kubeconfig"
|
|
|
|
|
"sigs.k8s.io/kind/pkg/cluster/internal/providers/docker"
|
2020-01-29 13:49:30 -08:00
|
|
|
"sigs.k8s.io/kind/pkg/cluster/internal/providers/podman"
|
2019-12-04 22:44:00 -08:00
|
|
|
internalprovider "sigs.k8s.io/kind/pkg/cluster/internal/providers/provider"
|
2018-07-23 10:06:37 -07:00
|
|
|
)
|
|
|
|
|
|
2019-02-28 16:23:48 -08:00
|
|
|
// DefaultName is the default cluster name
|
|
|
|
|
const DefaultName = constants.DefaultClusterName
|
|
|
|
|
|
2020-04-29 01:40:24 -07:00
|
|
|
// defaultName is a helper that given a name defaults it if unset
|
|
|
|
|
func defaultName(name string) string {
|
|
|
|
|
if name == "" {
|
|
|
|
|
name = DefaultName
|
|
|
|
|
}
|
|
|
|
|
return name
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-29 17:08:33 -07:00
|
|
|
// Provider is used to perform cluster operations
|
|
|
|
|
type Provider struct {
|
|
|
|
|
provider internalprovider.Provider
|
2019-11-05 17:59:00 -08:00
|
|
|
logger log.Logger
|
2019-01-08 13:00:44 -08:00
|
|
|
}
|
|
|
|
|
|
2019-10-29 17:08:33 -07:00
|
|
|
// NewProvider returns a new provider based on the supplied options
|
|
|
|
|
func NewProvider(options ...ProviderOption) *Provider {
|
2019-11-05 17:59:00 -08:00
|
|
|
p := &Provider{
|
|
|
|
|
logger: log.NoopLogger{},
|
|
|
|
|
}
|
|
|
|
|
// Ensure we apply the logger options first, while maintaining the order
|
|
|
|
|
// otherwise. This way we can trivially init the internal provider with
|
|
|
|
|
// the logger.
|
|
|
|
|
sort.SliceStable(options, func(i, j int) bool {
|
|
|
|
|
_, iIsLogger := options[i].(providerLoggerOption)
|
|
|
|
|
_, jIsLogger := options[j].(providerLoggerOption)
|
|
|
|
|
return iIsLogger && !jIsLogger
|
|
|
|
|
})
|
2019-10-29 17:08:33 -07:00
|
|
|
for _, o := range options {
|
2020-02-20 15:18:49 -08:00
|
|
|
if o != nil {
|
|
|
|
|
o.apply(p)
|
|
|
|
|
}
|
2020-02-19 15:06:46 -08:00
|
|
|
}
|
|
|
|
|
|
2020-02-20 15:18:49 -08:00
|
|
|
if p.provider == nil {
|
2020-02-19 15:06:46 -08:00
|
|
|
// auto-detect based on what is available in path
|
|
|
|
|
// default to docker for backwards compatibility
|
|
|
|
|
if path, err := exec.LookPath("docker"); err == nil && path != "" {
|
|
|
|
|
p.provider = docker.NewProvider(p.logger)
|
|
|
|
|
} else if path, err := exec.LookPath("podman"); err == nil && path != "" {
|
2020-01-29 13:49:30 -08:00
|
|
|
p.provider = podman.NewProvider(p.logger)
|
|
|
|
|
} else {
|
|
|
|
|
p.provider = docker.NewProvider(p.logger)
|
|
|
|
|
}
|
2019-10-29 17:08:33 -07:00
|
|
|
}
|
|
|
|
|
return p
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ProviderOption is an option for configuring a provider
|
2019-11-05 17:59:00 -08:00
|
|
|
type ProviderOption interface {
|
|
|
|
|
apply(p *Provider)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// providerLoggerOption is a trivial ProviderOption adapter
|
|
|
|
|
// we use a type specific to logging options so we can handle them first
|
|
|
|
|
type providerLoggerOption func(p *Provider)
|
|
|
|
|
|
|
|
|
|
func (a providerLoggerOption) apply(p *Provider) {
|
|
|
|
|
a(p)
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-20 15:18:49 -08:00
|
|
|
var _ ProviderOption = providerLoggerOption(nil)
|
|
|
|
|
|
2019-11-05 17:59:00 -08:00
|
|
|
// ProviderWithLogger configures the provider to use Logger logger
|
|
|
|
|
func ProviderWithLogger(logger log.Logger) ProviderOption {
|
|
|
|
|
return providerLoggerOption(func(p *Provider) {
|
|
|
|
|
p.logger = logger
|
|
|
|
|
})
|
|
|
|
|
}
|
2019-10-29 17:08:33 -07:00
|
|
|
|
2020-02-20 15:18:49 -08:00
|
|
|
// providerLoggerOption is a trivial ProviderOption adapter
|
|
|
|
|
// we use a type specific to logging options so we can handle them first
|
|
|
|
|
type providerRuntimeOption func(p *Provider)
|
|
|
|
|
|
|
|
|
|
func (a providerRuntimeOption) apply(p *Provider) {
|
|
|
|
|
a(p)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var _ ProviderOption = providerRuntimeOption(nil)
|
|
|
|
|
|
|
|
|
|
// ProviderWithDocker configures the provider to use docker runtime
|
|
|
|
|
func ProviderWithDocker() ProviderOption {
|
|
|
|
|
return providerRuntimeOption(func(p *Provider) {
|
|
|
|
|
p.provider = docker.NewProvider(p.logger)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ProviderWithPodman configures the provider to use podman runtime
|
|
|
|
|
func ProviderWithPodman() ProviderOption {
|
|
|
|
|
return providerRuntimeOption(func(p *Provider) {
|
|
|
|
|
p.provider = podman.NewProvider(p.logger)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-29 17:08:33 -07:00
|
|
|
// Create provisions and starts a kubernetes-in-docker cluster
|
2020-04-29 01:40:24 -07:00
|
|
|
// TODO: move name to an option to override config
|
2019-11-01 15:31:39 -07:00
|
|
|
func (p *Provider) Create(name string, options ...CreateOption) error {
|
|
|
|
|
// apply options
|
2020-04-29 01:40:24 -07:00
|
|
|
opts := &internalcreate.ClusterOptions{
|
|
|
|
|
NameOverride: name,
|
|
|
|
|
}
|
2019-11-01 15:31:39 -07:00
|
|
|
for _, o := range options {
|
|
|
|
|
if err := o.apply(opts); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-04-29 01:40:24 -07:00
|
|
|
return internalcreate.Cluster(p.logger, p.provider, opts)
|
2019-10-29 17:08:33 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Delete tears down a kubernetes-in-docker cluster
|
2019-10-29 22:01:22 -07:00
|
|
|
func (p *Provider) Delete(name, explicitKubeconfigPath string) error {
|
2020-04-29 01:40:24 -07:00
|
|
|
return internaldelete.Cluster(p.logger, p.provider, defaultName(name), explicitKubeconfigPath)
|
2019-10-29 17:08:33 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// List returns a list of clusters for which nodes exist
|
|
|
|
|
func (p *Provider) List() ([]string, error) {
|
|
|
|
|
return p.provider.ListClusters()
|
2018-11-14 16:26:53 -08:00
|
|
|
}
|
|
|
|
|
|
2019-09-16 16:10:50 -07:00
|
|
|
// KubeConfig returns the KUBECONFIG for the cluster
|
|
|
|
|
// If internal is true, this will contain the internal IP etc.
|
2019-12-11 11:06:43 -05:00
|
|
|
// If internal is false, this will contain the host IP etc.
|
2019-10-29 17:08:33 -07:00
|
|
|
func (p *Provider) KubeConfig(name string, internal bool) (string, error) {
|
2020-04-29 01:40:24 -07:00
|
|
|
return kubeconfig.Get(p.provider, defaultName(name), !internal)
|
2019-09-16 16:10:50 -07:00
|
|
|
}
|
|
|
|
|
|
2019-11-07 00:38:42 -08:00
|
|
|
// ExportKubeConfig exports the KUBECONFIG for the cluster, merging
|
|
|
|
|
// it into the selected file, following the rules from
|
|
|
|
|
// https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#config
|
|
|
|
|
// where explicitPath is the --kubeconfig value.
|
|
|
|
|
func (p *Provider) ExportKubeConfig(name string, explicitPath string) error {
|
2020-04-29 01:40:24 -07:00
|
|
|
return kubeconfig.Export(p.provider, defaultName(name), explicitPath)
|
2019-11-07 00:38:42 -08:00
|
|
|
}
|
|
|
|
|
|
2018-07-23 10:06:37 -07:00
|
|
|
// ListNodes returns the list of container IDs for the "nodes" in the cluster
|
2019-10-29 17:08:33 -07:00
|
|
|
func (p *Provider) ListNodes(name string) ([]nodes.Node, error) {
|
2020-04-29 01:40:24 -07:00
|
|
|
return p.provider.ListNodes(defaultName(name))
|
2018-07-23 10:06:37 -07:00
|
|
|
}
|
2018-11-20 12:01:24 -08:00
|
|
|
|
2019-06-05 13:12:48 +02:00
|
|
|
// ListInternalNodes returns the list of container IDs for the "nodes" in the cluster
|
|
|
|
|
// that are not external
|
2019-10-29 17:08:33 -07:00
|
|
|
func (p *Provider) ListInternalNodes(name string) ([]nodes.Node, error) {
|
2020-04-29 01:40:24 -07:00
|
|
|
n, err := p.provider.ListNodes(name)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
return nodeutils.InternalNodes(n)
|
2019-06-05 13:12:48 +02:00
|
|
|
}
|
|
|
|
|
|
2018-11-20 12:01:24 -08:00
|
|
|
// CollectLogs will populate dir with cluster logs and other debug files
|
2019-10-29 17:08:33 -07:00
|
|
|
func (p *Provider) CollectLogs(name, dir string) error {
|
2020-04-29 01:40:24 -07:00
|
|
|
// TODO: should use ListNodes and Collect should handle nodes differently
|
|
|
|
|
// based on role ...
|
|
|
|
|
n, err := p.ListInternalNodes(name)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
return p.provider.CollectLogs(dir, n)
|
2018-11-20 12:01:24 -08:00
|
|
|
}
|