minikube/pkg/libmachine/libmachine.go

221 lines
6.6 KiB
Go

/*
Copyright 2022 The Kubernetes Authors All rights reserved.
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.
*/
/*
Copyright 2014 Docker, Inc.
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 libmachine
import (
"fmt"
"path/filepath"
"io"
"k8s.io/minikube/pkg/libmachine/auth"
"k8s.io/minikube/pkg/libmachine/cert"
"k8s.io/minikube/pkg/libmachine/check"
"k8s.io/minikube/pkg/libmachine/drivers"
"k8s.io/minikube/pkg/libmachine/drivers/errdriver"
"k8s.io/minikube/pkg/libmachine/drivers/plugin/localbinary"
"k8s.io/minikube/pkg/libmachine/drivers/rpcdriver"
"k8s.io/minikube/pkg/libmachine/engine"
"k8s.io/minikube/pkg/libmachine/host"
"k8s.io/minikube/pkg/libmachine/log"
"k8s.io/minikube/pkg/libmachine/mcnerror"
"k8s.io/minikube/pkg/libmachine/mcnutils"
"k8s.io/minikube/pkg/libmachine/persist"
"k8s.io/minikube/pkg/libmachine/provision"
"k8s.io/minikube/pkg/libmachine/ssh"
"k8s.io/minikube/pkg/libmachine/state"
"k8s.io/minikube/pkg/libmachine/swarm"
"k8s.io/minikube/pkg/libmachine/version"
)
type API interface {
io.Closer
NewHost(driverName string, rawDriver []byte) (*host.Host, error)
Create(h *host.Host) error
persist.Store
GetMachinesDir() string
}
type Client struct {
certsDir string
IsDebug bool
SSHClientType ssh.ClientType
GithubAPIToken string
*persist.Filestore
clientDriverFactory rpcdriver.RPCClientDriverFactory
}
func NewClient(storePath, certsDir string) *Client {
return &Client{
certsDir: certsDir,
IsDebug: false,
SSHClientType: ssh.External,
Filestore: persist.NewFilestore(storePath, certsDir, certsDir),
clientDriverFactory: rpcdriver.NewRPCClientDriverFactory(),
}
}
func (api *Client) NewHost(driverName string, rawDriver []byte) (*host.Host, error) {
driver, err := api.clientDriverFactory.NewRPCClientDriver(driverName, rawDriver)
if err != nil {
return nil, err
}
return &host.Host{
ConfigVersion: version.ConfigVersion,
Name: driver.GetMachineName(),
Driver: driver,
DriverName: driver.DriverName(),
HostOptions: &host.Options{
AuthOptions: &auth.Options{
CertDir: api.certsDir,
CaCertPath: filepath.Join(api.certsDir, "ca.pem"),
CaPrivateKeyPath: filepath.Join(api.certsDir, "ca-key.pem"),
ClientCertPath: filepath.Join(api.certsDir, "cert.pem"),
ClientKeyPath: filepath.Join(api.certsDir, "key.pem"),
ServerCertPath: filepath.Join(api.GetMachinesDir(), "server.pem"),
ServerKeyPath: filepath.Join(api.GetMachinesDir(), "server-key.pem"),
},
EngineOptions: &engine.Options{
InstallURL: drivers.DefaultEngineInstallURL,
StorageDriver: "overlay2",
TLSVerify: true,
},
SwarmOptions: &swarm.Options{
Host: "tcp://0.0.0.0:3376",
Image: "swarm:latest",
Strategy: "spread",
},
},
}, nil
}
func (api *Client) Load(name string) (*host.Host, error) {
h, err := api.Filestore.Load(name)
if err != nil {
return nil, err
}
d, err := api.clientDriverFactory.NewRPCClientDriver(h.DriverName, h.RawDriver)
if err != nil {
// Not being able to find a driver binary is a "known error"
if _, ok := err.(localbinary.ErrPluginBinaryNotFound); ok {
h.Driver = errdriver.NewDriver(h.DriverName)
return h, nil
}
return nil, err
}
if h.DriverName == "virtualbox" {
h.Driver = drivers.NewSerialDriver(d)
} else {
h.Driver = d
}
return h, nil
}
// Create is the wrapper method which covers all of the boilerplate around
// actually creating, provisioning, and persisting an instance in the store.
func (api *Client) Create(h *host.Host) error {
if err := cert.BootstrapCertificates(h.AuthOptions()); err != nil {
return fmt.Errorf("Error generating certificates: %s", err)
}
log.Info("Running pre-create checks...")
if err := h.Driver.PreCreateCheck(); err != nil {
return mcnerror.ErrDuringPreCreate{
Cause: err,
}
}
if err := api.Save(h); err != nil {
return fmt.Errorf("Error saving host to store before attempting creation: %s", err)
}
log.Info("Creating machine...")
if err := api.performCreate(h); err != nil {
return fmt.Errorf("Error creating machine: %s", err)
}
log.Debug("Reticulating splines...")
return nil
}
func (api *Client) performCreate(h *host.Host) error {
if err := h.Driver.Create(); err != nil {
return fmt.Errorf("Error in driver during machine creation: %s", err)
}
if err := api.Save(h); err != nil {
return fmt.Errorf("Error saving host to store after attempting creation: %s", err)
}
// TODO: Not really a fan of just checking "none" or "ci-test" here.
if h.Driver.DriverName() == "none" || h.Driver.DriverName() == "ci-test" {
return nil
}
log.Info("Waiting for machine to be running, this may take a few minutes...")
if err := mcnutils.WaitFor(drivers.MachineInState(h.Driver, state.Running)); err != nil {
return fmt.Errorf("Error waiting for machine to be running: %s", err)
}
log.Info("Detecting operating system of created instance...")
provisioner, err := provision.DetectProvisioner(h.Driver)
if err != nil {
return fmt.Errorf("Error detecting OS: %s", err)
}
log.Infof("Provisioning with %s...", provisioner.String())
if err := provisioner.Provision(*h.HostOptions.SwarmOptions, *h.HostOptions.AuthOptions, *h.HostOptions.EngineOptions); err != nil {
return fmt.Errorf("Error running provisioning: %s", err)
}
// We should check the connection to docker here
log.Info("Checking connection to Docker...")
if _, _, err = check.DefaultConnChecker.Check(h, false); err != nil {
return fmt.Errorf("Error checking the host: %s", err)
}
log.Info("Docker is up and running!")
return nil
}
func (api *Client) Close() error {
return api.clientDriverFactory.Close()
}