diff --git a/cmd/root.go b/cmd/root.go index ee13ee97..361d0fb5 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -119,9 +119,8 @@ func findConfig() string { // Provide a default. if runtime.GOOS == "linux" { return strings.Join([]string{"etc", "pygmy", "config.yml"}, string(os.PathSeparator)) - } else { - return strings.Join([]string{home, ".pygmy.yml"}, string(os.PathSeparator)) } + return strings.Join([]string{home, ".pygmy.yml"}, string(os.PathSeparator)) } // initConfig reads in config file and ENV variables if set. diff --git a/service/color/color.go b/service/color/color.go index 469465d6..0496ece0 100644 --- a/service/color/color.go +++ b/service/color/color.go @@ -8,6 +8,7 @@ import ( var colorableOutput = colorable.NewColorableStdout() +// Print will print text to an interface using a colour via go-colourable. func Print(input interface{}) { fmt.Fprint(colorableOutput, input) } diff --git a/service/dnsmasq/dnsmasq.go b/service/dnsmasq/dnsmasq.go index 8760ad17..33077c95 100644 --- a/service/dnsmasq/dnsmasq.go +++ b/service/dnsmasq/dnsmasq.go @@ -1,6 +1,8 @@ package dnsmasq import ( + "fmt" + "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/network" "github.com/docker/go-connections/nat" @@ -8,13 +10,13 @@ import ( ) // New will provide the standard object for the dnsmasq container. -func New() model.Service { +func New(c *model.Params) model.Service { return model.Service{ Config: container.Config{ Image: "andyshinn/dnsmasq:2.83", Cmd: []string{ "-A", - "/docker.amazee.io/127.0.0.1", + fmt.Sprintf("/%s/127.0.0.1", c.Domain), }, Labels: map[string]string{ "pygmy.defaults": "true", diff --git a/service/dnsmasq/dnsmasq_test.go b/service/dnsmasq/dnsmasq_test.go index 47a5fd8c..be3777dd 100644 --- a/service/dnsmasq/dnsmasq_test.go +++ b/service/dnsmasq/dnsmasq_test.go @@ -6,16 +6,17 @@ import ( "github.com/docker/go-connections/nat" "github.com/fubarhouse/pygmy-go/service/dnsmasq" + model "github.com/fubarhouse/pygmy-go/service/interface" . "github.com/smartystreets/goconvey/convey" ) func Example() { - dnsmasq.New() + dnsmasq.New(&model.Params{}) } func Test(t *testing.T) { Convey("DNSMasq: Field equality tests...", t, func() { - obj := dnsmasq.New() + obj := dnsmasq.New(&model.Params{Domain: "docker.amazee.io"}) So(obj.Config.Image, ShouldEqual, "andyshinn/dnsmasq:2.83") So(fmt.Sprint(obj.Config.Cmd), ShouldEqual, fmt.Sprint([]string{"-A", "/docker.amazee.io/127.0.0.1"})) diff --git a/service/haproxy/haproxy.go b/service/haproxy/haproxy.go index 2e4f3922..b7214cba 100644 --- a/service/haproxy/haproxy.go +++ b/service/haproxy/haproxy.go @@ -1,6 +1,8 @@ package haproxy import ( + "fmt" + "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/network" "github.com/docker/go-connections/nat" @@ -8,7 +10,7 @@ import ( ) // New will provide the standard object for the haproxy container. -func New() model.Service { +func New(c *model.Params) model.Service { return model.Service{ Config: container.Config{ Image: "amazeeio/haproxy", @@ -17,9 +19,12 @@ func New() model.Service { "pygmy.enable": "true", "pygmy.name": "amazeeio-haproxy", "pygmy.network": "amazeeio-network", - "pygmy.url": "http://docker.amazee.io/stats", + "pygmy.url": fmt.Sprintf("http://%s/stats", c.Domain), "pygmy.weight": "14", }, + Env: []string{ + fmt.Sprintf("AMAZEEIO_URL=%s", c.Domain), + }, }, HostConfig: container.HostConfig{ Binds: []string{"/var/run/docker.sock:/tmp/docker.sock"}, diff --git a/service/haproxy/haproxy_test.go b/service/haproxy/haproxy_test.go index 11157329..614181fa 100644 --- a/service/haproxy/haproxy_test.go +++ b/service/haproxy/haproxy_test.go @@ -6,17 +6,18 @@ import ( "github.com/docker/go-connections/nat" "github.com/fubarhouse/pygmy-go/service/haproxy" + model "github.com/fubarhouse/pygmy-go/service/interface" . "github.com/smartystreets/goconvey/convey" ) func Example() { - haproxy.New() + haproxy.New(&model.Params{}) haproxy.NewDefaultPorts() } func Test(t *testing.T) { Convey("HAProxy: Field equality tests...", t, func() { - obj := haproxy.New() + obj := haproxy.New(&model.Params{Domain: "docker.amazee.io"}) objPorts := haproxy.NewDefaultPorts() So(obj.Config.Image, ShouldEqual, "amazeeio/haproxy") So(obj.Config.Labels["pygmy.defaults"], ShouldEqual, "true") diff --git a/service/interface/docker/docker.go b/service/interface/docker/docker.go index d1049478..360862b9 100644 --- a/service/interface/docker/docker.go +++ b/service/interface/docker/docker.go @@ -318,7 +318,7 @@ func DockerNetworkConnect(network string, containerName string) error { return nil } -// DockerNetworkConnect will check if a container is connected to a network. +// DockerNetworkConnected will check if a container is connected to a network. func DockerNetworkConnected(network string, containerName string) (bool, error) { // Reset network state: c, _ := DockerContainerList() @@ -417,22 +417,28 @@ func DockerExec(container string, command string) ([]byte, error) { return []byte{}, err } - if rst, err := cli.ContainerExecCreate(ctx, container, types.ExecConfig{ + rst, err := cli.ContainerExecCreate(ctx, container, types.ExecConfig{ AttachStdout: true, AttachStderr: true, - Cmd: strings.Split(command, " ")}); err != nil { + Cmd: strings.Split(command, " ")}) + + if err != nil { return []byte{}, err - } else { - if response, err := cli.ContainerExecAttach(context.Background(), rst.ID, types.ExecStartCheck{}); err != nil { - return []byte{}, err - } else { - data, _ := ioutil.ReadAll(response.Reader) - defer response.Close() - return data, nil - } } + + response, err := cli.ContainerExecAttach(context.Background(), rst.ID, types.ExecStartCheck{}) + + if err != nil { + return []byte{}, err + } + + data, _ := ioutil.ReadAll(response.Reader) + defer response.Close() + return data, nil + } +// DockerContainerCreate will create a container, but will not run it. func DockerContainerCreate(ID string, config container.Config, hostconfig container.HostConfig, networkconfig network.NetworkingConfig) (container.ContainerCreateCreatedBody, error) { ctx := context.Background() cli, err := client.NewEnvClient() @@ -447,6 +453,7 @@ func DockerContainerCreate(ID string, config container.Config, hostconfig contai return resp, err } +// DockerContainerStart will run an existing container. func DockerContainerStart(ID string, options types.ContainerStartOptions) error { ctx := context.Background() cli, err := client.NewEnvClient() @@ -460,6 +467,9 @@ func DockerContainerStart(ID string, options types.ContainerStartOptions) error return err } +// DockerContainerLogs will synchronously (blocking, non-concurrently) print +// logs to stdout and stderr, useful for quick containers with a small amount +// of output which are expected to exit quickly. func DockerContainerLogs(ID string) ([]byte, error) { ctx := context.Background() cli, err := client.NewEnvClient() diff --git a/service/interface/interface.go b/service/interface/interface.go index 4cc100a6..5f59c000 100644 --- a/service/interface/interface.go +++ b/service/interface/interface.go @@ -235,7 +235,7 @@ func (Service *Service) Stop() error { return nil } -// Stop will stop the container. +// Remove will stop the container. func (Service *Service) Remove() error { discrete, _ := Service.GetFieldBool("discrete") diff --git a/service/interface/types.go b/service/interface/types.go index a177e547..d044d838 100644 --- a/service/interface/types.go +++ b/service/interface/types.go @@ -6,6 +6,14 @@ import ( "github.com/docker/docker/api/types/network" ) +// Params is an arbitrary struct to pass around configuration from the top +// level to the lowest level - such as variable input to one of the +// containers. +type Params struct { + // Domain is the target domain for Pygmy to use. + Domain string +} + // DockerService is the requirements for a Docker container to be compatible. // The Service struct is used to implement this interface, and individual // variables of type Service can/have overwritten them when logic deems diff --git a/service/library/library.go b/service/library/library.go index 6918c4d6..188b0dd6 100644 --- a/service/library/library.go +++ b/service/library/library.go @@ -17,6 +17,9 @@ type Config struct { // Keys are the paths to the Keys which should be added. Keys []string `yaml:"Keys"` + // Domain is the default domain suffix to use. + Domain string `yaml:"domain"` + // Services is a []model.Service for an index of all Services. Services map[string]model.Service `yaml:"services"` diff --git a/service/library/setup.go b/service/library/setup.go index 9a014a08..2572a7e8 100644 --- a/service/library/setup.go +++ b/service/library/setup.go @@ -74,6 +74,9 @@ func Setup(c *Config) { // Set default value for default inheritance: viper.SetDefault("defaults", true) + // Set the default domain. + viper.SetDefault("domain", "docker.amazee.io") + // Resolvers don't have hard defaults defined which // are mergable. So we set them in viper before // unmarshalling the config so that config specified @@ -84,15 +87,15 @@ func Setup(c *Config) { var ResolvMacOS = resolv.Resolv{ Data: "# Generated by amazeeio pygmy\nnameserver 127.0.0.1\nport 6053\n", Enabled: true, - File: "docker.amazee.io", + File: c.Domain, Folder: "/etc/resolver", Name: "MacOS Resolver", } var ResolvLinux = resolv.Resolv{ - Data: "# Generated by amazeeio pygmy\n[Resolve]\nDNS=127.0.0.1:6053\nDomains=docker.amazee.io\n", + Data: fmt.Sprintf("# Generated by amazeeio pygmy\n[Resolve]\nDNS=127.0.0.1:6053\nDomains=%s\n", c.Domain), Enabled: true, - File: "docker.amazee.io.conf", + File: fmt.Sprintf("%s.conf", c.Domain), Folder: "/usr/lib/systemd/resolved.conf.d", Name: "Linux Resolver", } @@ -127,9 +130,9 @@ func Setup(c *Config) { ImportDefaults(c, "amazeeio-ssh-agent", agent.New()) ImportDefaults(c, "amazeeio-ssh-agent-add-key", key.NewAdder()) - ImportDefaults(c, "amazeeio-dnsmasq", dnsmasq.New()) - ImportDefaults(c, "amazeeio-haproxy", haproxy.New()) - ImportDefaults(c, "amazeeio-mailhog", mailhog.New()) + ImportDefaults(c, "amazeeio-dnsmasq", dnsmasq.New(&model.Params{Domain: c.Domain})) + ImportDefaults(c, "amazeeio-haproxy", haproxy.New(&model.Params{Domain: c.Domain})) + ImportDefaults(c, "amazeeio-mailhog", mailhog.New(&model.Params{Domain: c.Domain})) // We need Port 80 to be configured by default. // If a port on amazeeio-haproxy isn't explicitly declared, diff --git a/service/library/status.go b/service/library/status.go index ee2c7b41..2c433a71 100644 --- a/service/library/status.go +++ b/service/library/status.go @@ -6,6 +6,7 @@ import ( "github.com/fubarhouse/pygmy-go/service/color" "github.com/fubarhouse/pygmy-go/service/endpoint" + model "github.com/fubarhouse/pygmy-go/service/interface" "github.com/fubarhouse/pygmy-go/service/interface/docker" "github.com/fubarhouse/pygmy-go/service/resolv" . "github.com/logrusorgru/aurora" @@ -76,10 +77,10 @@ func Status(c Config) { for _, resolver := range c.Resolvers { r := resolv.Resolv{Name: resolver.Name, Data: resolver.Data, Folder: resolver.Folder, File: resolver.File} - if s := r.Status(); s { + if s := r.Status(&model.Params{Domain: c.Domain}); s { color.Print(Green(fmt.Sprintf("[*] Resolv %v is properly connected\n", resolver.Name))) } else { - color.Print(Red(fmt.Sprintf("[ ] Resolv %v is not properly conected\n", resolver.Name))) + color.Print(Red(fmt.Sprintf("[ ] Resolv %v is not properly connected\n", resolver.Name))) } } diff --git a/service/library/up.go b/service/library/up.go index 270db6b8..3e66652f 100644 --- a/service/library/up.go +++ b/service/library/up.go @@ -7,6 +7,7 @@ import ( "github.com/fubarhouse/pygmy-go/service/color" "github.com/fubarhouse/pygmy-go/service/endpoint" + model "github.com/fubarhouse/pygmy-go/service/interface" "github.com/fubarhouse/pygmy-go/service/interface/docker" . "github.com/logrusorgru/aurora" ) @@ -121,8 +122,8 @@ func Up(c Config) { } for _, resolver := range c.Resolvers { - if !resolver.Status() { - resolver.Configure() + if !resolver.Status(&model.Params{Domain: c.Domain}) { + resolver.Configure(&model.Params{Domain: c.Domain}) } } diff --git a/service/library/version_state.go b/service/library/version_state.go index 806a7e67..a4c6ceb2 100644 --- a/service/library/version_state.go +++ b/service/library/version_state.go @@ -2,6 +2,8 @@ package library import "fmt" +// PYGMY_VERSION is the equivalent to the version pygmy is being associated to. +// This variable is exclusively used when packaging a formal release. var PYGMY_VERSION = "" func printversion() bool { diff --git a/service/mailhog/mailhog.go b/service/mailhog/mailhog.go index 89996e9d..e22c7a88 100644 --- a/service/mailhog/mailhog.go +++ b/service/mailhog/mailhog.go @@ -1,6 +1,8 @@ package mailhog import ( + "fmt" + "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/network" "github.com/docker/go-connections/nat" @@ -8,7 +10,7 @@ import ( ) // New will provide the standard object for the mailhog container. -func New() model.Service { +func New(c *model.Params) model.Service { return model.Service{ Config: container.Config{ User: "0", @@ -21,7 +23,7 @@ func New() model.Service { "MH_UI_BIND_ADDR=0.0.0.0:80", "MH_API_BIND_ADDR=0.0.0.0:80", "AMAZEEIO=AMAZEEIO", - "AMAZEEIO_URL=mailhog.docker.amazee.io", + fmt.Sprintf("AMAZEEIO_URL=mailhog.%s", c.Domain), }, Image: "mailhog/mailhog", Labels: map[string]string{ @@ -29,7 +31,7 @@ func New() model.Service { "pygmy.enable": "true", "pygmy.name": "amazeeio-mailhog", "pygmy.network": "amazeeio-network", - "pygmy.url": "http://mailhog.docker.amazee.io", + "pygmy.url": fmt.Sprintf("http://mailhog.%s", c.Domain), "pygmy.weight": "15", }, }, diff --git a/service/mailhog/mailhog_test.go b/service/mailhog/mailhog_test.go index 2a882d80..a40dabd4 100644 --- a/service/mailhog/mailhog_test.go +++ b/service/mailhog/mailhog_test.go @@ -5,18 +5,19 @@ import ( "testing" "github.com/docker/go-connections/nat" + model "github.com/fubarhouse/pygmy-go/service/interface" "github.com/fubarhouse/pygmy-go/service/mailhog" . "github.com/smartystreets/goconvey/convey" ) func Example() { - mailhog.New() + mailhog.New(&model.Params{}) mailhog.NewDefaultPorts() } func Test(t *testing.T) { Convey("MailHog: Field equality tests...", t, func() { - obj := mailhog.New() + obj := mailhog.New(&model.Params{Domain: "docker.amazee.io"}) objPorts := mailhog.NewDefaultPorts() So(obj.Config.User, ShouldEqual, "0") So(obj.Config.Image, ShouldEqual, "mailhog/mailhog") diff --git a/service/resolv/resolv.go b/service/resolv/resolv.go index 0baad3c0..6d4c2738 100644 --- a/service/resolv/resolv.go +++ b/service/resolv/resolv.go @@ -11,6 +11,7 @@ import ( "strings" "github.com/fubarhouse/pygmy-go/service/color" + model "github.com/fubarhouse/pygmy-go/service/interface" . "github.com/logrusorgru/aurora" ) @@ -32,7 +33,7 @@ func run(args []string) error { // this function: // * sudo ifconfig lo0 alias 172.16.172.16 // * sudo killall mDNSResponder -func (resolv Resolv) Configure() { +func (resolv Resolv) Configure(c *model.Params) { var cmdOut []byte var tmpFile *os.File @@ -40,7 +41,7 @@ func (resolv Resolv) Configure() { if !resolv.Enabled { return } - if resolv.Status() { + if resolv.Status(c) { color.Print(Green(fmt.Sprintf("Already configured resolvr %s\n", resolv.Name))) } else { fullPath := fmt.Sprintf("%v%v%v", resolv.Folder, string(os.PathSeparator), resolv.File) @@ -118,7 +119,7 @@ func (resolv Resolv) Configure() { } } - if resolv.Status() { + if resolv.Status(c) { color.Print(Green(fmt.Sprintf("Successfully configured resolvr %s\n", resolv.Name))) } } @@ -197,7 +198,7 @@ func (resolv Resolv) Clean() { // Status is an exported state function which will check the file contents // matches Data on Linux, or return the result of three independent checks // on MacOS including the file, network and data checks. -func (resolv Resolv) Status() bool { +func (resolv Resolv) Status(c *model.Params) bool { if runtime.GOOS == "darwin" { return resolv.statusFile() && resolv.statusNet() && resolv.statusFileData() @@ -246,10 +247,12 @@ func (resolv Resolv) statusFile() bool { // This has completely ruled that situation out. func (resolv Resolv) statusNet() bool { ifConfigCmd := exec.Command("/bin/sh", "-c", "ifconfig lo0") - if out, ifConfigErr := ifConfigCmd.Output(); ifConfigErr != nil { + out, ifConfigErr := ifConfigCmd.Output() + + if ifConfigErr != nil { fmt.Println(ifConfigErr.Error()) return false - } else { - return strings.Contains(string(out), "172.16.172.16") } + + return strings.Contains(string(out), "172.16.172.16") } diff --git a/service/resolv/resolvWin.go b/service/resolv/resolvWin.go index cfff9ca3..4267f35b 100644 --- a/service/resolv/resolvWin.go +++ b/service/resolv/resolvWin.go @@ -8,6 +8,8 @@ import ( "os/exec" "strings" "sync" + + model "github.com/fubarhouse/pygmy-go/service/interface" ) // run will run a shell command and is not exported. @@ -52,22 +54,22 @@ func (resolv Resolv) Clean() { fmt.Println(error.Error()) } } -func (resolv Resolv) Configure() { +func (resolv Resolv) Configure(c *model.Params) { if resolv.Enabled { - _, error := run([]string{"Set-ItemProperty -Path HKLM:\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters -Name Domain -Value docker.amazee.io"}) + _, error := run([]string{fmt.Sprintf("Set-ItemProperty -Path HKLM:\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters -Name Domain -Value %s", c.Domain)}) if error != nil { fmt.Println(error.Error()) } } } -func (resolv Resolv) Status() bool { +func (resolv Resolv) Status(c *model.Params) bool { data, error := run([]string{"Get-ItemProperty -Path HKLM:\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"}) if error != nil { return false } for _, v := range strings.Split(string(data), "\n") { - if strings.HasPrefix(v, "Domain") && strings.Contains(v, "docker.amazee.io") { + if strings.HasPrefix(v, "Domain") && strings.Contains(v, c.Domain) { return true } } diff --git a/service/ssh/agent/ssh_agent.go b/service/ssh/agent/ssh_agent.go index c196ad2c..85f8e8fd 100644 --- a/service/ssh/agent/ssh_agent.go +++ b/service/ssh/agent/ssh_agent.go @@ -38,7 +38,7 @@ func New() model.Service { } } -// SshKeyLister will grab the output of all running containers with the proper +// List will grab the output of all running containers with the proper // config after starting them, and return it. // which is indicated by the purpose tag. func List(service model.Service) ([]byte, error) {