<commit_before>package jsonwriter

import (
	"encoding/json"
	"fmt"
	"io"
	"reflect"
	"strconv"
	"time"
	"unicode/utf8"
)

var (
	quote        = []byte(`"`)
	keyStart     = quote
	null         = []byte("null")
	_true        = []byte("true")
	_false       = []byte("false")
	comma        = []byte(",")
	keyEnd       = []byte(`":`)
	startObject  = []byte("{")
	endObject    = []byte("}")
	startArray   = []byte("[")
	endArray     = []byte("]")
	escapedQuote = []byte(`\"`)
	escapedSlash = []byte(`\\`)
	escapedBS    = []byte(`\b`)
	escapedFF    = []byte(`\f`)
	escapedNL    = []byte(`\n`)
	escapedLF    = []byte(`\r`)
	escapedTab   = []byte(`\t`)
)

type Writer struct {
	depth int
	first bool
	array bool
	W     io.Writer
}

// Creates a JsonWriter that writes to the provided io.Writer
func New(w io.Writer) *Writer {
	return &Writer{
		W:     w,
		first: true,
	}
}

// Starts the writing process by creating an object.
// Should only be called once
func (w *Writer) RootObject(f func()) {
	w.W.Write(startObject)
	f()
	w.W.Write(endObject)
}

// Starts the writing process by creating an array.
// Should only be called once
func (w *Writer) RootArray(f func()) {
	w.Separator()
	w.array = true
	w.first = true
	w.W.Write(startArray)
	f()
	w.W.Write(endArray)
}

// Star an object with the given key
func (w *Writer) Object(key string, f func()) {
	w.Key(key)
	w.first = true
	w.W.Write(startObject)
	f()
	w.first = false
	w.W.Write(endObject)
}

// Star an array with the given key
func (w *Writer) Array(key string, f func()) {
	w.Key(key)
	w.first, w.array = true, true
	w.W.Write(startArray)
	f()
	w.first, w.array = false, false
	w.W.Write(endArray)
}

// Star an object within an array (a keyless object)
func (w *Writer) ArrayObject(f func()) {
	w.Separator()
	w.first = true
	w.array = false
	w.W.Write(startObject)
	f()
	w.W.Write(endObject)
	w.array = true
}

// Writes an array with the given array of values
// (values must be an array or a slice)
func (w *Writer) ArrayValues(key string, values interface{}) {
	w.Key(key)
	w.first, w.array = true, true
	w.W.Write(startArray)

	vo := reflect.ValueOf(values)
	kind := vo.Kind()
	if kind == reflect.Array || kind == reflect.Slice {
		for i, l := 0, vo.Len(); i < l; i++ {
			w.Value(vo.Index(i).Interface())
		}
	}
	w.array = false
	w.W.Write(endArray)
}

// used to write an array of arrays
func (w *Writer) SubArray(f func()) {
	w.RootArray(f)
}

// Writes a key. The key is placed within quotes and ends
// with a colon
func (w *Writer) Key(key string) {
	w.Separator()
	w.W.Write(keyStart)
	w.writeString(key)
	w.W.Write(keyEnd)
}

// value can be a string, byte, u?int(8|16|32|64)?, float(32|64)?,
// time.Time, bool, nil or encoding/json.Marshaller
func (w *Writer) Value(value interface{}) {
	if w.array {
		w.Separator()
	}

	if value == nil {
		w.W.Write(null)
		return
	}

	switch t := value.(type) {
	case bool:
		if t == true {
			w.W.Write(_true)
		} else {
			w.W.Write(_false)
		}
	case uint8:
		w.Int(int(t))
	case uint16:
		w.Int(int(t))
	case uint32:
		w.Int(int(t))
	case uint:
		w.W.Write([]byte(strconv.FormatUint(uint64(t), 10)))
	case uint64:
		w.W.Write([]byte(strconv.FormatUint(t, 10)))
	case int8:
		w.Int(int(t))
	case int16:
		w.Int(int(t))
	case int32:
		w.Int(int(t))
	case int:
		w.Int(int(t))
	case int64:
		w.W.Write([]byte(strconv.FormatInt(t, 10)))
	case float32:
		w.W.Write([]byte(strconv.FormatFloat(float64(t), 'g', -1, 32)))
	case float64:
		w.W.Write([]byte(strconv.FormatFloat(t, 'g', -1, 64)))
	case json.Marshaler:
		b, _ := t.MarshalJSON()
		w.W.Write(b)
	case string:
		w.String(t)
	case time.Time:
		w.W.Write(quote)
		w.writeString(t.Format(time.RFC3339Nano))
		w.W.Write(quote)
	default:
		panic(fmt.Sprintf("unsuported valued type %v", value))
	}
}

func (w *Writer) Int(value int) {
	w.W.Write([]byte(strconv.Itoa(value)))
}

func (w *Writer) String(value string) {
	w.W.Write(quote)
	w.writeString(value)
	w.W.Write(quote)
}

// Writes raw data to an array as-is, leaving encoding up to the caller
func (w *Writer) RawValue(data []byte) {
	if w.array {
		w.Separator()
	}

	w.W.Write(data)
}

// Writes the value as-is, leaving delimiters and encoding up to the caller
func (w *Writer) Raw(data []byte) {
	w.W.Write(data)
}

// writes a key: value
// This is the same as calling WriteKey(key) followe by WriteValue(value)
func (w *Writer) KeyValue(key string, value interface{}) {
	w.Key(key)
	w.Value(value)
}

// writes a key: value
// write a key'd raw value
func (w *Writer) KeyRaw(key string, data []byte) {
	w.Key(key)
	w.W.Write(data)
}

// writes a key: value where value is a string
// This is an optimized Write method
func (w *Writer) KeyString(key string, value string) {
	w.Key(key)
	w.W.Write(quote)
	w.writeString(value)
	w.W.Write(quote)
}

// writes a key: value where value is a int
// This is an optimized Write method
func (w *Writer) KeyInt(key string, value int) {
	w.Key(key)
	w.W.Write([]byte(strconv.Itoa(value)))
}

// writes a key: value where value is a bool
// This is an optimized Write method
func (w *Writer) KeyBool(key string, value bool) {
	w.Key(key)
	if value {
		w.W.Write(_true)
	} else {
		w.W.Write(_false)
	}
}

// writes a key: value where value is a bool
// This is an optimized Write method
func (w *Writer) KeyFloat(key string, value float32) {
	w.Key(key)
	w.W.Write([]byte(strconv.FormatFloat(float64(value), 'g', -1, 32)))
}

// writes a key: value where value is a bool
// This is an optimized Write method
func (w *Writer) KeyFloat64(key string, value float64) {
	w.Key(key)
	w.W.Write([]byte(strconv.FormatFloat(value, 'g', -1, 64)))
}

func (w *Writer) Separator() {
	if w.first == false {
		w.W.Write(comma)
	} else {
		w.first = false
	}
}

func (w *Writer) writeString(s string) {
	start, end := 0, 0
	var special []byte
L:
	for i, r := range s {
		switch r {
		case '"':
			special = escapedQuote
		case '\\':
			special = escapedSlash
		case '\b':
			special = escapedBS
		case '\f':
			special = escapedFF
		case '\n':
			special = escapedNL
		case '\r':
			special = escapedLF
		case '\t':
			special = escapedTab
		default:
			end += utf8.RuneLen(r)
			continue L
		}

		if end > start {
			w.W.Write([]byte(s[start:end]))
		}
		w.W.Write(special)
		start = i + 1
		end = start
	}
	if end > start {
		w.W.Write([]byte(s[start:end]))
	}
}

func (w *Writer) Reset() {
	w.depth = 0
	w.first = true
	w.array = false
}
<commit_msg>literal, similar to Raw but without care for separators<commit_after>package jsonwriter

import (
	"encoding/json"
	"fmt"
	"io"
	"reflect"
	"strconv"
	"time"
	"unicode/utf8"
)

var (
	quote        = []byte(`"`)
	keyStart     = quote
	null         = []byte("null")
	_true        = []byte("true")
	_false       = []byte("false")
	comma        = []byte(",")
	keyEnd       = []byte(`":`)
	startObject  = []byte("{")
	endObject    = []byte("}")
	startArray   = []byte("[")
	endArray     = []byte("]")
	escapedQuote = []byte(`\"`)
	escapedSlash = []byte(`\\`)
	escapedBS    = []byte(`\b`)
	escapedFF    = []byte(`\f`)
	escapedNL    = []byte(`\n`)
	escapedLF    = []byte(`\r`)
	escapedTab   = []byte(`\t`)
)

type Writer struct {
	depth int
	first bool
	array bool
	W     io.Writer
}

// Creates a JsonWriter that writes to the provided io.Writer
func New(w io.Writer) *Writer {
	return &Writer{
		W:     w,
		first: true,
	}
}

// Starts the writing process by creating an object.
// Should only be called once
func (w *Writer) RootObject(f func()) {
	w.W.Write(startObject)
	f()
	w.W.Write(endObject)
}

// Starts the writing process by creating an array.
// Should only be called once
func (w *Writer) RootArray(f func()) {
	w.Separator()
	w.array = true
	w.first = true
	w.W.Write(startArray)
	f()
	w.W.Write(endArray)
}

// Star an object with the given key
func (w *Writer) Object(key string, f func()) {
	w.Key(key)
	w.first = true
	w.W.Write(startObject)
	f()
	w.first = false
	w.W.Write(endObject)
}

// Star an array with the given key
func (w *Writer) Array(key string, f func()) {
	w.Key(key)
	w.first, w.array = true, true
	w.W.Write(startArray)
	f()
	w.first, w.array = false, false
	w.W.Write(endArray)
}

// Star an object within an array (a keyless object)
func (w *Writer) ArrayObject(f func()) {
	w.Separator()
	w.first = true
	w.array = false
	w.W.Write(startObject)
	f()
	w.W.Write(endObject)
	w.array = true
}

// Writes an array with the given array of values
// (values must be an array or a slice)
func (w *Writer) ArrayValues(key string, values interface{}) {
	w.Key(key)
	w.first, w.array = true, true
	w.W.Write(startArray)

	vo := reflect.ValueOf(values)
	kind := vo.Kind()
	if kind == reflect.Array || kind == reflect.Slice {
		for i, l := 0, vo.Len(); i < l; i++ {
			w.Value(vo.Index(i).Interface())
		}
	}
	w.array = false
	w.W.Write(endArray)
}

// used to write an array of arrays
func (w *Writer) SubArray(f func()) {
	w.RootArray(f)
}

// Writes a key. The key is placed within quotes and ends
// with a colon
func (w *Writer) Key(key string) {
	w.Separator()
	w.W.Write(keyStart)
	w.writeString(key)
	w.W.Write(keyEnd)
}

// value can be a string, byte, u?int(8|16|32|64)?, float(32|64)?,
// time.Time, bool, nil or encoding/json.Marshaller
func (w *Writer) Value(value interface{}) {
	if w.array {
		w.Separator()
	}

	if value == nil {
		w.W.Write(null)
		return
	}

	switch t := value.(type) {
	case bool:
		if t == true {
			w.W.Write(_true)
		} else {
			w.W.Write(_false)
		}
	case uint8:
		w.Int(int(t))
	case uint16:
		w.Int(int(t))
	case uint32:
		w.Int(int(t))
	case uint:
		w.W.Write([]byte(strconv.FormatUint(uint64(t), 10)))
	case uint64:
		w.W.Write([]byte(strconv.FormatUint(t, 10)))
	case int8:
		w.Int(int(t))
	case int16:
		w.Int(int(t))
	case int32:
		w.Int(int(t))
	case int:
		w.Int(int(t))
	case int64:
		w.W.Write([]byte(strconv.FormatInt(t, 10)))
	case float32:
		w.W.Write([]byte(strconv.FormatFloat(float64(t), 'g', -1, 32)))
	case float64:
		w.W.Write([]byte(strconv.FormatFloat(t, 'g', -1, 64)))
	case json.Marshaler:
		b, _ := t.MarshalJSON()
		w.W.Write(b)
	case string:
		w.String(t)
	case time.Time:
		w.W.Write(quote)
		w.writeString(t.Format(time.RFC3339Nano))
		w.W.Write(quote)
	default:
		panic(fmt.Sprintf("unsuported valued type %v", value))
	}
}

func (w *Writer) Int(value int) {
	w.W.Write([]byte(strconv.Itoa(value)))
}

func (w *Writer) String(value string) {
	w.W.Write(quote)
	w.writeString(value)
	w.W.Write(quote)
}

// Writes raw data to an array as-is, leaving encoding up to the caller
func (w *Writer) RawValue(data []byte) {
	if w.array {
		w.Separator()
	}

	w.W.Write(data)
}

// Writes raw data, leaving encoding and field separation to the caller
func (w *Writer) Literal(data []byte) {
	w.W.Write(data)
}

// Writes the value as-is, leaving delimiters and encoding up to the caller
func (w *Writer) Raw(data []byte) {
	w.W.Write(data)
}

// writes a key: value
// This is the same as calling WriteKey(key) followe by WriteValue(value)
func (w *Writer) KeyValue(key string, value interface{}) {
	w.Key(key)
	w.Value(value)
}

// writes a key: value
// write a key'd raw value
func (w *Writer) KeyRaw(key string, data []byte) {
	w.Key(key)
	w.W.Write(data)
}

// writes a key: value where value is a string
// This is an optimized Write method
func (w *Writer) KeyString(key string, value string) {
	w.Key(key)
	w.W.Write(quote)
	w.writeString(value)
	w.W.Write(quote)
}

// writes a key: value where value is a int
// This is an optimized Write method
func (w *Writer) KeyInt(key string, value int) {
	w.Key(key)
	w.W.Write([]byte(strconv.Itoa(value)))
}

// writes a key: value where value is a bool
// This is an optimized Write method
func (w *Writer) KeyBool(key string, value bool) {
	w.Key(key)
	if value {
		w.W.Write(_true)
	} else {
		w.W.Write(_false)
	}
}

// writes a key: value where value is a bool
// This is an optimized Write method
func (w *Writer) KeyFloat(key string, value float32) {
	w.Key(key)
	w.W.Write([]byte(strconv.FormatFloat(float64(value), 'g', -1, 32)))
}

// writes a key: value where value is a bool
// This is an optimized Write method
func (w *Writer) KeyFloat64(key string, value float64) {
	w.Key(key)
	w.W.Write([]byte(strconv.FormatFloat(value, 'g', -1, 64)))
}

func (w *Writer) Separator() {
	if w.first == false {
		w.W.Write(comma)
	} else {
		w.first = false
	}
}

func (w *Writer) writeString(s string) {
	start, end := 0, 0
	var special []byte
L:
	for i, r := range s {
		switch r {
		case '"':
			special = escapedQuote
		case '\\':
			special = escapedSlash
		case '\b':
			special = escapedBS
		case '\f':
			special = escapedFF
		case '\n':
			special = escapedNL
		case '\r':
			special = escapedLF
		case '\t':
			special = escapedTab
		default:
			end += utf8.RuneLen(r)
			continue L
		}

		if end > start {
			w.W.Write([]byte(s[start:end]))
		}
		w.W.Write(special)
		start = i + 1
		end = start
	}
	if end > start {
		w.W.Write([]byte(s[start:end]))
	}
}

func (w *Writer) Reset() {
	w.depth = 0
	w.first = true
	w.array = false
}
<|endoftext|>


<commit_before><commit_msg>add initial methods<commit_after>package kafka_avro

import (
	"bytes"
	"fmt"
	"log"
	"os"
	"strconv"
	"strings"
	"text/template"
	"time"

	avro "github.com/elodina/go-avro"
	kafkaavro "github.com/elodina/go-kafka-avro"
	"github.com/gliderlabs/logspout/router"
	"gopkg.in/Shopify/sarama.v1"
)

func init() {
	router.AdapterFactories.Register(NewKafkaAvroAdapter, "kafka_avro")
}

type KafkaAvroAdapter struct {
	route       *router.Route
	brokers     []string
	topic       string
	schema_url  string
	registry    kafkaavro.KafkaAvroEncoder
	producer    sarama.AsyncProducer
	tmpl        *template.Template
}

func NewKafkaAvroAdapter(route *router.Route) (router.LogAdapter, error) {
	brokers := readBrokers(route.Address)
	if len(brokers) == 0 {
		return nil, errorf("The Kafka broker host:port is missing. Did you specify it as a route address?")
	}

	topic := readTopic(route.Address, route.Options)
	if topic == "" {
		return nil, errorf("The Kafka topic is missing. Did you specify it as a route option?")
	}

	schemaUrl := readSchemaRegistryUrl(route.Options)
	if schemaUrl == "" {
		return nil, errorf("The schema registry url is missing. Did you specify it as a route option?")
	}
	registry := kafkaavro.NewKafkaAvroEncoder(schemaUrl)

	var err error
	var tmpl *template.Template
	if rawTmpl := os.Getenv("KAFKA_TEMPLATE"); rawTmpl != "" {
		tmpl, err = template.New("kafka").Parse(rawTmpl)
		if err != nil {
			return nil, errorf("Couldn't parse Kafka message template. %v", err)
		}
	}

	var schema *avro.Schema
	if rawSchema := os.Getenv("KAFKA_AVRO_SCHEMA"); rawSchema != "" {
		schema, err := avro.ParseSchema(rawSchema)
		if err != nil {
			return nil, errorf("Couldn't parse Avro schema. %v", err)
		}
		if tmpl == nil {
			return nil, errorf("You must set KAFKA_TEMPLATE if you use a schema %v", err)
		}
	}

	if os.Getenv("DEBUG") != "" {
		log.Printf("Starting Kafka producer for address: %s, topic: %s.\n", brokers, topic)
	}

	var retries int
	retries, err = strconv.Atoi(os.Getenv("KAFKA_CONNECT_RETRIES"))
	if err != nil {
		retries = 3
	}
	var producer sarama.AsyncProducer
	for i := 0; i < retries; i++ {
		producer, err = sarama.NewAsyncProducer(brokers, newConfig())
		if err != nil {
			if os.Getenv("DEBUG") != "" {
				log.Println("Couldn't create Kafka producer. Retrying...", err)
			}
			if i == retries-1 {
				return nil, errorf("Couldn't create Kafka producer. %v", err)
			}
		} else {
			time.Sleep(1 * time.Second)
		}
	}

	return &KafkaAvroAdapter{
		route:     route,
		brokers:   brokers,
		topic:     topic,
		schemaUrl: schemaUrl,
		producer:  producer,
		tmpl:      tmpl,
		schema:    schema,
	}, nil
}

func (a *KafkaAvroAdapter) Stream(logstream chan *router.Message) {
	defer a.producer.Close()
	for rm := range logstream {
		message, err := a.formatMessage(rm)
		if err != nil {
			log.Println("kafka:", err)
			a.route.Close()
			break
		}

		a.producer.Input() <- message
	}
}

func newConfig() *sarama.Config {
	config := sarama.NewConfig()
	config.ClientID = "logspout"
	config.Producer.Return.Errors = false
	config.Producer.Return.Successes = false
	config.Producer.Flush.Frequency = 1 * time.Second
	config.Producer.RequiredAcks = sarama.WaitForLocal

	if opt := os.Getenv("KAFKA_COMPRESSION_CODEC"); opt != "" {
		switch opt {
		case "gzip":
			config.Producer.Compression = sarama.CompressionGZIP
		case "snappy":
			config.Producer.Compression = sarama.CompressionSnappy
		}
	}

	return config
}

func (a *KafkaAvroAdapter) formatMessage(message *router.Message) (*sarama.ProducerMessage, error) {
	var encoder sarama.Encoder
	if a.tmpl != nil {
		var w bytes.Buffer
		if err := a.tmpl.Execute(&w, message); err != nil {
			return nil, err
		}
		if a.schema != nil {
			var data interface{}
			if err := json.Unmarshal([]w.Bytes(), &data); err != nil {
				data = w.Bytes()
			}
		}
		encoder = sarama.ByteEncoder(w.Bytes())
	} else {
		encoder = sarama.StringEncoder(message.Data)
	}

	return &sarama.ProducerMessage{
		Topic: a.topic,
		Value: encoder,
	}, nil
}

func readBrokers(address string) []string {
	if strings.Contains(address, "/") {
		slash := strings.Index(address, "/")
		address = address[:slash]
	}

	return strings.Split(address, ",")
}

func readTopic(address string, options map[string]string) string {
	var topic string
	if !strings.Contains(address, "/") {
		topic = options["topic"]
	} else {
		slash := strings.Index(address, "/")
		topic = address[slash+1:]
	}

	return topic
}

func readSchemaRegistryUrl(options map[string]string) string {
	var url string
	if _, ok := options["schema_registry_url"]; ok {
		url = options["schema_registry_url"]
	}
	return url
}

func errorf(format string, a ...interface{}) (err error) {
	err = fmt.Errorf(format, a...)
	if os.Getenv("DEBUG") != "" {
		fmt.Println(err.Error())
	}
	return
}
<|endoftext|>


<commit_before>//
// Copyright (c) 2017 Intel Corporation
//
// 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 virtcontainers

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"syscall"

	vcAnnotations "github.com/containers/virtcontainers/pkg/annotations"

	kataclient "github.com/kata-containers/agent/protocols/client"
	"github.com/kata-containers/agent/protocols/grpc"

	"github.com/opencontainers/runtime-spec/specs-go"
)

var (
	defaultKataSockPathTemplate = "%s/%s/kata.sock"
	defaultKataChannel          = "io.katacontainers.channel"
	defaultKataDeviceID         = "channel0"
	defaultKataID               = "charch0"
	errorMissingGRPClient       = errors.New("Missing gRPC client")
	errorMissingOCISpec         = errors.New("Missing OCI specification")
	kataHostSharedDir           = "/tmp/kata-containers/shared/pods/"
	kataGuestSharedDir          = "/tmp/kata-containers/shared/pods/"
	mountGuest9pTag             = "kataShared"
	type9pFs                    = "9p"
	devPath                     = "/dev"
	vsockSocketScheme           = "vsock"
)

// KataAgentConfig is a structure storing information needed
// to reach the Kata Containers agent.
type KataAgentConfig struct {
	Volumes []Volume
}

type kataVSOCK struct {
	contextID uint32
	port      uint32
}

func (s *kataVSOCK) String() string {
	return fmt.Sprintf("%s://%d:%d", vsockSocketScheme, s.contextID, s.port)
}

type kataAgent struct {
	config KataAgentConfig

	client     *kataclient.AgentClient
	gRPCSocket string
	vmSocket   interface{}
}

func parseVSOCKAddr(sock string) (uint32, uint32, error) {
	sp := strings.Split(sock, ":")
	if len(sp) != 3 {
		return 0, 0, fmt.Errorf("Invalid vsock address: %s", sock)
	}
	if sp[0] != vsockSocketScheme {
		return 0, 0, fmt.Errorf("Invalid vsock URL scheme: %s", sp[0])
	}

	cid, err := strconv.ParseUint(sp[1], 10, 32)
	if err != nil {
		return 0, 0, fmt.Errorf("Invalid vsock cid: %s", sp[1])
	}
	port, err := strconv.ParseUint(sp[2], 10, 32)
	if err != nil {
		return 0, 0, fmt.Errorf("Invalid vsock port: %s", sp[2])
	}

	return uint32(cid), uint32(port), nil
}

func (k *kataAgent) validate(pod *Pod) error {
	if k.gRPCSocket == "" {
		return fmt.Errorf("Empty gRPC socket path")
	}

	cid, port, err := parseVSOCKAddr(k.gRPCSocket)
	if err != nil {
		// We need to generate a host UNIX socket path for the emulated serial port.
		k.vmSocket = Socket{
			DeviceID: defaultKataDeviceID,
			ID:       defaultKataID,
			HostPath: fmt.Sprintf(defaultKataSockPathTemplate, runStoragePath, pod.id),
			Name:     defaultKataChannel,
		}
	} else {
		// We want to go through VSOCK. The VM VSOCK endpoint will be our gRPC.
		k.vmSocket = kataVSOCK{
			contextID: cid,
			port:      port,
		}
	}

	return nil
}

func (k *kataAgent) init(pod *Pod, config interface{}) error {
	switch c := config.(type) {
	case KataAgentConfig:
		if err := k.validate(pod); err != nil {
			return err
		}
		k.config = c
	default:
		return fmt.Errorf("Invalid config type")
	}

	// Override pod agent configuration
	pod.config.AgentConfig = k.config

	client, err := kataclient.NewAgentClient(k.gRPCSocket)
	if err != nil {
		return err
	}

	k.client = client

	return nil
}

func (k *kataAgent) vmURL() (string, error) {
	switch s := k.vmSocket.(type) {
	case Socket:
		return s.HostPath, nil
	case kataVSOCK:
		return s.String(), nil
	default:
		return "", fmt.Errorf("Invalid socket type")
	}
}

func (k *kataAgent) setProxyURL(url string) error {
	k.gRPCSocket = url

	return nil
}

func (k *kataAgent) capabilities() capabilities {
	return capabilities{}
}

func (k *kataAgent) createPod(pod *Pod) error {
	for _, volume := range k.config.Volumes {
		err := pod.hypervisor.addDevice(volume, fsDev)
		if err != nil {
			return err
		}
	}

	switch s := k.vmSocket.(type) {
	case Socket:
		err := pod.hypervisor.addDevice(s, serialPortDev)
		if err != nil {
			return err
		}
	case kataVSOCK:
		// TODO Add an hypervisor vsock
	default:
		return fmt.Errorf("Invalid config type")
	}

	// Adding the shared volume.
	// This volume contains all bind mounted container bundles.
	sharedVolume := Volume{
		MountTag: mountGuest9pTag,
		HostPath: filepath.Join(kataHostSharedDir, pod.id),
	}

	if err := os.MkdirAll(sharedVolume.HostPath, dirMode); err != nil {
		return err
	}

	return pod.hypervisor.addDevice(sharedVolume, fsDev)
}

func (k *kataAgent) exec(pod *Pod, c Container, process Process, cmd Cmd) error {
	return nil
}

func (k *kataAgent) startPod(pod Pod) error {
	if k.client == nil {
		return errorMissingGRPClient
	}

	hostname := pod.config.Hostname
	if len(hostname) > maxHostnameLen {
		hostname = hostname[:maxHostnameLen]
	}

	// We mount the shared directory in a predefined location
	// in the guest.
	// This is where at least some of the host config files
	// (resolv.conf, etc...) and potentially all container
	// rootfs will reside.
	sharedVolume := &grpc.Storage{
		Source:     mountGuest9pTag,
		MountPoint: kataGuestSharedDir,
		Fstype:     type9pFs,
		Options:    []string{"trans=virtio", "nodev"},
	}

	req := &grpc.CreateSandboxRequest{
		Hostname:     hostname,
		Storages:     []*grpc.Storage{sharedVolume},
		SandboxPidns: true,
	}
	_, err := k.client.CreateSandbox(context.Background(), req)
	return err
}

func (k *kataAgent) stopPod(pod Pod) error {
	if k.client == nil {
		return errorMissingGRPClient
	}

	req := &grpc.DestroySandboxRequest{}
	_, err := k.client.DestroySandbox(context.Background(), req)
	return err
}

func appendStorageFromMounts(storage []*grpc.Storage, mounts []*Mount) []*grpc.Storage {
	for _, m := range mounts {
		s := &grpc.Storage{
			Source:     m.Source,
			MountPoint: m.Destination,
		}

		storage = append(storage, s)
	}

	return storage
}

func (k *kataAgent) createContainer(pod *Pod, c *Container) error {
	if k.client == nil {
		return errorMissingGRPClient
	}

	ociSpecJSON, ok := c.config.Annotations[vcAnnotations.ConfigJSONKey]
	if !ok {
		return errorMissingOCISpec
	}

	var ociSpec specs.Spec
	if err := json.Unmarshal([]byte(ociSpecJSON), &ociSpec); err != nil {
		return err
	}

	grpcSpec, err := grpc.OCItoGRPC(&ociSpec)
	if err != nil {
		return err
	}

	var containerStorage []*grpc.Storage

	// The rootfs storage volume represents the container rootfs
	// mount point inside the guest.
	// It can be a block based device (when using block based container
	// overlay on the host) mount or a 9pfs one (for all other overlay
	// implementations).
	rootfs := &grpc.Storage{}

	// First we need to give the OCI spec our absolute path in the guest.
	grpcSpec.Root.Path = filepath.Join(kataGuestSharedDir, pod.id, c.id, rootfsDir)

	if c.state.Fstype != "" {
		// This is a block based device rootfs.
		// driveName is the predicted virtio-block guest name (the vd* in /dev/vd*).
		driveName, err := getVirtDriveName(c.state.BlockIndex)
		if err != nil {
			return err
		}

		rootfs.Source = filepath.Join(devPath, driveName)
		rootfs.MountPoint = grpcSpec.Root.Path // Should we remove the "rootfs" suffix?
		rootfs.Fstype = c.state.Fstype

		// Add rootfs to the list of container storage.
		// We only need to do this for block based rootfs, as we
		// want the agent to mount it into the right location
		// (/tmp/kata-containers/shared/pods/podID/ctrID/
		containerStorage = append(containerStorage, rootfs)

	} else {
		// This is not a block based device rootfs.
		// We are going to bind mount it into the 9pfs
		// shared drive between the host and the guest.
		// With 9pfs we don't need to ask the agent to
		// mount the rootfs as the shared directory
		// (/tmp/kata-containers/shared/pods/) is already
		// mounted in the guest. We only need to mount the
		// rootfs from the host and it will show up in the guest.
		if err := bindMountContainerRootfs(kataHostSharedDir, pod.id, c.id, c.rootFs, false); err != nil {
			bindUnmountAllRootfs(kataHostSharedDir, *pod)
			return err
		}
	}

	// Handle container mounts
	newMounts, err := bindMountContainerMounts(kataHostSharedDir, pod.id, c.id, c.mounts)
	if err != nil {
		bindUnmountAllRootfs(kataHostSharedDir, *pod)
		return err
	}
	containerStorage = appendStorageFromMounts(containerStorage, newMounts)

	// Append container mounts for block devices passed with --device.
	for _, device := range c.devices {
		d, ok := device.(*BlockDevice)

		if !ok {
			continue
		}

		deviceStorage := &grpc.Storage{
			Source:     d.VirtPath,
			MountPoint: d.DeviceInfo.ContainerPath,
		}

		containerStorage = append(containerStorage, deviceStorage)
	}

	req := &grpc.CreateContainerRequest{
		ContainerId: c.id,
		Storages:    containerStorage,
		OCI:         grpcSpec,
	}

	_, err = k.client.CreateContainer(context.Background(), req)
	return err
}

func (k *kataAgent) startContainer(pod Pod, c Container) error {
	if k.client == nil {
		return errorMissingGRPClient
	}

	req := &grpc.StartContainerRequest{
		ContainerId: c.id,
	}

	_, err := k.client.StartContainer(context.Background(), req)
	return err
}

func (k *kataAgent) stopContainer(pod Pod, c Container) error {
	return nil
}

func (k *kataAgent) killContainer(pod Pod, c Container, signal syscall.Signal, all bool) error {
	return nil
}

func (k *kataAgent) processListContainer(pod Pod, c Container, options ProcessListOptions) (ProcessList, error) {
	return nil, nil
}
<commit_msg>agent: Add kata exec, stopContainer and killContainer<commit_after>//
// Copyright (c) 2017 Intel Corporation
//
// 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 virtcontainers

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"syscall"

	vcAnnotations "github.com/containers/virtcontainers/pkg/annotations"

	kataclient "github.com/kata-containers/agent/protocols/client"
	"github.com/kata-containers/agent/protocols/grpc"

	"github.com/opencontainers/runtime-spec/specs-go"
)

var (
	defaultKataSockPathTemplate = "%s/%s/kata.sock"
	defaultKataChannel          = "io.katacontainers.channel"
	defaultKataDeviceID         = "channel0"
	defaultKataID               = "charch0"
	errorMissingGRPClient       = errors.New("Missing gRPC client")
	errorMissingOCISpec         = errors.New("Missing OCI specification")
	kataHostSharedDir           = "/tmp/kata-containers/shared/pods/"
	kataGuestSharedDir          = "/tmp/kata-containers/shared/pods/"
	mountGuest9pTag             = "kataShared"
	type9pFs                    = "9p"
	devPath                     = "/dev"
	vsockSocketScheme           = "vsock"
)

// KataAgentConfig is a structure storing information needed
// to reach the Kata Containers agent.
type KataAgentConfig struct {
	Volumes []Volume
}

type kataVSOCK struct {
	contextID uint32
	port      uint32
}

func (s *kataVSOCK) String() string {
	return fmt.Sprintf("%s://%d:%d", vsockSocketScheme, s.contextID, s.port)
}

type kataAgent struct {
	config KataAgentConfig

	client     *kataclient.AgentClient
	gRPCSocket string
	vmSocket   interface{}
}

func parseVSOCKAddr(sock string) (uint32, uint32, error) {
	sp := strings.Split(sock, ":")
	if len(sp) != 3 {
		return 0, 0, fmt.Errorf("Invalid vsock address: %s", sock)
	}
	if sp[0] != vsockSocketScheme {
		return 0, 0, fmt.Errorf("Invalid vsock URL scheme: %s", sp[0])
	}

	cid, err := strconv.ParseUint(sp[1], 10, 32)
	if err != nil {
		return 0, 0, fmt.Errorf("Invalid vsock cid: %s", sp[1])
	}
	port, err := strconv.ParseUint(sp[2], 10, 32)
	if err != nil {
		return 0, 0, fmt.Errorf("Invalid vsock port: %s", sp[2])
	}

	return uint32(cid), uint32(port), nil
}

func (k *kataAgent) validate(pod *Pod) error {
	if k.gRPCSocket == "" {
		return fmt.Errorf("Empty gRPC socket path")
	}

	cid, port, err := parseVSOCKAddr(k.gRPCSocket)
	if err != nil {
		// We need to generate a host UNIX socket path for the emulated serial port.
		k.vmSocket = Socket{
			DeviceID: defaultKataDeviceID,
			ID:       defaultKataID,
			HostPath: fmt.Sprintf(defaultKataSockPathTemplate, runStoragePath, pod.id),
			Name:     defaultKataChannel,
		}
	} else {
		// We want to go through VSOCK. The VM VSOCK endpoint will be our gRPC.
		k.vmSocket = kataVSOCK{
			contextID: cid,
			port:      port,
		}
	}

	return nil
}

func (k *kataAgent) init(pod *Pod, config interface{}) error {
	switch c := config.(type) {
	case KataAgentConfig:
		if err := k.validate(pod); err != nil {
			return err
		}
		k.config = c
	default:
		return fmt.Errorf("Invalid config type")
	}

	// Override pod agent configuration
	pod.config.AgentConfig = k.config

	client, err := kataclient.NewAgentClient(k.gRPCSocket)
	if err != nil {
		return err
	}

	k.client = client

	return nil
}

func (k *kataAgent) vmURL() (string, error) {
	switch s := k.vmSocket.(type) {
	case Socket:
		return s.HostPath, nil
	case kataVSOCK:
		return s.String(), nil
	default:
		return "", fmt.Errorf("Invalid socket type")
	}
}

func (k *kataAgent) setProxyURL(url string) error {
	k.gRPCSocket = url

	return nil
}

func (k *kataAgent) capabilities() capabilities {
	return capabilities{}
}

func (k *kataAgent) createPod(pod *Pod) error {
	for _, volume := range k.config.Volumes {
		err := pod.hypervisor.addDevice(volume, fsDev)
		if err != nil {
			return err
		}
	}

	switch s := k.vmSocket.(type) {
	case Socket:
		err := pod.hypervisor.addDevice(s, serialPortDev)
		if err != nil {
			return err
		}
	case kataVSOCK:
		// TODO Add an hypervisor vsock
	default:
		return fmt.Errorf("Invalid config type")
	}

	// Adding the shared volume.
	// This volume contains all bind mounted container bundles.
	sharedVolume := Volume{
		MountTag: mountGuest9pTag,
		HostPath: filepath.Join(kataHostSharedDir, pod.id),
	}

	if err := os.MkdirAll(sharedVolume.HostPath, dirMode); err != nil {
		return err
	}

	return pod.hypervisor.addDevice(sharedVolume, fsDev)
}

func cmdToKataProcess(cmd Cmd) (process *grpc.Process, err error) {
	var i uint64
	var extraGids []uint32

	// Number of bits used to store user+group values in
	// the gRPC "User" type.
	const grpcUserBits = 32

	i, err = strconv.ParseUint(cmd.User, 10, grpcUserBits)
	if err != nil {
		return nil, err
	}

	uid := uint32(i)

	i, err = strconv.ParseUint(cmd.PrimaryGroup, 10, grpcUserBits)
	if err != nil {
		return nil, err
	}

	gid := uint32(i)

	for _, g := range cmd.SupplementaryGroups {
		var extraGid uint64

		extraGid, err = strconv.ParseUint(g, 10, grpcUserBits)
		if err != nil {
			return nil, err
		}

		extraGids = append(extraGids, uint32(extraGid))
	}

	process = &grpc.Process{
		Terminal: cmd.Interactive,
		User: grpc.User{
			UID:            uid,
			GID:            gid,
			AdditionalGids: extraGids,
		},
		Args: cmd.Args,
		Env:  cmdEnvsToStringSlice(cmd.Envs),
		Cwd:  cmd.WorkDir,
	}

	return process, nil
}

func cmdEnvsToStringSlice(ev []EnvVar) []string {
	var env []string

	for _, e := range ev {
		pair := []string{e.Var, e.Value}
		env = append(env, strings.Join(pair, "="))
	}

	return env
}

func (k *kataAgent) exec(pod *Pod, c Container, process Process, cmd Cmd) (err error) {
	var kataProcess *grpc.Process

	kataProcess, err = cmdToKataProcess(cmd)
	if err != nil {
		return err
	}

	req := &grpc.ExecProcessRequest{
		ContainerId: c.id,
		Process:     kataProcess,
	}

	_, err = k.client.ExecProcess(context.Background(), req)
	return err
}

func (k *kataAgent) startPod(pod Pod) error {
	if k.client == nil {
		return errorMissingGRPClient
	}

	hostname := pod.config.Hostname
	if len(hostname) > maxHostnameLen {
		hostname = hostname[:maxHostnameLen]
	}

	// We mount the shared directory in a predefined location
	// in the guest.
	// This is where at least some of the host config files
	// (resolv.conf, etc...) and potentially all container
	// rootfs will reside.
	sharedVolume := &grpc.Storage{
		Source:     mountGuest9pTag,
		MountPoint: kataGuestSharedDir,
		Fstype:     type9pFs,
		Options:    []string{"trans=virtio", "nodev"},
	}

	req := &grpc.CreateSandboxRequest{
		Hostname:     hostname,
		Storages:     []*grpc.Storage{sharedVolume},
		SandboxPidns: true,
	}
	_, err := k.client.CreateSandbox(context.Background(), req)
	return err
}

func (k *kataAgent) stopPod(pod Pod) error {
	if k.client == nil {
		return errorMissingGRPClient
	}

	req := &grpc.DestroySandboxRequest{}
	_, err := k.client.DestroySandbox(context.Background(), req)
	return err
}

func appendStorageFromMounts(storage []*grpc.Storage, mounts []*Mount) []*grpc.Storage {
	for _, m := range mounts {
		s := &grpc.Storage{
			Source:     m.Source,
			MountPoint: m.Destination,
		}

		storage = append(storage, s)
	}

	return storage
}

func (k *kataAgent) createContainer(pod *Pod, c *Container) error {
	if k.client == nil {
		return errorMissingGRPClient
	}

	ociSpecJSON, ok := c.config.Annotations[vcAnnotations.ConfigJSONKey]
	if !ok {
		return errorMissingOCISpec
	}

	var ociSpec specs.Spec
	if err := json.Unmarshal([]byte(ociSpecJSON), &ociSpec); err != nil {
		return err
	}

	grpcSpec, err := grpc.OCItoGRPC(&ociSpec)
	if err != nil {
		return err
	}

	var containerStorage []*grpc.Storage

	// The rootfs storage volume represents the container rootfs
	// mount point inside the guest.
	// It can be a block based device (when using block based container
	// overlay on the host) mount or a 9pfs one (for all other overlay
	// implementations).
	rootfs := &grpc.Storage{}

	// First we need to give the OCI spec our absolute path in the guest.
	grpcSpec.Root.Path = filepath.Join(kataGuestSharedDir, pod.id, c.id, rootfsDir)

	if c.state.Fstype != "" {
		// This is a block based device rootfs.
		// driveName is the predicted virtio-block guest name (the vd* in /dev/vd*).
		driveName, err := getVirtDriveName(c.state.BlockIndex)
		if err != nil {
			return err
		}

		rootfs.Source = filepath.Join(devPath, driveName)
		rootfs.MountPoint = grpcSpec.Root.Path // Should we remove the "rootfs" suffix?
		rootfs.Fstype = c.state.Fstype

		// Add rootfs to the list of container storage.
		// We only need to do this for block based rootfs, as we
		// want the agent to mount it into the right location
		// (/tmp/kata-containers/shared/pods/podID/ctrID/
		containerStorage = append(containerStorage, rootfs)

	} else {
		// This is not a block based device rootfs.
		// We are going to bind mount it into the 9pfs
		// shared drive between the host and the guest.
		// With 9pfs we don't need to ask the agent to
		// mount the rootfs as the shared directory
		// (/tmp/kata-containers/shared/pods/) is already
		// mounted in the guest. We only need to mount the
		// rootfs from the host and it will show up in the guest.
		if err := bindMountContainerRootfs(kataHostSharedDir, pod.id, c.id, c.rootFs, false); err != nil {
			bindUnmountAllRootfs(kataHostSharedDir, *pod)
			return err
		}
	}

	// Handle container mounts
	newMounts, err := bindMountContainerMounts(kataHostSharedDir, pod.id, c.id, c.mounts)
	if err != nil {
		bindUnmountAllRootfs(kataHostSharedDir, *pod)
		return err
	}
	containerStorage = appendStorageFromMounts(containerStorage, newMounts)

	// Append container mounts for block devices passed with --device.
	for _, device := range c.devices {
		d, ok := device.(*BlockDevice)

		if !ok {
			continue
		}

		deviceStorage := &grpc.Storage{
			Source:     d.VirtPath,
			MountPoint: d.DeviceInfo.ContainerPath,
		}

		containerStorage = append(containerStorage, deviceStorage)
	}

	req := &grpc.CreateContainerRequest{
		ContainerId: c.id,
		Storages:    containerStorage,
		OCI:         grpcSpec,
	}

	_, err = k.client.CreateContainer(context.Background(), req)
	return err
}

func (k *kataAgent) startContainer(pod Pod, c Container) error {
	if k.client == nil {
		return errorMissingGRPClient
	}

	req := &grpc.StartContainerRequest{
		ContainerId: c.id,
	}

	_, err := k.client.StartContainer(context.Background(), req)
	return err
}

func (k *kataAgent) stopContainer(pod Pod, c Container) error {
	req := &grpc.RemoveContainerRequest{
		ContainerId: c.id,
	}

	_, err := k.client.RemoveContainer(context.Background(), req)
	return err
}

func (k *kataAgent) killContainer(pod Pod, c Container, signal syscall.Signal, all bool) error {
	req := &grpc.SignalProcessRequest{
		ContainerId: c.id,
		PID:         uint32(c.process.Pid),
		Signal:      uint32(signal),
	}

	_, err := k.client.SignalProcess(context.Background(), req)
	return err
}

func (k *kataAgent) processListContainer(pod Pod, c Container, options ProcessListOptions) (ProcessList, error) {
	return nil, nil
}
<|endoftext|>


<commit_before>//
// Copyright (c) 2017 Intel Corporation
//
// 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 virtcontainers

import (
	"fmt"
	"os"
	"path/filepath"
	"syscall"

	kataclient "github.com/kata-containers/agent/protocols/client"
)

// KataAgentConfig is a structure storing information needed
// to reach the Kata Containers agent.
type KataAgentConfig struct {
	GRPCSocket string
	Volumes    []Volume
	VMSocket   Socket
}

func (c *KataAgentConfig) validate(pod *Pod) bool {
	return true
}

type kataAgent struct {
	config KataAgentConfig

	client *kataclient.AgentClient
}

func (k *kataAgent) init(pod *Pod, config interface{}) error {
	switch c := config.(type) {
	case KataAgentConfig:
		if c.validate(pod) == false {
			return fmt.Errorf("Invalid Kata agent configuration: %v", c)
		}
		k.config = c
	default:
		return fmt.Errorf("Invalid config type")
	}

	// Override pod agent configuration
	pod.config.AgentConfig = k.config

	client, err := kataclient.NewAgentClient(k.config.GRPCSocket)
	if err != nil {
		return err
	}

	k.client = client

	return nil
}

func (k *kataAgent) vmURL() (string, error) {
	return "", nil
}

func (k *kataAgent) setProxyURL(url string) error {
	return nil
}

func (k *kataAgent) capabilities() capabilities {
	return capabilities{}
}

func (k *kataAgent) createPod(pod *Pod) error {
	for _, volume := range k.config.Volumes {
		err := pod.hypervisor.addDevice(volume, fsDev)
		if err != nil {
			return err
		}
	}

	// TODO Look at the grpc scheme to understand if we want
	// a serial or a vsock socket.
	err := pod.hypervisor.addDevice(k.config.VMSocket, serialPortDev)
	if err != nil {
		return err
	}

	// Adding the shared volume.
	// This volume contains all bind mounted container bundles.
	sharedVolume := Volume{
		MountTag: mountTag,
		HostPath: filepath.Join(defaultSharedDir, pod.id),
	}

	if err := os.MkdirAll(sharedVolume.HostPath, dirMode); err != nil {
		return err
	}

	return pod.hypervisor.addDevice(sharedVolume, fsDev)
}

func (k *kataAgent) exec(pod *Pod, c Container, process Process, cmd Cmd) error {
	return nil
}

func (k *kataAgent) startPod(pod Pod) error {
	return nil
}

func (k *kataAgent) stopPod(pod Pod) error {
	return nil
}

func (k *kataAgent) createContainer(pod *Pod, c *Container) error {
	return nil
}

func (k *kataAgent) startContainer(pod Pod, c Container) error {
	return nil
}

func (k *kataAgent) stopContainer(pod Pod, c Container) error {
	return nil
}

func (k *kataAgent) killContainer(pod Pod, c Container, signal syscall.Signal, all bool) error {
	return nil
}

func (k *kataAgent) processListContainer(pod Pod, c Container, options ProcessListOptions) (ProcessList, error) {
	return nil, nil
}
<commit_msg>kata_agent: Implement pod start and stop ops<commit_after>//
// Copyright (c) 2017 Intel Corporation
//
// 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 virtcontainers

import (
	"context"
	"fmt"
	"os"
	"path/filepath"
	"syscall"

	kataclient "github.com/kata-containers/agent/protocols/client"
	"github.com/kata-containers/agent/protocols/grpc"
)

var errorMissingGRPClient = fmt.Errorf("Missing gRPC client")
var defaultHostSharedDir = "/tmp/kata-containers/shared/pods/"
var defaultGuestSharedDir = "/tmp/kata-containers/shared/pods/"
var mountGuest9pTag = "kataShared"
var type9pFs = "9p"

// KataAgentConfig is a structure storing information needed
// to reach the Kata Containers agent.
type KataAgentConfig struct {
	GRPCSocket string
	Volumes    []Volume
	VMSocket   Socket
}

func (c *KataAgentConfig) validate(pod *Pod) bool {
	return true
}

type kataAgent struct {
	config KataAgentConfig

	client *kataclient.AgentClient
}

func (k *kataAgent) init(pod *Pod, config interface{}) error {
	switch c := config.(type) {
	case KataAgentConfig:
		if c.validate(pod) == false {
			return fmt.Errorf("Invalid Kata agent configuration: %v", c)
		}
		k.config = c
	default:
		return fmt.Errorf("Invalid config type")
	}

	// Override pod agent configuration
	pod.config.AgentConfig = k.config

	client, err := kataclient.NewAgentClient(k.config.GRPCSocket)
	if err != nil {
		return err
	}

	k.client = client

	return nil
}

func (k *kataAgent) vmURL() (string, error) {
	return "", nil
}

func (k *kataAgent) setProxyURL(url string) error {
	return nil
}

func (k *kataAgent) capabilities() capabilities {
	return capabilities{}
}

func (k *kataAgent) createPod(pod *Pod) error {
	for _, volume := range k.config.Volumes {
		err := pod.hypervisor.addDevice(volume, fsDev)
		if err != nil {
			return err
		}
	}

	// TODO Look at the grpc scheme to understand if we want
	// a serial or a vsock socket.
	err := pod.hypervisor.addDevice(k.config.VMSocket, serialPortDev)
	if err != nil {
		return err
	}

	// Adding the shared volume.
	// This volume contains all bind mounted container bundles.
	sharedVolume := Volume{
		MountTag: mountGuest9pTag,
		HostPath: filepath.Join(defaultHostSharedDir, pod.id),
	}

	if err := os.MkdirAll(sharedVolume.HostPath, dirMode); err != nil {
		return err
	}

	return pod.hypervisor.addDevice(sharedVolume, fsDev)
}

func (k *kataAgent) exec(pod *Pod, c Container, process Process, cmd Cmd) error {
	return nil
}

func (k *kataAgent) startPod(pod Pod) error {
	if k.client == nil {
		return errorMissingGRPClient
	}

	hostname := pod.config.Hostname
	if len(hostname) > maxHostnameLen {
		hostname = hostname[:maxHostnameLen]
	}

	// We mount the shared directory in a predefined location
	// in the guest.
	// This is where at least some of the host config files
	// (resolv.conf, etc...) and potentially all container
	// rootfs will reside.
	sharedVolume := &grpc.Storage{
		Source:     mountGuest9pTag,
		MountPoint: defaultGuestSharedDir,
		Fstype:     type9pFs,
		Options:    []string{"trans=virtio", "nodev"},
	}

	req := &grpc.CreateSandboxRequest{
		Hostname:     hostname,
		Storages:     []*grpc.Storage{sharedVolume},
		SandboxPidns: true,
	}
	_, err := k.client.CreateSandbox(context.Background(), req)
	return err
}

func (k *kataAgent) stopPod(pod Pod) error {
	if k.client == nil {
		return errorMissingGRPClient
	}

	req := &grpc.DestroySandboxRequest{}
	_, err := k.client.DestroySandbox(context.Background(), req)
	return err
}

func (k *kataAgent) createContainer(pod *Pod, c *Container) error {
	return nil
}

func (k *kataAgent) startContainer(pod Pod, c Container) error {
	return nil
}

func (k *kataAgent) stopContainer(pod Pod, c Container) error {
	return nil
}

func (k *kataAgent) killContainer(pod Pod, c Container, signal syscall.Signal, all bool) error {
	return nil
}

func (k *kataAgent) processListContainer(pod Pod, c Container, options ProcessListOptions) (ProcessList, error) {
	return nil, nil
}
<|endoftext|>


<commit_before>package atlas

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

const testURL = "http://localhost:10000"

func TestGetPageNum(t *testing.T) {
	nurl := "https://foo.example.com/"

	n := getPageNum(nurl)
	if n != "" {
		t.Errorf("n=%s should be ''", n)
	}
	nurl = "https://foo.example.com/?page=42"
	n = getPageNum(nurl)
	if n != "42" {
		t.Errorf("n=%s should be 42", n)
	}
	nurl = "https://foo.example.com/?country=fr&page=43"
	n = getPageNum(nurl)
	if n != "43" {
		t.Errorf("n=%s should be 43", n)
	}
	nurl = "https://foo.example.com/?country=fr&page=666&bar=1"
	n = getPageNum(nurl)
	if n != "666" {
		t.Errorf("n=%s should be 666", n)
	}

	nurl = ""
	n = getPageNum(nurl)
	if n != "" {
		t.Errorf("n=%s should be ''", n)
	}
}

func TestClienthandleAPIResponsese(t *testing.T) {
	var (
		r http.Response
		b bytes.Buffer
	)

	client, err := NewClient()
	err = client.handleAPIResponse(nil)
	assert.Error(t, err)

	r = http.Response{StatusCode: 0}
	err = client.handleAPIResponse(&r)
	assert.NoError(t, err)

	r = http.Response{StatusCode: 200}
	err = client.handleAPIResponse(&r)
	assert.NoError(t, err)

	var jsonErr = `{"error":{"status": 501, "errors":[{"detail": "test"}],"code": 500, "detail":"issue"}}`

	fmt.Fprintf(&b, "%v", jsonErr)
	r.StatusCode = 300
	r.Body = ioutil.NopCloser(&b)
	err = client.handleAPIResponse(&r)
	assert.NoError(t, err)

	r.StatusCode = 500
	r.Body = ioutil.NopCloser(&b)
	err = client.handleAPIResponse(&r)
	assert.Error(t, err)
}

func TestAddQueryParameters(t *testing.T) {
	p := AddQueryParameters("", map[string]string{})
	assert.Equal(t, "", p)
}

func TestAddQueryParameters_1(t *testing.T) {
	p := AddQueryParameters("", map[string]string{"": ""})
	assert.Equal(t, "?=", p)
}

func TestAddQueryParameters_2(t *testing.T) {
	p := AddQueryParameters("foo", map[string]string{"bar": "baz"})
	assert.Equal(t, "foo?bar=baz", p)
}

func TestClient_AddAPIKey(t *testing.T) {
	c, err := NewClient(Config{APIKey: "foo"})
	require.NoError(t, err)
	assert.NotNil(t, c)
	assert.NotEmpty(t, c)

	opts := map[string]string{}

	newk := c.addAPIKey(opts)
	assert.NotEmpty(t, c.config.APIKey)
	assert.Equal(t, 1, len(newk))
	assert.EqualValues(t, map[string]string{"key": "foo"}, newk)
}

func TestClient_PrepareRequest(t *testing.T) {
	c, err := NewClient(Config{endpoint: testURL})
	require.NoError(t, err)

	opts := map[string]string{}
	req := c.prepareRequest("GET", "foo", opts)

	assert.NotNil(t, req)
	assert.IsType(t, (*http.Request)(nil), req)

	res, _ := url.Parse(testURL + "/foo")
	assert.Equal(t, "GET", req.Method)
	assert.EqualValues(t, res, req.URL)
}

func TestClient_PrepareRequest_2(t *testing.T) {
	c, err := NewClient(TesCfg)
	require.NoError(t, err)

	opts := map[string]string{}
	req := c.prepareRequest("GET", "foo", opts)

	assert.NotNil(t, req)
	assert.IsType(t, (*http.Request)(nil), req)

	res, _ := url.Parse(apiEndpoint + "/foo")
	assert.Equal(t, "GET", req.Method)
	assert.EqualValues(t, res, req.URL)
}

func TestClient_PrepareRequest_3(t *testing.T) {
	c, err := NewClient(TesCfg)
	require.NoError(t, err)

	opts := map[string]string{}
	req := c.prepareRequest("FETCH", testURL+"/foo", opts)

	assert.NotNil(t, req)
	assert.IsType(t, (*http.Request)(nil), req)

	res, _ := url.Parse(testURL + "/foo")
	assert.Equal(t, "GET", req.Method)
	assert.EqualValues(t, res, req.URL)
}

func TestClient_MergeGlobalOptions(t *testing.T) {
	c, err := NewClient(TesCfg)
	require.NoError(t, err)

	opts := map[string]string{"foo": "bar"}
	c.opts = map[string]string{"baz": "xyz"}
	res := map[string]string{"foo": "bar", "baz": "xyz"}

	c.mergeGlobalOptions(opts)
	assert.EqualValues(t, res, opts)
}
<commit_msg>Sync test with API change for handleAPIResponse().<commit_after>package atlas

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

const testURL = "http://localhost:10000"

func TestGetPageNum(t *testing.T) {
	nurl := "https://foo.example.com/"

	n := getPageNum(nurl)
	if n != "" {
		t.Errorf("n=%s should be ''", n)
	}
	nurl = "https://foo.example.com/?page=42"
	n = getPageNum(nurl)
	if n != "42" {
		t.Errorf("n=%s should be 42", n)
	}
	nurl = "https://foo.example.com/?country=fr&page=43"
	n = getPageNum(nurl)
	if n != "43" {
		t.Errorf("n=%s should be 43", n)
	}
	nurl = "https://foo.example.com/?country=fr&page=666&bar=1"
	n = getPageNum(nurl)
	if n != "666" {
		t.Errorf("n=%s should be 666", n)
	}

	nurl = ""
	n = getPageNum(nurl)
	if n != "" {
		t.Errorf("n=%s should be ''", n)
	}
}

func TestClienthandleAPIResponse(t *testing.T) {
	var (
		r http.Response
		b bytes.Buffer
	)

	client, err := NewClient()
	_, err = client.handleAPIResponse(nil)
	assert.Error(t, err)

	r = http.Response{StatusCode: 0}
	_, err = client.handleAPIResponse(&r)
	assert.NoError(t, err)

	r = http.Response{StatusCode: 200}
	_, err = client.handleAPIResponse(&r)
	assert.NoError(t, err)

	var jsonErr = `{"error":{"status": 501, "errors":[{"detail": "test"}],"code": 500, "detail":"issue"}}`

	fmt.Fprintf(&b, "%v", jsonErr)
	r.StatusCode = 300
	r.Body = ioutil.NopCloser(&b)
	_, err = client.handleAPIResponse(&r)
	assert.NoError(t, err)

	r.StatusCode = 500
	r.Body = ioutil.NopCloser(&b)
	_, err = client.handleAPIResponse(&r)
	assert.Error(t, err)
}

func TestAddQueryParameters(t *testing.T) {
	p := AddQueryParameters("", map[string]string{})
	assert.Equal(t, "", p)
}

func TestAddQueryParameters_1(t *testing.T) {
	p := AddQueryParameters("", map[string]string{"": ""})
	assert.Equal(t, "?=", p)
}

func TestAddQueryParameters_2(t *testing.T) {
	p := AddQueryParameters("foo", map[string]string{"bar": "baz"})
	assert.Equal(t, "foo?bar=baz", p)
}

func TestClient_AddAPIKey(t *testing.T) {
	c, err := NewClient(Config{APIKey: "foo"})
	require.NoError(t, err)
	assert.NotNil(t, c)
	assert.NotEmpty(t, c)

	opts := map[string]string{}

	newk := c.addAPIKey(opts)
	assert.NotEmpty(t, c.config.APIKey)
	assert.Equal(t, 1, len(newk))
	assert.EqualValues(t, map[string]string{"key": "foo"}, newk)
}

func TestClient_PrepareRequest(t *testing.T) {
	c, err := NewClient(Config{endpoint: testURL})
	require.NoError(t, err)

	opts := map[string]string{}
	req := c.prepareRequest("GET", "foo", opts)

	assert.NotNil(t, req)
	assert.IsType(t, (*http.Request)(nil), req)

	res, _ := url.Parse(testURL + "/foo")
	assert.Equal(t, "GET", req.Method)
	assert.EqualValues(t, res, req.URL)
}

func TestClient_PrepareRequest_2(t *testing.T) {
	c, err := NewClient(TesCfg)
	require.NoError(t, err)

	opts := map[string]string{}
	req := c.prepareRequest("GET", "foo", opts)

	assert.NotNil(t, req)
	assert.IsType(t, (*http.Request)(nil), req)

	res, _ := url.Parse(apiEndpoint + "/foo")
	assert.Equal(t, "GET", req.Method)
	assert.EqualValues(t, res, req.URL)
}

func TestClient_PrepareRequest_3(t *testing.T) {
	c, err := NewClient(TesCfg)
	require.NoError(t, err)

	opts := map[string]string{}
	req := c.prepareRequest("FETCH", testURL+"/foo", opts)

	assert.NotNil(t, req)
	assert.IsType(t, (*http.Request)(nil), req)

	res, _ := url.Parse(testURL + "/foo")
	assert.Equal(t, "GET", req.Method)
	assert.EqualValues(t, res, req.URL)
}

func TestClient_MergeGlobalOptions(t *testing.T) {
	c, err := NewClient(TesCfg)
	require.NoError(t, err)

	opts := map[string]string{"foo": "bar"}
	c.opts = map[string]string{"baz": "xyz"}
	res := map[string]string{"foo": "bar", "baz": "xyz"}

	c.mergeGlobalOptions(opts)
	assert.EqualValues(t, res, opts)
}
<|endoftext|>


<commit_before>// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file.

package codec

// All non-std package dependencies related to testing live in this file,
// so porting to different environment is easy (just update functions).
//
// This file sets up the variables used, including testInitFns.
// Each file should add initialization that should be performed
// after flags are parsed.
//
// init is a multi-step process:
//   - setup vars (handled by init functions in each file)
//   - parse flags
//   - setup derived vars (handled by pre-init registered functions - registered in init function)
//   - post init (handled by post-init registered functions - registered in init function)
// This way, no one has to manage carefully control the initialization
// using file names, etc.
//
// Tests which require external dependencies need the -tag=x parameter.
// They should be run as:
//    go test -tags=x -run=. <other parameters ...>
// Benchmarks should also take this parameter, to include the sereal, xdr, etc.
// To run against codecgen, etc, make sure you pass extra parameters.
// Example usage:
//    go test "-tags=x codecgen unsafe" -bench=. <other parameters ...>
//
// To fully test everything:
//    go test -tags=x -benchtime=100ms -tv -bg -bi  -brw -bu -v -run=. -bench=.

// Handling flags
// codec_test.go will define a set of global flags for testing, including:
//   - Use Reset
//   - Use IO reader/writer (vs direct bytes)
//   - Set Canonical
//   - Set InternStrings
//   - Use Symbols
//
// This way, we can test them all by running same set of tests with a different
// set of flags.
//
// Following this, all the benchmarks will utilize flags set by codec_test.go
// and will not redefine these "global" flags.

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"reflect"
	"sync"
	"testing"

	. "github.com/ugorji/go/codec"
)

type testHED struct {
	H Handle
	E *Encoder
	D *Decoder
}

var (
	testNoopH    = NoopHandle(8)
	testMsgpackH = &MsgpackHandle{}
	testBincH    = &BincHandle{}
	testSimpleH  = &SimpleHandle{}
	testCborH    = &CborHandle{}
	testJsonH    = &JsonHandle{}

	testHandles     []Handle
	testPreInitFns  []func()
	testPostInitFns []func()

	testOnce sync.Once

	testHEDs []testHED
)

// variables used by tests
var (
	testVerbose        bool
	testInitDebug      bool
	testUseIoEncDec    bool
	testStructToArray  bool
	testCanonical      bool
	testUseReset       bool
	testWriteNoSymbols bool
	testSkipIntf       bool
	testInternStr      bool
	testUseMust        bool
	testCheckCircRef   bool
	testJsonIndent     int
)

func init() {
	testHEDs = make([]testHED, 0, 32)
	testHandles = append(testHandles,
		testNoopH, testMsgpackH, testBincH, testSimpleH,
		testCborH, testJsonH)
}

func testHEDGet(h Handle) *testHED {
	for i := range testHEDs {
		v := &testHEDs[i]
		if v.H == h {
			return v
		}
	}
	testHEDs = append(testHEDs, testHED{h, NewEncoder(nil, h), NewDecoder(nil, h)})
	return &testHEDs[len(testHEDs)-1]
}

func testInitAll() {
	flag.Parse()
	for _, f := range testPreInitFns {
		f()
	}
	for _, f := range testPostInitFns {
		f()
	}
}

func testCodecEncode(ts interface{}, bsIn []byte,
	fn func([]byte) *bytes.Buffer, h Handle) (bs []byte, err error) {
	// bs = make([]byte, 0, approxSize)
	var e *Encoder
	var buf *bytes.Buffer
	if testUseReset {
		e = testHEDGet(h).E
	} else {
		e = NewEncoder(nil, h)
	}
	if testUseIoEncDec {
		buf = fn(bsIn)
		e.Reset(buf)
	} else {
		bs = bsIn
		e.ResetBytes(&bs)
	}
	if testUseMust {
		e.MustEncode(ts)
	} else {
		err = e.Encode(ts)
	}
	if testUseIoEncDec {
		bs = buf.Bytes()
	}
	return
}

func testCodecDecode(bs []byte, ts interface{}, h Handle) (err error) {
	var d *Decoder
	var buf *bytes.Reader
	if testUseReset {
		d = testHEDGet(h).D
	} else {
		d = NewDecoder(nil, h)
	}
	if testUseIoEncDec {
		buf = bytes.NewReader(bs)
		d.Reset(buf)
	} else {
		d.ResetBytes(bs)
	}
	if testUseMust {
		d.MustDecode(ts)
	} else {
		err = d.Decode(ts)
	}
	return
}

// ----- functions below are used only by benchmarks alone
func benchFnCodecEncode(ts interface{}, bsIn []byte, h Handle) (bs []byte, err error) {
	return testCodecEncode(ts, bsIn, fnBenchmarkByteBuf, h)
}

func benchFnCodecDecode(bs []byte, ts interface{}, h Handle) (err error) {
	return testCodecDecode(bs, ts, h)
}

// ----- functions below are used only by tests (not benchmarks)

const (
	testLogToT    = true
	failNowOnFail = true
)

func checkErrT(t *testing.T, err error) {
	if err != nil {
		logT(t, err.Error())
		failT(t)
	}
}

func checkEqualT(t *testing.T, v1 interface{}, v2 interface{}, desc string) (err error) {
	if err = deepEqual(v1, v2); err != nil {
		logT(t, "Not Equal: %s: %v. v1: %v, v2: %v", desc, err, v1, v2)
		failT(t)
	}
	return
}

func failT(t *testing.T) {
	if failNowOnFail {
		t.FailNow()
	} else {
		t.Fail()
	}
}

// --- these functions are used by both benchmarks and tests

func deepEqual(v1, v2 interface{}) (err error) {
	if !reflect.DeepEqual(v1, v2) {
		err = errors.New("Not Match")
	}
	return
}

func logT(x interface{}, format string, args ...interface{}) {
	if t, ok := x.(*testing.T); ok && t != nil && testLogToT {
		if testVerbose {
			t.Logf(format, args...)
		}
	} else if b, ok := x.(*testing.B); ok && b != nil && testLogToT {
		b.Logf(format, args...)
	} else {
		if len(format) == 0 || format[len(format)-1] != '\n' {
			format = format + "\n"
		}
		fmt.Printf(format, args...)
	}
}

func approxDataSize(rv reflect.Value) (sum int) {
	switch rk := rv.Kind(); rk {
	case reflect.Invalid:
	case reflect.Ptr, reflect.Interface:
		sum += int(rv.Type().Size())
		sum += approxDataSize(rv.Elem())
	case reflect.Slice:
		sum += int(rv.Type().Size())
		for j := 0; j < rv.Len(); j++ {
			sum += approxDataSize(rv.Index(j))
		}
	case reflect.String:
		sum += int(rv.Type().Size())
		sum += rv.Len()
	case reflect.Map:
		sum += int(rv.Type().Size())
		for _, mk := range rv.MapKeys() {
			sum += approxDataSize(mk)
			sum += approxDataSize(rv.MapIndex(mk))
		}
	case reflect.Struct:
		//struct size already includes the full data size.
		//sum += int(rv.Type().Size())
		for j := 0; j < rv.NumField(); j++ {
			sum += approxDataSize(rv.Field(j))
		}
	default:
		//pure value types
		sum += int(rv.Type().Size())
	}
	return
}
<commit_msg>codec: helper_test: added some missing variables<commit_after>// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file.

package codec

// All non-std package dependencies related to testing live in this file,
// so porting to different environment is easy (just update functions).
//
// This file sets up the variables used, including testInitFns.
// Each file should add initialization that should be performed
// after flags are parsed.
//
// init is a multi-step process:
//   - setup vars (handled by init functions in each file)
//   - parse flags
//   - setup derived vars (handled by pre-init registered functions - registered in init function)
//   - post init (handled by post-init registered functions - registered in init function)
// This way, no one has to manage carefully control the initialization
// using file names, etc.
//
// Tests which require external dependencies need the -tag=x parameter.
// They should be run as:
//    go test -tags=x -run=. <other parameters ...>
// Benchmarks should also take this parameter, to include the sereal, xdr, etc.
// To run against codecgen, etc, make sure you pass extra parameters.
// Example usage:
//    go test "-tags=x codecgen unsafe" -bench=. <other parameters ...>
//
// To fully test everything:
//    go test -tags=x -benchtime=100ms -tv -bg -bi  -brw -bu -v -run=. -bench=.

// Handling flags
// codec_test.go will define a set of global flags for testing, including:
//   - Use Reset
//   - Use IO reader/writer (vs direct bytes)
//   - Set Canonical
//   - Set InternStrings
//   - Use Symbols
//
// This way, we can test them all by running same set of tests with a different
// set of flags.
//
// Following this, all the benchmarks will utilize flags set by codec_test.go
// and will not redefine these "global" flags.

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"reflect"
	"sync"
	"testing"

	. "github.com/ugorji/go/codec"
)

type testHED struct {
	H Handle
	E *Encoder
	D *Decoder
}

var (
	testNoopH    = NoopHandle(8)
	testMsgpackH = &MsgpackHandle{}
	testBincH    = &BincHandle{}
	testSimpleH  = &SimpleHandle{}
	testCborH    = &CborHandle{}
	testJsonH    = &JsonHandle{}

	testHandles     []Handle
	testPreInitFns  []func()
	testPostInitFns []func()

	testOnce sync.Once

	testHEDs []testHED
)

// variables used by tests
var (
	testVerbose        bool
	testInitDebug      bool
	testUseIoEncDec    bool
	testStructToArray  bool
	testCanonical      bool
	testUseReset       bool
	testWriteNoSymbols bool
	testSkipIntf       bool
	testInternStr      bool
	testUseMust        bool
	testCheckCircRef   bool
	testJsonIndent     int
	testMaxInitLen     int

	testJsonHTMLCharsAsIs bool
)

func init() {
	testHEDs = make([]testHED, 0, 32)
	testHandles = append(testHandles,
		testNoopH, testMsgpackH, testBincH, testSimpleH,
		testCborH, testJsonH)
}

func testHEDGet(h Handle) *testHED {
	for i := range testHEDs {
		v := &testHEDs[i]
		if v.H == h {
			return v
		}
	}
	testHEDs = append(testHEDs, testHED{h, NewEncoder(nil, h), NewDecoder(nil, h)})
	return &testHEDs[len(testHEDs)-1]
}

func testInitAll() {
	flag.Parse()
	for _, f := range testPreInitFns {
		f()
	}
	for _, f := range testPostInitFns {
		f()
	}
}

func testCodecEncode(ts interface{}, bsIn []byte,
	fn func([]byte) *bytes.Buffer, h Handle) (bs []byte, err error) {
	// bs = make([]byte, 0, approxSize)
	var e *Encoder
	var buf *bytes.Buffer
	if testUseReset {
		e = testHEDGet(h).E
	} else {
		e = NewEncoder(nil, h)
	}
	if testUseIoEncDec {
		buf = fn(bsIn)
		e.Reset(buf)
	} else {
		bs = bsIn
		e.ResetBytes(&bs)
	}
	if testUseMust {
		e.MustEncode(ts)
	} else {
		err = e.Encode(ts)
	}
	if testUseIoEncDec {
		bs = buf.Bytes()
	}
	return
}

func testCodecDecode(bs []byte, ts interface{}, h Handle) (err error) {
	var d *Decoder
	var buf *bytes.Reader
	if testUseReset {
		d = testHEDGet(h).D
	} else {
		d = NewDecoder(nil, h)
	}
	if testUseIoEncDec {
		buf = bytes.NewReader(bs)
		d.Reset(buf)
	} else {
		d.ResetBytes(bs)
	}
	if testUseMust {
		d.MustDecode(ts)
	} else {
		err = d.Decode(ts)
	}
	return
}

// ----- functions below are used only by benchmarks alone
func benchFnCodecEncode(ts interface{}, bsIn []byte, h Handle) (bs []byte, err error) {
	return testCodecEncode(ts, bsIn, fnBenchmarkByteBuf, h)
}

func benchFnCodecDecode(bs []byte, ts interface{}, h Handle) (err error) {
	return testCodecDecode(bs, ts, h)
}

// ----- functions below are used only by tests (not benchmarks)

const (
	testLogToT    = true
	failNowOnFail = true
)

func checkErrT(t *testing.T, err error) {
	if err != nil {
		logT(t, err.Error())
		failT(t)
	}
}

func checkEqualT(t *testing.T, v1 interface{}, v2 interface{}, desc string) (err error) {
	if err = deepEqual(v1, v2); err != nil {
		logT(t, "Not Equal: %s: %v. v1: %v, v2: %v", desc, err, v1, v2)
		failT(t)
	}
	return
}

func failT(t *testing.T) {
	if failNowOnFail {
		t.FailNow()
	} else {
		t.Fail()
	}
}

// --- these functions are used by both benchmarks and tests

func deepEqual(v1, v2 interface{}) (err error) {
	if !reflect.DeepEqual(v1, v2) {
		err = errors.New("Not Match")
	}
	return
}

func logT(x interface{}, format string, args ...interface{}) {
	if t, ok := x.(*testing.T); ok && t != nil && testLogToT {
		if testVerbose {
			t.Logf(format, args...)
		}
	} else if b, ok := x.(*testing.B); ok && b != nil && testLogToT {
		b.Logf(format, args...)
	} else {
		if len(format) == 0 || format[len(format)-1] != '\n' {
			format = format + "\n"
		}
		fmt.Printf(format, args...)
	}
}

func approxDataSize(rv reflect.Value) (sum int) {
	switch rk := rv.Kind(); rk {
	case reflect.Invalid:
	case reflect.Ptr, reflect.Interface:
		sum += int(rv.Type().Size())
		sum += approxDataSize(rv.Elem())
	case reflect.Slice:
		sum += int(rv.Type().Size())
		for j := 0; j < rv.Len(); j++ {
			sum += approxDataSize(rv.Index(j))
		}
	case reflect.String:
		sum += int(rv.Type().Size())
		sum += rv.Len()
	case reflect.Map:
		sum += int(rv.Type().Size())
		for _, mk := range rv.MapKeys() {
			sum += approxDataSize(mk)
			sum += approxDataSize(rv.MapIndex(mk))
		}
	case reflect.Struct:
		//struct size already includes the full data size.
		//sum += int(rv.Type().Size())
		for j := 0; j < rv.NumField(); j++ {
			sum += approxDataSize(rv.Field(j))
		}
	default:
		//pure value types
		sum += int(rv.Type().Size())
	}
	return
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
// This file is available under the Apache license.

package vm

import (
	"strings"
	"testing"
	"time"

	"github.com/google/mtail/metrics"
	"github.com/google/mtail/watcher"
	"github.com/kylelemons/godebug/pretty"
	"github.com/spf13/afero"
)

func TestNewLoader(t *testing.T) {
	w := watcher.NewFakeWatcher()
	store := &metrics.Store{}
	inLines := make(chan string)
	fs := &afero.MemMapFs{}
	o := LoaderOptions{store, inLines, w, fs, false, false, true}
	l, err := NewLoader(o)
	if err != nil {
		t.Fatalf("couldn't create loader: %s", err)
	}
	done := make(chan struct{})
	outLines := make(chan string)
	handle := &vmHandle{outLines, done}
	l.handleMu.Lock()
	l.handles["test"] = handle
	l.handleMu.Unlock()
	go func() {
		for _ = range outLines {
		}
		close(done)
	}()
	close(inLines)
	<-outLines
}

func TestCompileAndRun(t *testing.T) {
	var testProgram = "/$/ {}\n"
	store := &metrics.Store{}
	lines := make(chan string)
	w := watcher.NewFakeWatcher()
	fs := &afero.MemMapFs{}
	o := LoaderOptions{store, lines, w, fs, false, false, true}
	l, err := NewLoader(o)
	if err != nil {
		t.Fatalf("couldn't create loader: %s", err)
	}
	if err := l.CompileAndRun("Test", strings.NewReader(testProgram)); err != nil {
		t.Errorf("CompileAndRun returned error: %s", err)
	}
	l.handleMu.Lock()
	if len(l.handles) < 1 {
		t.Errorf("no vm handles: %v", l.handles)
	}
	l.handleMu.Unlock()
	l.handleMu.Lock()
	c := l.handles["Test"].done
	if c == nil {
		t.Errorf("No done channel in handles: %v", l.handles)
	}
	l.handleMu.Unlock()
	close(lines)
	<-c
	{
		l.handleMu.Lock()
		defer l.handleMu.Unlock()
		if len(l.handles) != 0 {
			t.Errorf("some vm handles: %v", l.handles)
		}
	}
}

var testProcessEvents = []struct {
	name             string
	events           []watcher.Event
	expectedPrograms []string
}{
	{"load",
		[]watcher.Event{
			watcher.CreateEvent{Pathname: "foo.mtail"},
			watcher.UpdateEvent{Pathname: "foo.mtail"}},
		[]string{"foo.mtail"}},
	{"unload",
		[]watcher.Event{
			watcher.CreateEvent{Pathname: "foo.mtail"},
			watcher.UpdateEvent{Pathname: "foo.mtail"},
			watcher.DeleteEvent{Pathname: "foo.mtail"}},
		[]string{}},
	{"reload",
		[]watcher.Event{
			watcher.CreateEvent{Pathname: "foo.mtail"},
			watcher.UpdateEvent{Pathname: "foo.mtail"},
			watcher.UpdateEvent{Pathname: "foo.mtail"}},
		[]string{"foo.mtail"}},
	{"bad extension",
		[]watcher.Event{
			watcher.CreateEvent{Pathname: "foo.mtail.dpkg-dist"},
			watcher.UpdateEvent{Pathname: "foo.mtail.dpkg-dist"}},
		[]string{}},
	{"not exist",
		[]watcher.Event{
			watcher.CreateEvent{Pathname: "notexist.mtail"},
			watcher.UpdateEvent{Pathname: "notexist.mtail"}},
		[]string{}},
}

var testProgram = "/$/ {}\n"

func TestProcessEvents(t *testing.T) {
	for _, tt := range testProcessEvents {
		w := watcher.NewFakeWatcher()
		w.Add(".")
		store := &metrics.Store{}
		lines := make(chan string)
		fs := &afero.MemMapFs{}
		o := LoaderOptions{store, lines, w, fs, false, false, true}
		l, err := NewLoader(o)
		if err != nil {
			t.Fatalf("couldn't create loader: %s", err)
		}
		for i := range tt.events {
			e := tt.events[i]
			switch e := e.(type) {
			case watcher.CreateEvent:
				if e.Pathname != "notexist.mtail" {
					_, err := fs.Create(e.Pathname)
					if err != nil {
						t.Fatalf("Create failed for %s: %s", e.Pathname, err)
					}
				}
				w.InjectCreate(e.Pathname)
			case watcher.DeleteEvent:
				err := fs.Remove(e.Pathname)
				if err != nil {
					t.Fatalf("Remove failed for %s: %s", e.Pathname, err)
				}
				w.InjectDelete(e.Pathname)
			case watcher.UpdateEvent:
				if e.Pathname != "notexist.mtail" {
					f, err := fs.Open(e.Pathname)
					if err != nil {
						t.Fatalf("Couldn't open file %s for test: %s", e.Pathname, err)
					}
					_, err = f.WriteString(testProgram)
					if err != nil {
						t.Fatalf("Couldn't write file contents: %s", err)
					}
					if err = f.Close(); err != nil {
						t.Fatalf("Close failed: %s", err)
					}
				}
				w.InjectUpdate(e.Pathname)
			}
		}
		// ugh; figure out something to synchronise after LoadProg
		time.Sleep(10 * time.Millisecond)
		var programs []string
		l.handleMu.RLock()
		for program := range l.handles {
			programs = append(programs, program)
		}
		l.handleMu.RUnlock()
		l.handleMu.RLock()
		if diff := pretty.Compare(tt.expectedPrograms, programs); len(diff) > 0 {
			t.Errorf("%s: loaded programs don't match. l.handles: %+#v\n%s", tt.name, l.handles, diff)
		}
		l.handleMu.RUnlock()
		close(lines)

	}
}
<commit_msg>Quoted strings.<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
// This file is available under the Apache license.

package vm

import (
	"strings"
	"testing"
	"time"

	"github.com/google/mtail/metrics"
	"github.com/google/mtail/watcher"
	"github.com/kylelemons/godebug/pretty"
	"github.com/spf13/afero"
)

func TestNewLoader(t *testing.T) {
	w := watcher.NewFakeWatcher()
	store := &metrics.Store{}
	inLines := make(chan string)
	fs := &afero.MemMapFs{}
	o := LoaderOptions{store, inLines, w, fs, false, false, true}
	l, err := NewLoader(o)
	if err != nil {
		t.Fatalf("couldn't create loader: %s", err)
	}
	done := make(chan struct{})
	outLines := make(chan string)
	handle := &vmHandle{outLines, done}
	l.handleMu.Lock()
	l.handles["test"] = handle
	l.handleMu.Unlock()
	go func() {
		for _ = range outLines {
		}
		close(done)
	}()
	close(inLines)
	<-outLines
}

func TestCompileAndRun(t *testing.T) {
	var testProgram = "/$/ {}\n"
	store := &metrics.Store{}
	lines := make(chan string)
	w := watcher.NewFakeWatcher()
	fs := &afero.MemMapFs{}
	o := LoaderOptions{store, lines, w, fs, false, false, true}
	l, err := NewLoader(o)
	if err != nil {
		t.Fatalf("couldn't create loader: %s", err)
	}
	if err := l.CompileAndRun("Test", strings.NewReader(testProgram)); err != nil {
		t.Errorf("CompileAndRun returned error: %s", err)
	}
	l.handleMu.Lock()
	if len(l.handles) < 1 {
		t.Errorf("no vm handles: %v", l.handles)
	}
	l.handleMu.Unlock()
	l.handleMu.Lock()
	c := l.handles["Test"].done
	if c == nil {
		t.Errorf("No done channel in handles: %v", l.handles)
	}
	l.handleMu.Unlock()
	close(lines)
	<-c
	{
		l.handleMu.Lock()
		defer l.handleMu.Unlock()
		if len(l.handles) != 0 {
			t.Errorf("some vm handles: %v", l.handles)
		}
	}
}

var testProcessEvents = []struct {
	name             string
	events           []watcher.Event
	expectedPrograms []string
}{
	{"load",
		[]watcher.Event{
			watcher.CreateEvent{Pathname: "foo.mtail"},
			watcher.UpdateEvent{Pathname: "foo.mtail"}},
		[]string{"foo.mtail"}},
	{"unload",
		[]watcher.Event{
			watcher.CreateEvent{Pathname: "foo.mtail"},
			watcher.UpdateEvent{Pathname: "foo.mtail"},
			watcher.DeleteEvent{Pathname: "foo.mtail"}},
		[]string{}},
	{"reload",
		[]watcher.Event{
			watcher.CreateEvent{Pathname: "foo.mtail"},
			watcher.UpdateEvent{Pathname: "foo.mtail"},
			watcher.UpdateEvent{Pathname: "foo.mtail"}},
		[]string{"foo.mtail"}},
	{"bad extension",
		[]watcher.Event{
			watcher.CreateEvent{Pathname: "foo.mtail.dpkg-dist"},
			watcher.UpdateEvent{Pathname: "foo.mtail.dpkg-dist"}},
		[]string{}},
	{"not exist",
		[]watcher.Event{
			watcher.CreateEvent{Pathname: "notexist.mtail"},
			watcher.UpdateEvent{Pathname: "notexist.mtail"}},
		[]string{}},
}

var testProgram = "/$/ {}\n"

func TestProcessEvents(t *testing.T) {
	for _, tt := range testProcessEvents {
		w := watcher.NewFakeWatcher()
		w.Add(".")
		store := &metrics.Store{}
		lines := make(chan string)
		fs := &afero.MemMapFs{}
		o := LoaderOptions{store, lines, w, fs, false, false, true}
		l, err := NewLoader(o)
		if err != nil {
			t.Fatalf("couldn't create loader: %s", err)
		}
		for i := range tt.events {
			e := tt.events[i]
			switch e := e.(type) {
			case watcher.CreateEvent:
				if e.Pathname != "notexist.mtail" {
					_, err := fs.Create(e.Pathname)
					if err != nil {
						t.Fatalf("Create failed for %s: %s", e.Pathname, err)
					}
				}
				w.InjectCreate(e.Pathname)
			case watcher.DeleteEvent:
				err := fs.Remove(e.Pathname)
				if err != nil {
					t.Fatalf("Remove failed for %s: %s", e.Pathname, err)
				}
				w.InjectDelete(e.Pathname)
			case watcher.UpdateEvent:
				if e.Pathname != "notexist.mtail" {
					f, err := fs.Open(e.Pathname)
					if err != nil {
						t.Fatalf("Couldn't open file %s for test: %s", e.Pathname, err)
					}
					_, err = f.WriteString(testProgram)
					if err != nil {
						t.Fatalf("Couldn't write file contents: %s", err)
					}
					if err = f.Close(); err != nil {
						t.Fatalf("Close failed: %s", err)
					}
				}
				w.InjectUpdate(e.Pathname)
			}
		}
		// ugh; figure out something to synchronise after LoadProg
		time.Sleep(10 * time.Millisecond)
		var programs []string
		l.handleMu.RLock()
		for program := range l.handles {
			programs = append(programs, program)
		}
		l.handleMu.RUnlock()
		l.handleMu.RLock()
		if diff := pretty.Compare(tt.expectedPrograms, programs); len(diff) > 0 {
			t.Errorf("%q: loaded programs don't match. l.handles: %+#v\n%s", tt.name, l.handles, diff)
		}
		l.handleMu.RUnlock()
		close(lines)

	}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/dynport/dgtk/vmware"
)

type StopAction struct {
	Name string `cli:"type=arg required=true"`
}

func (action *StopAction) Run() error {
	vm, e := findFirst(action.Name)
	if e != nil {
		return e
	}
	return vmware.Stop(vm.Path)
}
<commit_msg>add opt to delete VMs when stopping them<commit_after>package main

import (
	"github.com/dynport/dgtk/vmware"
	"log"
)

type StopAction struct {
	Name   string `cli:"type=arg required=true"`
	Delete bool   `cli:"type=opt long=delete desc='delete vm after stopping'"`
}

func (action *StopAction) Run() error {
	vm, e := findFirst(action.Name)
	if e != nil {
		return e
	}
	log.Printf("stopping vm at %s", vm.Path)
	e = vmware.Stop(vm.Path)
	if e != nil {
		return e
	}
	if action.Delete {
		log.Printf("deleting vm at %s", vm.Path)
		return vmware.DeleteVM(vm.Path)
	}
	return nil
}
<|endoftext|>


<commit_before>package gohost

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"testing"
	"time"

	"github.com/eleniums/gohost/examples/hello"
	"golang.org/x/net/context"
	"google.golang.org/grpc"

	pb "github.com/eleniums/gohost/examples/hello/proto"
	assert "github.com/stretchr/testify/require"
)

func Test_Hoster_ListenAndServe_Successful(t *testing.T) {
	// arrange
	service := hello.NewService()
	httpAddr := "127.0.0.1:9090"
	grpcAddr := "127.0.0.1:50051"

	hoster := NewHoster(service, grpcAddr)
	hoster.HTTPAddr = httpAddr

	// act - start the service
	go hoster.ListenAndServe()

	// make sure service has time to start
	time.Sleep(time.Millisecond * 100)

	// call the service at the gRPC endpoint
	conn, err := grpc.Dial(grpcAddr, grpc.WithInsecure())
	assert.NoError(t, err)
	client := pb.NewHelloServiceClient(conn)
	grpcReq := pb.HelloRequest{
		Name: "eleniums",
	}
	grpcResp, err := client.Hello(context.Background(), &grpcReq)

	// assert
	assert.NoError(t, err)
	assert.NotNil(t, grpcResp)
	assert.Equal(t, "Hello eleniums!", grpcResp.Greeting)

	// call the service at the HTTP endpoint
	httpClient := http.Client{
		Timeout: time.Millisecond * 500,
	}
	httpReq, err := http.NewRequest(http.MethodGet, fmt.Sprintf("http://%v/v1/hello?name=eleniums", httpAddr), nil)
	assert.NoError(t, err)
	doResp, err := httpClient.Do(httpReq)
	assert.NoError(t, err)
	body, err := ioutil.ReadAll(doResp.Body)
	assert.NoError(t, err)
	httpResp := pb.HelloResponse{}
	err = json.Unmarshal(body, &httpResp)

	// assert
	assert.NoError(t, err)
	assert.NotNil(t, httpResp)
	assert.Equal(t, "Hello eleniums!", httpResp.Greeting)
}
<commit_msg>Split hoster test into two.<commit_after>package gohost

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"testing"
	"time"

	"github.com/eleniums/gohost/examples/hello"
	"golang.org/x/net/context"
	"google.golang.org/grpc"

	pb "github.com/eleniums/gohost/examples/hello/proto"
	assert "github.com/stretchr/testify/require"
)

func Test_Hoster_ListenAndServe_GRPCEndpoint(t *testing.T) {
	// arrange
	service := hello.NewService()
	grpcAddr := "127.0.0.1:50051"

	hoster := NewHoster(service, grpcAddr)

	// act - start the service
	go hoster.ListenAndServe()

	// make sure service has time to start
	time.Sleep(time.Millisecond * 100)

	// call the service at the gRPC endpoint
	conn, err := grpc.Dial(grpcAddr, grpc.WithInsecure())
	assert.NoError(t, err)
	client := pb.NewHelloServiceClient(conn)
	grpcReq := pb.HelloRequest{
		Name: "eleniums",
	}
	grpcResp, err := client.Hello(context.Background(), &grpcReq)

	// assert
	assert.NoError(t, err)
	assert.NotNil(t, grpcResp)
	assert.Equal(t, "Hello eleniums!", grpcResp.Greeting)
}

func Test_Hoster_ListenAndServe_HTTPEndpoint(t *testing.T) {
	// arrange
	service := hello.NewService()
	httpAddr := "127.0.0.1:9090"
	grpcAddr := "127.0.0.1:50051"

	hoster := NewHoster(service, grpcAddr)
	hoster.HTTPAddr = httpAddr

	// act - start the service
	go hoster.ListenAndServe()

	// make sure service has time to start
	time.Sleep(time.Millisecond * 100)

	// call the service at the HTTP endpoint
	httpClient := http.Client{
		Timeout: time.Millisecond * 500,
	}
	httpReq, err := http.NewRequest(http.MethodGet, fmt.Sprintf("http://%v/v1/hello?name=eleniums", httpAddr), nil)
	assert.NoError(t, err)
	doResp, err := httpClient.Do(httpReq)
	assert.NoError(t, err)
	body, err := ioutil.ReadAll(doResp.Body)
	assert.NoError(t, err)
	httpResp := pb.HelloResponse{}
	err = json.Unmarshal(body, &httpResp)

	// assert
	assert.NoError(t, err)
	assert.NotNil(t, httpResp)
	assert.Equal(t, "Hello eleniums!", httpResp.Greeting)
}
<|endoftext|>