Merge pull request #1040 from nathanleclaire/engine_options

Implement configurable engine options
This commit is contained in:
Evan Hazlett
2015-04-30 13:55:58 -04:00
14 changed files with 451 additions and 85 deletions

View File

@@ -1,16 +1,18 @@
package engine
type EngineOptions struct {
Dns []string
GraphDir string
Ipv6 bool
Labels []string
LogLevel string
StorageDriver string
SelinuxEnabled bool
TlsCaCert string
TlsCert string
TlsKey string
TlsVerify bool
RegistryMirror []string
ArbitraryFlags []string
Dns []string
GraphDir string
Ipv6 bool
InsecureRegistry []string
Labels []string
LogLevel string
StorageDriver string
SelinuxEnabled bool
TlsCaCert string
TlsCert string
TlsKey string
TlsVerify bool
RegistryMirror []string
}

View File

@@ -118,7 +118,7 @@ func (h *Host) Create(name string) error {
return err
}
if err := provisioner.Provision(*h.HostOptions.SwarmOptions, *h.HostOptions.AuthOptions); err != nil {
if err := provisioner.Provision(*h.HostOptions.SwarmOptions, *h.HostOptions.AuthOptions, *h.HostOptions.EngineOptions); err != nil {
return err
}
}
@@ -315,7 +315,7 @@ func (h *Host) ConfigureAuth() error {
return err
}
if err := provision.ConfigureAuth(provisioner, *h.HostOptions.AuthOptions); err != nil {
if err := provision.ConfigureAuth(provisioner); err != nil {
return err
}

View File

@@ -5,10 +5,12 @@ import (
"errors"
"fmt"
"path"
"text/template"
log "github.com/Sirupsen/logrus"
"github.com/docker/machine/drivers"
"github.com/docker/machine/libmachine/auth"
"github.com/docker/machine/libmachine/engine"
"github.com/docker/machine/libmachine/provision/pkgaction"
"github.com/docker/machine/libmachine/swarm"
"github.com/docker/machine/ssh"
@@ -31,6 +33,8 @@ func NewBoot2DockerProvisioner(d drivers.Driver) Provisioner {
type Boot2DockerProvisioner struct {
OsReleaseInfo *OsRelease
Driver drivers.Driver
AuthOptions auth.AuthOptions
EngineOptions engine.EngineOptions
SwarmOptions swarm.SwarmOptions
}
@@ -127,18 +131,49 @@ func (provisioner *Boot2DockerProvisioner) GetDockerOptionsDir() string {
return "/var/lib/boot2docker"
}
func (provisioner *Boot2DockerProvisioner) GenerateDockerOptions(dockerPort int, authOptions auth.AuthOptions) (*DockerOptions, error) {
defaultDaemonOpts := getDefaultDaemonOpts(provisioner.Driver.DriverName(), authOptions)
daemonOpts := fmt.Sprintf("-H tcp://0.0.0.0:%d", dockerPort)
func (provisioner *Boot2DockerProvisioner) GetAuthOptions() auth.AuthOptions {
return provisioner.AuthOptions
}
func (provisioner *Boot2DockerProvisioner) GenerateDockerOptions(dockerPort int) (*DockerOptions, error) {
var (
engineCfg bytes.Buffer
)
driverNameLabel := fmt.Sprintf("provider=%s", provisioner.Driver.DriverName())
provisioner.EngineOptions.Labels = append(provisioner.EngineOptions.Labels, driverNameLabel)
engineConfigTmpl := `
EXTRA_ARGS='
{{ range .EngineOptions.Labels }}--label {{.}}
{{ end }}{{ range .EngineOptions.InsecureRegistry }}--insecure-registry {{.}}
{{ end }}{{ range .EngineOptions.RegistryMirror }}--registry-mirror {{.}}
{{ end }}{{ range .EngineOptions.ArbitraryFlags }}--{{.}}
{{ end }}
'
CACERT={{.AuthOptions.CaCertRemotePath}}
DOCKER_HOST='-H tcp://0.0.0.0:{{.DockerPort}}'
DOCKER_STORAGE={{.EngineOptions.StorageDriver}}
DOCKER_TLS=auto
SERVERKEY={{.AuthOptions.ServerKeyRemotePath}}
SERVERCERT={{.AuthOptions.ServerCertRemotePath}}
`
t, err := template.New("engineConfig").Parse(engineConfigTmpl)
if err != nil {
return nil, err
}
engineConfigContext := EngineConfigContext{
DockerPort: dockerPort,
AuthOptions: provisioner.AuthOptions,
EngineOptions: provisioner.EngineOptions,
}
t.Execute(&engineCfg, engineConfigContext)
daemonOptsDir := path.Join(provisioner.GetDockerOptionsDir(), "profile")
opts := fmt.Sprintf("%s %s", defaultDaemonOpts, daemonOpts)
daemonCfg := fmt.Sprintf(`EXTRA_ARGS='%s'
CACERT=%s
SERVERCERT=%s
SERVERKEY=%s
DOCKER_TLS=no`, opts, authOptions.CaCertRemotePath, authOptions.ServerCertRemotePath, authOptions.ServerKeyRemotePath)
return &DockerOptions{
EngineOptions: daemonCfg,
EngineOptions: engineCfg.String(),
EngineOptionsPath: daemonOptsDir,
}, nil
}
@@ -151,7 +186,11 @@ func (provisioner *Boot2DockerProvisioner) SetOsReleaseInfo(info *OsRelease) {
provisioner.OsReleaseInfo = info
}
func (provisioner *Boot2DockerProvisioner) Provision(swarmOptions swarm.SwarmOptions, authOptions auth.AuthOptions) error {
func (provisioner *Boot2DockerProvisioner) Provision(swarmOptions swarm.SwarmOptions, authOptions auth.AuthOptions, engineOptions engine.EngineOptions) error {
provisioner.SwarmOptions = swarmOptions
provisioner.AuthOptions = authOptions
provisioner.EngineOptions = engineOptions
if err := provisioner.SetHostname(provisioner.Driver.GetMachineName()); err != nil {
return err
}
@@ -171,7 +210,13 @@ func (provisioner *Boot2DockerProvisioner) Provision(swarmOptions swarm.SwarmOpt
return err
}
if err := ConfigureAuth(provisioner, authOptions); err != nil {
if err := makeDockerOptionsDir(provisioner); err != nil {
return err
}
provisioner.AuthOptions = setRemoteAuthOptions(provisioner)
if err := ConfigureAuth(provisioner); err != nil {
return err
}

View File

@@ -0,0 +1,12 @@
package provision
import (
"github.com/docker/machine/libmachine/auth"
"github.com/docker/machine/libmachine/engine"
)
type EngineConfigContext struct {
DockerPort int
AuthOptions auth.AuthOptions
EngineOptions engine.EngineOptions
}

View File

@@ -6,6 +6,7 @@ import (
"github.com/docker/machine/drivers"
"github.com/docker/machine/libmachine/auth"
"github.com/docker/machine/libmachine/engine"
"github.com/docker/machine/libmachine/provision/pkgaction"
"github.com/docker/machine/libmachine/swarm"
"github.com/docker/machine/ssh"
@@ -16,11 +17,14 @@ var provisioners = make(map[string]*RegisteredProvisioner)
// Distribution specific actions
type Provisioner interface {
// Create the files for the daemon to consume configuration settings (return struct of content and path)
GenerateDockerOptions(dockerPort int, authOptions auth.AuthOptions) (*DockerOptions, error)
GenerateDockerOptions(dockerPort int) (*DockerOptions, error)
// Get the directory where the settings files for docker are to be found
GetDockerOptionsDir() string
// Return the auth options used to configure remote connection for the daemon.
GetAuthOptions() auth.AuthOptions
// Run a package action e.g. install
Package(name string, action pkgaction.PackageAction) error
@@ -39,7 +43,7 @@ type Provisioner interface {
// 3. Configure the daemon to accept connections over TLS.
// 4. Copy the needed certificates to the server and local config dir.
// 5. Configure / activate swarm if applicable.
Provision(swarmOptions swarm.SwarmOptions, authOptions auth.AuthOptions) error
Provision(swarmOptions swarm.SwarmOptions, authOptions auth.AuthOptions, engineOptions engine.EngineOptions) error
// Perform action on a named service e.g. stop
Service(name string, action pkgaction.ServiceAction) error

View File

@@ -3,10 +3,12 @@ package provision
import (
"bytes"
"fmt"
"text/template"
log "github.com/Sirupsen/logrus"
"github.com/docker/machine/drivers"
"github.com/docker/machine/libmachine/auth"
"github.com/docker/machine/libmachine/engine"
"github.com/docker/machine/libmachine/provision/pkgaction"
"github.com/docker/machine/libmachine/swarm"
"github.com/docker/machine/ssh"
@@ -32,6 +34,8 @@ type UbuntuProvisioner struct {
packages []string
OsReleaseInfo *OsRelease
Driver drivers.Driver
AuthOptions auth.AuthOptions
EngineOptions engine.EngineOptions
SwarmOptions swarm.SwarmOptions
}
@@ -82,7 +86,10 @@ func (provisioner *UbuntuProvisioner) dockerDaemonResponding() bool {
return true
}
func (provisioner *UbuntuProvisioner) Provision(swarmOptions swarm.SwarmOptions, authOptions auth.AuthOptions) error {
func (provisioner *UbuntuProvisioner) Provision(swarmOptions swarm.SwarmOptions, authOptions auth.AuthOptions, engineOptions engine.EngineOptions) error {
provisioner.SwarmOptions = swarmOptions
provisioner.AuthOptions = authOptions
provisioner.EngineOptions = engineOptions
if err := provisioner.SetHostname(provisioner.Driver.GetMachineName()); err != nil {
return err
}
@@ -101,7 +108,13 @@ func (provisioner *UbuntuProvisioner) Provision(swarmOptions swarm.SwarmOptions,
return err
}
if err := ConfigureAuth(provisioner, authOptions); err != nil {
if err := makeDockerOptionsDir(provisioner); err != nil {
return err
}
provisioner.AuthOptions = setRemoteAuthOptions(provisioner)
if err := ConfigureAuth(provisioner); err != nil {
return err
}
@@ -159,18 +172,54 @@ func (provisioner *UbuntuProvisioner) CompatibleWithHost() bool {
return provisioner.OsReleaseInfo.Id == "ubuntu"
}
func (provisioner *UbuntuProvisioner) GetAuthOptions() auth.AuthOptions {
return provisioner.AuthOptions
}
func (provisioner *UbuntuProvisioner) SetOsReleaseInfo(info *OsRelease) {
provisioner.OsReleaseInfo = info
}
func (provisioner *UbuntuProvisioner) GenerateDockerOptions(dockerPort int, authOptions auth.AuthOptions) (*DockerOptions, error) {
defaultDaemonOpts := getDefaultDaemonOpts(provisioner.Driver.DriverName(), authOptions)
daemonOpts := fmt.Sprintf("--host=unix:///var/run/docker.sock --host=tcp://0.0.0.0:%d", dockerPort)
func (provisioner *UbuntuProvisioner) GenerateDockerOptions(dockerPort int) (*DockerOptions, error) {
var (
engineCfg bytes.Buffer
)
driverNameLabel := fmt.Sprintf("provider=%s", provisioner.Driver.DriverName())
provisioner.EngineOptions.Labels = append(provisioner.EngineOptions.Labels, driverNameLabel)
engineConfigTmpl := `
DOCKER_OPTS='
-H tcp://0.0.0.0:{{.DockerPort}}
-H unix:///var/run/docker.sock
--storage-driver {{.EngineOptions.StorageDriver}}
--tlsverify
--tlscacert {{.AuthOptions.CaCertRemotePath}}
--tlscert {{.AuthOptions.ServerCertRemotePath}}
--tlskey {{.AuthOptions.ServerKeyRemotePath}}
{{ range .EngineOptions.Labels }}--label {{.}}
{{ end }}{{ range .EngineOptions.InsecureRegistry }}--insecure-registry {{.}}
{{ end }}{{ range .EngineOptions.RegistryMirror }}--registry-mirror {{.}}
{{ end }}{{ range .EngineOptions.ArbitraryFlags }}--{{.}}
{{ end }}
'
`
t, err := template.New("engineConfig").Parse(engineConfigTmpl)
if err != nil {
return nil, err
}
engineConfigContext := EngineConfigContext{
DockerPort: dockerPort,
AuthOptions: provisioner.AuthOptions,
EngineOptions: provisioner.EngineOptions,
}
t.Execute(&engineCfg, engineConfigContext)
daemonOptsDir := "/etc/default/docker"
opts := fmt.Sprintf("%s %s", defaultDaemonOpts, daemonOpts)
daemonCfg := fmt.Sprintf("export DOCKER_OPTS=\\\"%s\\\"", opts)
return &DockerOptions{
EngineOptions: daemonCfg,
EngineOptions: engineCfg.String(),
EngineOptionsPath: daemonOptsDir,
}, nil
}

View File

@@ -37,12 +37,35 @@ func installDockerGeneric(p Provisioner) error {
return nil
}
func ConfigureAuth(p Provisioner, authOptions auth.AuthOptions) error {
func makeDockerOptionsDir(p Provisioner) error {
dockerDir := p.GetDockerOptionsDir()
if _, err := p.SSHCommand(fmt.Sprintf("sudo mkdir -p %s", dockerDir)); err != nil {
return err
}
return nil
}
func setRemoteAuthOptions(p Provisioner) auth.AuthOptions {
dockerDir := p.GetDockerOptionsDir()
authOptions := p.GetAuthOptions()
// due to windows clients, we cannot use filepath.Join as the paths
// will be mucked on the linux hosts
authOptions.CaCertRemotePath = path.Join(dockerDir, "ca.pem")
authOptions.ServerCertRemotePath = path.Join(dockerDir, "server.pem")
authOptions.ServerKeyRemotePath = path.Join(dockerDir, "server-key.pem")
return authOptions
}
func ConfigureAuth(p Provisioner) error {
var (
err error
)
machineName := p.GetDriver().GetMachineName()
authOptions := p.GetAuthOptions()
org := machineName
bits := 2048
@@ -92,46 +115,30 @@ func ConfigureAuth(p Provisioner, authOptions auth.AuthOptions) error {
return err
}
dockerDir := p.GetDockerOptionsDir()
if _, err := p.SSHCommand(fmt.Sprintf("sudo mkdir -p %s", dockerDir)); err != nil {
return err
}
// upload certs and configure TLS auth
caCert, err := ioutil.ReadFile(authOptions.CaCertPath)
if err != nil {
return err
}
// due to windows clients, we cannot use filepath.Join as the paths
// will be mucked on the linux hosts
machineCaCertPath := path.Join(dockerDir, "ca.pem")
authOptions.CaCertRemotePath = machineCaCertPath
serverCert, err := ioutil.ReadFile(authOptions.ServerCertPath)
if err != nil {
return err
}
machineServerCertPath := path.Join(dockerDir, "server.pem")
authOptions.ServerCertRemotePath = machineServerCertPath
serverKey, err := ioutil.ReadFile(authOptions.ServerKeyPath)
if err != nil {
return err
}
machineServerKeyPath := path.Join(dockerDir, "server-key.pem")
authOptions.ServerKeyRemotePath = machineServerKeyPath
if _, err = p.SSHCommand(fmt.Sprintf("echo \"%s\" | sudo tee %s", string(caCert), machineCaCertPath)); err != nil {
if _, err := p.SSHCommand(fmt.Sprintf("echo \"%s\" | sudo tee %s", string(caCert), authOptions.CaCertRemotePath)); err != nil {
return err
}
if _, err = p.SSHCommand(fmt.Sprintf("echo \"%s\" | sudo tee %s", string(serverKey), machineServerKeyPath)); err != nil {
if _, err := p.SSHCommand(fmt.Sprintf("echo \"%s\" | sudo tee %s", string(serverCert), authOptions.ServerCertRemotePath)); err != nil {
return err
}
if _, err = p.SSHCommand(fmt.Sprintf("echo \"%s\" | sudo tee %s", string(serverCert), machineServerCertPath)); err != nil {
if _, err := p.SSHCommand(fmt.Sprintf("echo \"%s\" | sudo tee %s", string(serverKey), authOptions.ServerKeyRemotePath)); err != nil {
return err
}
@@ -153,7 +160,7 @@ func ConfigureAuth(p Provisioner, authOptions auth.AuthOptions) error {
dockerPort = dPort
}
dkrcfg, err := p.GenerateDockerOptions(dockerPort, authOptions)
dkrcfg, err := p.GenerateDockerOptions(dockerPort)
if err != nil {
return err
}
@@ -166,16 +173,12 @@ func ConfigureAuth(p Provisioner, authOptions auth.AuthOptions) error {
return err
}
return nil
}
// TODO: Do not hardcode daemon port, ask the driver
if err := utils.WaitForDocker(ip, dockerPort); err != nil {
return err
}
func getDefaultDaemonOpts(driverName string, authOptions auth.AuthOptions) string {
return fmt.Sprintf(`--tlsverify --tlscacert=%s --tlskey=%s --tlscert=%s %s`,
authOptions.CaCertRemotePath,
authOptions.ServerKeyRemotePath,
authOptions.ServerCertRemotePath,
fmt.Sprintf("--label=provider=%s", driverName),
)
return nil
}
func configureSwarm(p Provisioner, swarmOptions swarm.SwarmOptions) error {
@@ -204,11 +207,6 @@ func configureSwarm(p Provisioner, swarmOptions swarm.SwarmOptions) error {
parts := strings.Split(u.Host, ":")
port := parts[1]
// TODO: Do not hardcode daemon port, ask the driver
if err := utils.WaitForDocker(ip, 2376); err != nil {
return err
}
if _, err := p.SSHCommand(fmt.Sprintf("sudo docker pull %s", swarm.DockerImage)); err != nil {
return err
}

View File

@@ -15,14 +15,14 @@ func TestGenerateDockerOptionsBoot2Docker(t *testing.T) {
Driver: &fakedriver.FakeDriver{},
}
dockerPort := 1234
authOptions := auth.AuthOptions{
p.AuthOptions = auth.AuthOptions{
CaCertRemotePath: "/test/ca-cert",
ServerKeyRemotePath: "/test/server-key",
ServerCertRemotePath: "/test/server-cert",
}
engineConfigPath := "/var/lib/boot2docker/profile"
dockerCfg, err := p.GenerateDockerOptions(dockerPort, authOptions)
dockerCfg, err := p.GenerateDockerOptions(dockerPort)
if err != nil {
t.Fatal(err)
}
@@ -35,16 +35,16 @@ func TestGenerateDockerOptionsBoot2Docker(t *testing.T) {
t.Fatalf("-H docker port invalid; expected %d", dockerPort)
}
if strings.Index(dockerCfg.EngineOptions, fmt.Sprintf("CACERT=%s", authOptions.CaCertRemotePath)) == -1 {
t.Fatalf("CACERT option invalid; expected %s", authOptions.CaCertRemotePath)
if strings.Index(dockerCfg.EngineOptions, fmt.Sprintf("CACERT=%s", p.AuthOptions.CaCertRemotePath)) == -1 {
t.Fatalf("CACERT option invalid; expected %s", p.AuthOptions.CaCertRemotePath)
}
if strings.Index(dockerCfg.EngineOptions, fmt.Sprintf("SERVERKEY=%s", authOptions.ServerKeyRemotePath)) == -1 {
t.Fatalf("SERVERKEY option invalid; expected %s", authOptions.ServerKeyRemotePath)
if strings.Index(dockerCfg.EngineOptions, fmt.Sprintf("SERVERKEY=%s", p.AuthOptions.ServerKeyRemotePath)) == -1 {
t.Fatalf("SERVERKEY option invalid; expected %s", p.AuthOptions.ServerKeyRemotePath)
}
if strings.Index(dockerCfg.EngineOptions, fmt.Sprintf("SERVERCERT=%s", authOptions.ServerCertRemotePath)) == -1 {
t.Fatalf("SERVERCERT option invalid; expected %s", authOptions.ServerCertRemotePath)
if strings.Index(dockerCfg.EngineOptions, fmt.Sprintf("SERVERCERT=%s", p.AuthOptions.ServerCertRemotePath)) == -1 {
t.Fatalf("SERVERCERT option invalid; expected %s", p.AuthOptions.ServerCertRemotePath)
}
}
@@ -54,13 +54,13 @@ func TestMachinePortBoot2Docker(t *testing.T) {
}
dockerPort := 2376
bindUrl := fmt.Sprintf("tcp://0.0.0.0:%d", dockerPort)
authOptions := auth.AuthOptions{
p.AuthOptions = auth.AuthOptions{
CaCertRemotePath: "/test/ca-cert",
ServerKeyRemotePath: "/test/server-key",
ServerCertRemotePath: "/test/server-cert",
}
cfg, err := p.GenerateDockerOptions(dockerPort, authOptions)
cfg, err := p.GenerateDockerOptions(dockerPort)
if err != nil {
t.Fatal(err)
}
@@ -86,13 +86,13 @@ func TestMachineCustomPortBoot2Docker(t *testing.T) {
}
dockerPort := 3376
bindUrl := fmt.Sprintf("tcp://0.0.0.0:%d", dockerPort)
authOptions := auth.AuthOptions{
p.AuthOptions = auth.AuthOptions{
CaCertRemotePath: "/test/ca-cert",
ServerKeyRemotePath: "/test/server-key",
ServerCertRemotePath: "/test/server-cert",
}
cfg, err := p.GenerateDockerOptions(dockerPort, authOptions)
cfg, err := p.GenerateDockerOptions(dockerPort)
if err != nil {
t.Fatal(err)
}