<commit_before>package main

import (
	"encoding/base64"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"net"

	"golang.org/x/crypto/ssh"
)

type event struct {
	Source string   `json:"source"`
	Type   string   `json:"type"`
	Entry  logEntry `json:"entry"`
}

type source int

const (
	client source = iota
	server
)

func (src source) String() string {
	switch src {
	case client:
		return "client"
	case server:
		return "server"
	default:
		return "unknown"
	}
}

func (src source) MarshalJSON() ([]byte, error) {
	return json.Marshal(src.String())
}

type logEntry interface {
	eventType() string
}

type channelLog struct {
	ChannelID int `json:"channel_id"`
}

type requestLog struct {
	Type      string `json:"type"`
	WantReply bool   `json:"want_reply"`
	Payload   string `json:"payload"`

	Accepted bool `json:"accepted"`
}

type globalRequestLog struct {
	requestLog

	Response string `json:"response"`
}

func (entry globalRequestLog) eventType() string {
	return "global_request"
}

type newChannelLog struct {
	Type      string `json:"type"`
	ExtraData string `json:"extra_data"`

	Accepted     bool   `json:"accepted"`
	RejectReason uint32 `json:"reject_reason"`
	Message      string `json:"message"`
}

func (entry newChannelLog) eventType() string {
	return "new_channel"
}

type channelRequestLog struct {
	channelLog
	requestLog
}

func (entry channelRequestLog) eventType() string {
	return "channel_request"
}

type channelDataLog struct {
	channelLog
	Data string `json:"data"`
}

func (entry channelDataLog) eventType() string {
	return "channel_data"
}

type channelErrorLog struct {
	channelLog
	Data string `json:"data"`
}

func (entry channelErrorLog) eventType() string {
	return "channel_error"
}

type channelEOFLog struct {
	channelLog
}

func (entry channelEOFLog) eventType() string {
	return "channel_eof"
}

type channelCloseLog struct {
	channelLog
}

func (entry channelCloseLog) eventType() string {
	return "channel_close"
}

type connectionCloseLog struct{}

func (entry connectionCloseLog) eventType() string {
	return "connection_close"
}

var output struct {
	Events    []event                  `json:"events"`
	PlainLogs []string                 `json:"plain_logs"`
	JSONLogs  []map[string]interface{} `json:"json_logs"`
}

func recordEntry(entry logEntry, src source) {
	event := event{
		Source: src.String(),
		Type:   entry.eventType(),
		Entry:  entry,
	}
	output.Events = append(output.Events, event)
}

func streamReader(reader io.Reader) <-chan string {
	input := make(chan string)
	go func() {
		defer close(input)
		buffer := make([]byte, 256)
		for {
			n, err := reader.Read(buffer)
			if n > 0 {
				input <- string(buffer[:n])
			}
			if err != nil {
				if err != io.EOF {
					panic(err)
				}
				return
			}
		}
	}()
	return input
}

func handleChannel(channelID int, clientChannel ssh.Channel, clientRequests <-chan *ssh.Request, serverChannel ssh.Channel, serverRequests <-chan *ssh.Request) {
	clientInputStream := streamReader(clientChannel)
	serverInputStream := streamReader(serverChannel)
	serverErrorStream := streamReader(serverChannel.Stderr())

	for clientInputStream != nil || clientRequests != nil || serverInputStream != nil || serverRequests != nil {
		select {
		case clientInput, ok := <-clientInputStream:
			if !ok {
				if serverInputStream != nil {
					recordEntry(channelEOFLog{
						channelLog: channelLog{
							ChannelID: channelID,
						},
					}, client)
					if err := serverChannel.CloseWrite(); err != nil {
						panic(err)
					}
				}
				clientInputStream = nil
				continue
			}
			recordEntry(channelDataLog{
				channelLog: channelLog{
					ChannelID: channelID,
				},
				Data: clientInput,
			}, client)
			if _, err := serverChannel.Write([]byte(clientInput)); err != nil {
				panic(err)
			}
		case clientRequest, ok := <-clientRequests:
			if !ok {
				if clientInputStream != nil && serverInputStream != nil {
					continue
				}
				if serverRequests != nil {
					recordEntry(channelCloseLog{
						channelLog: channelLog{
							ChannelID: channelID,
						},
					}, client)
					if err := serverChannel.Close(); err != nil {
						panic(err)
					}
				}
				clientRequests = nil
				continue
			}
			accepted, err := serverChannel.SendRequest(clientRequest.Type, clientRequest.WantReply, clientRequest.Payload)
			if err != nil {
				panic(err)
			}
			recordEntry(channelRequestLog{
				channelLog: channelLog{
					ChannelID: channelID,
				},
				requestLog: requestLog{
					Type:      clientRequest.Type,
					WantReply: clientRequest.WantReply,
					Payload:   base64.RawStdEncoding.EncodeToString(clientRequest.Payload),
					Accepted:  accepted,
				},
			}, client)
			if clientRequest.WantReply {
				if err := clientRequest.Reply(accepted, nil); err != nil {
					panic(err)
				}
			}
		case serverInput, ok := <-serverInputStream:
			if !ok {
				if clientInputStream != nil {
					recordEntry(channelEOFLog{
						channelLog: channelLog{
							ChannelID: channelID,
						},
					}, server)
					if err := clientChannel.CloseWrite(); err != nil {
						panic(err)
					}
				}
				serverInputStream = nil
				continue
			}
			recordEntry(channelDataLog{
				channelLog: channelLog{
					ChannelID: channelID,
				},
				Data: serverInput,
			}, server)
			if _, err := clientChannel.Write([]byte(serverInput)); err != nil {
				panic(err)
			}
		case serverError, ok := <-serverErrorStream:
			if !ok {
				serverErrorStream = nil
				continue
			}
			recordEntry(channelErrorLog{
				channelLog: channelLog{
					ChannelID: channelID,
				},
				Data: serverError,
			}, server)
			if _, err := clientChannel.Stderr().Write([]byte(serverError)); err != nil {
				panic(err)
			}
		case serverRequest, ok := <-serverRequests:
			if !ok {
				if clientInputStream != nil && serverInputStream != nil {
					continue
				}
				if clientRequests != nil {
					recordEntry(channelCloseLog{
						channelLog: channelLog{
							ChannelID: channelID,
						},
					}, server)
					if err := clientChannel.Close(); err != nil {
						panic(err)
					}
				}
				serverRequests = nil
				continue
			}
			accepted, err := clientChannel.SendRequest(serverRequest.Type, serverRequest.WantReply, serverRequest.Payload)
			if err != nil {
				panic(err)
			}
			recordEntry(channelRequestLog{
				channelLog: channelLog{
					ChannelID: channelID,
				},
				requestLog: requestLog{
					Type:      serverRequest.Type,
					WantReply: serverRequest.WantReply,
					Payload:   base64.RawStdEncoding.EncodeToString(serverRequest.Payload),
					Accepted:  accepted,
				},
			}, server)
			if serverRequest.WantReply {
				if err := serverRequest.Reply(accepted, nil); err != nil {
					panic(err)
				}
			}
		}
	}
}

func handleConn(clientConn net.Conn, sshServerConfig *ssh.ServerConfig, serverAddress string, clientKey ssh.Signer) {
	clientSSHConn, clientNewChannels, clientRequests, err := ssh.NewServerConn(clientConn, sshServerConfig)
	if err != nil {
		panic(err)
	}

	serverConn, err := net.Dial("tcp", serverAddress)
	if err != nil {
		panic(err)
	}

	serverSSHConn, serverNewChannels, serverRequests, err := ssh.NewClientConn(serverConn, serverAddress, &ssh.ClientConfig{
		User:            clientSSHConn.User(),
		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
		Auth: []ssh.AuthMethod{
			ssh.PublicKeys(clientKey),
		},
		ClientVersion: "SSH-2.0-OpenSSH_7.2",
	})
	if err != nil {
		panic(err)
	}

	channelID := 0

	for clientNewChannels != nil || clientRequests != nil || serverNewChannels != nil || serverRequests != nil {
		select {
		case clientNewChannel, ok := <-clientNewChannels:
			if !ok {
				clientNewChannels = nil
				if serverNewChannels != nil {
					recordEntry(connectionCloseLog{}, client)
					if err := serverSSHConn.Close(); err != nil {
						panic(err)
					}
				}
				continue
			}
			serverChannel, serverChannelRequests, err := serverSSHConn.OpenChannel(clientNewChannel.ChannelType(), clientNewChannel.ExtraData())
			accepted := true
			var rejectReason ssh.RejectionReason
			var message string
			if err != nil {
				if err, ok := err.(*ssh.OpenChannelError); ok {
					accepted = false
					rejectReason = err.Reason
					message = err.Message
				} else {
					panic(err)
				}
			}
			recordEntry(newChannelLog{
				Type:         clientNewChannel.ChannelType(),
				ExtraData:    base64.RawStdEncoding.EncodeToString(clientNewChannel.ExtraData()),
				Accepted:     err == nil,
				RejectReason: uint32(rejectReason),
				Message:      message,
			}, client)
			if !accepted {
				if err := clientNewChannel.Reject(rejectReason, message); err != nil {
					panic(err)
				}
				continue
			}
			clientChannel, clientChannelRequests, err := clientNewChannel.Accept()
			if err != nil {
				panic(err)
			}
			go handleChannel(channelID, clientChannel, clientChannelRequests, serverChannel, serverChannelRequests)
			channelID++
		case clientRequest, ok := <-clientRequests:
			if !ok {
				clientRequests = nil
				continue
			}
			if clientRequest.Type == "no-more-sessions@openssh.com" {
				recordEntry(globalRequestLog{
					requestLog: requestLog{
						Type:      clientRequest.Type,
						WantReply: clientRequest.WantReply,
						Payload:   base64.RawStdEncoding.EncodeToString(clientRequest.Payload),
						Accepted:  clientRequest.WantReply,
					},
					Response: "",
				}, client)
				continue
			}
			accepted, response, err := serverSSHConn.SendRequest(clientRequest.Type, clientRequest.WantReply, clientRequest.Payload)
			if err != nil {
				panic(err)
			}
			recordEntry(globalRequestLog{
				requestLog: requestLog{
					Type:      clientRequest.Type,
					WantReply: clientRequest.WantReply,
					Payload:   base64.RawStdEncoding.EncodeToString(clientRequest.Payload),
					Accepted:  accepted,
				},
				Response: base64.RawStdEncoding.EncodeToString(response),
			}, client)
			if err := clientRequest.Reply(accepted, response); err != nil {
				panic(err)
			}
		case serverNewChannel, ok := <-serverNewChannels:
			if !ok {
				if clientNewChannels != nil {
					recordEntry(connectionCloseLog{}, server)
					if err := clientSSHConn.Close(); err != nil {
						panic(err)
					}
				}
				serverNewChannels = nil
				continue
			}
			panic(serverNewChannel.ChannelType())
		case serverRequest, ok := <-serverRequests:
			if !ok {
				serverRequests = nil
				continue
			}
			accepted, response, err := clientSSHConn.SendRequest(serverRequest.Type, serverRequest.WantReply, serverRequest.Payload)
			recordEntry(globalRequestLog{
				requestLog: requestLog{
					Type:      serverRequest.Type,
					WantReply: serverRequest.WantReply,
					Payload:   base64.RawStdEncoding.EncodeToString(serverRequest.Payload),
					Accepted:  accepted,
				},
				Response: base64.RawStdEncoding.EncodeToString(response),
			}, server)
			if err != nil {
				panic(err)
			}
			if err := serverRequest.Reply(accepted, response); err != nil {
				panic(err)
			}
		}
	}
}

func main() {
	listenAddress := flag.String("listen_address", "127.0.0.1:2022", "listen address")
	hostKeyFile := flag.String("host_key_file", "", "host key file")
	serverAddress := flag.String("server_address", "127.0.0.1:22", "server address")
	clientKeyFile := flag.String("client_key_file", "", "client key file")
	flag.Parse()
	if *listenAddress == "" {
		panic("listen address is required")
	}
	if *hostKeyFile == "" {
		panic("host key file is required")
	}
	if *serverAddress == "" {
		panic("server address is required")
	}
	if *clientKeyFile == "" {
		panic("client key file is required")
	}

	serverConfig := &ssh.ServerConfig{
		NoClientAuth:  true,
		ServerVersion: "SSH-2.0-OpenSSH_7.2",
	}
	hostKeyBytes, err := ioutil.ReadFile(*hostKeyFile)
	if err != nil {
		panic(err)
	}
	hostKey, err := ssh.ParsePrivateKey(hostKeyBytes)
	if err != nil {
		panic(err)
	}
	serverConfig.AddHostKey(hostKey)

	clientKeyBytes, err := ioutil.ReadFile(*clientKeyFile)
	if err != nil {
		panic(err)
	}
	clientKey, err := ssh.ParsePrivateKey(clientKeyBytes)
	if err != nil {
		panic(err)
	}

	listener, err := net.Listen("tcp", *listenAddress)
	if err != nil {
		panic(err)
	}
	defer listener.Close()

	conn, err := listener.Accept()
	if err != nil {
		panic(err)
	}
	handleConn(conn, serverConfig, *serverAddress, clientKey)

	outputBytes, err := json.MarshalIndent(output, "", "  ")
	if err != nil {
		panic(err)
	}
	fmt.Println(string(outputBytes))
}
<commit_msg>testproxy: initialize an empty plain and JSON log in the output<commit_after>package main

import (
	"encoding/base64"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"net"

	"golang.org/x/crypto/ssh"
)

type event struct {
	Source string   `json:"source"`
	Type   string   `json:"type"`
	Entry  logEntry `json:"entry"`
}

type source int

const (
	client source = iota
	server
)

func (src source) String() string {
	switch src {
	case client:
		return "client"
	case server:
		return "server"
	default:
		return "unknown"
	}
}

func (src source) MarshalJSON() ([]byte, error) {
	return json.Marshal(src.String())
}

type logEntry interface {
	eventType() string
}

type channelLog struct {
	ChannelID int `json:"channel_id"`
}

type requestLog struct {
	Type      string `json:"type"`
	WantReply bool   `json:"want_reply"`
	Payload   string `json:"payload"`

	Accepted bool `json:"accepted"`
}

type globalRequestLog struct {
	requestLog

	Response string `json:"response"`
}

func (entry globalRequestLog) eventType() string {
	return "global_request"
}

type newChannelLog struct {
	Type      string `json:"type"`
	ExtraData string `json:"extra_data"`

	Accepted     bool   `json:"accepted"`
	RejectReason uint32 `json:"reject_reason"`
	Message      string `json:"message"`
}

func (entry newChannelLog) eventType() string {
	return "new_channel"
}

type channelRequestLog struct {
	channelLog
	requestLog
}

func (entry channelRequestLog) eventType() string {
	return "channel_request"
}

type channelDataLog struct {
	channelLog
	Data string `json:"data"`
}

func (entry channelDataLog) eventType() string {
	return "channel_data"
}

type channelErrorLog struct {
	channelLog
	Data string `json:"data"`
}

func (entry channelErrorLog) eventType() string {
	return "channel_error"
}

type channelEOFLog struct {
	channelLog
}

func (entry channelEOFLog) eventType() string {
	return "channel_eof"
}

type channelCloseLog struct {
	channelLog
}

func (entry channelCloseLog) eventType() string {
	return "channel_close"
}

type connectionCloseLog struct{}

func (entry connectionCloseLog) eventType() string {
	return "connection_close"
}

var output struct {
	Events    []event                  `json:"events"`
	PlainLogs []string                 `json:"plain_logs"`
	JSONLogs  []map[string]interface{} `json:"json_logs"`
}

func recordEntry(entry logEntry, src source) {
	event := event{
		Source: src.String(),
		Type:   entry.eventType(),
		Entry:  entry,
	}
	output.Events = append(output.Events, event)
}

func streamReader(reader io.Reader) <-chan string {
	input := make(chan string)
	go func() {
		defer close(input)
		buffer := make([]byte, 256)
		for {
			n, err := reader.Read(buffer)
			if n > 0 {
				input <- string(buffer[:n])
			}
			if err != nil {
				if err != io.EOF {
					panic(err)
				}
				return
			}
		}
	}()
	return input
}

func handleChannel(channelID int, clientChannel ssh.Channel, clientRequests <-chan *ssh.Request, serverChannel ssh.Channel, serverRequests <-chan *ssh.Request) {
	clientInputStream := streamReader(clientChannel)
	serverInputStream := streamReader(serverChannel)
	serverErrorStream := streamReader(serverChannel.Stderr())

	for clientInputStream != nil || clientRequests != nil || serverInputStream != nil || serverRequests != nil {
		select {
		case clientInput, ok := <-clientInputStream:
			if !ok {
				if serverInputStream != nil {
					recordEntry(channelEOFLog{
						channelLog: channelLog{
							ChannelID: channelID,
						},
					}, client)
					if err := serverChannel.CloseWrite(); err != nil {
						panic(err)
					}
				}
				clientInputStream = nil
				continue
			}
			recordEntry(channelDataLog{
				channelLog: channelLog{
					ChannelID: channelID,
				},
				Data: clientInput,
			}, client)
			if _, err := serverChannel.Write([]byte(clientInput)); err != nil {
				panic(err)
			}
		case clientRequest, ok := <-clientRequests:
			if !ok {
				if clientInputStream != nil && serverInputStream != nil {
					continue
				}
				if serverRequests != nil {
					recordEntry(channelCloseLog{
						channelLog: channelLog{
							ChannelID: channelID,
						},
					}, client)
					if err := serverChannel.Close(); err != nil {
						panic(err)
					}
				}
				clientRequests = nil
				continue
			}
			accepted, err := serverChannel.SendRequest(clientRequest.Type, clientRequest.WantReply, clientRequest.Payload)
			if err != nil {
				panic(err)
			}
			recordEntry(channelRequestLog{
				channelLog: channelLog{
					ChannelID: channelID,
				},
				requestLog: requestLog{
					Type:      clientRequest.Type,
					WantReply: clientRequest.WantReply,
					Payload:   base64.RawStdEncoding.EncodeToString(clientRequest.Payload),
					Accepted:  accepted,
				},
			}, client)
			if clientRequest.WantReply {
				if err := clientRequest.Reply(accepted, nil); err != nil {
					panic(err)
				}
			}
		case serverInput, ok := <-serverInputStream:
			if !ok {
				if clientInputStream != nil {
					recordEntry(channelEOFLog{
						channelLog: channelLog{
							ChannelID: channelID,
						},
					}, server)
					if err := clientChannel.CloseWrite(); err != nil {
						panic(err)
					}
				}
				serverInputStream = nil
				continue
			}
			recordEntry(channelDataLog{
				channelLog: channelLog{
					ChannelID: channelID,
				},
				Data: serverInput,
			}, server)
			if _, err := clientChannel.Write([]byte(serverInput)); err != nil {
				panic(err)
			}
		case serverError, ok := <-serverErrorStream:
			if !ok {
				serverErrorStream = nil
				continue
			}
			recordEntry(channelErrorLog{
				channelLog: channelLog{
					ChannelID: channelID,
				},
				Data: serverError,
			}, server)
			if _, err := clientChannel.Stderr().Write([]byte(serverError)); err != nil {
				panic(err)
			}
		case serverRequest, ok := <-serverRequests:
			if !ok {
				if clientInputStream != nil && serverInputStream != nil {
					continue
				}
				if clientRequests != nil {
					recordEntry(channelCloseLog{
						channelLog: channelLog{
							ChannelID: channelID,
						},
					}, server)
					if err := clientChannel.Close(); err != nil {
						panic(err)
					}
				}
				serverRequests = nil
				continue
			}
			accepted, err := clientChannel.SendRequest(serverRequest.Type, serverRequest.WantReply, serverRequest.Payload)
			if err != nil {
				panic(err)
			}
			recordEntry(channelRequestLog{
				channelLog: channelLog{
					ChannelID: channelID,
				},
				requestLog: requestLog{
					Type:      serverRequest.Type,
					WantReply: serverRequest.WantReply,
					Payload:   base64.RawStdEncoding.EncodeToString(serverRequest.Payload),
					Accepted:  accepted,
				},
			}, server)
			if serverRequest.WantReply {
				if err := serverRequest.Reply(accepted, nil); err != nil {
					panic(err)
				}
			}
		}
	}
}

func handleConn(clientConn net.Conn, sshServerConfig *ssh.ServerConfig, serverAddress string, clientKey ssh.Signer) {
	clientSSHConn, clientNewChannels, clientRequests, err := ssh.NewServerConn(clientConn, sshServerConfig)
	if err != nil {
		panic(err)
	}

	serverConn, err := net.Dial("tcp", serverAddress)
	if err != nil {
		panic(err)
	}

	serverSSHConn, serverNewChannels, serverRequests, err := ssh.NewClientConn(serverConn, serverAddress, &ssh.ClientConfig{
		User:            clientSSHConn.User(),
		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
		Auth: []ssh.AuthMethod{
			ssh.PublicKeys(clientKey),
		},
		ClientVersion: "SSH-2.0-OpenSSH_7.2",
	})
	if err != nil {
		panic(err)
	}

	channelID := 0

	for clientNewChannels != nil || clientRequests != nil || serverNewChannels != nil || serverRequests != nil {
		select {
		case clientNewChannel, ok := <-clientNewChannels:
			if !ok {
				clientNewChannels = nil
				if serverNewChannels != nil {
					recordEntry(connectionCloseLog{}, client)
					if err := serverSSHConn.Close(); err != nil {
						panic(err)
					}
				}
				continue
			}
			serverChannel, serverChannelRequests, err := serverSSHConn.OpenChannel(clientNewChannel.ChannelType(), clientNewChannel.ExtraData())
			accepted := true
			var rejectReason ssh.RejectionReason
			var message string
			if err != nil {
				if err, ok := err.(*ssh.OpenChannelError); ok {
					accepted = false
					rejectReason = err.Reason
					message = err.Message
				} else {
					panic(err)
				}
			}
			recordEntry(newChannelLog{
				Type:         clientNewChannel.ChannelType(),
				ExtraData:    base64.RawStdEncoding.EncodeToString(clientNewChannel.ExtraData()),
				Accepted:     accepted,
				RejectReason: uint32(rejectReason),
				Message:      message,
			}, client)
			if !accepted {
				if err := clientNewChannel.Reject(rejectReason, message); err != nil {
					panic(err)
				}
				continue
			}
			clientChannel, clientChannelRequests, err := clientNewChannel.Accept()
			if err != nil {
				panic(err)
			}
			go handleChannel(channelID, clientChannel, clientChannelRequests, serverChannel, serverChannelRequests)
			channelID++
		case clientRequest, ok := <-clientRequests:
			if !ok {
				clientRequests = nil
				continue
			}
			if clientRequest.Type == "no-more-sessions@openssh.com" {
				recordEntry(globalRequestLog{
					requestLog: requestLog{
						Type:      clientRequest.Type,
						WantReply: clientRequest.WantReply,
						Payload:   base64.RawStdEncoding.EncodeToString(clientRequest.Payload),
						Accepted:  clientRequest.WantReply,
					},
					Response: "",
				}, client)
				continue
			}
			accepted, response, err := serverSSHConn.SendRequest(clientRequest.Type, clientRequest.WantReply, clientRequest.Payload)
			if err != nil {
				panic(err)
			}
			recordEntry(globalRequestLog{
				requestLog: requestLog{
					Type:      clientRequest.Type,
					WantReply: clientRequest.WantReply,
					Payload:   base64.RawStdEncoding.EncodeToString(clientRequest.Payload),
					Accepted:  accepted,
				},
				Response: base64.RawStdEncoding.EncodeToString(response),
			}, client)
			if err := clientRequest.Reply(accepted, response); err != nil {
				panic(err)
			}
		case serverNewChannel, ok := <-serverNewChannels:
			if !ok {
				if clientNewChannels != nil {
					recordEntry(connectionCloseLog{}, server)
					if err := clientSSHConn.Close(); err != nil {
						panic(err)
					}
				}
				serverNewChannels = nil
				continue
			}
			panic(serverNewChannel.ChannelType())
		case serverRequest, ok := <-serverRequests:
			if !ok {
				serverRequests = nil
				continue
			}
			accepted, response, err := clientSSHConn.SendRequest(serverRequest.Type, serverRequest.WantReply, serverRequest.Payload)
			recordEntry(globalRequestLog{
				requestLog: requestLog{
					Type:      serverRequest.Type,
					WantReply: serverRequest.WantReply,
					Payload:   base64.RawStdEncoding.EncodeToString(serverRequest.Payload),
					Accepted:  accepted,
				},
				Response: base64.RawStdEncoding.EncodeToString(response),
			}, server)
			if err != nil {
				panic(err)
			}
			if err := serverRequest.Reply(accepted, response); err != nil {
				panic(err)
			}
		}
	}
}

func main() {
	listenAddress := flag.String("listen_address", "127.0.0.1:2022", "listen address")
	hostKeyFile := flag.String("host_key_file", "", "host key file")
	serverAddress := flag.String("server_address", "127.0.0.1:22", "server address")
	clientKeyFile := flag.String("client_key_file", "", "client key file")
	flag.Parse()
	if *listenAddress == "" {
		panic("listen address is required")
	}
	if *hostKeyFile == "" {
		panic("host key file is required")
	}
	if *serverAddress == "" {
		panic("server address is required")
	}
	if *clientKeyFile == "" {
		panic("client key file is required")
	}

	serverConfig := &ssh.ServerConfig{
		NoClientAuth:  true,
		ServerVersion: "SSH-2.0-OpenSSH_7.2",
	}
	hostKeyBytes, err := ioutil.ReadFile(*hostKeyFile)
	if err != nil {
		panic(err)
	}
	hostKey, err := ssh.ParsePrivateKey(hostKeyBytes)
	if err != nil {
		panic(err)
	}
	serverConfig.AddHostKey(hostKey)

	clientKeyBytes, err := ioutil.ReadFile(*clientKeyFile)
	if err != nil {
		panic(err)
	}
	clientKey, err := ssh.ParsePrivateKey(clientKeyBytes)
	if err != nil {
		panic(err)
	}

	listener, err := net.Listen("tcp", *listenAddress)
	if err != nil {
		panic(err)
	}
	defer listener.Close()

	conn, err := listener.Accept()
	if err != nil {
		panic(err)
	}
	handleConn(conn, serverConfig, *serverAddress, clientKey)

	output.PlainLogs = []string{}
	output.JSONLogs = []map[string]interface{}{}

	outputBytes, err := json.MarshalIndent(output, "", "  ")
	if err != nil {
		panic(err)
	}
	fmt.Println(string(outputBytes))
}
<|endoftext|>


<commit_before>/*
Copyright 2016 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 openstack

import (
	"context"
	"fmt"
	"regexp"
	"strings"

	"github.com/golang/glog"
	"github.com/gophercloud/gophercloud"
	"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"

	"k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/kubernetes/pkg/cloudprovider"
)

// Instances encapsulates an implementation of Instances for OpenStack.
type Instances struct {
	compute *gophercloud.ServiceClient
	opts    MetadataOpts
}

// Instances returns an implementation of Instances for OpenStack.
func (os *OpenStack) Instances() (cloudprovider.Instances, bool) {
	glog.V(4).Info("openstack.Instances() called")

	compute, err := os.NewComputeV2()
	if err != nil {
		return nil, false
	}

	glog.V(4).Info("Claiming to support Instances")

	return &Instances{
		compute: compute,
		opts:    os.metadataOpts,
	}, true
}

// CurrentNodeName implements Instances.CurrentNodeName
// Note this is *not* necessarily the same as hostname.
func (i *Instances) CurrentNodeName(ctx context.Context, hostname string) (types.NodeName, error) {
	md, err := getMetadata(i.opts.SearchOrder)
	if err != nil {
		return "", err
	}
	return types.NodeName(strings.Split(md.Hostname, ".")[0]), nil
}

// AddSSHKeyToAllInstances is not implemented for OpenStack
func (i *Instances) AddSSHKeyToAllInstances(ctx context.Context, user string, keyData []byte) error {
	return cloudprovider.NotImplemented
}

// NodeAddresses implements Instances.NodeAddresses
func (i *Instances) NodeAddresses(ctx context.Context, name types.NodeName) ([]v1.NodeAddress, error) {
	glog.V(4).Infof("NodeAddresses(%v) called", name)

	addrs, err := getAddressesByName(i.compute, name)
	if err != nil {
		return nil, err
	}

	glog.V(4).Infof("NodeAddresses(%v) => %v", name, addrs)
	return addrs, nil
}

// NodeAddressesByProviderID returns the node addresses of an instances with the specified unique providerID
// This method will not be called from the node that is requesting this ID. i.e. metadata service
// and other local methods cannot be used here
func (i *Instances) NodeAddressesByProviderID(ctx context.Context, providerID string) ([]v1.NodeAddress, error) {
	instanceID, err := instanceIDFromProviderID(providerID)

	if err != nil {
		return []v1.NodeAddress{}, err
	}

	server, err := servers.Get(i.compute, instanceID).Extract()

	if err != nil {
		return []v1.NodeAddress{}, err
	}

	addresses, err := nodeAddresses(server)
	if err != nil {
		return []v1.NodeAddress{}, err
	}

	return addresses, nil
}

// ExternalID returns the cloud provider ID of the specified instance (deprecated).
func (i *Instances) ExternalID(ctx context.Context, name types.NodeName) (string, error) {
	srv, err := getServerByName(i.compute, name, true)
	if err != nil {
		if err == ErrNotFound {
			return "", cloudprovider.InstanceNotFound
		}
		return "", err
	}
	return srv.ID, nil
}

// InstanceExistsByProviderID returns true if the instance with the given provider id still exists and is running.
// If false is returned with no error, the instance will be immediately deleted by the cloud controller manager.
func (i *Instances) InstanceExistsByProviderID(ctx context.Context, providerID string) (bool, error) {
	instanceID, err := instanceIDFromProviderID(providerID)
	if err != nil {
		return false, err
	}

	server, err := servers.Get(i.compute, instanceID).Extract()
	if err != nil {
		if isNotFound(err) {
			return false, nil
		}
		return false, err
	}

	if server.Status != "ACTIVE" {
		glog.Warningf("the instance %s is not active", instanceID)
		return false, nil
	}

	return true, nil
}

// InstanceID returns the kubelet's cloud provider ID.
func (os *OpenStack) InstanceID() (string, error) {
	if len(os.localInstanceID) == 0 {
		id, err := readInstanceID(os.metadataOpts.SearchOrder)
		if err != nil {
			return "", err
		}
		os.localInstanceID = id
	}
	return os.localInstanceID, nil
}

// InstanceID returns the cloud provider ID of the specified instance.
func (i *Instances) InstanceID(ctx context.Context, name types.NodeName) (string, error) {
	srv, err := getServerByName(i.compute, name, true)
	if err != nil {
		if err == ErrNotFound {
			return "", cloudprovider.InstanceNotFound
		}
		return "", err
	}
	// In the future it is possible to also return an endpoint as:
	// <endpoint>/<instanceid>
	return "/" + srv.ID, nil
}

// InstanceTypeByProviderID returns the cloudprovider instance type of the node with the specified unique providerID
// This method will not be called from the node that is requesting this ID. i.e. metadata service
// and other local methods cannot be used here
func (i *Instances) InstanceTypeByProviderID(ctx context.Context, providerID string) (string, error) {
	instanceID, err := instanceIDFromProviderID(providerID)

	if err != nil {
		return "", err
	}

	server, err := servers.Get(i.compute, instanceID).Extract()

	if err != nil {
		return "", err
	}

	return srvInstanceType(server)
}

// InstanceType returns the type of the specified instance.
func (i *Instances) InstanceType(ctx context.Context, name types.NodeName) (string, error) {
	srv, err := getServerByName(i.compute, name, true)

	if err != nil {
		return "", err
	}

	return srvInstanceType(srv)
}

func srvInstanceType(srv *servers.Server) (string, error) {
	keys := []string{"name", "id", "original_name"}
	for _, key := range keys {
		val, found := srv.Flavor[key]
		if found {
			flavor, ok := val.(string)
			if ok {
				return flavor, nil
			}
		}
	}
	return "", fmt.Errorf("flavor name/id not found")
}

// instanceIDFromProviderID splits a provider's id and return instanceID.
// A providerID is build out of '${ProviderName}:///${instance-id}'which contains ':///'.
// See cloudprovider.GetInstanceProviderID and Instances.InstanceID.
func instanceIDFromProviderID(providerID string) (instanceID string, err error) {
	// If Instances.InstanceID or cloudprovider.GetInstanceProviderID is changed, the regexp should be changed too.
	var providerIDRegexp = regexp.MustCompile(`^` + ProviderName + `:///([^/]+)$`)

	matches := providerIDRegexp.FindStringSubmatch(providerID)
	if len(matches) != 2 {
		return "", fmt.Errorf("ProviderID \"%s\" didn't match expected format \"openstack:///InstanceID\"", providerID)
	}
	return matches[1], nil
}
<commit_msg>Revert "Split out the hostname when default dhcp_domain is used in nova.conf"<commit_after>/*
Copyright 2016 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 openstack

import (
	"context"
	"fmt"
	"regexp"

	"github.com/golang/glog"
	"github.com/gophercloud/gophercloud"
	"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"

	"k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/kubernetes/pkg/cloudprovider"
)

// Instances encapsulates an implementation of Instances for OpenStack.
type Instances struct {
	compute *gophercloud.ServiceClient
	opts    MetadataOpts
}

// Instances returns an implementation of Instances for OpenStack.
func (os *OpenStack) Instances() (cloudprovider.Instances, bool) {
	glog.V(4).Info("openstack.Instances() called")

	compute, err := os.NewComputeV2()
	if err != nil {
		return nil, false
	}

	glog.V(4).Info("Claiming to support Instances")

	return &Instances{
		compute: compute,
		opts:    os.metadataOpts,
	}, true
}

// CurrentNodeName implements Instances.CurrentNodeName
// Note this is *not* necessarily the same as hostname.
func (i *Instances) CurrentNodeName(ctx context.Context, hostname string) (types.NodeName, error) {
	md, err := getMetadata(i.opts.SearchOrder)
	if err != nil {
		return "", err
	}
	return types.NodeName(md.Hostname), nil
}

// AddSSHKeyToAllInstances is not implemented for OpenStack
func (i *Instances) AddSSHKeyToAllInstances(ctx context.Context, user string, keyData []byte) error {
	return cloudprovider.NotImplemented
}

// NodeAddresses implements Instances.NodeAddresses
func (i *Instances) NodeAddresses(ctx context.Context, name types.NodeName) ([]v1.NodeAddress, error) {
	glog.V(4).Infof("NodeAddresses(%v) called", name)

	addrs, err := getAddressesByName(i.compute, name)
	if err != nil {
		return nil, err
	}

	glog.V(4).Infof("NodeAddresses(%v) => %v", name, addrs)
	return addrs, nil
}

// NodeAddressesByProviderID returns the node addresses of an instances with the specified unique providerID
// This method will not be called from the node that is requesting this ID. i.e. metadata service
// and other local methods cannot be used here
func (i *Instances) NodeAddressesByProviderID(ctx context.Context, providerID string) ([]v1.NodeAddress, error) {
	instanceID, err := instanceIDFromProviderID(providerID)

	if err != nil {
		return []v1.NodeAddress{}, err
	}

	server, err := servers.Get(i.compute, instanceID).Extract()

	if err != nil {
		return []v1.NodeAddress{}, err
	}

	addresses, err := nodeAddresses(server)
	if err != nil {
		return []v1.NodeAddress{}, err
	}

	return addresses, nil
}

// ExternalID returns the cloud provider ID of the specified instance (deprecated).
func (i *Instances) ExternalID(ctx context.Context, name types.NodeName) (string, error) {
	srv, err := getServerByName(i.compute, name, true)
	if err != nil {
		if err == ErrNotFound {
			return "", cloudprovider.InstanceNotFound
		}
		return "", err
	}
	return srv.ID, nil
}

// InstanceExistsByProviderID returns true if the instance with the given provider id still exists and is running.
// If false is returned with no error, the instance will be immediately deleted by the cloud controller manager.
func (i *Instances) InstanceExistsByProviderID(ctx context.Context, providerID string) (bool, error) {
	instanceID, err := instanceIDFromProviderID(providerID)
	if err != nil {
		return false, err
	}

	server, err := servers.Get(i.compute, instanceID).Extract()
	if err != nil {
		if isNotFound(err) {
			return false, nil
		}
		return false, err
	}

	if server.Status != "ACTIVE" {
		glog.Warningf("the instance %s is not active", instanceID)
		return false, nil
	}

	return true, nil
}

// InstanceID returns the kubelet's cloud provider ID.
func (os *OpenStack) InstanceID() (string, error) {
	if len(os.localInstanceID) == 0 {
		id, err := readInstanceID(os.metadataOpts.SearchOrder)
		if err != nil {
			return "", err
		}
		os.localInstanceID = id
	}
	return os.localInstanceID, nil
}

// InstanceID returns the cloud provider ID of the specified instance.
func (i *Instances) InstanceID(ctx context.Context, name types.NodeName) (string, error) {
	srv, err := getServerByName(i.compute, name, true)
	if err != nil {
		if err == ErrNotFound {
			return "", cloudprovider.InstanceNotFound
		}
		return "", err
	}
	// In the future it is possible to also return an endpoint as:
	// <endpoint>/<instanceid>
	return "/" + srv.ID, nil
}

// InstanceTypeByProviderID returns the cloudprovider instance type of the node with the specified unique providerID
// This method will not be called from the node that is requesting this ID. i.e. metadata service
// and other local methods cannot be used here
func (i *Instances) InstanceTypeByProviderID(ctx context.Context, providerID string) (string, error) {
	instanceID, err := instanceIDFromProviderID(providerID)

	if err != nil {
		return "", err
	}

	server, err := servers.Get(i.compute, instanceID).Extract()

	if err != nil {
		return "", err
	}

	return srvInstanceType(server)
}

// InstanceType returns the type of the specified instance.
func (i *Instances) InstanceType(ctx context.Context, name types.NodeName) (string, error) {
	srv, err := getServerByName(i.compute, name, true)

	if err != nil {
		return "", err
	}

	return srvInstanceType(srv)
}

func srvInstanceType(srv *servers.Server) (string, error) {
	keys := []string{"name", "id", "original_name"}
	for _, key := range keys {
		val, found := srv.Flavor[key]
		if found {
			flavor, ok := val.(string)
			if ok {
				return flavor, nil
			}
		}
	}
	return "", fmt.Errorf("flavor name/id not found")
}

// instanceIDFromProviderID splits a provider's id and return instanceID.
// A providerID is build out of '${ProviderName}:///${instance-id}'which contains ':///'.
// See cloudprovider.GetInstanceProviderID and Instances.InstanceID.
func instanceIDFromProviderID(providerID string) (instanceID string, err error) {
	// If Instances.InstanceID or cloudprovider.GetInstanceProviderID is changed, the regexp should be changed too.
	var providerIDRegexp = regexp.MustCompile(`^` + ProviderName + `:///([^/]+)$`)

	matches := providerIDRegexp.FindStringSubmatch(providerID)
	if len(matches) != 2 {
		return "", fmt.Errorf("ProviderID \"%s\" didn't match expected format \"openstack:///InstanceID\"", providerID)
	}
	return matches[1], nil
}
<|endoftext|>


<commit_before>package list

import "fmt"

// Head returns the first value at the front of a list.
func (l *List) Head() (i int, err error) {
	if l.IsEmpty() {
		err = fmt.Errorf("Cannot take head of empty list")
		return
	}
	i = l.first.val
	return
}

// Tail returns a new list containing all elements other than the Head.
// If no elements remain an empty list is returned.
func (l *List) Tail() (rl *List, err error) {
	switch l.Size() {
	case 0:
		err = fmt.Errorf("Cannot take tail of empty list")
	case 1:
		rl = new(List)
	default:
		first, last, size := l.first.next.clone()
		rl = &List{first, last, size}
	}
	return
}

// Clone coppies the current node value and all child nodes connected by 'next'
// into a new linked list.
func (n *Node) clone() (first *Node, last *Node, size int) {
	first = &Node{val: n.val}
	if n.next == nil {
		return first, first, 1
	}

	next, last, size := n.next.clone()
	first.next, next.prev = next, first
	size++
	return
}

// Map returns a new list with function f applied to each element.
func (l *List) Map(f func(int) int) (rl *List) {
	rl = new(List)
	if l.first == nil {
		return
	}

	prev := &Node{val: f(l.first.val)}
	rl.first = prev
	for next := l.first.next; next != nil; next = next.next {
		prev.next = &Node{val: f(next.val), prev: prev}
		prev = prev.next
	}

	rl.last, rl.size = prev, l.size
	return
}

// FlatMap returns a new list consisting of the concatenation of all lists
// returned by function f.
func (l *List) FlatMap(f func(int) []int) (rl *List) {
	rl = new(List)
	if l.first == nil {
		return
	}

	fake := new(Node)
	prev := fake
	for next := l.first; next != nil; next = next.next {
		for _, v := range f(next.val) {
			prev.next = &Node{val: v, prev: prev}
			prev = prev.next
			rl.size++
		}
	}
	fake.next.prev = nil

	rl.first, rl.last = fake.next, prev
	return
}

// Filter returns a new list containing only elements where function f is true.
func (l *List) Filter(f func(int) bool) (rl *List) {
	rl = new(List)
	if l.first == nil {
		return
	}

	fake := new(Node)
	prev := fake
	for next := l.first; next != nil; next = next.next {
		if n := next.val; f(n) {
			prev.next = &Node{val: n, prev: prev}
			prev = prev.next
			rl.size++
		}
	}
	fake.next.prev = nil

	rl.first, rl.last = fake.next, prev
	return
}
<commit_msg>Add Exists and ForAll functions for testing element membership<commit_after>package list

import "fmt"

// Head returns the first value at the front of a list.
func (l *List) Head() (i int, err error) {
	if l.IsEmpty() {
		err = fmt.Errorf("Cannot take head of empty list")
		return
	}
	i = l.first.val
	return
}

// Tail returns a new list containing all elements other than the Head.
// If no elements remain an empty list is returned.
func (l *List) Tail() (rl *List, err error) {
	switch l.Size() {
	case 0:
		err = fmt.Errorf("Cannot take tail of empty list")
	case 1:
		rl = new(List)
	default:
		first, last, size := l.first.next.clone()
		rl = &List{first, last, size}
	}
	return
}

// Clone coppies the current node value and all child nodes connected by 'next'
// into a new linked list.
func (n *Node) clone() (first *Node, last *Node, size int) {
	first = &Node{val: n.val}
	if n.next == nil {
		return first, first, 1
	}

	next, last, size := n.next.clone()
	first.next, next.prev = next, first
	size++
	return
}

// Map returns a new list with function f applied to each element.
func (l *List) Map(f func(int) int) (rl *List) {
	rl = new(List)
	if l.first == nil {
		return
	}

	prev := &Node{val: f(l.first.val)}
	rl.first = prev
	for next := l.first.next; next != nil; next = next.next {
		prev.next = &Node{val: f(next.val), prev: prev}
		prev = prev.next
	}

	rl.last, rl.size = prev, l.size
	return
}

// FlatMap returns a new list consisting of the concatenation of all lists
// returned by function f.
func (l *List) FlatMap(f func(int) []int) (rl *List) {
	rl = new(List)
	if l.first == nil {
		return
	}

	fake := new(Node)
	prev := fake
	for next := l.first; next != nil; next = next.next {
		for _, v := range f(next.val) {
			prev.next = &Node{val: v, prev: prev}
			prev = prev.next
			rl.size++
		}
	}
	fake.next.prev = nil

	rl.first, rl.last = fake.next, prev
	return
}

// Filter returns a new list containing only elements where function f is true.
func (l *List) Filter(f func(int) bool) (rl *List) {
	rl = new(List)
	if l.first == nil {
		return
	}

	fake := new(Node)
	prev := fake
	for next := l.first; next != nil; next = next.next {
		if n := next.val; f(n) {
			prev.next = &Node{val: n, prev: prev}
			prev = prev.next
			rl.size++
		}
	}
	fake.next.prev = nil

	rl.first, rl.last = fake.next, prev
	return
}

// Exists checks if function f holds for at least one element.
func (l *List) Exists(f func(int) bool) bool {
	if l.IsEmpty() {
		return false
	}

	for next := l.first; next != nil; next = next.next {
		if f(next.val) {
			return true
		}
	}

	return false
}

// ForAll checks if function f holds for all elements.
func (l *List) ForAll(f func(int) bool) bool {
	if l.IsEmpty() {
		return false
	}

	for next := l.first; next != nil; next = next.next {
		if !f(next.val) {
			return false
		}
	}

	return true
}
<|endoftext|>


<commit_before>package logbcli

import (
	"flag"
	"fmt"
)

logbcli
func main() {
logBase := flag.Float64("Base", 0, "hvilken log base du vil bruke")
param := flag.Float64("Parameter", 0, "tallet du vil regne ut logaritmen av")
flag.Parse()

var log2 float64 = 2
var log10 float64 = 10

if *logBase == log2 {
fmt.Println(functions.Log2(*param))
} else if *logBase == log10 {
fmt.Println(functions.Log10(*param))
} else  {
fmt.Println("Not valid")
}

}<commit_msg>Delete reserve.go<commit_after><|endoftext|>


<commit_before>// (C) Copyright 2017 Hewlett Packard Enterprise Development LP
// 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 main

import (
	"flag"
	"fmt"
	"net/http"
	"os"
	"strings"
	"sync"
	"time"

	"github.com/HewlettPackard/lustre_exporter/sources"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/prometheus/common/log"
	"github.com/prometheus/common/version"
)

var (
	scrapeDurations = prometheus.NewSummaryVec(
		prometheus.SummaryOpts{
			Namespace: sources.Namespace,
			Subsystem: "exporter",
			Name:      "scrape_duration_seconds",
			Help:      "lustre_exporter: Duration of a scrape job.",
		},
		[]string{"source", "result"},
	)
)

//LustreSource is a list of all sources that the user would like to collect.
type LustreSource struct {
	sourceList map[string]sources.LustreSource
}

//Describe implements the prometheus.Describe interface
func (l LustreSource) Describe(ch chan<- *prometheus.Desc) {
	scrapeDurations.Describe(ch)
}

//Collect implements the prometheus.Collect interface
func (l LustreSource) Collect(ch chan<- prometheus.Metric) {
	wg := sync.WaitGroup{}
	wg.Add(len(l.sourceList))
	for name, c := range l.sourceList {
		go func(name string, c sources.LustreSource) {
			collectFromSource(name, c, ch)
			wg.Done()
		}(name, c)
	}
	wg.Wait()
	scrapeDurations.Collect(ch)
}

func collectFromSource(name string, s sources.LustreSource, ch chan<- prometheus.Metric) {
	result := "success"
	begin := time.Now()
	err := s.Update(ch)
	duration := time.Since(begin)
	if err != nil {
		log.Errorf("ERROR: %q source failed after %f seconds: %s", name, duration.Seconds(), err)
		result = "error"
	} else {
		log.Debugf("OK: %q source succeeded after %f seconds: %s", name, duration.Seconds(), err)
	}
	scrapeDurations.WithLabelValues(name, result).Observe(duration.Seconds())
}

func loadSources(list string) (map[string]sources.LustreSource, error) {
	sourceList := map[string]sources.LustreSource{}
	for _, name := range strings.Split(list, ",") {
		fn, ok := sources.Factories[name]
		if !ok {
			return nil, fmt.Errorf("source %q not available", name)
		}
		c, err := fn()
		if err != nil {
			return nil, err
		}
		sourceList[name] = c
	}
	return sourceList, nil
}

func init() {
	prometheus.MustRegister(version.NewCollector("lustre_exporter"))
}

func main() {
	var (
		showVersion   = flag.Bool("version", false, "Print version information.")
		listenAddress = flag.String("web.listen-address", ":9169", "Address to use to expose Lustre metrics.")
		metricsPath   = flag.String("web.telemetry-path", "/metrics", "Path to use to expose Lustre metrics.")
	)
	flag.Parse()

	if *showVersion {
		fmt.Fprintln(os.Stdout, version.Print("lustre_exporter"))
		os.Exit(0)
	}

	log.Infoln("Starting lustre_exporter", version.Info())
	log.Infoln("Build context", version.BuildContext())

	//expand to include more sources eventually (CLI, other?)
	enabledSources := "procfs"

	sourceList, err := loadSources(enabledSources)
	if err != nil {
		log.Fatalf("Couldn't load sources: %q", err)
	}

	log.Infof("Enabled sources:")
	for s := range sourceList {
		log.Infof(" - %s", s)
	}

	prometheus.MustRegister(LustreSource{sourceList: sourceList})
	handler := promhttp.HandlerFor(prometheus.DefaultGatherer, promhttp.HandlerOpts{ErrorLog: log.NewErrorLogger()})

	http.Handle(*metricsPath, prometheus.InstrumentHandler("prometheus", handler))
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(`
			<title>Lustre Exporter</title>

Lustre Exporter

<a href="` + *metricsPath + `">Metrics

			`))
	})

	log.Infoln("Listening on", *listenAddress)
	err = http.ListenAndServe(*listenAddress, nil)
	if err != nil {
		log.Fatal(err)
	}
}
<commit_msg>Allow multiple sources<commit_after>// (C) Copyright 2017 Hewlett Packard Enterprise Development LP
// 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 main

import (
	"flag"
	"fmt"
	"net/http"
	"os"
	"sync"
	"time"

	"github.com/HewlettPackard/lustre_exporter/sources"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/prometheus/common/log"
	"github.com/prometheus/common/version"
)

var (
	scrapeDurations = prometheus.NewSummaryVec(
		prometheus.SummaryOpts{
			Namespace: sources.Namespace,
			Subsystem: "exporter",
			Name:      "scrape_duration_seconds",
			Help:      "lustre_exporter: Duration of a scrape job.",
		},
		[]string{"source", "result"},
	)
)

//LustreSource is a list of all sources that the user would like to collect.
type LustreSource struct {
	sourceList map[string]sources.LustreSource
}

//Describe implements the prometheus.Describe interface
func (l LustreSource) Describe(ch chan<- *prometheus.Desc) {
	scrapeDurations.Describe(ch)
}

//Collect implements the prometheus.Collect interface
func (l LustreSource) Collect(ch chan<- prometheus.Metric) {
	wg := sync.WaitGroup{}
	wg.Add(len(l.sourceList))
	for name, c := range l.sourceList {
		go func(name string, c sources.LustreSource) {
			collectFromSource(name, c, ch)
			wg.Done()
		}(name, c)
	}
	wg.Wait()
	scrapeDurations.Collect(ch)
}

func collectFromSource(name string, s sources.LustreSource, ch chan<- prometheus.Metric) {
	result := "success"
	begin := time.Now()
	err := s.Update(ch)
	duration := time.Since(begin)
	if err != nil {
		log.Errorf("ERROR: %q source failed after %f seconds: %s", name, duration.Seconds(), err)
		result = "error"
	} else {
		log.Debugf("OK: %q source succeeded after %f seconds: %s", name, duration.Seconds(), err)
	}
	scrapeDurations.WithLabelValues(name, result).Observe(duration.Seconds())
}

func loadSources(list []string) (map[string]sources.LustreSource, error) {
	sourceList := map[string]sources.LustreSource{}
	for _, name := range list {
		fn, ok := sources.Factories[name]
		if !ok {
			return nil, fmt.Errorf("source %q not available", name)
		}
		c, err := fn()
		if err != nil {
			return nil, err
		}
		sourceList[name] = c
	}
	return sourceList, nil
}

func init() {
	prometheus.MustRegister(version.NewCollector("lustre_exporter"))
}

func main() {
	var (
		showVersion   = flag.Bool("version", false, "Print version information.")
		listenAddress = flag.String("web.listen-address", ":9169", "Address to use to expose Lustre metrics.")
		metricsPath   = flag.String("web.telemetry-path", "/metrics", "Path to use to expose Lustre metrics.")
	)
	flag.Parse()

	if *showVersion {
		fmt.Fprintln(os.Stdout, version.Print("lustre_exporter"))
		os.Exit(0)
	}

	log.Infoln("Starting lustre_exporter", version.Info())
	log.Infoln("Build context", version.BuildContext())

	//expand to include more sources eventually (CLI, other?)
	enabledSources := []string{"procfs"}

	sourceList, err := loadSources(enabledSources)
	if err != nil {
		log.Fatalf("Couldn't load sources: %q", err)
	}

	log.Infof("Enabled sources:")
	for s := range sourceList {
		log.Infof(" - %s", s)
	}

	prometheus.MustRegister(LustreSource{sourceList: sourceList})
	handler := promhttp.HandlerFor(prometheus.DefaultGatherer, promhttp.HandlerOpts{ErrorLog: log.NewErrorLogger()})

	http.Handle(*metricsPath, prometheus.InstrumentHandler("prometheus", handler))
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(`
			<title>Lustre Exporter</title>

Lustre Exporter

<a href="` + *metricsPath + `">Metrics

			`))
	})

	log.Infoln("Listening on", *listenAddress)
	err = http.ListenAndServe(*listenAddress, nil)
	if err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package dns

import (
	"fmt"
	"net"
	"strings"
	"time"

	"github.com/miekg/dns"

	"github.com/lxc/lxd/shared/api"
	"github.com/lxc/lxd/shared/logger"
)

type dnsHandler struct {
	server *Server
}

func (d dnsHandler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
	// Check if we're ready to serve queries.
	if d.server.zoneRetriever == nil {
		m := new(dns.Msg)
		m.SetRcode(r, dns.RcodeServerFailure)
		err := w.WriteMsg(m)
		if err != nil {
			logger.Error("Unable to write message", logger.Ctx{"err": err})
		}
		return
	}

	// Only allow a single request.
	if len(r.Question) != 1 {
		m := new(dns.Msg)
		m.SetRcode(r, dns.RcodeServerFailure)
		err := w.WriteMsg(m)
		if err != nil {
			logger.Error("Unable to write message", logger.Ctx{"err": err})
		}
		return
	}

	// Check that it's a supported request type.
	if r.Question[0].Qtype != dns.TypeAXFR && r.Question[0].Qtype != dns.TypeIXFR && r.Question[0].Qtype != dns.TypeSOA {
		m := new(dns.Msg)
		m.SetRcode(r, dns.RcodeNotImplemented)
		err := w.WriteMsg(m)
		if err != nil {
			logger.Error("Unable to write message", logger.Ctx{"err": err})
		}
		return
	}

	// Extract the request information.
	name := strings.TrimSuffix(r.Question[0].Name, ".")
	ip, _, err := net.SplitHostPort(w.RemoteAddr().String())
	if err != nil {
		m := new(dns.Msg)
		m.SetRcode(r, dns.RcodeServerFailure)
		err := w.WriteMsg(m)
		if err != nil {
			logger.Error("Unable to write message", logger.Ctx{"err": err})
		}
		return
	}

	// Prepare the response.
	m := new(dns.Msg)
	m.SetReply(r)
	m.Authoritative = true

	// Load the zone.
	zone, err := d.server.zoneRetriever(name, r.Question[0].Qtype != dns.TypeSOA)
	if err != nil {
		// On failure, return NXDOMAIN.
		m := new(dns.Msg)
		m.SetRcode(r, dns.RcodeNameError)
		err := w.WriteMsg(m)
		if err != nil {
			logger.Error("Unable to write message", logger.Ctx{"err": err})
		}
		return
	}

	// Check access.
	if !d.isAllowed(zone.Info, ip, r.IsTsig(), w.TsigStatus() == nil) {
		// On auth failure, return NXDOMAIN to avoid information leaks.
		m := new(dns.Msg)
		m.SetRcode(r, dns.RcodeNameError)
		err := w.WriteMsg(m)
		if err != nil {
			logger.Error("Unable to write message", logger.Ctx{"err": err})
		}
		return
	}

	zoneRR := dns.NewZoneParser(strings.NewReader(zone.Content), "", "")
	for {
		rr, ok := zoneRR.Next()
		if !ok {
			err := zoneRR.Err()
			if err != nil {
				logger.Errorf("Bad DNS record in zone %q: %v", name, err)

				m := new(dns.Msg)
				m.SetRcode(r, dns.RcodeFormatError)
				err := w.WriteMsg(m)
				if err != nil {
					logger.Error("Unable to write message", logger.Ctx{"err": err})
				}
				return
			}

			break
		}

		m.Answer = append(m.Answer, rr)
	}

	tsig := r.IsTsig()
	if tsig != nil && w.TsigStatus() == nil {
		m.SetTsig(tsig.Hdr.Name, tsig.Algorithm, 300, time.Now().Unix())
	}

	err = w.WriteMsg(m)
	if err != nil {
		logger.Error("Unable to write message", logger.Ctx{"err": err})
	}

	return
}

func (d *dnsHandler) isAllowed(zone api.NetworkZone, ip string, tsig *dns.TSIG, tsigStatus bool) bool {
	type peer struct {
		address string
		key     string
	}

	// Build a list of peers.
	peers := map[string]*peer{}
	for k, v := range zone.Config {
		if !strings.HasPrefix(k, "peers.") {
			continue
		}

		// Extract the fields.
		fields := strings.SplitN(k, ".", 3)
		if len(fields) != 3 {
			continue
		}

		peerName := fields[1]

		if peers[peerName] == nil {
			peers[peerName] = &peer{}
		}

		// Add the correct validation rule for the dynamic field based on last part of key.
		switch fields[2] {
		case "address":
			peers[peerName].address = v
		case "key":
			peers[peerName].key = v
		}
	}

	// Validate access.
	for peerName, peer := range peers {
		peerKeyName := fmt.Sprintf("%s_%s.", zone.Name, peerName)

		if peer.address != "" && ip != peer.address {
			// Bad IP address.
			continue
		}

		if peer.key != "" && (tsig == nil || !tsigStatus) {
			// Missing or invalid TSIG.
			continue
		}

		if peer.key != "" && tsig.Hdr.Name != peerKeyName {
			// Bad key name (valid TSIG but potentially for another domain).
			continue
		}

		// We have a trusted peer.
		return true
	}

	return false
}
<commit_msg>lxd/dns: Fixes gosimple lint errors.<commit_after>package dns

import (
	"fmt"
	"net"
	"strings"
	"time"

	"github.com/miekg/dns"

	"github.com/lxc/lxd/shared/api"
	"github.com/lxc/lxd/shared/logger"
)

type dnsHandler struct {
	server *Server
}

func (d dnsHandler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
	// Check if we're ready to serve queries.
	if d.server.zoneRetriever == nil {
		m := new(dns.Msg)
		m.SetRcode(r, dns.RcodeServerFailure)
		err := w.WriteMsg(m)
		if err != nil {
			logger.Error("Unable to write message", logger.Ctx{"err": err})
		}
		return
	}

	// Only allow a single request.
	if len(r.Question) != 1 {
		m := new(dns.Msg)
		m.SetRcode(r, dns.RcodeServerFailure)
		err := w.WriteMsg(m)
		if err != nil {
			logger.Error("Unable to write message", logger.Ctx{"err": err})
		}
		return
	}

	// Check that it's a supported request type.
	if r.Question[0].Qtype != dns.TypeAXFR && r.Question[0].Qtype != dns.TypeIXFR && r.Question[0].Qtype != dns.TypeSOA {
		m := new(dns.Msg)
		m.SetRcode(r, dns.RcodeNotImplemented)
		err := w.WriteMsg(m)
		if err != nil {
			logger.Error("Unable to write message", logger.Ctx{"err": err})
		}
		return
	}

	// Extract the request information.
	name := strings.TrimSuffix(r.Question[0].Name, ".")
	ip, _, err := net.SplitHostPort(w.RemoteAddr().String())
	if err != nil {
		m := new(dns.Msg)
		m.SetRcode(r, dns.RcodeServerFailure)
		err := w.WriteMsg(m)
		if err != nil {
			logger.Error("Unable to write message", logger.Ctx{"err": err})
		}
		return
	}

	// Prepare the response.
	m := new(dns.Msg)
	m.SetReply(r)
	m.Authoritative = true

	// Load the zone.
	zone, err := d.server.zoneRetriever(name, r.Question[0].Qtype != dns.TypeSOA)
	if err != nil {
		// On failure, return NXDOMAIN.
		m := new(dns.Msg)
		m.SetRcode(r, dns.RcodeNameError)
		err := w.WriteMsg(m)
		if err != nil {
			logger.Error("Unable to write message", logger.Ctx{"err": err})
		}
		return
	}

	// Check access.
	if !d.isAllowed(zone.Info, ip, r.IsTsig(), w.TsigStatus() == nil) {
		// On auth failure, return NXDOMAIN to avoid information leaks.
		m := new(dns.Msg)
		m.SetRcode(r, dns.RcodeNameError)
		err := w.WriteMsg(m)
		if err != nil {
			logger.Error("Unable to write message", logger.Ctx{"err": err})
		}
		return
	}

	zoneRR := dns.NewZoneParser(strings.NewReader(zone.Content), "", "")
	for {
		rr, ok := zoneRR.Next()
		if !ok {
			err := zoneRR.Err()
			if err != nil {
				logger.Errorf("Bad DNS record in zone %q: %v", name, err)

				m := new(dns.Msg)
				m.SetRcode(r, dns.RcodeFormatError)
				err := w.WriteMsg(m)
				if err != nil {
					logger.Error("Unable to write message", logger.Ctx{"err": err})
				}
				return
			}

			break
		}

		m.Answer = append(m.Answer, rr)
	}

	tsig := r.IsTsig()
	if tsig != nil && w.TsigStatus() == nil {
		m.SetTsig(tsig.Hdr.Name, tsig.Algorithm, 300, time.Now().Unix())
	}

	err = w.WriteMsg(m)
	if err != nil {
		logger.Error("Unable to write message", logger.Ctx{"err": err})
	}
}

func (d *dnsHandler) isAllowed(zone api.NetworkZone, ip string, tsig *dns.TSIG, tsigStatus bool) bool {
	type peer struct {
		address string
		key     string
	}

	// Build a list of peers.
	peers := map[string]*peer{}
	for k, v := range zone.Config {
		if !strings.HasPrefix(k, "peers.") {
			continue
		}

		// Extract the fields.
		fields := strings.SplitN(k, ".", 3)
		if len(fields) != 3 {
			continue
		}

		peerName := fields[1]

		if peers[peerName] == nil {
			peers[peerName] = &peer{}
		}

		// Add the correct validation rule for the dynamic field based on last part of key.
		switch fields[2] {
		case "address":
			peers[peerName].address = v
		case "key":
			peers[peerName].key = v
		}
	}

	// Validate access.
	for peerName, peer := range peers {
		peerKeyName := fmt.Sprintf("%s_%s.", zone.Name, peerName)

		if peer.address != "" && ip != peer.address {
			// Bad IP address.
			continue
		}

		if peer.key != "" && (tsig == nil || !tsigStatus) {
			// Missing or invalid TSIG.
			continue
		}

		if peer.key != "" && tsig.Hdr.Name != peerKeyName {
			// Bad key name (valid TSIG but potentially for another domain).
			continue
		}

		// We have a trusted peer.
		return true
	}

	return false
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/gorilla/websocket"

	"github.com/lxc/lxd/shared"

	log "gopkg.in/inconshreveable/log15.v2"
)

type storageDir struct {
	d *Daemon

	storageShared
}

func (s *storageDir) Init(config map[string]interface{}) (storage, error) {
	s.sType = storageTypeDir
	s.sTypeName = storageTypeToString(s.sType)
	if err := s.initShared(); err != nil {
		return s, err
	}

	return s, nil
}

func (s *storageDir) ContainerCreate(container container) error {
	cPath := container.Path()
	if err := os.MkdirAll(cPath, 0755); err != nil {
		return fmt.Errorf("Error creating containers directory")
	}

	if container.IsPrivileged() {
		if err := os.Chmod(cPath, 0700); err != nil {
			return err
		}
	}

	return container.TemplateApply("create")
}

func (s *storageDir) ContainerCreateFromImage(
	container container, imageFingerprint string) error {

	rootfsPath := container.RootfsPath()
	if err := os.MkdirAll(rootfsPath, 0755); err != nil {
		return fmt.Errorf("Error creating rootfs directory")
	}

	if container.IsPrivileged() {
		if err := os.Chmod(container.Path(), 0700); err != nil {
			return err
		}
	}

	imagePath := shared.VarPath("images", imageFingerprint)
	if err := unpackImage(imagePath, container.Path()); err != nil {
		s.ContainerDelete(container)
		return err
	}

	if !container.IsPrivileged() {
		if err := s.shiftRootfs(container); err != nil {
			s.ContainerDelete(container)
			return err
		}
	}

	return container.TemplateApply("create")
}

func (s *storageDir) ContainerCanRestore(container container, sourceContainer container) error {
	return nil
}

func (s *storageDir) ContainerDelete(container container) error {
	cPath := container.Path()

	if !shared.PathExists(cPath) {
		return nil
	}

	err := os.RemoveAll(cPath)
	if err != nil {
		// RemovaAll fails on very long paths, so attempt an rm -Rf
		output, err := exec.Command("rm", "-Rf", cPath).CombinedOutput()
		if err != nil {
			s.log.Error("ContainerDelete: failed", log.Ctx{"cPath": cPath, "output": output})
			return fmt.Errorf("Error cleaning up %s: %s", cPath, string(output))
		}
	}

	return nil
}

func (s *storageDir) ContainerCopy(
	container container, sourceContainer container) error {

	oldPath := sourceContainer.RootfsPath()
	newPath := container.RootfsPath()

	/*
	 * Copy by using rsync
	 */
	output, err := storageRsyncCopy(oldPath, newPath)
	if err != nil {
		s.ContainerDelete(container)
		s.log.Error("ContainerCopy: rsync failed", log.Ctx{"output": string(output)})
		return fmt.Errorf("rsync failed: %s", string(output))
	}

	err = s.setUnprivUserAcl(sourceContainer, container.Path())
	if err != nil {
		return err
	}

	return container.TemplateApply("copy")
}

func (s *storageDir) ContainerStart(container container) error {
	return nil
}

func (s *storageDir) ContainerStop(container container) error {
	return nil
}

func (s *storageDir) ContainerRename(container container, newName string) error {
	oldName := container.Name()

	oldPath := container.Path()
	newPath := containerPath(newName, false)

	if err := os.Rename(oldPath, newPath); err != nil {
		return err
	}

	if shared.PathExists(shared.VarPath(fmt.Sprintf("snapshots/%s", oldName))) {
		err := os.Rename(shared.VarPath(fmt.Sprintf("snapshots/%s", oldName)), shared.VarPath(fmt.Sprintf("snapshots/%s", newName)))
		if err != nil {
			return err
		}
	}

	return nil
}

func (s *storageDir) ContainerRestore(
	container container, sourceContainer container) error {

	targetPath := container.Path()
	sourcePath := sourceContainer.Path()

	// Restore using rsync
	output, err := storageRsyncCopy(
		sourcePath,
		targetPath)

	if err != nil {
		s.log.Error(
			"ContainerRestore: rsync failed",
			log.Ctx{"output": string(output)})

		return err
	}

	// Now allow unprivileged users to access its data.
	if err := s.setUnprivUserAcl(sourceContainer, targetPath); err != nil {
		return err
	}

	return nil
}

func (s *storageDir) ContainerSetQuota(container container, size int64) error {
	return fmt.Errorf("The directory container backend doesn't support quotas.")
}

func (s *storageDir) ContainerGetUsage(container container) (int64, error) {
	return -1, fmt.Errorf("The directory container backend doesn't support quotas.")
}

func (s *storageDir) ContainerSnapshotCreate(
	snapshotContainer container, sourceContainer container) error {

	oldPath := sourceContainer.Path()
	newPath := snapshotContainer.Path()

	/*
	 * Copy by using rsync
	 */
	output, err := storageRsyncCopy(oldPath, newPath)
	if err != nil {
		s.ContainerDelete(snapshotContainer)
		s.log.Error("ContainerSnapshotCreate: rsync failed",
			log.Ctx{"output": string(output)})

		return fmt.Errorf("rsync failed: %s", string(output))
	}

	return nil
}

func (s *storageDir) ContainerSnapshotCreateEmpty(snapshotContainer container) error {
	return os.MkdirAll(snapshotContainer.Path(), 0700)
}

func (s *storageDir) ContainerSnapshotDelete(
	snapshotContainer container) error {
	err := s.ContainerDelete(snapshotContainer)
	if err != nil {
		return fmt.Errorf("Error deleting snapshot %s: %s", snapshotContainer.Name(), err)
	}

	oldPathParent := filepath.Dir(snapshotContainer.Path())
	if ok, _ := shared.PathIsEmpty(oldPathParent); ok {
		os.Remove(oldPathParent)
	}

	return nil
}

func (s *storageDir) ContainerSnapshotRename(
	snapshotContainer container, newName string) error {

	oldPath := snapshotContainer.Path()
	newPath := containerPath(newName, true)

	// Create the new parent.
	if strings.Contains(snapshotContainer.Name(), "/") {
		if !shared.PathExists(filepath.Dir(newPath)) {
			os.MkdirAll(filepath.Dir(newPath), 0700)
		}
	}

	// Now rename the snapshot.
	if err := os.Rename(oldPath, newPath); err != nil {
		return err
	}

	// Remove the old parent (on container rename) if its empty.
	if strings.Contains(snapshotContainer.Name(), "/") {
		if ok, _ := shared.PathIsEmpty(filepath.Dir(oldPath)); ok {
			os.Remove(filepath.Dir(oldPath))
		}
	}

	return nil
}

func (s *storageDir) ContainerSnapshotStart(container container) error {
	return nil
}

func (s *storageDir) ContainerSnapshotStop(container container) error {
	return nil
}

func (s *storageDir) ImageCreate(fingerprint string) error {
	return nil
}

func (s *storageDir) ImageDelete(fingerprint string) error {
	return nil
}

func (s *storageDir) MigrationType() MigrationFSType {
	return MigrationFSType_RSYNC
}

func (s *storageDir) PreservesInodes() bool {
	return false
}

func (s *storageDir) MigrationSource(container container) (MigrationStorageSourceDriver, error) {
	return rsyncMigrationSource(container)
}

func (s *storageDir) MigrationSink(live bool, container container, snapshots []container, conn *websocket.Conn) error {
	return rsyncMigrationSink(live, container, snapshots, conn)
}
<commit_msg>dir: Copy everything on container copy<commit_after>package main

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/gorilla/websocket"

	"github.com/lxc/lxd/shared"

	log "gopkg.in/inconshreveable/log15.v2"
)

type storageDir struct {
	d *Daemon

	storageShared
}

func (s *storageDir) Init(config map[string]interface{}) (storage, error) {
	s.sType = storageTypeDir
	s.sTypeName = storageTypeToString(s.sType)
	if err := s.initShared(); err != nil {
		return s, err
	}

	return s, nil
}

func (s *storageDir) ContainerCreate(container container) error {
	cPath := container.Path()
	if err := os.MkdirAll(cPath, 0755); err != nil {
		return fmt.Errorf("Error creating containers directory")
	}

	if container.IsPrivileged() {
		if err := os.Chmod(cPath, 0700); err != nil {
			return err
		}
	}

	return container.TemplateApply("create")
}

func (s *storageDir) ContainerCreateFromImage(
	container container, imageFingerprint string) error {

	rootfsPath := container.RootfsPath()
	if err := os.MkdirAll(rootfsPath, 0755); err != nil {
		return fmt.Errorf("Error creating rootfs directory")
	}

	if container.IsPrivileged() {
		if err := os.Chmod(container.Path(), 0700); err != nil {
			return err
		}
	}

	imagePath := shared.VarPath("images", imageFingerprint)
	if err := unpackImage(imagePath, container.Path()); err != nil {
		s.ContainerDelete(container)
		return err
	}

	if !container.IsPrivileged() {
		if err := s.shiftRootfs(container); err != nil {
			s.ContainerDelete(container)
			return err
		}
	}

	return container.TemplateApply("create")
}

func (s *storageDir) ContainerCanRestore(container container, sourceContainer container) error {
	return nil
}

func (s *storageDir) ContainerDelete(container container) error {
	cPath := container.Path()

	if !shared.PathExists(cPath) {
		return nil
	}

	err := os.RemoveAll(cPath)
	if err != nil {
		// RemovaAll fails on very long paths, so attempt an rm -Rf
		output, err := exec.Command("rm", "-Rf", cPath).CombinedOutput()
		if err != nil {
			s.log.Error("ContainerDelete: failed", log.Ctx{"cPath": cPath, "output": output})
			return fmt.Errorf("Error cleaning up %s: %s", cPath, string(output))
		}
	}

	return nil
}

func (s *storageDir) ContainerCopy(
	container container, sourceContainer container) error {

	oldPath := sourceContainer.Path()
	newPath := container.Path()

	/*
	 * Copy by using rsync
	 */
	output, err := storageRsyncCopy(oldPath, newPath)
	if err != nil {
		s.ContainerDelete(container)
		s.log.Error("ContainerCopy: rsync failed", log.Ctx{"output": string(output)})
		return fmt.Errorf("rsync failed: %s", string(output))
	}

	err = s.setUnprivUserAcl(sourceContainer, container.Path())
	if err != nil {
		return err
	}

	return container.TemplateApply("copy")
}

func (s *storageDir) ContainerStart(container container) error {
	return nil
}

func (s *storageDir) ContainerStop(container container) error {
	return nil
}

func (s *storageDir) ContainerRename(container container, newName string) error {
	oldName := container.Name()

	oldPath := container.Path()
	newPath := containerPath(newName, false)

	if err := os.Rename(oldPath, newPath); err != nil {
		return err
	}

	if shared.PathExists(shared.VarPath(fmt.Sprintf("snapshots/%s", oldName))) {
		err := os.Rename(shared.VarPath(fmt.Sprintf("snapshots/%s", oldName)), shared.VarPath(fmt.Sprintf("snapshots/%s", newName)))
		if err != nil {
			return err
		}
	}

	return nil
}

func (s *storageDir) ContainerRestore(
	container container, sourceContainer container) error {

	targetPath := container.Path()
	sourcePath := sourceContainer.Path()

	// Restore using rsync
	output, err := storageRsyncCopy(
		sourcePath,
		targetPath)

	if err != nil {
		s.log.Error(
			"ContainerRestore: rsync failed",
			log.Ctx{"output": string(output)})

		return err
	}

	// Now allow unprivileged users to access its data.
	if err := s.setUnprivUserAcl(sourceContainer, targetPath); err != nil {
		return err
	}

	return nil
}

func (s *storageDir) ContainerSetQuota(container container, size int64) error {
	return fmt.Errorf("The directory container backend doesn't support quotas.")
}

func (s *storageDir) ContainerGetUsage(container container) (int64, error) {
	return -1, fmt.Errorf("The directory container backend doesn't support quotas.")
}

func (s *storageDir) ContainerSnapshotCreate(
	snapshotContainer container, sourceContainer container) error {

	oldPath := sourceContainer.Path()
	newPath := snapshotContainer.Path()

	/*
	 * Copy by using rsync
	 */
	output, err := storageRsyncCopy(oldPath, newPath)
	if err != nil {
		s.ContainerDelete(snapshotContainer)
		s.log.Error("ContainerSnapshotCreate: rsync failed",
			log.Ctx{"output": string(output)})

		return fmt.Errorf("rsync failed: %s", string(output))
	}

	return nil
}

func (s *storageDir) ContainerSnapshotCreateEmpty(snapshotContainer container) error {
	return os.MkdirAll(snapshotContainer.Path(), 0700)
}

func (s *storageDir) ContainerSnapshotDelete(
	snapshotContainer container) error {
	err := s.ContainerDelete(snapshotContainer)
	if err != nil {
		return fmt.Errorf("Error deleting snapshot %s: %s", snapshotContainer.Name(), err)
	}

	oldPathParent := filepath.Dir(snapshotContainer.Path())
	if ok, _ := shared.PathIsEmpty(oldPathParent); ok {
		os.Remove(oldPathParent)
	}

	return nil
}

func (s *storageDir) ContainerSnapshotRename(
	snapshotContainer container, newName string) error {

	oldPath := snapshotContainer.Path()
	newPath := containerPath(newName, true)

	// Create the new parent.
	if strings.Contains(snapshotContainer.Name(), "/") {
		if !shared.PathExists(filepath.Dir(newPath)) {
			os.MkdirAll(filepath.Dir(newPath), 0700)
		}
	}

	// Now rename the snapshot.
	if err := os.Rename(oldPath, newPath); err != nil {
		return err
	}

	// Remove the old parent (on container rename) if its empty.
	if strings.Contains(snapshotContainer.Name(), "/") {
		if ok, _ := shared.PathIsEmpty(filepath.Dir(oldPath)); ok {
			os.Remove(filepath.Dir(oldPath))
		}
	}

	return nil
}

func (s *storageDir) ContainerSnapshotStart(container container) error {
	return nil
}

func (s *storageDir) ContainerSnapshotStop(container container) error {
	return nil
}

func (s *storageDir) ImageCreate(fingerprint string) error {
	return nil
}

func (s *storageDir) ImageDelete(fingerprint string) error {
	return nil
}

func (s *storageDir) MigrationType() MigrationFSType {
	return MigrationFSType_RSYNC
}

func (s *storageDir) PreservesInodes() bool {
	return false
}

func (s *storageDir) MigrationSource(container container) (MigrationStorageSourceDriver, error) {
	return rsyncMigrationSource(container)
}

func (s *storageDir) MigrationSink(live bool, container container, snapshots []container, conn *websocket.Conn) error {
	return rsyncMigrationSink(live, container, snapshots, conn)
}
<|endoftext|>


<commit_before>package lzbase

import (
	"fmt"
	"io"
	"unicode"
)

// operation represents an operation on the dictionary during encoding or
// decoding.
type Operation interface {
	Len() int
}

// rep represents a repetition at the given distance and the given length
type match struct {
	// supports all possible distance values, including the eos marker
	distance int64
	length   int
}

// eos is a special kind of match.
var eos = match{distance: maxDistance, length: MinLength}

// EOS may mark the end of an LZMA stream.
var EOS = Operation(eos)

// Len return the length of the repetition.
func (m match) Len() int {
	return m.length
}

// String returns a string representation for the repetition.
func (m match) String() string {
	return fmt.Sprintf("match{%d,%d}", m.distance, m.length)
}

// lit represents a single byte literal.
type lit struct {
	b byte
}

// Len returns 1 for the single byte literal.
func (l lit) Len() int {
	return 1
}

// String returns a string representation for the literal.
func (l lit) String() string {
	var c byte
	if unicode.IsPrint(rune(l.b)) {
		c = l.b
	} else {
		c = '.'
	}
	return fmt.Sprintf("lit{%02x %c}", l.b, c)
}

// OpEncoder translates a sequences of operations to a byte stream.
type OpEncoder struct {
	W     io.Writer
	State *State
	re    *rangeEncoder
}

// NewOpEncoder creates a new OpEncoder value. Writer and state cannot be
// shared with other instances.
func NewOpEncoder(w io.Writer, state *State) (e *OpEncoder, err error) {
	switch {
	case w == nil:
		return nil, newError("NewOpEncoder argument w is nil")
	case state == nil:
		return nil, newError("NewOpEncoder argument state is nil")
	}
	e = &OpEncoder{
		W:     w,
		State: state,
		re:    newRangeEncoder(w),
	}
	return e, nil
}

// iverson translates a boolean into an integer value. Donald Knuth calls a
// mathematical operator doing the same Iverson operator in Concrete
// Mathematics.
func iverson(ok bool) uint32 {
	if ok {
		return 1
	}
	return 0
}

// writeMatch writes a match operation into the range encoder.
func (e *OpEncoder) writeMatch(m match) error {
	var err error
	if !(minDistance <= m.distance && m.distance <= maxDistance) {
		return newError("distance out of range")
	}
	dist := uint32(m.distance - minDistance)
	if !(MinLength <= m.length && m.length <= MaxLength) &&
		!(dist == e.State.rep[0] && m.length == 1) {
		return newError("length out of range")
	}
	state, state2, posState := e.State.states()
	if err = e.State.isMatch[state2].Encode(e.re, 1); err != nil {
		return err
	}
	var g int
	for g = 0; g < 4; g++ {
		if e.State.rep[g] == dist {
			break
		}
	}
	b := iverson(g < 4)
	if err = e.State.isRep[state].Encode(e.re, b); err != nil {
		return err
	}
	n := uint32(m.length - MinLength)
	if b == 0 {
		// simple match
		e.State.rep[3], e.State.rep[2], e.State.rep[1], e.State.rep[0] = e.State.rep[2], e.State.rep[1], e.State.rep[0], dist
		e.State.updateStateMatch()
		if err = e.State.lenCodec.Encode(e.re, n, posState); err != nil {
			return err
		}
		return e.State.distCodec.Encode(e.re, dist, n)
	}
	b = iverson(g != 0)
	if err = e.State.isRepG0[state].Encode(e.re, b); err != nil {
		return err
	}
	if b == 0 {
		// g == 0
		b = iverson(m.length != 1)
		if err = e.State.isRepG0Long[state2].Encode(e.re, b); err != nil {
			return err
		}
		if b == 0 {
			e.State.updateStateShortRep()
			return nil
		}
	} else {
		// g in {1,2,3}
		b = iverson(g != 1)
		if err = e.State.isRepG1[state].Encode(e.re, b); err != nil {
			return err
		}
		if b == 1 {
			// g in {2,3}
			b = iverson(g != 2)
			err = e.State.isRepG2[state].Encode(e.re, b)
			if err != nil {
				return err
			}
			if b == 1 {
				e.State.rep[3] = e.State.rep[2]
			}
			e.State.rep[2] = e.State.rep[1]
		}
		e.State.rep[1] = e.State.rep[0]
		e.State.rep[0] = dist
	}
	e.State.updateStateRep()
	return e.State.repLenCodec.Encode(e.re, n, posState)
}

// writeLiteral writes a literal into the operation stream
func (e *OpEncoder) writeLiteral(l lit) error {
	var err error
	state, state2, _ := e.State.states()
	if err = e.State.isMatch[state2].Encode(e.re, 0); err != nil {
		return err
	}
	litState := e.State.litState()
	match := e.State.dict.Byte(int64(e.State.rep[0]) + 1)
	err = e.State.litCodec.Encode(e.re, l.b, state, match, litState)
	if err != nil {
		return err
	}
	e.State.updateStateLiteral()
	return nil
}

// WriteOps translates the given operations into an encoded byte stream. The
// number of operations written will be reported and any error condition. Note
// that an error might indicate that parts of the operation have already been
// written.
func (e *OpEncoder) WriteOps(ops []Operation) (n int, err error) {
	for _, op := range ops {
		switch x := op.(type) {
		case match:
			if err = e.writeMatch(x); err != nil {
				return n, err
			}
		case lit:
			if err = e.writeLiteral(x); err != nil {
				return n, err
			}
		default:
			return n, newError("unknown operation type")
		}
		n++
	}
	return n, nil
}

// Close closes the encoder.
func (e *OpEncoder) Close() error {
	return e.re.Close()
}

// OpDecoder translates a byte stream to a sequence of operations.
type OpDecoder struct {
	R     io.Reader
	State *State
	rd    *rangeDecoder
}

// NewOpDecoder creates a new OpDecoder valure. Reader and state cannot be
// shared with other instances.
func NewOpDecoder(r io.Reader, state *State) (d *OpDecoder, err error) {
	panic("TODO")
}

// ReadOps reads a sequence of operations. The number of operations read will
// be returned. Note that an error may indicate that the read of a full
// operation has not been successful.
func (d *OpDecoder) ReadOps(ops []Operation) (n int, err error) {
	panic("TODO")
}
<commit_msg>lzbase: implemented OpDecoder<commit_after>package lzbase

import (
	"fmt"
	"io"
	"unicode"
)

// operation represents an operation on the dictionary during encoding or
// decoding.
type Operation interface {
	Len() int
}

// rep represents a repetition at the given distance and the given length
type match struct {
	// supports all possible distance values, including the eos marker
	distance int64
	length   int
}

// eos is a special kind of match.
var eos = match{distance: maxDistance, length: MinLength}

// EOSOp may mark the end of an LZMA stream.
var EOSOp = Operation(eos)

// Len return the length of the repetition.
func (m match) Len() int {
	return m.length
}

// String returns a string representation for the repetition.
func (m match) String() string {
	return fmt.Sprintf("match{%d,%d}", m.distance, m.length)
}

// lit represents a single byte literal.
type lit struct {
	b byte
}

// Len returns 1 for the single byte literal.
func (l lit) Len() int {
	return 1
}

// String returns a string representation for the literal.
func (l lit) String() string {
	var c byte
	if unicode.IsPrint(rune(l.b)) {
		c = l.b
	} else {
		c = '.'
	}
	return fmt.Sprintf("lit{%02x %c}", l.b, c)
}

// OpEncoder translates a sequences of operations to a byte stream.
type OpEncoder struct {
	W     io.Writer
	State *State
	re    *rangeEncoder
}

// NewOpEncoder creates a new OpEncoder value. Writer and state cannot be
// shared with other instances.
func NewOpEncoder(w io.Writer, state *State) (e *OpEncoder, err error) {
	switch {
	case w == nil:
		return nil, newError("NewOpEncoder argument w is nil")
	case state == nil:
		return nil, newError("NewOpEncoder argument state is nil")
	}
	e = &OpEncoder{
		W:     w,
		State: state,
		re:    newRangeEncoder(w),
	}
	return e, nil
}

// iverson translates a boolean into an integer value. Donald Knuth calls a
// mathematical operator doing the same Iverson operator in Concrete
// Mathematics.
func iverson(ok bool) uint32 {
	if ok {
		return 1
	}
	return 0
}

// writeMatch writes a match operation into the range encoder.
func (e *OpEncoder) writeMatch(m match) error {
	var err error
	if !(minDistance <= m.distance && m.distance <= maxDistance) {
		return newError("distance out of range")
	}
	dist := uint32(m.distance - minDistance)
	if !(MinLength <= m.length && m.length <= MaxLength) &&
		!(dist == e.State.rep[0] && m.length == 1) {
		return newError("length out of range")
	}
	state, state2, posState := e.State.states()
	if err = e.State.isMatch[state2].Encode(e.re, 1); err != nil {
		return err
	}
	var g int
	for g = 0; g < 4; g++ {
		if e.State.rep[g] == dist {
			break
		}
	}
	b := iverson(g < 4)
	if err = e.State.isRep[state].Encode(e.re, b); err != nil {
		return err
	}
	n := uint32(m.length - MinLength)
	if b == 0 {
		// simple match
		e.State.rep[3], e.State.rep[2], e.State.rep[1], e.State.rep[0] = e.State.rep[2], e.State.rep[1], e.State.rep[0], dist
		e.State.updateStateMatch()
		if err = e.State.lenCodec.Encode(e.re, n, posState); err != nil {
			return err
		}
		return e.State.distCodec.Encode(e.re, dist, n)
	}
	b = iverson(g != 0)
	if err = e.State.isRepG0[state].Encode(e.re, b); err != nil {
		return err
	}
	if b == 0 {
		// g == 0
		b = iverson(m.length != 1)
		if err = e.State.isRepG0Long[state2].Encode(e.re, b); err != nil {
			return err
		}
		if b == 0 {
			e.State.updateStateShortRep()
			return nil
		}
	} else {
		// g in {1,2,3}
		b = iverson(g != 1)
		if err = e.State.isRepG1[state].Encode(e.re, b); err != nil {
			return err
		}
		if b == 1 {
			// g in {2,3}
			b = iverson(g != 2)
			err = e.State.isRepG2[state].Encode(e.re, b)
			if err != nil {
				return err
			}
			if b == 1 {
				e.State.rep[3] = e.State.rep[2]
			}
			e.State.rep[2] = e.State.rep[1]
		}
		e.State.rep[1] = e.State.rep[0]
		e.State.rep[0] = dist
	}
	e.State.updateStateRep()
	return e.State.repLenCodec.Encode(e.re, n, posState)
}

// writeLiteral writes a literal into the operation stream
func (e *OpEncoder) writeLiteral(l lit) error {
	var err error
	state, state2, _ := e.State.states()
	if err = e.State.isMatch[state2].Encode(e.re, 0); err != nil {
		return err
	}
	litState := e.State.litState()
	match := e.State.dict.Byte(int64(e.State.rep[0]) + 1)
	err = e.State.litCodec.Encode(e.re, l.b, state, match, litState)
	if err != nil {
		return err
	}
	e.State.updateStateLiteral()
	return nil
}

// WriteOps translates the given operations into an encoded byte stream. The
// number of operations written will be reported and any error condition. Note
// that an error might indicate that parts of the operation have already been
// written.
func (e *OpEncoder) WriteOps(ops []Operation) (n int, err error) {
	for _, op := range ops {
		switch x := op.(type) {
		case match:
			if err = e.writeMatch(x); err != nil {
				return n, err
			}
		case lit:
			if err = e.writeLiteral(x); err != nil {
				return n, err
			}
		default:
			return n, newError("unknown operation type")
		}
		n++
	}
	return n, nil
}

// Close closes the encoder.
func (e *OpEncoder) Close() error {
	return e.re.Close()
}

// OpDecoder translates a byte stream to a sequence of operations.
type OpDecoder struct {
	R     io.Reader
	State *State
	rd    *rangeDecoder
}

// NewOpDecoder creates a new OpDecoder valure. Reader and state cannot be
// shared with other instances. Note that the function will read five bytes
// from the reader.
func NewOpDecoder(r io.Reader, state *State) (d *OpDecoder, err error) {
	switch {
	case r == nil:
		return nil, newError("NewOpDecoder argument r is nil")
	case state == nil:
		return nil, newError("NewOpDecoder argumen state is nil")
	}
	d = &OpDecoder{
		R:     r,
		State: state,
	}
	if d.rd, err = newRangeDecoder(r); err != nil {
		return nil, err
	}
	return d, nil
}

// decodeLiteral reads a literal
func (d *OpDecoder) decodeLiteral() (op Operation, err error) {
	litState := d.State.litState()

	match := d.State.dict.Byte(int64(d.State.rep[0]) + 1)
	s, err := d.State.litCodec.Decode(d.rd, d.State.state, match, litState)
	if err != nil {
		return nil, err
	}
	return lit{s}, nil
}

// errWrongTermination indicates that a termination symbol has been received,
// but the range decoder could still produces more data
var errWrongTermination = newError("end of stream marker at wrong place")

// readOp decodes the next operation from the compressed stream. It returns
// EOSOp if present in stream. If the EOS operation is not at the end of the
// stream then errWrongTermination is returned.
func (d *OpDecoder) readOp() (op Operation, err error) {
	state, state2, posState := d.State.states()

	b, err := d.State.isMatch[state2].Decode(d.rd)
	if err != nil {
		return nil, err
	}
	if b == 0 {
		// literal
		op, err := d.decodeLiteral()
		if err != nil {
			return nil, err
		}
		d.State.updateStateLiteral()
		return op, nil
	}
	b, err = d.State.isRep[state].Decode(d.rd)
	if err != nil {
		return nil, err
	}
	if b == 0 {
		// simple match
		d.State.rep[3], d.State.rep[2], d.State.rep[1] = d.State.rep[2], d.State.rep[1], d.State.rep[0]

		d.State.updateStateMatch()
		// The length decoder returns the length offset.
		n, err := d.State.lenCodec.Decode(d.rd, posState)
		if err != nil {
			return nil, err
		}
		// The dist decoder returns the distance offset. The actual
		// distance is 1 higher.
		d.State.rep[0], err = d.State.distCodec.Decode(d.rd, n)
		if err != nil {
			return nil, err
		}
		if d.State.rep[0] == eosDist {
			if !d.rd.possiblyAtEnd() {
				return nil, errWrongTermination
			}
			return EOSOp, nil
		}
		op = match{length: int(n) + MinLength,
			distance: int64(d.State.rep[0]) + minDistance}
		return op, nil
	}
	b, err = d.State.isRepG0[state].Decode(d.rd)
	if err != nil {
		return nil, err
	}
	dist := d.State.rep[0]
	if b == 0 {
		// rep match 0
		b, err = d.State.isRepG0Long[state2].Decode(d.rd)
		if err != nil {
			return nil, err
		}
		if b == 0 {
			d.State.updateStateShortRep()
			op = match{length: 1,
				distance: int64(dist) + minDistance}
			return op, nil
		}
	} else {
		b, err = d.State.isRepG1[state].Decode(d.rd)
		if err != nil {
			return nil, err
		}
		if b == 0 {
			dist = d.State.rep[1]
		} else {
			b, err = d.State.isRepG2[state].Decode(d.rd)
			if err != nil {
				return nil, err
			}
			if b == 0 {
				dist = d.State.rep[2]
			} else {
				dist = d.State.rep[3]
				d.State.rep[3] = d.State.rep[2]
			}
			d.State.rep[2] = d.State.rep[1]
		}
		d.State.rep[1] = d.State.rep[0]
		d.State.rep[0] = dist
	}
	n, err := d.State.repLenCodec.Decode(d.rd, posState)
	if err != nil {
		return nil, err
	}
	d.State.updateStateRep()
	op = match{length: int(n) + MinLength,
		distance: int64(dist) + minDistance}
	return op, nil
}

// EOS error indicates the end of the stream
var EOS = newError("end of stream")

// ReadOps reads a sequence of operations. The number of operations read will
// be returned. The end of the operation stream is marked by EOS. Note that an
// error may indicate that the read of a full operation has not been
// successful.
func (d *OpDecoder) ReadOps(ops []Operation) (n int, err error) {
	for ; n < len(ops); n++ {
		if ops[n], err = d.readOp(); err != nil {
			if err == io.EOF {
				return n, EOS
			}
			return n, err
		}
		if ops[n] == EOSOp {
			return n, EOS
		}
	}
	return n, nil
}
<|endoftext|>