Exemplo n.º 1
0
func ensureSCCExists(ns string, serviceAccountName string) error {
	binary, err := exec.LookPath("oc")
	if err != nil {
		// no openshift so ignore
		return nil
	}

	text, err := getCommandOutputString(binary, []string{"export", "scc", serviceAccountName}, os.Stdin)
	if err != nil {
		log.Debug("Failed to get SecurityContextConstraints %s. %s", serviceAccountName, err)
	}
	if err != nil || len(text) == 0 {
		text = `
apiVersion: v1
kind: SecurityContextConstraints
groups:
- system:cluster-admins
- system:nodes
metadata:
  creationTimestamp: null
  name: ` + serviceAccountName + `
runAsUser:
  type: RunAsAny
seLinuxContext:
  type: RunAsAny
supplementalGroups:
  type: RunAsAny
users:
`
	}
	// lets ensure there's a users section
	if !strings.Contains(text, "\nusers:") {
		text = text + "\nusers:\n"
	}

	line := "system:serviceaccount:" + ns + ":" + serviceAccountName

	if strings.Contains(text, line) {
		log.Info("No need to modify SecurityContextConstraints as it already contains line for namespace %s and service account %s", ns, serviceAccountName)
		return nil
	}

	text = text + "\n- " + line + "\n"
	log.Debug("created SecurityContextConstraints YAML: %s", text)

	log.Info("Applying changes for SecurityContextConstraints %s for namespace %s and ServiceAccount %s", serviceAccountName, ns, serviceAccountName)
	reader := bytes.NewReader([]byte(text))
	err = runCommand(binary, []string{"apply", "-f", "-"}, reader)
	if err != nil {
		log.Err("Failed to update OpenShift SecurityContextConstraints named %s. %s", serviceAccountName, err)
	}
	return err
}
Exemplo n.º 2
0
func forwardPort(conn net.Conn, address string) {
	client, err := net.Dial("tcp", address)
	if err != nil {
		log.Err("Dial failed: %v", err)
	}
	log.Info("Connected to localhost %v\n", conn)
	go func() {
		defer client.Close()
		defer conn.Close()
		io.Copy(client, conn)
	}()
	go func() {
		defer client.Close()
		defer conn.Close()
		io.Copy(conn, client)
	}()
}
Exemplo n.º 3
0
func forwardPortLoop(name string, address string, forwardAddress string) error {
	log.Info("forwarding port %s %s => %s", name, address, forwardAddress)
	listener, err := net.Listen("tcp", address)
	if err != nil {
		return err
	}

	log.Info("About to start the acceptor goroutine!")
	go func() {
		for {
			conn, err := listener.Accept()
			if err != nil {
				log.Err("Failed to accept listener: %v", err)
			}
			log.Info("Accepted connection %v\n", conn)
			go forwardPort(conn, forwardAddress)
		}
	}()
	return nil
}
Exemplo n.º 4
0
// Run runs a remote command on a given host to test out SSH / WinRM
func Run(c *cli.Context) {
	port, err := osExpandAndVerifyGlobal(c, "port")
	if err != nil {
		fail(err)
	}
	command, err := osExpandAndVerify(c, "command")
	if err != nil {
		fail(err)
	}
	host, err := osExpandAndVerify(c, "host")
	if err != nil {
		fail(err)
	}
	user, err := osExpandAndVerify(c, "user")
	if err != nil {
		fail(err)
	}
	connection := c.String("connection")
	if connection == ansible.ConnectionWinRM {
		password, err := osExpandAndVerify(c, "password")
		if err != nil {
			fail(err)
		}
		err = winrm.RemoteWinRmCommand(user, password, host, port, command)
	} else {
		privatekey, err := osExpandAndVerify(c, "privatekey")
		if err != nil {
			fail(err)
		}
		envVars := make(map[string]string)
		err = ssh.RemoteSSHCommand(user, privatekey, host, port, command, envVars)
	}
	if err != nil {
		log.Err("Failed: %v", err)
	}
}
Exemplo n.º 5
0
		}
		host = os.ExpandEnv(host)
		if host == "" {
			log.Die("Host is required")
		}
		user = os.ExpandEnv(user)
		if user == "" {
			log.Die("User is required")
		}
		if connection == ansible.ConnectionWinRM {
			password = os.ExpandEnv(password)
			if password == "" {
				log.Die("Password is required")
			}
			err := winrm.RemoteWinRmCommand(user, password, host, strconv.Itoa(sshPort), command, nil, nil, "")
			if err != nil {
				log.Err("Failed: %v", err)
			}
		} else {
			privatekey = os.ExpandEnv(privatekey)
			if privatekey == "" {
				log.Die("Private key is required")
			}
			err := ssh.RemoteSSHCommand(user, privatekey, host, strconv.Itoa(sshPort), command, nil)
			if err != nil {
				log.Err("Failed: %v", err)
			}
		}
	},
}
Exemplo n.º 6
0
		if len(command) == 0 {
			command = os.Getenv(ansible.EnvCommand)
		}
		if len(command) == 0 {
			plural := ""
			if len(commandEnvVars) > 1 {
				plural = "s"
			}
			log.Die("Could not find a command to execute from the environment variable%s: %s", plural, strings.Join(commandEnvVars, ", "))
		}

		bash := os.ExpandEnv(bash)
		if len(bash) > 0 {
			err = generateBashScript(bash, connection)
			if err != nil {
				log.Err("Failed to generate bash script at %s due to: %v", bash, err)
				return
			}
		}

		if connection == ansible.ConnectionWinRM {
			password := hostEntry.Password
			if len(password) == 0 {
				password = os.ExpandEnv(passwordFlag)
				if password == "" {
					log.Die("Cannot connect without a password")
				}
			}
			err = winrm.RemoteWinRmCommand(user, password, host, port, command, kubeclient, rc, hostEntry.Name)
		} else {
			privatekey := hostEntry.PrivateKey
Exemplo n.º 7
0
func main() {
	app := cli.NewApp()
	app.Name = "kansible"
	app.Usage = `Kansible

Kansible orchestrates processes in the same way as you orchestrate Docker containers with Kubernetes.

Once you have created an Ansible playbook to install and configure your software you can use Kansible to create
a Kubernetes Replication Controller to run, scale and manage the processes providing a universal view in Kubernetes
of all your containers and processes along with common scaling, high availability, service discovery and load balancing.

More help is here: https://github.com/fabric8io/kansible/blob/master/README.md`
	app.Version = version
	app.EnableBashCompletion = true
	app.After = func(c *cli.Context) error {
		if log.ErrorState {
			return errors.New("Exiting with errors")
		}

		return nil
	}

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "port",
			Value: "22",
			Usage: "The port for the remote SSH connection",
		},
		cli.BoolFlag{
			Name:  "debug",
			Usage: "Enable verbose debugging output",
		},
	}

	app.CommandNotFound = func(c *cli.Context, command string) {
		log.Err("No matching command '%s'", command)
		cli.ShowAppHelp(c)
		log.Die("")
	}

	app.Commands = []cli.Command{
		{
			Name:        "rc",
			Usage:       "Creates or updates the kansible ReplicationController for some hosts in an Ansible inventory.",
			Description: `This commmand will analyse the hosts in an Ansible inventory and creates or updates the ReplicationController for the kansible pods.`,
			ArgsUsage:   "[hosts] [command]",
			Action:      cmds.RC,
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "inventory",
					Value: "inventory",
					Usage: "The location of your Ansible inventory file",
				},
				cli.StringFlag{
					Name:  "rc",
					Value: "rc.yml",
					Usage: "The YAML file of the ReplicationController for the supervisors",
				},
			},
		},
		{
			Name:        "pod",
			Usage:       "Runs the kansible pod which owns a host from the Ansible inventory then runs a remote command on the host.",
			Description: `This commmand will pick an available host from the Ansible inventory, then run a remote command on that host.`,
			ArgsUsage:   "[hosts] [command]",
			Action:      cmds.Pod,
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "inventory",
					Value: "inventory",
					Usage: "The location of your Ansible inventory file",
				},
				cli.StringFlag{
					Name:  "rc",
					Value: "$KANSIBLE_RC",
					Usage: "The name of the ReplicationController for the supervisors",
				},
				cli.StringFlag{
					Name:  "password",
					Value: "$KANSIBLE_PASSWORD",
					Usage: "The password used for WinRM connections",
				},
				cli.StringFlag{
					Name:  "connection",
					Usage: "The Ansible connection type to use. Defaults to SSH unless 'winrm' is defined to use WinRM on Windows",
				},
				cli.StringFlag{
					Name:  "bash",
					Value: "$KANSIBLE_BASH",
					Usage: "If specified a script is generated for running a bash like shell on the remote machine",
				},
			},
		},
		{
			Name:        "run",
			Usage:       "Runs a remote command on a given host to test out SSH / WinRM",
			Description: `This commmand will begin running the supervisor on an avaiable host.`,
			ArgsUsage:   "[string]",
			Action:      cmds.Run,
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "user",
					Value: "$KANSIBLE_USER",
					Usage: "The user to use on the remote connection",
				},
				cli.StringFlag{
					Name:  "privatekey",
					Value: "$KANSIBLE_PRIVATEKEY",
					Usage: "The private key used for SSH",
				},
				cli.StringFlag{
					Name:  "host",
					Value: "$KANSIBLE_HOST",
					Usage: "The host for the remote connection",
				},
				cli.StringFlag{
					Name:  "command",
					Value: "$KANSIBLE_COMMAND",
					Usage: "The remote command to invoke on the host",
				},
				cli.StringFlag{
					Name:  "password",
					Usage: "The password if using WinRM to execute the command",
				},
				cli.StringFlag{
					Name:  "connection",
					Usage: "The Ansible connection type to use. Defaults to SSH unless 'winrm' is defined to use WinRM on Windows",
				},
			},
		},
	}

	app.Before = func(c *cli.Context) error {
		log.IsDebugging = c.Bool("debug")
		return nil
	}

	app.RunAndExitOnError()
}
Exemplo n.º 8
0
// Pod runs the kansible pod for a given group of hosts in an Ansible playbook
// this grabs a specific host (using annotations on the RC) then runs a remote command
// on that host binding stdin, stdout, stderr to the remote process
func Pod(c *cli.Context) {
	args := c.Args()
	if len(args) < 1 {
		log.Die("Expected arguments [hosts] [command]")
	}
	hosts := os.ExpandEnv(args[0])
	command := ""
	if len(args) > 1 {
		command = os.ExpandEnv(strings.Join(args[1:], " "))
	}

	f := cmdutil.NewFactory(nil)
	if f == nil {
		log.Die("Failed to create Kubernetes client factory!")
	}
	kubeclient, _ := f.Client()
	if kubeclient == nil {
		log.Die("Failed to create Kubernetes client!")
	}
	ns, _, _ := f.DefaultNamespace()
	if len(ns) == 0 {
		ns = "default"
	}

	inventory, err := osExpandAndVerify(c, "inventory")
	if err != nil {
		fail(err)
	}
	rcName, err := osExpandAndVerify(c, "rc")
	if err != nil {
		fail(err)
	}
	envVars := make(map[string]string)
	hostEntry, err := ansible.ChooseHostAndPrivateKey(inventory, hosts, kubeclient, ns, rcName, envVars)
	if err != nil {
		fail(err)
	}
	host := hostEntry.Host
	user := hostEntry.User
	port := hostEntry.Port
	if len(port) == 0 {
		port, err = osExpandAndVerifyGlobal(c, "port")
	}
	if err != nil {
		fail(err)
	}

	connection := hostEntry.Connection
	if len(connection) == 0 {
		connection = osExpand(c, "connection")
	}

	runCommand := hostEntry.RunCommand
	if len(runCommand) != 0 {
		command = runCommand
	}

	commandEnvVars := []string{}
	if len(command) == 0 {
		if len(connection) > 0 {
			envVarName := ansible.EnvCommand + "_" + strings.ToUpper(connection)
			commandEnvVars = append(commandEnvVars, envVarName)
			command = os.Getenv(envVarName)
		}
	}
	commandEnvVars = append(commandEnvVars, ansible.EnvCommand)
	if len(command) == 0 {
		command = os.Getenv(ansible.EnvCommand)
	}
	if len(command) == 0 {
		plural := ""
		if len(commandEnvVars) > 1 {
			plural = "s"
		}
		fail(fmt.Errorf("Could not find a command to execute from the environment variable%s: %s", plural, strings.Join(commandEnvVars, ", ")))
	}

	log.Info("running command on a host from %s and command `%s`", hosts, command)
	bash := osExpand(c, "bash")
	if len(bash) > 0 {
		err = generateBashScript(bash, connection)
		if err != nil {
			log.Err("Failed to generate bash script at %s due to: %v", bash, err)
		}
	}

	log.Info("using connection %s", connection)
	if connection == ansible.ConnectionWinRM {
		log.Info("Using WinRM to connect to the hosts %s", hosts)
		password := hostEntry.Password
		if len(password) == 0 {
			password, err = osExpandAndVerify(c, "password")
			if err != nil {
				fail(err)
			}
		}
		err = winrm.RemoteWinRmCommand(user, password, host, port, command)
	} else {
		privatekey := hostEntry.PrivateKey

		err = ssh.RemoteSSHCommand(user, privatekey, host, port, command, envVars)
	}
	if err != nil {
		log.Err("Failed: %v", err)
	}
}