Skip to content

Commit

Permalink
Change provisioners to return an exec.Cmd in preparation for k3s
Browse files Browse the repository at this point in the history
  • Loading branch information
ColinChartier committed Aug 20, 2019
1 parent 42c5cef commit 85a9ba2
Show file tree
Hide file tree
Showing 12 changed files with 108 additions and 153 deletions.
24 changes: 15 additions & 9 deletions commands/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import (
"fmt"
"github.com/distributed-containers-inc/sanic/bridge/git"
"github.com/distributed-containers-inc/sanic/config"
"github.com/distributed-containers-inc/sanic/provisioners"
"github.com/distributed-containers-inc/sanic/provisioners/provisioner"
"github.com/distributed-containers-inc/sanic/shell"
"github.com/distributed-containers-inc/sanic/util"
"github.com/pkg/errors"
"github.com/urfave/cli"
"io/ioutil"
"math/rand"
Expand Down Expand Up @@ -138,25 +139,30 @@ func runTemplater(folderIn, folderOut, templaterImage, namespace string) error {
return nil
}

func createNamespace(namespace string, provisioner provisioners.Provisioner) error {
cmd := exec.Command("kubectl", "--kubeconfig", provisioner.KubeConfigLocation(), "create", "namespace", namespace)
func createNamespace(namespace string, provisioner provisioner.Provisioner) error {
cmd, err := provisioner.KubectlCommand("create", "namespace", namespace)
if err != nil {
return errors.Wrapf(err, "error creating namespace %s", namespace)
}
out := &bytes.Buffer{}
cmd.Stdout = out
cmd.Stderr = out
err := cmd.Run()
err = cmd.Run()
if err != nil && !strings.Contains(out.String(), "AlreadyExists") {
return fmt.Errorf(strings.TrimSpace(out.String()))
return errors.New(strings.TrimSpace(out.String()))
}
return nil
}

func kubectlApplyFolder(folder string, provisioner provisioners.Provisioner) error {
args := []string{"--kubeconfig", provisioner.KubeConfigLocation(), "apply", "-f", folder}
cmd := exec.Command("kubectl", args...)
func kubectlApplyFolder(folder string, provisioner provisioner.Provisioner) error {
cmd, err := provisioner.KubectlCommand("apply", "-f", folder)
if err != nil {
return errors.Wrapf(err, "error while applying folder %s", folder)
}
out := &bytes.Buffer{}
cmd.Stdout = out
cmd.Stderr = out
err := cmd.Run()
err = cmd.Run()
if err != nil {
return fmt.Errorf(strings.TrimSpace(out.String()))
}
Expand Down
22 changes: 9 additions & 13 deletions commands/enter.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ package commands
import (
"bytes"
"fmt"
"github.com/pkg/errors"
"github.com/urfave/cli"
"os"
"os/exec"
"strings"
"syscall"
)
Expand All @@ -15,25 +15,18 @@ func enterCommandAction(cliContext *cli.Context) error {
return newUsageError(cliContext)
}

kubeExecutableLocation, err := exec.LookPath("kubectl")
if err != nil {
return cli.NewExitError(fmt.Sprintf("could not find kubectl, is it installed? %s", err.Error()), 1)
}

provisioner, err := getProvisioner()
if err != nil {
return cli.NewExitError(err.Error(), 1)
}
kubeConfigLocation := provisioner.KubeConfigLocation()
if _, err := os.Stat(kubeConfigLocation); os.IsNotExist(err) {
return cli.NewExitError("the kubernetes configuration doesn't exist yet, use sanic deploy first if in localdev", 1)
cmd, err := provisioner.KubectlCommand("get", "pods", "-o", "jsonpath={.items[*].metadata.name}")
if err != nil {
return errors.Wrap(err, "error while getting kubernetes pods")
}
cmd := exec.Command("kubectl", "get", "pods", "-o", "jsonpath={.items[*].metadata.name}")
stdout := &bytes.Buffer{}
stderr := &bytes.Buffer{}
cmd.Stdout = stdout
cmd.Stderr = stderr
cmd.Env = append(os.Environ(), "KUBECONFIG="+kubeConfigLocation)
err = cmd.Run()
if err != nil {
fmt.Fprint(os.Stderr, stderr.String())
Expand Down Expand Up @@ -62,10 +55,13 @@ func enterCommandAction(cliContext *cli.Context) error {
1)
}

env, err := getKubectlEnvironment()
cmd, err = provisioner.KubectlCommand("exec", "-it", filteredPodNames[0], "bash")
if err != nil {
return cli.NewExitError(err.Error(), 1)
}

return cli.NewExitError(
syscall.Exec(kubeExecutableLocation, []string{"kubectl", "exec", "-it", filteredPodNames[0], "bash"}, env).Error(),
syscall.Exec(cmd.Path, cmd.Args, cmd.Env).Error(),
1)
}

Expand Down
25 changes: 7 additions & 18 deletions commands/kubectl.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
package commands

import (
"fmt"
"github.com/distributed-containers-inc/sanic/config"
"github.com/distributed-containers-inc/sanic/shell"
"github.com/urfave/cli"
"os"
"os/exec"
"syscall"
)

Expand All @@ -25,29 +22,21 @@ func kubectlCommandAction(cliContext *cli.Context) error {
if err != nil {
return cli.NewExitError(err.Error(), 1)
}
kubeConfigLocation := provisioner.KubeConfigLocation()
if _, err := os.Stat(kubeConfigLocation); os.IsNotExist(err) {
return cli.NewExitError("the kubernetes configuration doesn't exist yet, use sanic deploy first", 1)
}
kubeExecutableLocation, err := exec.LookPath("kubectl")
if err != nil {
return cli.NewExitError(fmt.Sprintf("could not find kubectl, is it installed? %s", err.Error()), 1)
}

env, err := getKubectlEnvironment()
if err != nil {
return cli.NewExitError(err.Error(), 1)
}

args := []string{kubeExecutableLocation}
args := []string{}
if env, err := cfg.CurrentEnvironment(s); err == nil {
if env.Namespace != "" {
args = append(args, "--namespace="+env.Namespace)
}
}

args = append(args, cliContext.Args()...)
cmd, err := provisioner.KubectlCommand(args...)
if err != nil {
return cli.NewExitError(err.Error(), 1)
}

err = syscall.Exec(kubeExecutableLocation, args, env)
err = syscall.Exec(cmd.Path, cmd.Args, cmd.Env)
if err != nil {
return cli.NewExitError(err.Error(), 1)
}
Expand Down
16 changes: 2 additions & 14 deletions commands/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import (
"fmt"
"github.com/distributed-containers-inc/sanic/config"
"github.com/distributed-containers-inc/sanic/provisioners"
"github.com/distributed-containers-inc/sanic/provisioners/provisioner"
"github.com/distributed-containers-inc/sanic/shell"
"github.com/urfave/cli"
"os"
)

func newUsageError(ctx *cli.Context) error {
Expand All @@ -21,19 +21,7 @@ func newUsageError(ctx *cli.Context) error {
1)
}

func getKubectlEnvironment() ([]string, error) {
provisioner, err := getProvisioner()
if err != nil {
return nil, err
}
kubeConfigLocation := provisioner.KubeConfigLocation()
if _, err := os.Stat(kubeConfigLocation); os.IsNotExist(err) {
return nil, errors.New("the kubernetes configuration doesn't exist yet, use sanic deploy first if in localdev")
}
return append(os.Environ(), "KUBECONFIG="+kubeConfigLocation), nil
}

func getProvisioner() (provisioners.Provisioner, error) {
func getProvisioner() (provisioner.Provisioner, error) {
s, err := shell.Current()
if err != nil {
return nil, err
Expand Down
44 changes: 5 additions & 39 deletions provisioners/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,59 +2,25 @@

import (
"fmt"
"github.com/distributed-containers-inc/sanic/provisioners/dummy"
"github.com/distributed-containers-inc/sanic/provisioners/external"
"github.com/distributed-containers-inc/sanic/provisioners/localdev"
"github.com/distributed-containers-inc/sanic/provisioners/provisioner"
)

//Provisioner is an interface which represents a way to deploy kubernetes services.
type Provisioner interface {
//EnsureCluster checks if the cluster exists and is configured correctly. Otherwise, it prompts the user
//with instructions on how to set up the cluster.
EnsureCluster() error

//KubeConfigLocation returns where the absolute path to where the configuration file is placed for this provisioner
//Note: it might not necessarily exist
KubeConfigLocation() string

//Registry returns:
// - registryAddr: the registry to push to, e.g., registry.example.com:3000, or "" if none is defined
// - registryInsecure: whether the registry uses HTTP (currently only used in localdev)
Registry() (registryAddr string, registryInsecure bool, err error)

//EdgeNodes returns a list of hostnames or IP addresses that will expose the edge nodes (where the ingress controllers are hosted)
EdgeNodes() ([]string, error)

//InClusterDir is the primary mechanism for live mounting:
//It returns where the specified host folder is synchronized in all of the kubernetes nodes
//If a provisioner does not support live mounting, or has an error, it should return a descriptive error string
//I.e., if your sanic project is at /home/user/project, and provisioner is localdev, this returns /hosthome/project
InClusterDir(hostDir string) string
}

type provisionerBuilder func(map[string]string) Provisioner
type provisionerBuilder func(map[string]string) provisioner.Provisioner

var provisionerBuilders = map[string]provisionerBuilder{
"dummy": func(args map[string]string) Provisioner {
return &dummy.ProvisionerDummy{}
},
"external": func(args map[string]string) Provisioner {
"external": func(args map[string]string) provisioner.Provisioner {
return external.Create(args)
},
"localdev": func(args map[string]string) Provisioner {
"localdev": func(args map[string]string) provisioner.Provisioner {
return &localdev.ProvisionerLocalDev{}
},
}

type provisionerConfigValidator func(map[string]string) error

var provisionerValidators = map[string]provisionerConfigValidator{
"dummy": func(args map[string]string) error {
for k := range args {
return fmt.Errorf("dummy takes no arguments, got %s", k)
}
return nil
},
"external": func(args map[string]string) error {
return external.ValidateConfig(args)
},
Expand Down Expand Up @@ -82,7 +48,7 @@ func GetProvisionerNames() []string {
}

//GetProvisioner returns the provisioner for the current environment
func GetProvisioner(provisionerName string, provisionerArgs map[string]string) Provisioner {
func GetProvisioner(provisionerName string, provisionerArgs map[string]string) provisioner.Provisioner {
return provisionerBuilders[provisionerName](provisionerArgs)
}

Expand Down
42 changes: 0 additions & 42 deletions provisioners/dummy/dummy.go

This file was deleted.

15 changes: 13 additions & 2 deletions provisioners/external/external.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package external
import (
"fmt"
"github.com/distributed-containers-inc/sanic/util"
"github.com/pkg/errors"
"os"
"os/exec"
"strings"
)

Expand All @@ -19,8 +21,17 @@ func (provisioner *ProvisionerExternal) EnsureCluster() error {
return nil
}

func (provisioner *ProvisionerExternal) KubeConfigLocation() string {
return provisioner.kubeConfigLocation
//KubectlCommand for external just returns a provisioner that has KUBECONFIG pointing to the configured directory
func (provisioner *ProvisionerExternal) KubectlCommand(args ...string) (*exec.Cmd, error) {
cmd := exec.Command("kubectl", args...)

kubeconfig := provisioner.kubeConfigLocation
if _, err := os.Stat(kubeconfig); err != nil {
return nil, errors.Wrapf(err, "could not find the kubeconfig at %s for this environment", kubeconfig)
}

cmd.Env = append(os.Environ(), "KUBECONFIG="+kubeconfig)
return cmd, nil
}

func (provisioner *ProvisionerExternal) Registry() (registryAddr string, registryInsecure bool, err error) {
Expand Down
9 changes: 5 additions & 4 deletions provisioners/localdev/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,20 @@ func clusterMasterNodes() ([]kindnode.Node, error) {
}

func (provisioner *ProvisionerLocalDev) checkClusterReady() error {
cmd := exec.Command(
"kubectl",
"--kubeconfig="+provisioner.KubeConfigLocation(),
cmd, err := provisioner.KubectlCommand(
"get",
"nodes",
"-o",
"jsonpath={.items..status.conditions[-1:].lastTransitionTime}\t{.items..status.conditions[-1:].status}",
)
if err != nil {
return err
}
stdout := &bytes.Buffer{}
stderr := &bytes.Buffer{}
cmd.Stdout = stdout
cmd.Stderr = stderr
err := cmd.Run()
err = cmd.Run()
if err != nil {
return fmt.Errorf("could not check if the cluster was running: %s %s", err.Error(), stderr.String())
}
Expand Down
9 changes: 5 additions & 4 deletions provisioners/localdev/ingress.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"fmt"
"github.com/distributed-containers-inc/sanic/util"
"os"
"os/exec"
)

const traefikIngressYaml = `
Expand Down Expand Up @@ -99,13 +98,15 @@ spec:
`

func (provisioner *ProvisionerLocalDev) startIngressController(ctx context.Context) error {
cmd := exec.Command("kubectl", "apply", "-f", "-")
cmd.Env = append(os.Environ(), "KUBECONFIG="+provisioner.KubeConfigLocation())
cmd, err := provisioner.KubectlCommand("apply", "-f", "-")
if err != nil {
return err
}
cmd.Stdin = bytes.NewBufferString(traefikIngressYaml)
errBuffer := &bytes.Buffer{}
cmd.Stdout = os.Stdout
cmd.Stderr = errBuffer
err := cmd.Start()
err = cmd.Start()
if err != nil {
return err
}
Expand Down
Loading

0 comments on commit 85a9ba2

Please sign in to comment.