<commit_before>package main

import (
	"bufio"
	"crypto/rand"
	"encoding/hex"
	"fmt"
	"github.com/dotcloud/docker/pkg/beam"
	"github.com/dotcloud/docker/pkg/beam/data"
	"github.com/dotcloud/docker/pkg/dockerscript"
	"github.com/dotcloud/docker/pkg/term"
	"io"
	"net"
	"net/url"
	"os"
	"os/exec"
	"path"
	"strings"
	"sync"
)

func main() {
	devnull, err := Devnull()
	if err != nil {
		Fatal(err)
	}
	defer devnull.Close()
	if term.IsTerminal(0) {
		input := bufio.NewScanner(os.Stdin)
		for {
			os.Stdout.Write([]byte("beamsh> "))
			if !input.Scan() {
				break
			}
			line := input.Text()
			if len(line) != 0 {
				cmd, err := dockerscript.Parse(strings.NewReader(line))
				if err != nil {
					fmt.Fprintf(os.Stderr, "error: %v\n", err)
					continue
				}
				executeScript(devnull, cmd)
			}
			if err := input.Err(); err == io.EOF {
				break
			} else if err != nil {
				Fatal(err)
			}
		}
	} else {
		script, err := dockerscript.Parse(os.Stdin)
		if err != nil {
			Fatal("parse error: %v\n", err)
		}
		executeScript(devnull, script)
	}
}

func beamCopy(dst *net.UnixConn, src *net.UnixConn) error {
	for {
		payload, attachment, err := beam.Receive(src)
		if err == io.EOF {
			return nil
		} else if err != nil {
			return err
		}
		if err := beam.Send(dst, payload, attachment); err != nil {
			if attachment != nil {
				attachment.Close()
			}
			return err
		}
	}
	panic("impossibru!")
	return nil
}

type Handler func([]string, *net.UnixConn, *net.UnixConn)

func Devnull() (*net.UnixConn, error) {
	priv, pub, err := beam.USocketPair()
	if err != nil {
		return nil, err
	}
	go func() {
		defer priv.Close()
		for {
			payload, attachment, err := beam.Receive(priv)
			if err != nil {
				return
			}
			fmt.Fprintf(os.Stderr, "[devnull] discarding '%s'\n", data.Message(string(payload)).Pretty())
			if attachment != nil {
				attachment.Close()
			}
		}
	}()
	return pub, nil
}

func scriptString(script []*dockerscript.Command) string {
	lines := make([]string, 0, len(script))
	for _, cmd := range script {
		line := strings.Join(cmd.Args, " ")
		if len(cmd.Children) > 0 {
			line += fmt.Sprintf(" { %s }", scriptString(cmd.Children))
		} else {
			line += " {}"
		}
		lines = append(lines, line)
	}
	return fmt.Sprintf("'%s'", strings.Join(lines, "; "))
}

func executeScript(client *net.UnixConn, script []*dockerscript.Command) error {
	Debugf("executeScript(%s)\n", scriptString(script))
	defer Debugf("executeScript(%s) DONE\n", scriptString(script))
	for _, cmd := range script {
		if err := executeCommand(client, cmd); err != nil {
			return err
		}
	}
	return nil
}

//	1) Find a handler for the command (if no handler, fail)
//	2) Attach new in & out pair to the handler
//	3) [in the background] Copy handler output to our own output
//	4) [in the background] Run the handler
//	5) Recursively executeScript() all children commands and wait for them to complete
//	6) Wait for handler to return and (shortly afterwards) output copy to complete
//	7)
func executeCommand(client *net.UnixConn, cmd *dockerscript.Command) error {
	Debugf("executeCommand(%s)\n", strings.Join(cmd.Args, " "))
	defer Debugf("executeCommand(%s) DONE\n", strings.Join(cmd.Args, " "))
	handler := GetHandler(cmd.Args[0])
	if handler == nil {
		return fmt.Errorf("no such command: %s", cmd.Args[0])
	}
	inPub, inPriv, err := beam.USocketPair()
	if err != nil {
		return err
	}
	// Don't close inPub here. We close it to signify the end of input once
	// all children are completed (guaranteeing that no more input will be sent
	// by children).
	// Otherwise we get a deadlock.
	defer inPriv.Close()
	outPub, outPriv, err := beam.USocketPair()
	if err != nil {
		return err
	}
	defer outPub.Close()
	// don't close outPriv here. It must be closed after the handler is called,
	// but before the copy tasks associated with it completes.
	// Otherwise we get a deadlock.
	var tasks sync.WaitGroup
	tasks.Add(2)
	go func() {
		handler(cmd.Args, inPriv, outPriv)
		// FIXME: do we need to outPriv.sync before closing it?
		Debugf("[%s] handler returned, closing output\n", strings.Join(cmd.Args, " "))
		outPriv.Close()
		tasks.Done()
	}()
	go func() {
		Debugf("[%s] copy start...\n", strings.Join(cmd.Args, " "))
		beamCopy(client, outPub)
		Debugf("[%s] copy done\n", strings.Join(cmd.Args, " "))
		tasks.Done()
	}()
	// depth-first execution of children commands
	// executeScript() blocks until all commands are completed
	executeScript(inPub, cmd.Children)
	inPub.Close()
	Debugf("[%s] waiting for handler and output copy to complete...\n", strings.Join(cmd.Args, " "))
	tasks.Wait()
	Debugf("[%s] handler and output copy complete!\n", strings.Join(cmd.Args, " "))
	return nil
}

func randomId() string {
	id := make([]byte, 4)
	io.ReadFull(rand.Reader, id)
	return hex.EncodeToString(id)
}

func GetHandler(name string) Handler {
	if name == "exec" {
		return func(args []string, in *net.UnixConn, out *net.UnixConn) {
			cmd := exec.Command(args[1], args[2:]...)
			outR, outW, err := os.Pipe()
			if err != nil {
				return
			}
			cmd.Stdout = outW
			errR, errW, err := os.Pipe()
			if err != nil {
				return
			}
			cmd.Stderr = errW
			beam.Send(out, data.Empty().Set("cmd", "log", "stdout").Bytes(), outR)
			beam.Send(out, data.Empty().Set("cmd", "log", "stderr").Bytes(), errR)
			execErr := cmd.Run()
			var status string
			if execErr != nil {
				status = execErr.Error()
			} else {
				status = "ok"
			}
			beam.Send(out, data.Empty().Set("status", status).Set("cmd", args...).Bytes(), nil)
		}
	} else if name == "trace" {
		return func(args []string, in *net.UnixConn, out *net.UnixConn) {
			for {
				p, a, err := beam.Receive(in)
				if err != nil {
					return
				}
				var msg string
				if pretty := data.Message(string(p)).Pretty(); pretty != "" {
					msg = pretty
				} else {
					msg = string(p)
				}
				if a != nil {
					msg = fmt.Sprintf("%s [%d]", msg, a.Fd())
				}
				fmt.Printf("===> %s\n", msg)
				beam.Send(out, p, a)
			}
		}
	} else if name == "emit" {
		return func(args []string, in *net.UnixConn, out *net.UnixConn) {
			beam.Send(out, data.Empty().Set("foo", args[1:]...).Bytes(), nil)
		}
	} else if name == "print" {
		return func(args []string, in *net.UnixConn, out *net.UnixConn) {
			for {
				_, a, err := beam.Receive(in)
				if err != nil {
					return
				}
				if a != nil {
					io.Copy(os.Stdout, a)
				}
			}
		}
	} else if name == "multiprint" {
		return func(args []string, in *net.UnixConn, out *net.UnixConn) {
			var tasks sync.WaitGroup
			for {
				payload, a, err := beam.Receive(in)
				if err != nil {
					return
				}
				if a != nil {
					tasks.Add(1)
					go func(payload []byte, attachment *os.File) {
						defer tasks.Done()
						msg := data.Message(string(payload))
						input := bufio.NewScanner(attachment)
						for input.Scan() {
							fmt.Printf("[%s] %s\n", msg.Pretty(), input.Text())
						}
					}(payload, a)
				}
			}
			tasks.Wait()
		}
	} else if name == "listen" {
		return func(args []string, in *net.UnixConn, out *net.UnixConn) {
			if len(args) != 2 {
				beam.Send(out, data.Empty().Set("status", "1").Set("message", "wrong number of arguments").Bytes(), nil)
				return
			}
			u, err := url.Parse(args[1])
			if err != nil {
				beam.Send(out, data.Empty().Set("status", "1").Set("message", err.Error()).Bytes(), nil)
				return
			}
			l, err := net.Listen(u.Scheme, u.Host)
			if err != nil {
				beam.Send(out, data.Empty().Set("status", "1").Set("message", err.Error()).Bytes(), nil)
				return
			}
			for {
				conn, err := l.Accept()
				if err != nil {
					beam.Send(out, data.Empty().Set("status", "1").Set("message", err.Error()).Bytes(), nil)
					return
				}
				var f *os.File
				if connWithFile, ok := conn.(interface { File() (*os.File, error) }); !ok {
					conn.Close()
					continue
				} else {
					f, err = connWithFile.File()
					if err != nil {
						conn.Close()
						continue
					}
				}
				beam.Send(out, data.Empty().Set("type", "socket").Set("remoteaddr", conn.RemoteAddr().String()).Bytes(), f)
			}
		}
	} else if name == "connect" {
		return func(args []string, in *net.UnixConn, out *net.UnixConn) {
			if len(args) != 2 {
				beam.Send(out, data.Empty().Set("status", "1").Set("message", "wrong number of arguments").Bytes(), nil)
				return
			}
			u, err := url.Parse(args[1])
			if err != nil {
				beam.Send(out, data.Empty().Set("status", "1").Set("message", err.Error()).Bytes(), nil)
				return
			}
			var tasks sync.WaitGroup
			for {
				_, attachment, err := beam.Receive(in)
				if err != nil {
					break
				}
				if attachment == nil {
					continue
				}
				Logf("connecting to %s/%s\n", u.Scheme, u.Host)
				conn, err := net.Dial(u.Scheme, u.Host)
				if err != nil {
					beam.Send(out, data.Empty().Set("cmd", "msg", "connect error: " + err.Error()).Bytes(), nil)
					return
				}
				beam.Send(out, data.Empty().Set("cmd", "msg", "connection established").Bytes(), nil)
				tasks.Add(1)
				go func(attachment *os.File, conn net.Conn) {
					defer tasks.Done()
					// even when successful, conn.File() returns a duplicate,
					// so we must close the original
					var iotasks sync.WaitGroup
					iotasks.Add(2)
					go func(attachment *os.File, conn net.Conn) {
						defer iotasks.Done()
						io.Copy(attachment, conn)
					}(attachment, conn)
					go func(attachment *os.File, conn net.Conn) {
						defer iotasks.Done()
						io.Copy(conn, attachment)
					}(attachment, conn)
					iotasks.Wait()
					conn.Close()
					attachment.Close()
				}(attachment, conn)
			}
			tasks.Wait()
		}
	} else if name == "openfile" {
		return func(args []string, in *net.UnixConn, out *net.UnixConn) {
			for _, name := range args {
				f, err := os.Open(name)
				if err != nil {
					continue
				}
				if err := beam.Send(out, data.Empty().Set("path", name).Set("type", "file").Bytes(), f); err != nil {
					f.Close()
				}
			}
		}
	}
	return nil
}

// 'status' is a notification of a job's status.
//
func parseEnv(args []string) ([]string, map[string]string) {
	var argsOut []string
	env := make(map[string]string)
	for _, word := range args[1:] {
		if strings.Contains(word, "=") {
			kv := strings.SplitN(word, "=", 2)
			key := kv[0]
			var val string
			if len(kv) == 2 {
				val = kv[1]
			}
			env[key] = val
		} else {
			argsOut = append(argsOut, word)
		}
	}
	return argsOut, env
}

type Msg struct {
	payload		[]byte
	attachment	*os.File
}

func Logf(msg string, args ...interface{}) (int, error) {
	if len(msg) == 0 || msg[len(msg) - 1] != '\n' {
		msg = msg + "\n"
	}
	msg = fmt.Sprintf("[%v] [%v] %s", os.Getpid(), path.Base(os.Args[0]), msg)
	return fmt.Printf(msg, args...)
}

func Debugf(msg string, args ...interface{}) {
	if os.Getenv("BEAMDEBUG") != "" {
		Logf(msg, args...)
	}
}

func Fatalf(msg string, args ...interface{})  {
	Logf(msg, args)
	os.Exit(1)
}

func Fatal(args ...interface{}) {
	Fatalf("%v", args[0])
}
<commit_msg>beam/examples/beamsh: utility function 'fileToConn'<commit_after>package main

import (
	"bufio"
	"crypto/rand"
	"encoding/hex"
	"fmt"
	"github.com/dotcloud/docker/pkg/beam"
	"github.com/dotcloud/docker/pkg/beam/data"
	"github.com/dotcloud/docker/pkg/dockerscript"
	"github.com/dotcloud/docker/pkg/term"
	"io"
	"net"
	"net/url"
	"os"
	"os/exec"
	"path"
	"strings"
	"sync"
)

func main() {
	devnull, err := Devnull()
	if err != nil {
		Fatal(err)
	}
	defer devnull.Close()
	if term.IsTerminal(0) {
		input := bufio.NewScanner(os.Stdin)
		for {
			os.Stdout.Write([]byte("beamsh> "))
			if !input.Scan() {
				break
			}
			line := input.Text()
			if len(line) != 0 {
				cmd, err := dockerscript.Parse(strings.NewReader(line))
				if err != nil {
					fmt.Fprintf(os.Stderr, "error: %v\n", err)
					continue
				}
				executeScript(devnull, cmd)
			}
			if err := input.Err(); err == io.EOF {
				break
			} else if err != nil {
				Fatal(err)
			}
		}
	} else {
		script, err := dockerscript.Parse(os.Stdin)
		if err != nil {
			Fatal("parse error: %v\n", err)
		}
		executeScript(devnull, script)
	}
}

func beamCopy(dst *net.UnixConn, src *net.UnixConn) error {
	for {
		payload, attachment, err := beam.Receive(src)
		if err == io.EOF {
			return nil
		} else if err != nil {
			return err
		}
		if err := beam.Send(dst, payload, attachment); err != nil {
			if attachment != nil {
				attachment.Close()
			}
			return err
		}
	}
	panic("impossibru!")
	return nil
}

type Handler func([]string, *net.UnixConn, *net.UnixConn)

func Devnull() (*net.UnixConn, error) {
	priv, pub, err := beam.USocketPair()
	if err != nil {
		return nil, err
	}
	go func() {
		defer priv.Close()
		for {
			payload, attachment, err := beam.Receive(priv)
			if err != nil {
				return
			}
			fmt.Fprintf(os.Stderr, "[devnull] discarding '%s'\n", data.Message(string(payload)).Pretty())
			if attachment != nil {
				attachment.Close()
			}
		}
	}()
	return pub, nil
}

func scriptString(script []*dockerscript.Command) string {
	lines := make([]string, 0, len(script))
	for _, cmd := range script {
		line := strings.Join(cmd.Args, " ")
		if len(cmd.Children) > 0 {
			line += fmt.Sprintf(" { %s }", scriptString(cmd.Children))
		} else {
			line += " {}"
		}
		lines = append(lines, line)
	}
	return fmt.Sprintf("'%s'", strings.Join(lines, "; "))
}

func executeScript(client *net.UnixConn, script []*dockerscript.Command) error {
	Debugf("executeScript(%s)\n", scriptString(script))
	defer Debugf("executeScript(%s) DONE\n", scriptString(script))
	for _, cmd := range script {
		if err := executeCommand(client, cmd); err != nil {
			return err
		}
	}
	return nil
}

//	1) Find a handler for the command (if no handler, fail)
//	2) Attach new in & out pair to the handler
//	3) [in the background] Copy handler output to our own output
//	4) [in the background] Run the handler
//	5) Recursively executeScript() all children commands and wait for them to complete
//	6) Wait for handler to return and (shortly afterwards) output copy to complete
//	7)
func executeCommand(client *net.UnixConn, cmd *dockerscript.Command) error {
	Debugf("executeCommand(%s)\n", strings.Join(cmd.Args, " "))
	defer Debugf("executeCommand(%s) DONE\n", strings.Join(cmd.Args, " "))
	handler := GetHandler(cmd.Args[0])
	if handler == nil {
		return fmt.Errorf("no such command: %s", cmd.Args[0])
	}
	inPub, inPriv, err := beam.USocketPair()
	if err != nil {
		return err
	}
	// Don't close inPub here. We close it to signify the end of input once
	// all children are completed (guaranteeing that no more input will be sent
	// by children).
	// Otherwise we get a deadlock.
	defer inPriv.Close()
	outPub, outPriv, err := beam.USocketPair()
	if err != nil {
		return err
	}
	defer outPub.Close()
	// don't close outPriv here. It must be closed after the handler is called,
	// but before the copy tasks associated with it completes.
	// Otherwise we get a deadlock.
	var tasks sync.WaitGroup
	tasks.Add(2)
	go func() {
		handler(cmd.Args, inPriv, outPriv)
		// FIXME: do we need to outPriv.sync before closing it?
		Debugf("[%s] handler returned, closing output\n", strings.Join(cmd.Args, " "))
		outPriv.Close()
		tasks.Done()
	}()
	go func() {
		Debugf("[%s] copy start...\n", strings.Join(cmd.Args, " "))
		beamCopy(client, outPub)
		Debugf("[%s] copy done\n", strings.Join(cmd.Args, " "))
		tasks.Done()
	}()
	// depth-first execution of children commands
	// executeScript() blocks until all commands are completed
	executeScript(inPub, cmd.Children)
	inPub.Close()
	Debugf("[%s] waiting for handler and output copy to complete...\n", strings.Join(cmd.Args, " "))
	tasks.Wait()
	Debugf("[%s] handler and output copy complete!\n", strings.Join(cmd.Args, " "))
	return nil
}

func randomId() string {
	id := make([]byte, 4)
	io.ReadFull(rand.Reader, id)
	return hex.EncodeToString(id)
}

func GetHandler(name string) Handler {
	if name == "exec" {
		return func(args []string, in *net.UnixConn, out *net.UnixConn) {
			cmd := exec.Command(args[1], args[2:]...)
			outR, outW, err := os.Pipe()
			if err != nil {
				return
			}
			cmd.Stdout = outW
			errR, errW, err := os.Pipe()
			if err != nil {
				return
			}
			cmd.Stderr = errW
			beam.Send(out, data.Empty().Set("cmd", "log", "stdout").Bytes(), outR)
			beam.Send(out, data.Empty().Set("cmd", "log", "stderr").Bytes(), errR)
			execErr := cmd.Run()
			var status string
			if execErr != nil {
				status = execErr.Error()
			} else {
				status = "ok"
			}
			beam.Send(out, data.Empty().Set("status", status).Set("cmd", args...).Bytes(), nil)
		}
	} else if name == "trace" {
		return func(args []string, in *net.UnixConn, out *net.UnixConn) {
			for {
				p, a, err := beam.Receive(in)
				if err != nil {
					return
				}
				var msg string
				if pretty := data.Message(string(p)).Pretty(); pretty != "" {
					msg = pretty
				} else {
					msg = string(p)
				}
				if a != nil {
					msg = fmt.Sprintf("%s [%d]", msg, a.Fd())
				}
				fmt.Printf("===> %s\n", msg)
				beam.Send(out, p, a)
			}
		}
	} else if name == "emit" {
		return func(args []string, in *net.UnixConn, out *net.UnixConn) {
			beam.Send(out, data.Empty().Set("foo", args[1:]...).Bytes(), nil)
		}
	} else if name == "print" {
		return func(args []string, in *net.UnixConn, out *net.UnixConn) {
			for {
				_, a, err := beam.Receive(in)
				if err != nil {
					return
				}
				if a != nil {
					io.Copy(os.Stdout, a)
				}
			}
		}
	} else if name == "multiprint" {
		return func(args []string, in *net.UnixConn, out *net.UnixConn) {
			var tasks sync.WaitGroup
			for {
				payload, a, err := beam.Receive(in)
				if err != nil {
					return
				}
				if a != nil {
					tasks.Add(1)
					go func(payload []byte, attachment *os.File) {
						defer tasks.Done()
						msg := data.Message(string(payload))
						input := bufio.NewScanner(attachment)
						for input.Scan() {
							fmt.Printf("[%s] %s\n", msg.Pretty(), input.Text())
						}
					}(payload, a)
				}
			}
			tasks.Wait()
		}
	} else if name == "listen" {
		return func(args []string, in *net.UnixConn, out *net.UnixConn) {
			if len(args) != 2 {
				beam.Send(out, data.Empty().Set("status", "1").Set("message", "wrong number of arguments").Bytes(), nil)
				return
			}
			u, err := url.Parse(args[1])
			if err != nil {
				beam.Send(out, data.Empty().Set("status", "1").Set("message", err.Error()).Bytes(), nil)
				return
			}
			l, err := net.Listen(u.Scheme, u.Host)
			if err != nil {
				beam.Send(out, data.Empty().Set("status", "1").Set("message", err.Error()).Bytes(), nil)
				return
			}
			for {
				conn, err := l.Accept()
				if err != nil {
					beam.Send(out, data.Empty().Set("status", "1").Set("message", err.Error()).Bytes(), nil)
					return
				}
				f, err := connToFile(conn)
				if err != nil {
					conn.Close()
					continue
				}
				beam.Send(out, data.Empty().Set("type", "socket").Set("remoteaddr", conn.RemoteAddr().String()).Bytes(), f)
			}
		}
	} else if name == "connect" {
		return func(args []string, in *net.UnixConn, out *net.UnixConn) {
			if len(args) != 2 {
				beam.Send(out, data.Empty().Set("status", "1").Set("message", "wrong number of arguments").Bytes(), nil)
				return
			}
			u, err := url.Parse(args[1])
			if err != nil {
				beam.Send(out, data.Empty().Set("status", "1").Set("message", err.Error()).Bytes(), nil)
				return
			}
			var tasks sync.WaitGroup
			for {
				_, attachment, err := beam.Receive(in)
				if err != nil {
					break
				}
				if attachment == nil {
					continue
				}
				Logf("connecting to %s/%s\n", u.Scheme, u.Host)
				conn, err := net.Dial(u.Scheme, u.Host)
				if err != nil {
					beam.Send(out, data.Empty().Set("cmd", "msg", "connect error: " + err.Error()).Bytes(), nil)
					return
				}
				beam.Send(out, data.Empty().Set("cmd", "msg", "connection established").Bytes(), nil)
				tasks.Add(1)
				go func(attachment *os.File, conn net.Conn) {
					defer tasks.Done()
					// even when successful, conn.File() returns a duplicate,
					// so we must close the original
					var iotasks sync.WaitGroup
					iotasks.Add(2)
					go func(attachment *os.File, conn net.Conn) {
						defer iotasks.Done()
						io.Copy(attachment, conn)
					}(attachment, conn)
					go func(attachment *os.File, conn net.Conn) {
						defer iotasks.Done()
						io.Copy(conn, attachment)
					}(attachment, conn)
					iotasks.Wait()
					conn.Close()
					attachment.Close()
				}(attachment, conn)
			}
			tasks.Wait()
		}
	} else if name == "openfile" {
		return func(args []string, in *net.UnixConn, out *net.UnixConn) {
			for _, name := range args {
				f, err := os.Open(name)
				if err != nil {
					continue
				}
				if err := beam.Send(out, data.Empty().Set("path", name).Set("type", "file").Bytes(), f); err != nil {
					f.Close()
				}
			}
		}
	}
	return nil
}

func connToFile(conn net.Conn) (f *os.File, err error) {
	if connWithFile, ok := conn.(interface { File() (*os.File, error) }); !ok {
		return nil, fmt.Errorf("no file descriptor available")
	} else {
		f, err = connWithFile.File()
		if err != nil {
			return nil, err
		}
	}
	return f, err
}

// 'status' is a notification of a job's status.
//
func parseEnv(args []string) ([]string, map[string]string) {
	var argsOut []string
	env := make(map[string]string)
	for _, word := range args[1:] {
		if strings.Contains(word, "=") {
			kv := strings.SplitN(word, "=", 2)
			key := kv[0]
			var val string
			if len(kv) == 2 {
				val = kv[1]
			}
			env[key] = val
		} else {
			argsOut = append(argsOut, word)
		}
	}
	return argsOut, env
}

type Msg struct {
	payload		[]byte
	attachment	*os.File
}

func Logf(msg string, args ...interface{}) (int, error) {
	if len(msg) == 0 || msg[len(msg) - 1] != '\n' {
		msg = msg + "\n"
	}
	msg = fmt.Sprintf("[%v] [%v] %s", os.Getpid(), path.Base(os.Args[0]), msg)
	return fmt.Printf(msg, args...)
}

func Debugf(msg string, args ...interface{}) {
	if os.Getenv("BEAMDEBUG") != "" {
		Logf(msg, args...)
	}
}

func Fatalf(msg string, args ...interface{})  {
	Logf(msg, args)
	os.Exit(1)
}

func Fatal(args ...interface{}) {
	Fatalf("%v", args[0])
}
<|endoftext|>


<commit_before>// Copyright 2018-2019 Authors of Cilium
//
// 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.

// +build privileged_tests

package loader

import (
	"context"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"
	"time"

	"github.com/cilium/cilium/pkg/testutils"

	"github.com/vishvananda/netlink"
	. "gopkg.in/check.v1"
)

// Hook up gocheck into the "go test" runner.
type LoaderTestSuite struct{}

var (
	_              = Suite(&LoaderTestSuite{})
	contextTimeout = 10 * time.Second

	dirInfo *directoryInfo
	ep      = testutils.NewTestEndpoint()
)

func Test(t *testing.T) {
	TestingT(t)
}

func (s *LoaderTestSuite) TearDownTest(c *C) {
	// Old map names as created by older versions of these tests
	//
	// FIXME GH-6701: Remove for 1.5.0
	os.Remove("/sys/fs/bpf/tc/globals/cilium_policy_foo")
	os.Remove("/sys/fs/bpf/tc/globals/cilium_calls_111")
	os.Remove("/sys/fs/bpf/tc/globals/cilium_ep_config_111")

	files, err := filepath.Glob("/sys/fs/bpf/tc/globals/test_*")
	if err != nil {
		panic(err)
	}
	for _, f := range files {
		if err := os.Remove(f); err != nil {
			panic(err)
		}
	}
}

// runTests configures devices for running the whole testsuite, and runs the
// tests. It is kept separate from TestMain() so that this function can defer
// cleanups and pass the exit code of the test run to the caller which can run
// os.Exit() with the result.
func runTests(m *testing.M) (int, error) {
	testIncludes = "-I/usr/include/x86_64-linux-gnu/"

	tmpDir, err := ioutil.TempDir("/tmp/", "cilium_")
	if err != nil {
		return 1, fmt.Errorf("Failed to create temporary directory: %s", err)
	}
	defer os.RemoveAll(tmpDir)
	if dirInfo, err = getDirs(tmpDir); err != nil {
		return 1, err
	}

	cleanup, err := prepareEnv(&ep)
	if err != nil {
		return 1, fmt.Errorf("Failed to prepare environment: %s", err)
	}
	defer func() {
		if err := cleanup(); err != nil {
			log.Errorf(err.Error())
		}
	}()

	return m.Run(), nil
}

func TestMain(m *testing.M) {
	exitCode, err := runTests(m)
	if err != nil {
		log.Fatal(err)
	}
	os.Exit(exitCode)
}

func prepareEnv(ep *testutils.TestEndpoint) (func() error, error) {
	link := netlink.Dummy{
		LinkAttrs: netlink.LinkAttrs{
			Name: ep.InterfaceName(),
		},
	}
	if err := netlink.LinkAdd(&link); err != nil {
		if !os.IsExist(err) {
			return nil, fmt.Errorf("Failed to add link: %s", err)
		}
	}
	cleanupFn := func() error {
		if err := netlink.LinkDel(&link); err != nil {
			return fmt.Errorf("Failed to delete link: %s", err)
		}
		return nil
	}
	return cleanupFn, nil
}

func getDirs(tmpDir string) (*directoryInfo, error) {
	wd, err := os.Getwd()
	if err != nil {
		return nil, fmt.Errorf("Failed to get working directory: %s", err)
	}
	bpfdir := filepath.Join(wd, "..", "..", "..", "bpf")
	dirs := directoryInfo{
		Library: bpfdir,
		Runtime: bpfdir,
		State:   bpfdir,
		Output:  tmpDir,
	}

	return &dirs, nil
}

// TestCompileAndLoad checks that the datapath can be compiled and loaded.
func (s *LoaderTestSuite) TestCompileAndLoad(c *C) {
	ctx, cancel := context.WithTimeout(context.Background(), contextTimeout)
	defer cancel()

	err := compileAndLoad(ctx, &ep, dirInfo)
	c.Assert(err, IsNil)
}

// TestReload compiles and attaches the datapath multiple times.
func (s *LoaderTestSuite) TestReload(c *C) {
	ctx, cancel := context.WithTimeout(context.Background(), contextTimeout)
	defer cancel()

	err := compileDatapath(ctx, &ep, dirInfo, true)
	c.Assert(err, IsNil)

	objPath := fmt.Sprintf("%s/%s", dirInfo.Output, endpointObj)
	err = replaceDatapath(ctx, ep.InterfaceName(), objPath, symbolFromEndpoint)
	c.Assert(err, IsNil)

	err = replaceDatapath(ctx, ep.InterfaceName(), objPath, symbolFromEndpoint)
	c.Assert(err, IsNil)
}

// TestCompileFailure attempts to compile then cancels the context and ensures
// that the failure paths may be hit.
func (s *LoaderTestSuite) TestCompileFailure(c *C) {
	ctx, cancel := context.WithTimeout(context.Background(), contextTimeout)
	defer cancel()

	exit := make(chan bool)
	defer close(exit)
	go func() {
		select {
		case <-time.After(100 * time.Millisecond):
			cancel()
		case <-exit:
			break
		}
	}()

	timeout := time.Now().Add(contextTimeout)
	var err error
	for err == nil && time.Now().Before(timeout) {
		err = compileAndLoad(ctx, &ep, dirInfo)
	}
	c.Assert(err, NotNil)
}

// BenchmarkCompileOnly benchmarks the just the entire compilation process.
func BenchmarkCompileOnly(b *testing.B) {
	ctx, cancel := context.WithTimeout(context.Background(), contextTimeout)
	defer cancel()

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		debug := false // Otherwise we compile lots more.
		if err := compileDatapath(ctx, &ep, dirInfo, debug); err != nil {
			b.Fatal(err)
		}
	}
}

// BenchmarkCompileAndLoad benchmarks the entire compilation + loading process.
func BenchmarkCompileAndLoad(b *testing.B) {
	ctx, cancel := context.WithTimeout(context.Background(), contextTimeout)
	defer cancel()

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		if err := compileAndLoad(ctx, &ep, dirInfo); err != nil {
			b.Fatal(err)
		}
	}
}

// BenchmarkReplaceDatapath compiles the datapath program, then benchmarks only
// the loading of the program into the kernel.
func BenchmarkReplaceDatapath(b *testing.B) {
	ctx, cancel := context.WithTimeout(context.Background(), contextTimeout)
	defer cancel()

	if err := compileDatapath(ctx, &ep, dirInfo, false); err != nil {
		b.Fatal(err)
	}
	objPath := fmt.Sprintf("%s/%s", dirInfo.Output, endpointObj)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		if err := replaceDatapath(ctx, ep.InterfaceName(), objPath, symbolFromEndpoint); err != nil {
			b.Fatal(err)
		}
	}
}
<commit_msg>loader: Update benchmark context timeout<commit_after>// Copyright 2018-2019 Authors of Cilium
//
// 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.

// +build privileged_tests

package loader

import (
	"context"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"
	"time"

	"github.com/cilium/cilium/pkg/testutils"

	"github.com/vishvananda/netlink"
	. "gopkg.in/check.v1"
)

// Hook up gocheck into the "go test" runner.
type LoaderTestSuite struct{}

var (
	_              = Suite(&LoaderTestSuite{})
	contextTimeout = 10 * time.Second
	benchTimeout   = 5*time.Minute + 5*time.Second

	dirInfo *directoryInfo
	ep      = testutils.NewTestEndpoint()
)

func Test(t *testing.T) {
	TestingT(t)
}

func (s *LoaderTestSuite) TearDownTest(c *C) {
	// Old map names as created by older versions of these tests
	//
	// FIXME GH-6701: Remove for 1.5.0
	os.Remove("/sys/fs/bpf/tc/globals/cilium_policy_foo")
	os.Remove("/sys/fs/bpf/tc/globals/cilium_calls_111")
	os.Remove("/sys/fs/bpf/tc/globals/cilium_ep_config_111")

	files, err := filepath.Glob("/sys/fs/bpf/tc/globals/test_*")
	if err != nil {
		panic(err)
	}
	for _, f := range files {
		if err := os.Remove(f); err != nil {
			panic(err)
		}
	}
}

// runTests configures devices for running the whole testsuite, and runs the
// tests. It is kept separate from TestMain() so that this function can defer
// cleanups and pass the exit code of the test run to the caller which can run
// os.Exit() with the result.
func runTests(m *testing.M) (int, error) {
	testIncludes = "-I/usr/include/x86_64-linux-gnu/"

	tmpDir, err := ioutil.TempDir("/tmp/", "cilium_")
	if err != nil {
		return 1, fmt.Errorf("Failed to create temporary directory: %s", err)
	}
	defer os.RemoveAll(tmpDir)
	if dirInfo, err = getDirs(tmpDir); err != nil {
		return 1, err
	}

	cleanup, err := prepareEnv(&ep)
	if err != nil {
		return 1, fmt.Errorf("Failed to prepare environment: %s", err)
	}
	defer func() {
		if err := cleanup(); err != nil {
			log.Errorf(err.Error())
		}
	}()

	return m.Run(), nil
}

func TestMain(m *testing.M) {
	exitCode, err := runTests(m)
	if err != nil {
		log.Fatal(err)
	}
	os.Exit(exitCode)
}

func prepareEnv(ep *testutils.TestEndpoint) (func() error, error) {
	link := netlink.Dummy{
		LinkAttrs: netlink.LinkAttrs{
			Name: ep.InterfaceName(),
		},
	}
	if err := netlink.LinkAdd(&link); err != nil {
		if !os.IsExist(err) {
			return nil, fmt.Errorf("Failed to add link: %s", err)
		}
	}
	cleanupFn := func() error {
		if err := netlink.LinkDel(&link); err != nil {
			return fmt.Errorf("Failed to delete link: %s", err)
		}
		return nil
	}
	return cleanupFn, nil
}

func getDirs(tmpDir string) (*directoryInfo, error) {
	wd, err := os.Getwd()
	if err != nil {
		return nil, fmt.Errorf("Failed to get working directory: %s", err)
	}
	bpfdir := filepath.Join(wd, "..", "..", "..", "bpf")
	dirs := directoryInfo{
		Library: bpfdir,
		Runtime: bpfdir,
		State:   bpfdir,
		Output:  tmpDir,
	}

	return &dirs, nil
}

// TestCompileAndLoad checks that the datapath can be compiled and loaded.
func (s *LoaderTestSuite) TestCompileAndLoad(c *C) {
	ctx, cancel := context.WithTimeout(context.Background(), contextTimeout)
	defer cancel()

	err := compileAndLoad(ctx, &ep, dirInfo)
	c.Assert(err, IsNil)
}

// TestReload compiles and attaches the datapath multiple times.
func (s *LoaderTestSuite) TestReload(c *C) {
	ctx, cancel := context.WithTimeout(context.Background(), contextTimeout)
	defer cancel()

	err := compileDatapath(ctx, &ep, dirInfo, true)
	c.Assert(err, IsNil)

	objPath := fmt.Sprintf("%s/%s", dirInfo.Output, endpointObj)
	err = replaceDatapath(ctx, ep.InterfaceName(), objPath, symbolFromEndpoint)
	c.Assert(err, IsNil)

	err = replaceDatapath(ctx, ep.InterfaceName(), objPath, symbolFromEndpoint)
	c.Assert(err, IsNil)
}

// TestCompileFailure attempts to compile then cancels the context and ensures
// that the failure paths may be hit.
func (s *LoaderTestSuite) TestCompileFailure(c *C) {
	ctx, cancel := context.WithTimeout(context.Background(), contextTimeout)
	defer cancel()

	exit := make(chan bool)
	defer close(exit)
	go func() {
		select {
		case <-time.After(100 * time.Millisecond):
			cancel()
		case <-exit:
			break
		}
	}()

	timeout := time.Now().Add(contextTimeout)
	var err error
	for err == nil && time.Now().Before(timeout) {
		err = compileAndLoad(ctx, &ep, dirInfo)
	}
	c.Assert(err, NotNil)
}

// BenchmarkCompileOnly benchmarks the just the entire compilation process.
func BenchmarkCompileOnly(b *testing.B) {
	ctx, cancel := context.WithTimeout(context.Background(), benchTimeout)
	defer cancel()

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		debug := false // Otherwise we compile lots more.
		if err := compileDatapath(ctx, &ep, dirInfo, debug); err != nil {
			b.Fatal(err)
		}
	}
}

// BenchmarkCompileAndLoad benchmarks the entire compilation + loading process.
func BenchmarkCompileAndLoad(b *testing.B) {
	ctx, cancel := context.WithTimeout(context.Background(), benchTimeout)
	defer cancel()

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		if err := compileAndLoad(ctx, &ep, dirInfo); err != nil {
			b.Fatal(err)
		}
	}
}

// BenchmarkReplaceDatapath compiles the datapath program, then benchmarks only
// the loading of the program into the kernel.
func BenchmarkReplaceDatapath(b *testing.B) {
	ctx, cancel := context.WithTimeout(context.Background(), benchTimeout)
	defer cancel()

	if err := compileDatapath(ctx, &ep, dirInfo, false); err != nil {
		b.Fatal(err)
	}
	objPath := fmt.Sprintf("%s/%s", dirInfo.Output, endpointObj)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		if err := replaceDatapath(ctx, ep.InterfaceName(), objPath, symbolFromEndpoint); err != nil {
			b.Fatal(err)
		}
	}
}
<|endoftext|>


<commit_before>package waiter

import (
	"context"
	"fmt"
	"sync"
	"time"

	"github.com/rebuy-de/kubernetes-deployment/pkg/kubeutil"
	log "github.com/sirupsen/logrus"
	v1meta "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/fields"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/pkg/apis/extensions/v1beta1"
)

var (
	ErrImagePullMuteDuration = 30 * time.Second
)

type DeploymentWaitInterceptor struct {
	client kubernetes.Interface

	ctx              context.Context
	cancel           context.CancelFunc
	waitgroup        *sync.WaitGroup
	errImagePullMute time.Time
}

func NewDeploymentWaitInterceptor(client kubernetes.Interface) *DeploymentWaitInterceptor {
	ctx, cancel := context.WithCancel(context.Background())

	return &DeploymentWaitInterceptor{
		client:           client,
		ctx:              ctx,
		cancel:           cancel,
		waitgroup:        new(sync.WaitGroup),
		errImagePullMute: time.Now(),
	}
}

func (dwi *DeploymentWaitInterceptor) PostApply([]runtime.Object) error {
	dwi.waitgroup.Wait()
	dwi.cancel()
	return nil
}

func (dwi *DeploymentWaitInterceptor) Close() error {
	dwi.cancel()
	return nil
}

func (dwi *DeploymentWaitInterceptor) PostManifestApply(obj runtime.Object) error {
	deployment, ok := obj.(*v1beta1.Deployment)
	if !ok {
		return nil
	}

	log.WithFields(log.Fields{
		"Manifest": deployment,
	}).Debugf("registering waiter for deployment")

	dwi.waitgroup.Add(1)
	go dwi.run(deployment)
	return nil
}

func (dwi *DeploymentWaitInterceptor) run(deployment *v1beta1.Deployment) {
	defer dwi.waitgroup.Done()

	ctx, done := context.WithCancel(dwi.ctx)
	defer done()

	// We need to sleep a short time to let the controller update the revision
	// number and then update the deployment to see the current revision.
	time.Sleep(1 * time.Second)
	deployment, err := dwi.client.
		Extensions().
		Deployments(deployment.ObjectMeta.Namespace).
		Get(deployment.ObjectMeta.Name, v1meta.GetOptions{})

	rs, err := kubeutil.GetReplicaSetForDeployment(dwi.client, deployment)
	if err != nil {
		log.WithFields(log.Fields{
			"Error":      err,
			"StackTrace": fmt.Sprintf("%+v", err),
		}).Warn("Failed to get replica set for deployment")
		return
	}

	log.WithFields(log.Fields{
		"Name":      rs.ObjectMeta.Name,
		"Namespace": rs.ObjectMeta.Namespace,
	}).Debugf("found replica set for deployment")

	dwi.waitgroup.Add(1)
	go dwi.podNotifier(ctx, rs)

	selector := fields.OneTermEqualSelector("metadata.name", deployment.ObjectMeta.Name)
	for deployment := range kubeutil.WatchDeployments(ctx, dwi.client, selector) {
		if kubeutil.DeploymentRolloutComplete(deployment) {
			break
		}
	}

	log.WithFields(log.Fields{
		"Name":      deployment.ObjectMeta.Name,
		"Namespace": deployment.ObjectMeta.Namespace,
	}).Debugf("deployment succeeded")
}

func (dwi *DeploymentWaitInterceptor) podNotifier(ctx context.Context, rs *v1beta1.ReplicaSet) {
	defer dwi.waitgroup.Done()

	for pod := range kubeutil.WatchPods(ctx, dwi.client, fields.Everything()) {
		if !kubeutil.IsOwner(rs.ObjectMeta, pod.ObjectMeta) {
			continue
		}

		log.WithFields(log.Fields{
			"Manifest": pod,
		}).Debugf("pod changed")

		err := kubeutil.PodWarnings(pod)

		_, ok := err.(kubeutil.ErrImagePull)
		if ok {
			if time.Now().Before(dwi.errImagePullMute) {
				continue
			}
			dwi.errImagePullMute = time.Now().Add(ErrImagePullMuteDuration)
		}

		if err != nil {
			log.WithFields(log.Fields{
				"Name":      pod.ObjectMeta.Name,
				"Namespace": pod.ObjectMeta.Namespace,
			}).Warn(err)
		}
	}
}
<commit_msg>add manifest to pod failure logs<commit_after>package waiter

import (
	"context"
	"fmt"
	"sync"
	"time"

	"github.com/rebuy-de/kubernetes-deployment/pkg/kubeutil"
	log "github.com/sirupsen/logrus"
	v1meta "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/fields"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/pkg/apis/extensions/v1beta1"
)

var (
	ErrImagePullMuteDuration = 30 * time.Second
)

type DeploymentWaitInterceptor struct {
	client kubernetes.Interface

	ctx              context.Context
	cancel           context.CancelFunc
	waitgroup        *sync.WaitGroup
	errImagePullMute time.Time
}

func NewDeploymentWaitInterceptor(client kubernetes.Interface) *DeploymentWaitInterceptor {
	ctx, cancel := context.WithCancel(context.Background())

	return &DeploymentWaitInterceptor{
		client:           client,
		ctx:              ctx,
		cancel:           cancel,
		waitgroup:        new(sync.WaitGroup),
		errImagePullMute: time.Now(),
	}
}

func (dwi *DeploymentWaitInterceptor) PostApply([]runtime.Object) error {
	dwi.waitgroup.Wait()
	dwi.cancel()
	return nil
}

func (dwi *DeploymentWaitInterceptor) Close() error {
	dwi.cancel()
	return nil
}

func (dwi *DeploymentWaitInterceptor) PostManifestApply(obj runtime.Object) error {
	deployment, ok := obj.(*v1beta1.Deployment)
	if !ok {
		return nil
	}

	log.WithFields(log.Fields{
		"Manifest": deployment,
	}).Debugf("registering waiter for deployment")

	dwi.waitgroup.Add(1)
	go dwi.run(deployment)
	return nil
}

func (dwi *DeploymentWaitInterceptor) run(deployment *v1beta1.Deployment) {
	defer dwi.waitgroup.Done()

	ctx, done := context.WithCancel(dwi.ctx)
	defer done()

	// We need to sleep a short time to let the controller update the revision
	// number and then update the deployment to see the current revision.
	time.Sleep(1 * time.Second)
	deployment, err := dwi.client.
		Extensions().
		Deployments(deployment.ObjectMeta.Namespace).
		Get(deployment.ObjectMeta.Name, v1meta.GetOptions{})

	rs, err := kubeutil.GetReplicaSetForDeployment(dwi.client, deployment)
	if err != nil {
		log.WithFields(log.Fields{
			"Error":      err,
			"StackTrace": fmt.Sprintf("%+v", err),
		}).Warn("Failed to get replica set for deployment")
		return
	}

	log.WithFields(log.Fields{
		"Name":      rs.ObjectMeta.Name,
		"Namespace": rs.ObjectMeta.Namespace,
	}).Debugf("found replica set for deployment")

	dwi.waitgroup.Add(1)
	go dwi.podNotifier(ctx, rs)

	selector := fields.OneTermEqualSelector("metadata.name", deployment.ObjectMeta.Name)
	for deployment := range kubeutil.WatchDeployments(ctx, dwi.client, selector) {
		if kubeutil.DeploymentRolloutComplete(deployment) {
			break
		}
	}

	log.WithFields(log.Fields{
		"Name":      deployment.ObjectMeta.Name,
		"Namespace": deployment.ObjectMeta.Namespace,
	}).Debugf("deployment succeeded")
}

func (dwi *DeploymentWaitInterceptor) podNotifier(ctx context.Context, rs *v1beta1.ReplicaSet) {
	defer dwi.waitgroup.Done()

	for pod := range kubeutil.WatchPods(ctx, dwi.client, fields.Everything()) {
		if !kubeutil.IsOwner(rs.ObjectMeta, pod.ObjectMeta) {
			continue
		}

		log.WithFields(log.Fields{
			"Manifest": pod,
		}).Debugf("pod changed")

		err := kubeutil.PodWarnings(pod)

		_, ok := err.(kubeutil.ErrImagePull)
		if ok {
			if time.Now().Before(dwi.errImagePullMute) {
				continue
			}
			dwi.errImagePullMute = time.Now().Add(ErrImagePullMuteDuration)
		}

		if err != nil {
			log.WithFields(log.Fields{
				"Name":      pod.ObjectMeta.Name,
				"Namespace": pod.ObjectMeta.Namespace,
				"PodData":   pod,
			}).Warn(err)
		}
	}
}
<|endoftext|>


<commit_before>package network

import (
	"errors"
	"fmt"
	"os"
	"os/signal"
	"syscall"
	"time"

	flag "github.com/spf13/pflag"

	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/apiserver/pkg/storage/names"
	kapi "k8s.io/kubernetes/pkg/api"
	kclientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"

	osclientcmd "github.com/openshift/origin/pkg/cmd/util/clientcmd"
	"github.com/openshift/origin/pkg/diagnostics/networkpod/util"
	"github.com/openshift/origin/pkg/diagnostics/types"
	networktypedclient "github.com/openshift/origin/pkg/network/generated/internalclientset/typed/network/internalversion"
)

const (
	NetworkDiagnosticName = "NetworkCheck"
)

// NetworkDiagnostic is a diagnostic that runs a network diagnostic pod and relays the results.
type NetworkDiagnostic struct {
	KubeClient           kclientset.Interface
	NetNamespacesClient  networktypedclient.NetNamespacesGetter
	ClusterNetworkClient networktypedclient.ClusterNetworksGetter
	ClientFlags          *flag.FlagSet
	Level                int
	Factory              *osclientcmd.Factory
	PreventModification  bool
	LogDir               string
	PodImage             string
	TestPodImage         string
	TestPodProtocol      string
	TestPodPort          int

	pluginName    string
	nodes         []kapi.Node
	nsName1       string
	nsName2       string
	globalnsName1 string
	globalnsName2 string
	res           types.DiagnosticResult
}

// Name is part of the Diagnostic interface and just returns name.
func (d *NetworkDiagnostic) Name() string {
	return NetworkDiagnosticName
}

// Description is part of the Diagnostic interface and provides a user-focused description of what the diagnostic does.
func (d *NetworkDiagnostic) Description() string {
	return "Create a pod on all schedulable nodes and run network diagnostics from the application standpoint"
}

// CanRun is part of the Diagnostic interface; it determines if the conditions are right to run this diagnostic.
func (d *NetworkDiagnostic) CanRun() (bool, error) {
	if d.PreventModification {
		return false, errors.New("running the network diagnostic pod is an API change, which is prevented as you indicated")
	} else if d.KubeClient == nil {
		return false, errors.New("must have kube client")
	} else if d.NetNamespacesClient == nil || d.ClusterNetworkClient == nil {
		return false, errors.New("must have openshift client")
	} else if _, err := d.getKubeConfig(); err != nil {
		return false, err
	}
	return true, nil
}

// Check is part of the Diagnostic interface; it runs the actual diagnostic logic
func (d *NetworkDiagnostic) Check() types.DiagnosticResult {
	d.res = types.NewDiagnosticResult(NetworkDiagnosticName)

	var err error
	var ok bool
	d.pluginName, ok, err = util.GetOpenShiftNetworkPlugin(d.ClusterNetworkClient)
	if err != nil {
		d.res.Error("DNet2001", err, fmt.Sprintf("Checking network plugin failed. Error: %s", err))
		return d.res
	}
	if !ok {
		d.res.Warn("DNet2002", nil, "Skipping network diagnostics check. Reason: Not using openshift network plugin.")
		return d.res
	}

	d.nodes, err = util.GetSchedulableNodes(d.KubeClient)
	if err != nil {
		d.res.Error("DNet2003", err, fmt.Sprintf("Fetching schedulable nodes failed. Error: %s", err))
		return d.res
	}
	if len(d.nodes) == 0 {
		d.res.Warn("DNet2004", nil, "Skipping network checks. Reason: No schedulable/ready nodes found.")
		return d.res
	}

	d.runNetworkDiagnostic()
	return d.res
}

func (d *NetworkDiagnostic) runNetworkDiagnostic() {
	// Do clean up if there is an interrupt/terminate signal while running network diagnostics
	c := make(chan os.Signal, 2)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
	go func() {
		<-c
		d.Cleanup()
	}()

	defer func() {
		d.Cleanup()
	}()
	// Setup test environment
	if err := d.TestSetup(); err != nil {
		d.res.Error("DNet2005", err, fmt.Sprintf("Setting up test environment for network diagnostics failed: %v", err))
		return
	}

	// Need to show summary at least
	loglevel := d.Level
	if loglevel > 2 {
		loglevel = 2
	}

	// Network diagnostics has 2 phases: Testing and Collection phase.
	// In Testing phase, various network related diagnostics are performed on every node and results are stored on the respective nodes.
	// In Collection phase, results from each node are moved to the user machine where the CLI cmd is executed.

	// TEST Phase: Run network diagnostic pod on all valid nodes in parallel
	command := fmt.Sprintf("openshift infra network-diagnostic-pod -l %d", loglevel)
	if err := d.runNetworkPod(command); err != nil {
		d.res.Error("DNet2006", err, err.Error())
		return
	}
	// Wait for network diagnostic pod completion (timeout: ~3 mins)
	backoff := wait.Backoff{Steps: 38, Duration: 500 * time.Millisecond, Factor: 1.1}
	if err := d.waitForNetworkPod(d.nsName1, util.NetworkDiagPodNamePrefix, backoff, []kapi.PodPhase{kapi.PodSucceeded, kapi.PodFailed}); err != nil {
		d.res.Error("DNet2007", err, err.Error())
		return
	}
	// Gather logs from network diagnostic pod on all valid nodes
	diagsFailed := false
	if err := d.CollectNetworkPodLogs(); err != nil {
		d.res.Error("DNet2008", err, err.Error())
		diagsFailed = true
	}

	// Collection Phase: Run network diagnostic pod on all valid nodes
	// Block the network diagnostic pod on every node so that results can be moved to the user machine.
	command = "sleep 1000"
	if err := d.runNetworkPod(command); err != nil {
		d.res.Error("DNet2009", err, err.Error())
		return
	}

	// Wait for network diagnostic pod to start (timeout: ~5 mins)
	backoff = wait.Backoff{Steps: 36, Duration: time.Second, Factor: 1.1}
	if err := d.waitForNetworkPod(d.nsName1, util.NetworkDiagPodNamePrefix, backoff, []kapi.PodPhase{kapi.PodRunning, kapi.PodFailed, kapi.PodSucceeded}); err != nil {
		d.res.Error("DNet2010", err, err.Error())
		// Do not bail out here, collect what ever info is available from all valid nodes
	}

	if err := d.CollectNetworkInfo(diagsFailed); err != nil {
		d.res.Error("DNet2011", err, err.Error())
	}

	if diagsFailed {
		d.res.Info("DNet2012", fmt.Sprintf("Additional info collected under %q for further analysis", d.LogDir))
	}
	return
}

func (d *NetworkDiagnostic) runNetworkPod(command string) error {
	for _, node := range d.nodes {
		podName := names.SimpleNameGenerator.GenerateName(fmt.Sprintf("%s-", util.NetworkDiagPodNamePrefix))

		pod := GetNetworkDiagnosticsPod(d.PodImage, command, podName, node.Name)
		_, err := d.KubeClient.Core().Pods(d.nsName1).Create(pod)
		if err != nil {
			return fmt.Errorf("Creating network diagnostic pod %q on node %q with command %q failed: %v", podName, node.Name, command, err)
		}
		d.res.Debug("DNet2013", fmt.Sprintf("Created network diagnostic pod %q on node %q with command: %q", podName, node.Name, command))
	}
	return nil
}
<commit_msg>NetworkCheck: handle interrupt<commit_after>package network

import (
	"errors"
	"fmt"
	"os"
	"os/signal"
	"syscall"
	"time"

	flag "github.com/spf13/pflag"

	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/apiserver/pkg/storage/names"
	kapi "k8s.io/kubernetes/pkg/api"
	kclientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"

	osclientcmd "github.com/openshift/origin/pkg/cmd/util/clientcmd"
	"github.com/openshift/origin/pkg/diagnostics/networkpod/util"
	"github.com/openshift/origin/pkg/diagnostics/types"
	networktypedclient "github.com/openshift/origin/pkg/network/generated/internalclientset/typed/network/internalversion"
)

const (
	NetworkDiagnosticName = "NetworkCheck"
)

// NetworkDiagnostic is a diagnostic that runs a network diagnostic pod and relays the results.
type NetworkDiagnostic struct {
	KubeClient           kclientset.Interface
	NetNamespacesClient  networktypedclient.NetNamespacesGetter
	ClusterNetworkClient networktypedclient.ClusterNetworksGetter
	ClientFlags          *flag.FlagSet
	Level                int
	Factory              *osclientcmd.Factory
	PreventModification  bool
	LogDir               string
	PodImage             string
	TestPodImage         string
	TestPodProtocol      string
	TestPodPort          int

	pluginName    string
	nodes         []kapi.Node
	nsName1       string
	nsName2       string
	globalnsName1 string
	globalnsName2 string
	res           types.DiagnosticResult
}

// Name is part of the Diagnostic interface and just returns name.
func (d *NetworkDiagnostic) Name() string {
	return NetworkDiagnosticName
}

// Description is part of the Diagnostic interface and provides a user-focused description of what the diagnostic does.
func (d *NetworkDiagnostic) Description() string {
	return "Create a pod on all schedulable nodes and run network diagnostics from the application standpoint"
}

// CanRun is part of the Diagnostic interface; it determines if the conditions are right to run this diagnostic.
func (d *NetworkDiagnostic) CanRun() (bool, error) {
	if d.PreventModification {
		return false, errors.New("running the network diagnostic pod is an API change, which is prevented as you indicated")
	} else if d.KubeClient == nil {
		return false, errors.New("must have kube client")
	} else if d.NetNamespacesClient == nil || d.ClusterNetworkClient == nil {
		return false, errors.New("must have openshift client")
	} else if _, err := d.getKubeConfig(); err != nil {
		return false, err
	}
	return true, nil
}

// Check is part of the Diagnostic interface; it runs the actual diagnostic logic
func (d *NetworkDiagnostic) Check() types.DiagnosticResult {
	d.res = types.NewDiagnosticResult(NetworkDiagnosticName)

	var err error
	var ok bool
	d.pluginName, ok, err = util.GetOpenShiftNetworkPlugin(d.ClusterNetworkClient)
	if err != nil {
		d.res.Error("DNet2001", err, fmt.Sprintf("Checking network plugin failed. Error: %s", err))
		return d.res
	}
	if !ok {
		d.res.Warn("DNet2002", nil, "Skipping network diagnostics check. Reason: Not using openshift network plugin.")
		return d.res
	}

	d.nodes, err = util.GetSchedulableNodes(d.KubeClient)
	if err != nil {
		d.res.Error("DNet2003", err, fmt.Sprintf("Fetching schedulable nodes failed. Error: %s", err))
		return d.res
	}
	if len(d.nodes) == 0 {
		d.res.Warn("DNet2004", nil, "Skipping network checks. Reason: No schedulable/ready nodes found.")
		return d.res
	}

	// Abort and clean up if there is an interrupt/terminate signal while running network diagnostics
	done := make(chan bool, 1)
	sig := make(chan os.Signal, 1)
	signal.Notify(sig, os.Interrupt, syscall.SIGTERM)
	go func() {
		<-sig
		d.res.Warn("DNet2014", nil, "Interrupt received; aborting network diagnostic.")
		done <- true
	}()
	go func() {
		d.runNetworkDiagnostic()
		done <- true
	}()
	<-done
	signal.Stop(sig)
	d.Cleanup()

	return d.res
}

func (d *NetworkDiagnostic) runNetworkDiagnostic() {
	// Setup test environment
	if err := d.TestSetup(); err != nil {
		d.res.Error("DNet2005", err, fmt.Sprintf("Setting up test environment for network diagnostics failed: %v", err))
		return
	}

	// Need to show summary at least
	loglevel := d.Level
	if loglevel > 2 {
		loglevel = 2
	}

	// Network diagnostics has 2 phases: Testing and Collection phase.
	// In Testing phase, various network related diagnostics are performed on every node and results are stored on the respective nodes.
	// In Collection phase, results from each node are moved to the user machine where the CLI cmd is executed.

	// TEST Phase: Run network diagnostic pod on all valid nodes in parallel
	command := fmt.Sprintf("openshift infra network-diagnostic-pod -l %d", loglevel)
	if err := d.runNetworkPod(command); err != nil {
		d.res.Error("DNet2006", err, err.Error())
		return
	}
	// Wait for network diagnostic pod completion (timeout: ~3 mins)
	backoff := wait.Backoff{Steps: 38, Duration: 500 * time.Millisecond, Factor: 1.1}
	if err := d.waitForNetworkPod(d.nsName1, util.NetworkDiagPodNamePrefix, backoff, []kapi.PodPhase{kapi.PodSucceeded, kapi.PodFailed}); err != nil {
		d.res.Error("DNet2007", err, err.Error())
		return
	}
	// Gather logs from network diagnostic pod on all valid nodes
	diagsFailed := false
	if err := d.CollectNetworkPodLogs(); err != nil {
		d.res.Error("DNet2008", err, err.Error())
		diagsFailed = true
	}

	// Collection Phase: Run network diagnostic pod on all valid nodes
	// Block the network diagnostic pod on every node so that results can be moved to the user machine.
	command = "sleep 1000"
	if err := d.runNetworkPod(command); err != nil {
		d.res.Error("DNet2009", err, err.Error())
		return
	}

	// Wait for network diagnostic pod to start (timeout: ~5 mins)
	backoff = wait.Backoff{Steps: 36, Duration: time.Second, Factor: 1.1}
	if err := d.waitForNetworkPod(d.nsName1, util.NetworkDiagPodNamePrefix, backoff, []kapi.PodPhase{kapi.PodRunning, kapi.PodFailed, kapi.PodSucceeded}); err != nil {
		d.res.Error("DNet2010", err, err.Error())
		// Do not bail out here, collect what ever info is available from all valid nodes
	}

	if err := d.CollectNetworkInfo(diagsFailed); err != nil {
		d.res.Error("DNet2011", err, err.Error())
	}

	if diagsFailed {
		d.res.Info("DNet2012", fmt.Sprintf("Additional info collected under %q for further analysis", d.LogDir))
	}
	return
}

func (d *NetworkDiagnostic) runNetworkPod(command string) error {
	for _, node := range d.nodes {
		podName := names.SimpleNameGenerator.GenerateName(fmt.Sprintf("%s-", util.NetworkDiagPodNamePrefix))

		pod := GetNetworkDiagnosticsPod(d.PodImage, command, podName, node.Name)
		_, err := d.KubeClient.Core().Pods(d.nsName1).Create(pod)
		if err != nil {
			return fmt.Errorf("Creating network diagnostic pod %q on node %q with command %q failed: %v", podName, node.Name, command, err)
		}
		d.res.Debug("DNet2013", fmt.Sprintf("Created network diagnostic pod %q on node %q with command: %q", podName, node.Name, command))
	}
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2015 The Kubernetes Authors.

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 hairpin

import (
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"path"
	"regexp"
	"strconv"

	"github.com/golang/glog"
	"k8s.io/kubernetes/pkg/util/exec"
)

const (
	sysfsNetPath            = "/sys/devices/virtual/net"
	brportRelativePath      = "brport"
	hairpinModeRelativePath = "hairpin_mode"
	hairpinEnable           = "1"
)

var (
	ethtoolOutputRegex = regexp.MustCompile("peer_ifindex: (\\d+)")
)

func SetUpContainerPid(containerPid int, containerInterfaceName string) error {
	pidStr := fmt.Sprintf("%d", containerPid)
	nsenterArgs := []string{"-t", pidStr, "-n"}
	return setUpContainerInternal(containerInterfaceName, pidStr, nsenterArgs)
}

func SetUpContainerPath(netnsPath string, containerInterfaceName string) error {
	if netnsPath[0] != '/' {
		return fmt.Errorf("netnsPath path '%s' was invalid", netnsPath)
	}
	nsenterArgs := []string{"-n", netnsPath}
	return setUpContainerInternal(containerInterfaceName, netnsPath, nsenterArgs)
}

func setUpContainerInternal(containerInterfaceName, containerDesc string, nsenterArgs []string) error {
	e := exec.New()
	hostIfName, err := findPairInterfaceOfContainerInterface(e, containerInterfaceName, containerDesc, nsenterArgs)
	if err != nil {
		glog.Infof("Unable to find pair interface, setting up all interfaces: %v", err)
		return setUpAllInterfaces()
	}
	return setUpInterface(hostIfName)
}

func findPairInterfaceOfContainerInterface(e exec.Interface, containerInterfaceName, containerDesc string, nsenterArgs []string) (string, error) {
	nsenterPath, err := e.LookPath("nsenter")
	if err != nil {
		return "", err
	}
	ethtoolPath, err := e.LookPath("ethtool")
	if err != nil {
		return "", err
	}

	nsenterArgs = append(nsenterArgs, "-F", "--", ethtoolPath, "--statistics", containerInterfaceName)
	output, err := e.Command(nsenterPath, nsenterArgs...).CombinedOutput()
	if err != nil {
		return "", fmt.Errorf("Unable to query interface %s of container %s: %v: %s", containerInterfaceName, containerDesc, err, string(output))
	}
	// look for peer_ifindex
	match := ethtoolOutputRegex.FindSubmatch(output)
	if match == nil {
		return "", fmt.Errorf("No peer_ifindex in interface statistics for %s of container %s", containerInterfaceName, containerDesc)
	}
	peerIfIndex, err := strconv.Atoi(string(match[1]))
	if err != nil { // seems impossible (\d+ not numeric)
		return "", fmt.Errorf("peer_ifindex wasn't numeric: %s: %v", match[1], err)
	}
	iface, err := net.InterfaceByIndex(peerIfIndex)
	if err != nil {
		return "", err
	}
	return iface.Name, nil
}

func setUpAllInterfaces() error {
	interfaces, err := net.Interfaces()
	if err != nil {
		return err
	}
	for _, netIf := range interfaces {
		setUpInterface(netIf.Name) // ignore errors
	}
	return nil
}

func setUpInterface(ifName string) error {
	glog.V(3).Infof("Enabling hairpin on interface %s", ifName)
	ifPath := path.Join(sysfsNetPath, ifName)
	if _, err := os.Stat(ifPath); err != nil {
		return err
	}
	brportPath := path.Join(ifPath, brportRelativePath)
	if _, err := os.Stat(brportPath); err != nil && os.IsNotExist(err) {
		// Device is not on a bridge, so doesn't need hairpin mode
		return nil
	}
	hairpinModeFile := path.Join(brportPath, hairpinModeRelativePath)
	return ioutil.WriteFile(hairpinModeFile, []byte(hairpinEnable), 0644)
}
<commit_msg>[hairpin] fix argument of nsenter<commit_after>/*
Copyright 2015 The Kubernetes Authors.

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 hairpin

import (
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"path"
	"regexp"
	"strconv"

	"github.com/golang/glog"
	"k8s.io/kubernetes/pkg/util/exec"
)

const (
	sysfsNetPath            = "/sys/devices/virtual/net"
	brportRelativePath      = "brport"
	hairpinModeRelativePath = "hairpin_mode"
	hairpinEnable           = "1"
)

var (
	ethtoolOutputRegex = regexp.MustCompile("peer_ifindex: (\\d+)")
)

func SetUpContainerPid(containerPid int, containerInterfaceName string) error {
	pidStr := fmt.Sprintf("%d", containerPid)
	nsenterArgs := []string{"-t", pidStr, "-n"}
	return setUpContainerInternal(containerInterfaceName, pidStr, nsenterArgs)
}

func SetUpContainerPath(netnsPath string, containerInterfaceName string) error {
	if netnsPath[0] != '/' {
		return fmt.Errorf("netnsPath path '%s' was invalid", netnsPath)
	}
	nsenterArgs := []string{"--net=" + netnsPath}
	return setUpContainerInternal(containerInterfaceName, netnsPath, nsenterArgs)
}

func setUpContainerInternal(containerInterfaceName, containerDesc string, nsenterArgs []string) error {
	e := exec.New()
	hostIfName, err := findPairInterfaceOfContainerInterface(e, containerInterfaceName, containerDesc, nsenterArgs)
	if err != nil {
		glog.Infof("Unable to find pair interface, setting up all interfaces: %v", err)
		return setUpAllInterfaces()
	}
	return setUpInterface(hostIfName)
}

func findPairInterfaceOfContainerInterface(e exec.Interface, containerInterfaceName, containerDesc string, nsenterArgs []string) (string, error) {
	nsenterPath, err := e.LookPath("nsenter")
	if err != nil {
		return "", err
	}
	ethtoolPath, err := e.LookPath("ethtool")
	if err != nil {
		return "", err
	}

	nsenterArgs = append(nsenterArgs, "-F", "--", ethtoolPath, "--statistics", containerInterfaceName)
	output, err := e.Command(nsenterPath, nsenterArgs...).CombinedOutput()
	if err != nil {
		return "", fmt.Errorf("Unable to query interface %s of container %s: %v: %s", containerInterfaceName, containerDesc, err, string(output))
	}
	// look for peer_ifindex
	match := ethtoolOutputRegex.FindSubmatch(output)
	if match == nil {
		return "", fmt.Errorf("No peer_ifindex in interface statistics for %s of container %s", containerInterfaceName, containerDesc)
	}
	peerIfIndex, err := strconv.Atoi(string(match[1]))
	if err != nil { // seems impossible (\d+ not numeric)
		return "", fmt.Errorf("peer_ifindex wasn't numeric: %s: %v", match[1], err)
	}
	iface, err := net.InterfaceByIndex(peerIfIndex)
	if err != nil {
		return "", err
	}
	return iface.Name, nil
}

func setUpAllInterfaces() error {
	interfaces, err := net.Interfaces()
	if err != nil {
		return err
	}
	for _, netIf := range interfaces {
		setUpInterface(netIf.Name) // ignore errors
	}
	return nil
}

func setUpInterface(ifName string) error {
	glog.V(3).Infof("Enabling hairpin on interface %s", ifName)
	ifPath := path.Join(sysfsNetPath, ifName)
	if _, err := os.Stat(ifPath); err != nil {
		return err
	}
	brportPath := path.Join(ifPath, brportRelativePath)
	if _, err := os.Stat(brportPath); err != nil && os.IsNotExist(err) {
		// Device is not on a bridge, so doesn't need hairpin mode
		return nil
	}
	hairpinModeFile := path.Join(brportPath, hairpinModeRelativePath)
	return ioutil.WriteFile(hairpinModeFile, []byte(hairpinEnable), 0644)
}
<|endoftext|>


<commit_before>package service

import (
	"net/url"
	"strconv"
	"strings"
	"time"

	"github.com/containerum/chkit/pkg/model"
	"github.com/ninedraft/boxofstuff/str"
)

var (
	_ model.TableRenderer = new(Service)
)

func (serv Service) RenderTable() string {
	return model.RenderTable(&serv)
}

func (_ *Service) TableHeaders() []string {
	return []string{"Name", "Deploy", "URL", "Age"}
}

func (serv *Service) TableRows() [][]string {
	age := "undefined"
	if serv.CreatedAt != (time.Time{}) {
		age = model.Age(serv.CreatedAt)
	}
	var links = make(str.Vector, 0, len(serv.Ports))
	if serv.Domain != "" {
		for _, p := range serv.Ports {
			switch strings.ToLower(p.Protocol) {
			case "tcp":
				links = append(links, (&url.URL{
					Scheme: "http",
					Host:   serv.Domain + ":" + strconv.Itoa(*p.Port),
				}).String())
			case "upd":
				links = append(links, (&url.URL{
					Scheme: "udp",
					Host:   serv.Domain + ":" + strconv.Itoa(*p.Port),
				}).String())
			default:
				links = append(links, (&url.URL{
					Host: serv.Domain + ":" + strconv.Itoa(*p.Port),
				}).String())
			}
		}
	}

	return [][]string{{
		serv.Name,
		serv.Deploy,
		strings.Join(links, "\n"),
		age,
	}}
}
<commit_msg>Fix services with udp ports<commit_after>package service

import (
	"net/url"
	"strconv"
	"strings"
	"time"

	"github.com/containerum/chkit/pkg/model"
	"github.com/ninedraft/boxofstuff/str"
)

var (
	_ model.TableRenderer = new(Service)
)

func (serv Service) RenderTable() string {
	return model.RenderTable(&serv)
}

func (_ *Service) TableHeaders() []string {
	return []string{"Name", "Deploy", "URL", "Age"}
}

func (serv *Service) TableRows() [][]string {
	age := "undefined"
	if serv.CreatedAt != (time.Time{}) {
		age = model.Age(serv.CreatedAt)
	}
	var links = make(str.Vector, 0, len(serv.Ports))
	if serv.Domain != "" {
		for _, p := range serv.Ports {
			switch strings.ToLower(p.Protocol) {
			case "tcp":
				links = append(links, (&url.URL{
					Scheme: "http",
					Host:   serv.Domain + ":" + strconv.Itoa(*p.Port),
				}).String())
			case "udp":
				links = append(links, (&url.URL{
					Scheme: "udp",
					Host:   serv.Domain + ":" + strconv.Itoa(*p.Port),
				}).String())
			default:
				links = append(links, (&url.URL{
					Host: serv.Domain + ":" + strconv.Itoa(*p.Port),
				}).String())
			}
		}
	}

	return [][]string{{
		serv.Name,
		serv.Deploy,
		strings.Join(links, "\n"),
		age,
	}}
}
<|endoftext|>


<commit_before>package helm

import (
	"errors"
	"fmt"
	"github.com/Aptomi/aptomi/pkg/slinga/event"
	"github.com/Aptomi/aptomi/pkg/slinga/lang"
	"k8s.io/helm/pkg/helm/portforwarder"
	"k8s.io/helm/pkg/kube"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
	"k8s.io/kubernetes/pkg/client/restclient"
)

func (cache *clusterCache) setupTillerConnection(cluster *lang.Cluster, eventLog *event.Log) error {
	cache.lock.Lock()
	defer cache.lock.Unlock()

	if len(cache.tillerHost) > 0 {
		// todo(slukjanov): verify that tunnel is still alive??
		// connection already set up, skip
		return nil
	}

	config, client, err := cache.newKubeClient(cluster, eventLog)
	if err != nil {
		return err
	}

	tillerNamespace := cluster.Config.TillerNamespace
	if tillerNamespace == "" {
		tillerNamespace = "kube-system"
	}
	tunnel, err := portforwarder.New(tillerNamespace, client, config)
	if err != nil {
		return err
	}

	cache.tillerTunnel = tunnel
	cache.tillerHost = fmt.Sprintf("localhost:%d", tunnel.Local)

	eventLog.WithFields(event.Fields{}).Debugf("Created k8s tunnel using local port: %s", tunnel.Local)

	return nil
}

func (cache *clusterCache) newKubeClient(cluster *lang.Cluster, eventLog *event.Log) (*restclient.Config, *internalclientset.Clientset, error) {
	// todo(slukjanov): cache kube client config?
	kubeContext := cluster.Config.KubeContext
	config, err := kube.GetConfig(kubeContext).ClientConfig()
	if err != nil {
		return nil, nil, fmt.Errorf("Could not get kubernetes config for context %s: %s", kubeContext, err)
	}
	// todo(slukjanov): could we cache client?
	client, err := internalclientset.NewForConfig(config)
	if err != nil {
		return nil, nil, fmt.Errorf("Could not get kubernetes client: %s", err)
	}
	return config, client, nil
}

func (cache *clusterCache) getKubeExternalAddress(cluster *lang.Cluster, eventLog *event.Log) (string, error) {
	cache.lock.Lock()
	defer cache.lock.Unlock()

	if len(cache.kubeExternalAddress) > 0 {
		return cache.kubeExternalAddress, nil
	}

	_, client, err := cache.newKubeClient(cluster, eventLog)
	if err != nil {
		return "", fmt.Errorf("Error while creating k8s client to cluster %s: %s", cluster.Name, err)
	}

	nodes, err := client.Nodes().List(api.ListOptions{})
	if err != nil {
		return "", err
	}
	if len(nodes.Items) == 0 {
		return "", fmt.Errorf("No nodes found for k8s cluster %s, it's critical eror", cluster.Name)
	}

	returnFirst := func(addrType api.NodeAddressType) string {
		for _, node := range nodes.Items {
			for _, addr := range node.Status.Addresses {
				if addr.Type == addrType {
					return addr.Address
				}
			}
		}
		return ""
	}

	addr := returnFirst(api.NodeExternalIP)
	if addr == "" {
		// TODO: this will be removed in 1.7
		addr = returnFirst(api.NodeLegacyHostIP)
	}
	if addr == "" {
		addr = returnFirst(api.NodeInternalIP)
	}
	if addr == "" {
		return "", errors.New("Couldn't find external IP for cluster")
	}

	cache.kubeExternalAddress = addr

	return addr, nil
}
<commit_msg>Fix logging format<commit_after>package helm

import (
	"errors"
	"fmt"
	"github.com/Aptomi/aptomi/pkg/slinga/event"
	"github.com/Aptomi/aptomi/pkg/slinga/lang"
	"k8s.io/helm/pkg/helm/portforwarder"
	"k8s.io/helm/pkg/kube"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
	"k8s.io/kubernetes/pkg/client/restclient"
)

func (cache *clusterCache) setupTillerConnection(cluster *lang.Cluster, eventLog *event.Log) error {
	cache.lock.Lock()
	defer cache.lock.Unlock()

	if len(cache.tillerHost) > 0 {
		// todo(slukjanov): verify that tunnel is still alive??
		// connection already set up, skip
		return nil
	}

	config, client, err := cache.newKubeClient(cluster, eventLog)
	if err != nil {
		return err
	}

	tillerNamespace := cluster.Config.TillerNamespace
	if tillerNamespace == "" {
		tillerNamespace = "kube-system"
	}
	tunnel, err := portforwarder.New(tillerNamespace, client, config)
	if err != nil {
		return err
	}

	cache.tillerTunnel = tunnel
	cache.tillerHost = fmt.Sprintf("localhost:%d", tunnel.Local)

	eventLog.WithFields(event.Fields{}).Debugf("Created k8s tunnel using local port: %d", tunnel.Local)

	return nil
}

func (cache *clusterCache) newKubeClient(cluster *lang.Cluster, eventLog *event.Log) (*restclient.Config, *internalclientset.Clientset, error) {
	// todo(slukjanov): cache kube client config?
	kubeContext := cluster.Config.KubeContext
	config, err := kube.GetConfig(kubeContext).ClientConfig()
	if err != nil {
		return nil, nil, fmt.Errorf("Could not get kubernetes config for context %s: %s", kubeContext, err)
	}
	// todo(slukjanov): could we cache client?
	client, err := internalclientset.NewForConfig(config)
	if err != nil {
		return nil, nil, fmt.Errorf("Could not get kubernetes client: %s", err)
	}
	return config, client, nil
}

func (cache *clusterCache) getKubeExternalAddress(cluster *lang.Cluster, eventLog *event.Log) (string, error) {
	cache.lock.Lock()
	defer cache.lock.Unlock()

	if len(cache.kubeExternalAddress) > 0 {
		return cache.kubeExternalAddress, nil
	}

	_, client, err := cache.newKubeClient(cluster, eventLog)
	if err != nil {
		return "", fmt.Errorf("Error while creating k8s client to cluster %s: %s", cluster.Name, err)
	}

	nodes, err := client.Nodes().List(api.ListOptions{})
	if err != nil {
		return "", err
	}
	if len(nodes.Items) == 0 {
		return "", fmt.Errorf("No nodes found for k8s cluster %s, it's critical eror", cluster.Name)
	}

	returnFirst := func(addrType api.NodeAddressType) string {
		for _, node := range nodes.Items {
			for _, addr := range node.Status.Addresses {
				if addr.Type == addrType {
					return addr.Address
				}
			}
		}
		return ""
	}

	addr := returnFirst(api.NodeExternalIP)
	if addr == "" {
		// TODO: this will be removed in 1.7
		addr = returnFirst(api.NodeLegacyHostIP)
	}
	if addr == "" {
		addr = returnFirst(api.NodeInternalIP)
	}
	if addr == "" {
		return "", errors.New("Couldn't find external IP for cluster")
	}

	cache.kubeExternalAddress = addr

	return addr, nil
}
<|endoftext|>


<commit_before>/*
 * This file is part of the KubeVirt project
 *
 * 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 2019 Red Hat, Inc.
 *
 */
package rest

import (
	"fmt"
	"io"
	"net/http"

	"github.com/emicklei/go-restful"

	k8sv1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/util/yaml"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/tools/record"

	v12 "kubevirt.io/api/core/v1"
	"kubevirt.io/client-go/log"
	cmdclient "kubevirt.io/kubevirt/pkg/virt-handler/cmd-client"
)

const (
	failedRetrieveVMI      = "Failed to retrieve VMI"
	failedDetectCmdClient  = "Failed to detect cmd client"
	failedConnectCmdClient = "Failed to connect cmd client"
)

type LifecycleHandler struct {
	recorder     record.EventRecorder
	vmiInformer  cache.SharedIndexInformer
	virtShareDir string
}

func NewLifecycleHandler(recorder record.EventRecorder, vmiInformer cache.SharedIndexInformer, virtShareDir string) *LifecycleHandler {
	return &LifecycleHandler{
		recorder:     recorder,
		vmiInformer:  vmiInformer,
		virtShareDir: virtShareDir,
	}
}

func (lh *LifecycleHandler) PauseHandler(request *restful.Request, response *restful.Response) {
	vmi, code, err := getVMI(request, lh.vmiInformer)
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error(failedRetrieveVMI)
		response.WriteError(code, err)
		return
	}

	sockFile, err := cmdclient.FindSocketOnHost(vmi)
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error(failedDetectCmdClient)
		response.WriteError(http.StatusInternalServerError, err)
		return
	}
	client, err := cmdclient.NewClient(sockFile)
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error(failedConnectCmdClient)
		response.WriteError(http.StatusInternalServerError, err)
		return
	}

	err = client.PauseVirtualMachine(vmi)
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error("Failed to pause VMI")
		response.WriteError(http.StatusInternalServerError, err)
		return
	}

	response.WriteHeader(http.StatusAccepted)
}

func (lh *LifecycleHandler) UnpauseHandler(request *restful.Request, response *restful.Response) {
	vmi, code, err := getVMI(request, lh.vmiInformer)
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error(failedRetrieveVMI)
		response.WriteError(code, err)
		return
	}

	sockFile, err := cmdclient.FindSocketOnHost(vmi)
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error(failedDetectCmdClient)
		response.WriteError(http.StatusInternalServerError, err)
		return
	}
	client, err := cmdclient.NewClient(sockFile)
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error(failedConnectCmdClient)
		response.WriteError(http.StatusInternalServerError, err)
		return
	}

	err = client.UnpauseVirtualMachine(vmi)
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error("Failed to unpause VMI")
		response.WriteError(http.StatusInternalServerError, err)
		return
	}

	response.WriteHeader(http.StatusAccepted)
}

func (lh *LifecycleHandler) FreezeHandler(request *restful.Request, response *restful.Response) {
	vmi, code, err := getVMI(request, lh.vmiInformer)
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error(failedRetrieveVMI)
		response.WriteError(code, err)
		return
	}

	unfreezeTimeout := &v12.FreezeUnfreezeTimeout{}
	if request.Request.Body == nil {
		log.Log.Object(vmi).Reason(err).Error("No unfreeze timeout in freeze request")
		response.WriteError(code, fmt.Errorf("failed to retrieve unfreeze timeout"))
		return
	}

	defer request.Request.Body.Close()
	err = yaml.NewYAMLOrJSONDecoder(request.Request.Body, 1024).Decode(unfreezeTimeout)
	switch err {
	case io.EOF, nil:
		break
	default:
		log.Log.Object(vmi).Reason(err).Error("Failed to unmarshal unfreeze timeout in freeze request")
		response.WriteError(code, fmt.Errorf("failed to unmarshal unfreeze timeout"))
		return
	}

	if unfreezeTimeout.UnfreezeTimeout == nil {
		log.Log.Object(vmi).Reason(err).Error("Unfreeze timeout in freeze request is not set")
		response.WriteError(code, fmt.Errorf("Unfreeze timeout in freeze request is not set"))
		return
	}

	sockFile, err := cmdclient.FindSocketOnHost(vmi)
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error(failedDetectCmdClient)
		response.WriteError(http.StatusInternalServerError, err)
		return
	}
	client, err := cmdclient.NewClient(sockFile)
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error(failedConnectCmdClient)
		response.WriteError(http.StatusInternalServerError, err)
		return
	}

	unfreezeTimeoutSeconds := int32(unfreezeTimeout.UnfreezeTimeout.Seconds())
	err = client.FreezeVirtualMachine(vmi, unfreezeTimeoutSeconds)
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error("Failed to freeze VMI")
		response.WriteError(http.StatusBadRequest, err)
		return
	}

	response.WriteHeader(http.StatusAccepted)
}

func (lh *LifecycleHandler) UnfreezeHandler(request *restful.Request, response *restful.Response) {
	vmi, code, err := getVMI(request, lh.vmiInformer)
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error(failedRetrieveVMI)
		response.WriteError(code, err)
		return
	}

	sockFile, err := cmdclient.FindSocketOnHost(vmi)
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error(failedDetectCmdClient)
		response.WriteError(http.StatusInternalServerError, err)
		return
	}
	client, err := cmdclient.NewClient(sockFile)
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error(failedConnectCmdClient)
		response.WriteError(http.StatusInternalServerError, err)
		return
	}

	err = client.UnfreezeVirtualMachine(vmi)
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error("Failed to unfreeze VMI")
		response.WriteError(http.StatusBadRequest, err)
		return
	}

	response.WriteHeader(http.StatusAccepted)
}

func (lh *LifecycleHandler) SoftRebootHandler(request *restful.Request, response *restful.Response) {
	vmi, code, err := getVMI(request, lh.vmiInformer)
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error(failedRetrieveVMI)
		response.WriteError(code, err)
		return
	}

	sockFile, err := cmdclient.FindSocketOnHost(vmi)
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error(failedDetectCmdClient)
		response.WriteError(http.StatusInternalServerError, err)
		return
	}
	client, err := cmdclient.NewClient(sockFile)
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error(failedConnectCmdClient)
		response.WriteError(http.StatusInternalServerError, err)
		return
	}

	err = client.SoftRebootVirtualMachine(vmi)
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error("Failed to soft reboot VMI")
		response.WriteError(http.StatusInternalServerError, err)
		return
	}

	lh.recorder.Eventf(vmi, k8sv1.EventTypeNormal, "SoftRebooted", "VirtualMachineInstance soft rebooted")
	response.WriteHeader(http.StatusAccepted)
}

func (lh *LifecycleHandler) GetGuestInfo(request *restful.Request, response *restful.Response) {
	log.Log.Info("Retreiving guestinfo")
	vmi, code, err := getVMI(request, lh.vmiInformer)
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error(failedRetrieveVMI)
		response.WriteError(code, err)
		return
	}

	log.Log.Object(vmi).Infof("Retreiving guestinfo from %s", vmi.Name)

	sockFile, err := cmdclient.FindSocketOnHost(vmi)
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error(failedDetectCmdClient)
		response.WriteError(http.StatusInternalServerError, err)
		return
	}
	client, err := cmdclient.NewClient(sockFile)
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error(failedConnectCmdClient)
		response.WriteError(http.StatusInternalServerError, err)
		return
	}

	guestInfo, err := client.GetGuestInfo()
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error("Failed to get guest info")
		response.WriteError(http.StatusInternalServerError, err)
		return
	}

	log.Log.Object(vmi).Infof("returning guestinfo :%v", guestInfo)
	response.WriteEntity(guestInfo)
}

func (lh *LifecycleHandler) GetUsers(request *restful.Request, response *restful.Response) {
	vmi, code, err := getVMI(request, lh.vmiInformer)
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error(failedRetrieveVMI)
		response.WriteError(code, err)
		return
	}

	log.Log.Object(vmi).Infof("Retreiving userlist from %s", vmi.Name)

	sockFile, err := cmdclient.FindSocketOnHost(vmi)
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error(failedDetectCmdClient)
		response.WriteError(http.StatusInternalServerError, err)
		return
	}
	client, err := cmdclient.NewClient(sockFile)
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error(failedConnectCmdClient)
		response.WriteError(http.StatusInternalServerError, err)
		return
	}

	userList, err := client.GetUsers()
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error("Failed to get user list")
		response.WriteError(http.StatusInternalServerError, err)
		return
	}

	response.WriteEntity(userList)
}

func (lh *LifecycleHandler) GetFilesystems(request *restful.Request, response *restful.Response) {
	vmi, code, err := getVMI(request, lh.vmiInformer)
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error(failedRetrieveVMI)
		response.WriteError(code, err)
		return
	}

	log.Log.Object(vmi).Infof("Retreiving filesystem list from %s", vmi.Name)

	sockFile, err := cmdclient.FindSocketOnHost(vmi)
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error(failedDetectCmdClient)
		response.WriteError(http.StatusInternalServerError, err)
		return
	}
	client, err := cmdclient.NewClient(sockFile)
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error(failedConnectCmdClient)
		response.WriteError(http.StatusInternalServerError, err)
		return
	}

	fsList, err := client.GetFilesystems()
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error("Failed to get guest info")
		response.WriteError(http.StatusInternalServerError, err)
		return
	}

	response.WriteEntity(fsList)
}
<commit_msg>Refactor of pkg/virt-handler/rest/lifecycle.go to remove redundant code<commit_after>/*
 * This file is part of the KubeVirt project
 *
 * 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 2019 Red Hat, Inc.
 *
 */
package rest

import (
	"fmt"
	"io"
	"net/http"

	"github.com/emicklei/go-restful"

	k8sv1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/util/yaml"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/tools/record"

	v1 "kubevirt.io/api/core/v1"
	"kubevirt.io/client-go/log"
	cmdclient "kubevirt.io/kubevirt/pkg/virt-handler/cmd-client"
)

const (
	failedRetrieveVMI      = "Failed to retrieve VMI"
	failedDetectCmdClient  = "Failed to detect cmd client"
	failedConnectCmdClient = "Failed to connect cmd client"
)

type LifecycleHandler struct {
	recorder     record.EventRecorder
	vmiInformer  cache.SharedIndexInformer
	virtShareDir string
}

func NewLifecycleHandler(recorder record.EventRecorder, vmiInformer cache.SharedIndexInformer, virtShareDir string) *LifecycleHandler {
	return &LifecycleHandler{
		recorder:     recorder,
		vmiInformer:  vmiInformer,
		virtShareDir: virtShareDir,
	}
}

func (lh *LifecycleHandler) PauseHandler(request *restful.Request, response *restful.Response) {
	vmi, client, err := lh.getVMILauncherClient(request, response)
	if err != nil {
		return
	}

	err = client.PauseVirtualMachine(vmi)
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error("Failed to pause VMI")
		response.WriteError(http.StatusInternalServerError, err)
		return
	}

	response.WriteHeader(http.StatusAccepted)
}

func (lh *LifecycleHandler) UnpauseHandler(request *restful.Request, response *restful.Response) {
	vmi, client, err := lh.getVMILauncherClient(request, response)
	if err != nil {
		return
	}

	err = client.UnpauseVirtualMachine(vmi)
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error("Failed to unpause VMI")
		response.WriteError(http.StatusInternalServerError, err)
		return
	}

	response.WriteHeader(http.StatusAccepted)
}

func (lh *LifecycleHandler) FreezeHandler(request *restful.Request, response *restful.Response) {
	vmi, client, err := lh.getVMILauncherClient(request, response)
	if err != nil {
		return
	}

	unfreezeTimeout := &v1.FreezeUnfreezeTimeout{}
	if request.Request.Body == nil {
		log.Log.Object(vmi).Reason(err).Error("No unfreeze timeout in freeze request")
		response.WriteError(http.StatusBadRequest, fmt.Errorf("failed to retrieve unfreeze timeout"))
		return
	}

	defer request.Request.Body.Close()
	err = yaml.NewYAMLOrJSONDecoder(request.Request.Body, 1024).Decode(unfreezeTimeout)
	switch err {
	case io.EOF, nil:
		break
	default:
		log.Log.Object(vmi).Reason(err).Error("Failed to unmarshal unfreeze timeout in freeze request")
		response.WriteError(http.StatusBadRequest, fmt.Errorf("failed to unmarshal unfreeze timeout"))
		return
	}

	if unfreezeTimeout.UnfreezeTimeout == nil {
		log.Log.Object(vmi).Reason(err).Error("Unfreeze timeout in freeze request is not set")
		response.WriteError(http.StatusBadRequest, fmt.Errorf("Unfreeze timeout in freeze request is not set"))
		return
	}

	unfreezeTimeoutSeconds := int32(unfreezeTimeout.UnfreezeTimeout.Seconds())
	err = client.FreezeVirtualMachine(vmi, unfreezeTimeoutSeconds)
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error("Failed to freeze VMI")
		response.WriteError(http.StatusBadRequest, err)
		return
	}

	response.WriteHeader(http.StatusAccepted)
}

func (lh *LifecycleHandler) UnfreezeHandler(request *restful.Request, response *restful.Response) {
	vmi, client, err := lh.getVMILauncherClient(request, response)
	if err != nil {
		return
	}

	err = client.UnfreezeVirtualMachine(vmi)
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error("Failed to unfreeze VMI")
		response.WriteError(http.StatusBadRequest, err)
		return
	}

	response.WriteHeader(http.StatusAccepted)
}

func (lh *LifecycleHandler) SoftRebootHandler(request *restful.Request, response *restful.Response) {
	vmi, client, err := lh.getVMILauncherClient(request, response)
	if err != nil {
		return
	}

	err = client.SoftRebootVirtualMachine(vmi)
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error("Failed to soft reboot VMI")
		response.WriteError(http.StatusInternalServerError, err)
		return
	}

	lh.recorder.Eventf(vmi, k8sv1.EventTypeNormal, "SoftRebooted", "VirtualMachineInstance soft rebooted")
	response.WriteHeader(http.StatusAccepted)
}

func (lh *LifecycleHandler) GetGuestInfo(request *restful.Request, response *restful.Response) {
	log.Log.Info("Retreiving guestinfo")
	vmi, client, err := lh.getVMILauncherClient(request, response)
	if err != nil {
		return
	}

	log.Log.Object(vmi).Infof("Retreiving guestinfo from %s", vmi.Name)

	guestInfo, err := client.GetGuestInfo()
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error("Failed to get guest info")
		response.WriteError(http.StatusInternalServerError, err)
		return
	}

	log.Log.Object(vmi).Infof("returning guestinfo :%v", guestInfo)
	response.WriteEntity(guestInfo)
}

func (lh *LifecycleHandler) GetUsers(request *restful.Request, response *restful.Response) {
	vmi, client, err := lh.getVMILauncherClient(request, response)
	if err != nil {
		return
	}

	log.Log.Object(vmi).Infof("Retreiving userlist from %s", vmi.Name)

	userList, err := client.GetUsers()
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error("Failed to get user list")
		response.WriteError(http.StatusInternalServerError, err)
		return
	}

	response.WriteEntity(userList)
}

func (lh *LifecycleHandler) GetFilesystems(request *restful.Request, response *restful.Response) {
	vmi, client, err := lh.getVMILauncherClient(request, response)
	if err != nil {
		return
	}

	log.Log.Object(vmi).Infof("Retreiving filesystem list from %s", vmi.Name)

	fsList, err := client.GetFilesystems()
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error("Failed to get file systems")
		response.WriteError(http.StatusInternalServerError, err)
		return
	}

	response.WriteEntity(fsList)
}

func (lh *LifecycleHandler) getVMILauncherClient(request *restful.Request, response *restful.Response) (*v1.VirtualMachineInstance, cmdclient.LauncherClient, error) {
	vmi, code, err := getVMI(request, lh.vmiInformer)
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error(failedRetrieveVMI)
		response.WriteError(code, err)
		return nil, nil, err
	}

	sockFile, err := cmdclient.FindSocketOnHost(vmi)
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error(failedDetectCmdClient)
		response.WriteError(http.StatusInternalServerError, err)
		return nil, nil, err
	}
	client, err := cmdclient.NewClient(sockFile)
	if err != nil {
		log.Log.Object(vmi).Reason(err).Error(failedConnectCmdClient)
		response.WriteError(http.StatusInternalServerError, err)
		return nil, nil, err
	}

	return vmi, client, nil
}
<|endoftext|>