<commit_before>package main

import (
	"errors"
	"github.com/couchbaselabs/indexing/api"
	"log"
	"net"
	"net/rpc"
	"net/rpc/jsonrpc"
)

type MutationManager struct {
	indexmap map[string]api.Finder
}

var mutationMgr MutationManager

type ddlNotification struct {
	indexinfo api.IndexInfo
	ddltype   api.RequestType
}

func (m *MutationManager) ProcessSingleMutation(mutation *api.Mutation, reply *bool) error {
	log.Printf("Received Mutation Type %s Indexid %v, Docid %v, Vbucket %v, Seqno %v", mutation.Type, mutation.Indexid, mutation.Docid, mutation.Vbucket, mutation.Seqno)

	//FIXME change this to channel based
	*reply = false

	if mutation.Type == "INSERT" {

		var key api.Key
		var value api.Value
		var err error

		if key, err = api.NewKey(mutation.SecondaryKey, mutation.Docid); err != nil {
			log.Printf("Error Generating Key From Mutation %v", err)
			*reply = false
			return err
		}

		if value, err = api.NewValue(mutation.SecondaryKey, mutation.Docid, mutation.Vbucket, mutation.Seqno); err != nil {
			log.Printf("Error Generating Value From Mutation %v", err)
			*reply = false
			return err
		}

		if engine, ok := m.indexmap[mutation.Indexid]; ok {
			if err := engine.InsertMutation(key, value); err != nil {
				log.Printf("Error from Engine during InsertMutation %v", err)
				*reply = false
				return err
			}
		} else {
			log.Printf("Unknown Index %v or Engine not found", mutation.Indexid)
			*reply = false
			return errors.New("Unknown Index or Engine not found")
		}

		*reply = true

	} else if mutation.Type == "DELETE" {

		if engine, ok := m.indexmap[mutation.Indexid]; ok {
			if err := engine.DeleteMutation(mutation.Docid); err != nil {
				log.Printf("Error from Engine during Delete Mutation %v", err)
				*reply = false
				return err
			}
		} else {
			log.Printf("Unknown Index %v or Engine not found", mutation.Indexid)
			*reply = false
			return errors.New("Unknown Index or Engine not found")
		}
		*reply = true

	}
	return nil
}

func StartMutationManager() (chan ddlNotification, error) {

	var err error
	//start the rpc server
	if err = startRPCServer(); err != nil {
		return nil, err
	}

	//create a channel to receive notification from indexer
	//and start a goroutine to listen to it
	chnotify = make(chan ddlNotification)
	go acceptIndexerNotification(chnotify)
	return chnotify, nil
}

func startRPCServer() error {

	log.Println("Starting Mutation Manager")
	server := rpc.NewServer()
	server.Register(&mutationMgr)

	server.HandleHTTP(rpc.DefaultRPCPath, rpc.DefaultDebugPath)
	mutationMgr.indexmap = make(map[string]api.Finder)

	l, err := net.Listen("tcp", ":8096")
	if err != nil {
		return err
	}

	go func() {
		for {
			conn, err := l.Accept()
			if err != nil {
				log.Printf("Error in Accept %v. Shutting down")
				//FIXME Add a cleanup function
				return
			}
			go server.ServeCodec(jsonrpc.NewServerCodec(conn))
		}
	}()
	return nil

}

func acceptIndexerNotification(chnotify chan ddlNotification) {

	ok := true
	var ddl ddlNotification
	for ok {
		ddl, ok = <-chnotify
		if ok {
			switch ddl.ddltype {
			case api.CREATE:
				mutationMgr.indexmap[ddl.indexinfo.Uuid] = ddl.indexinfo.Engine
			case api.DROP:
				delete(mutationMgr.indexmap, ddl.indexinfo.Uuid)
			default:
				log.Printf("Mutation Manager Received Unsupported Notification %v", ddl.ddltype)
			}
		}
	}
}
<commit_msg>Add restartability support in mutation manager<commit_after>package main

import (
	"encoding/json"
	"errors"
	"github.com/couchbaselabs/indexing/api"
	"log"
	"net"
	"net/rpc"
	"net/rpc/jsonrpc"
)

type MutationManager struct {
	enginemap   map[string]api.Finder
	sequencemap api.IndexSequenceMap
}

var META_DOC_ID = "."
var mutationMgr MutationManager

type ddlNotification struct {
	indexinfo api.IndexInfo
	engine    api.Finder
	ddltype   api.RequestType
}

type seqNotification struct {
	engine  api.Finder
	indexid string
	seqno   uint64
	vbucket uint
}

var chseq chan seqNotification

//This function returns a map of <Index, SequenceVector> based on the IndexList received in request
func (m *MutationManager) GetSequenceVector(indexList api.IndexList, reply *api.IndexSequenceMap) error {

	//if indexList is nil, return the complete map
	if len(indexList) == 0 {
		*reply = m.sequencemap
		log.Printf("Mutation Manager returning complete SequenceMap")
		return nil
	}

	//loop through the list of requested indexes and return the sequenceVector for those indexes
	var replyMap = make(api.IndexSequenceMap)
	for _, idx := range indexList {
		//if the requested index is not found, return an error
		v, ok := m.sequencemap[idx]
		if !ok {
			return errors.New("Requested Index Not Found")
		}

		//add to the reply map
		log.Printf("Mutation Manager returning sequence vector for index %v", idx)
		replyMap[idx] = v
	}
	*reply = replyMap
	return nil

}

func (m *MutationManager) ProcessSingleMutation(mutation *api.Mutation, reply *bool) error {
	log.Printf("Received Mutation Type %s Indexid %v, Docid %v, Vbucket %v, Seqno %v", mutation.Type, mutation.Indexid, mutation.Docid, mutation.Vbucket, mutation.Seqno)

	//FIXME change this to channel based
	*reply = false

	if mutation.Type == "INSERT" {

		var key api.Key
		var value api.Value
		var err error

		if key, err = api.NewKey(mutation.SecondaryKey, mutation.Docid); err != nil {
			log.Printf("Error Generating Key From Mutation %v", err)
			*reply = false
			return err
		}

		if value, err = api.NewValue(mutation.SecondaryKey, mutation.Docid, mutation.Vbucket, mutation.Seqno); err != nil {
			log.Printf("Error Generating Value From Mutation %v", err)
			*reply = false
			return err
		}

		if engine, ok := m.enginemap[mutation.Indexid]; ok {
			if err := engine.InsertMutation(key, value); err != nil {
				log.Printf("Error from Engine during InsertMutation %v", err)
				*reply = false
				return err
			}
			//send notification for this seqno to be recorded in SeqVector
			seqnotify := seqNotification{engine: engine,
				indexid: mutation.Indexid,
				seqno:   mutation.Seqno,
				vbucket: mutation.Vbucket,
			}
			chseq <- seqnotify
		} else {
			log.Printf("Unknown Index %v or Engine not found", mutation.Indexid)
			*reply = false
			return errors.New("Unknown Index or Engine not found")
		}

		*reply = true

	} else if mutation.Type == "DELETE" {

		if engine, ok := m.enginemap[mutation.Indexid]; ok {
			if err := engine.DeleteMutation(mutation.Docid); err != nil {
				log.Printf("Error from Engine during Delete Mutation %v", err)
				*reply = false
				return err
			}
			//send notification for this seqno to be recorded in SeqVector
			seqnotify := seqNotification{engine: engine,
				indexid: mutation.Indexid,
				seqno:   mutation.Seqno,
				vbucket: mutation.Vbucket,
			}
			chseq <- seqnotify
		} else {
			log.Printf("Unknown Index %v or Engine not found", mutation.Indexid)
			*reply = false
			return errors.New("Unknown Index or Engine not found")
		}
		*reply = true

	}
	return nil
}

func StartMutationManager(engineMap map[string]api.Finder) (chan ddlNotification, error) {

	var err error

	//init the mutation manager maps
	//mutationMgr.enginemap= make(map[string]api.Finder)
	mutationMgr.sequencemap = make(api.IndexSequenceMap)
	//copy the inital map from the indexer
	mutationMgr.enginemap = engineMap
	mutationMgr.initSequenceMapFromPersistence()

	//create channel to receive notification for new sequence numbers
	//and start a goroutine to manage it
	chseq = make(chan seqNotification, 1024)
	go mutationMgr.manageSeqNotification(chseq)

	//create a channel to receive notification from indexer
	//and start a goroutine to listen to it
	chnotify = make(chan ddlNotification)
	go acceptIndexerNotification(chnotify)

	//start the rpc server
	if err = startRPCServer(); err != nil {
		return nil, err
	}

	return chnotify, nil
}

func startRPCServer() error {

	log.Println("Starting Mutation Manager")
	server := rpc.NewServer()
	server.Register(&mutationMgr)

	server.HandleHTTP(rpc.DefaultRPCPath, rpc.DefaultDebugPath)

	l, err := net.Listen("tcp", ":8096")
	if err != nil {
		return err
	}

	go func() {
		for {
			conn, err := l.Accept()
			if err != nil {
				log.Printf("Error in Accept %v. Shutting down")
				//FIXME Add a cleanup function
				return
			}
			go server.ServeCodec(jsonrpc.NewServerCodec(conn))
		}
	}()
	return nil

}

func acceptIndexerNotification(chnotify chan ddlNotification) {

	ok := true
	var ddl ddlNotification
	for ok {
		ddl, ok = <-chnotify
		if ok {
			switch ddl.ddltype {
			case api.CREATE:
				mutationMgr.enginemap[ddl.indexinfo.Uuid] = ddl.engine
			case api.DROP:
				delete(mutationMgr.enginemap, ddl.indexinfo.Uuid)
			default:
				log.Printf("Mutation Manager Received Unsupported Notification %v", ddl.ddltype)
			}
		}
	}
}

func (m *MutationManager) manageSeqNotification(chseq chan seqNotification) {

	ok := true
	var seq seqNotification
	for ok {
		seq, ok = <-chseq
		if ok {
			seqVector := m.sequencemap[seq.indexid]
			seqVector[seq.vbucket] = seq.seqno
			m.sequencemap[seq.indexid] = seqVector
			jsonval, err := json.Marshal(m.sequencemap[seq.indexid])
			if err != nil {
				log.Printf("Error Marshalling SequenceMap %v", err)
			} else {
				m.enginemap[seq.indexid].InsertMeta(META_DOC_ID, string(jsonval))
			}
		}
	}
}

func (m *MutationManager) initSequenceMapFromPersistence() {

	var sequenceVector api.SequenceVector
	for idx, engine := range m.enginemap {
		metaval, err := engine.GetMeta(META_DOC_ID)
		if err != nil {
			log.Printf("Error retreiving Meta from Engine %v", err)
		}
		err = json.Unmarshal([]byte(metaval), &sequenceVector)
		if err != nil {
			log.Printf("Error unmarshalling SequenceVector %v", err)
		}
		m.sequencemap[idx] = sequenceVector
	}
}
<|endoftext|>


<commit_before>package plate

import (
	"io"
	"sync"
)

// Execution represents one occurence of template being executed.
// It provides access to the output produced,
// the context that was passed to the template
// and the error returned from the Execute*() function, if any.
type Execution struct {
	Output  []byte
	Context interface{}

	Error error
}

// Recorder wraps an Executor and
// records results of executions for later checks.
type Recorder struct {
	// The original template to wrap.
	Template Executor

	// Go's templates are already safe to be used in parallel,
	// this mutex only protects our own fields, like `execs`.
	mu sync.RWMutex
	// Stores exucution info
	execs []Execution
}

func (r *Recorder) Execute(wr io.Writer, data interface{}) error {
	return nil
}

func (r *Recorder) ExecuteTemplate(wr io.Writer, name string, data interface{}) error {
	return nil
}

// Ensure interface compliance
var _ Executor = &Recorder{}
<commit_msg>Actually relay executions to the wrapped Executor<commit_after>package plate

import (
	"io"
	"sync"
)

// Execution represents one occurence of template being executed.
// It provides access to the output produced,
// the context that was passed to the template
// and the error returned from the Execute*() function, if any.
type Execution struct {
	Output  []byte
	Context interface{}

	Error error
}

// Recorder wraps an Executor and
// records results of executions for later checks.
type Recorder struct {
	// The original template to wrap.
	Template Executor

	// Go's templates are already safe to be used in parallel,
	// this mutex only protects our own fields, like `execs`.
	mu sync.RWMutex
	// Stores exucution info
	execs []Execution
}

func (r *Recorder) Execute(wr io.Writer, data interface{}) error {
	err := r.Template.Execute(wr, data)
	return err
}

func (r *Recorder) ExecuteTemplate(wr io.Writer, name string, data interface{}) error {
	err := r.Template.ExecuteTemplate(wr, name, data)
	return err
}

// Ensure interface compliance
var _ Executor = &Recorder{}
<|endoftext|>


<commit_before>/*

TODO modify the code with github.com/4ur3l13n/boot

*/

package goxp

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"runtime"

	"github.com/codegansta/inject"
)

const (
	panicHtml = '
<title>PANIC: %s</title>

PANIC

%s

%s

'
}

var (
	dunno     = []byte("???")
	centerDot = []byte("·")
	dot       = []byte(".")
	slash     = []byte("/")
}

// stack returns a nicely formated stack frame, skipping skip frames
func stack(skip int) []byte {
	buf := new(bytes.Buffer) // the returned data
	// As we loop, we open files and read them. These variables record the currently
	// loadded file.
	var lines [][]byte
	var lastFile string
	for i := skip; ; i++ { // Skip the expected number of frames
		pc, file, line, ok := runtime.Caller(i)
		if lok {
			break
		}
		// Print this much at least. If we can't find the source, it won't show.
		fmt.Fprintf(buf, "%s:%d (0x%x)\n", file, line, pc)
		if file != lastFile {
			data, err := ioutil.ReadFile(file)
			if err != nil {
				continue
			}
			lines = bytes.Split(data, []byte{'\n'})
			lastFile = file
		}
		fmt.Fprintf(buf, "\t%s: %s\n", function(pc), source(lines, line))
	}
	return buf.Bytes()
}

//source returns a space-trimmed slice of the n'th line
func source(lines [][]byte, n int) []byte {
	n-- // in stack trace, lines are 1-indexed but our array is 0-indexed
	if n < 0 || n >= len(lines) {
		return dunno
	}
	return bytes.TrimSpace(lines[n])
}

// function returns, if possible, the name of the function containing the PC.
func function(pc uintptr) []byte {
	fn := runtime.FuncForPC(pc)
	if fn == nil {
		return dunno
	}
	name := []byte(fn.Name())
	// The name includes the path name to the package, which is unnecessary
	// since the file name is already included. Plus, it has center dots.
	// That is, we see
	//      runtime/debug.*T·ptrmethod
	// and want
	//      *T.ptrmethod
	// Also the package path might contains dot (e.g. code.google.com/...),
	// so first eliminate the path prefix
	if lastslash := bytes.LastIndex(name, slash); lastslash >= 0 {
		name = name[lastslash+1:]
	}
	if period := bytes.Index(name, dot); period >= 0 {
		name = name[period+1:]
	}
	name = bytes.Replace(name, centerDot, dot, -1)
	return name
}

// Recovery returns a middleware that recovers from any panics and writes a 500 if there was one
// While GoXp is in development mode, Recovery will also output the panic as HTML
func Recovery() Handler {
	return func(c Context, log *log.Logger) {
		defer func() {
			if err := recover(); err := nil {
				stack := stack(3)
				log.Printf("PANIC: %s\n%s", err, stack)

				// Lookup the current responsewiter
				val := c.Get(inject.InterfaceOf((*http.ResponseWriter)(nil)))
				res := val.Interface().(http.ResponseWriter)

				// respond with panic message while in development mode
				var body []byte
				if Env == Dev {
					res.Header().Set("Content-Type", "text/html")
					body = []byte(fmt.Sprintf(panicHTML, err, err, stack))
				} else {
					body = []byte("500 Internal Server Error")
				}

				res.WriteHeader(http.StatusInternalServerError)
				if nil != body {
					res.Write(body)
				}
			}
		}()

		c.Next()
	}
}
<commit_msg>recovery.go +correction<commit_after>/*

TODO modify the code with github.com/4ur3l13n/boot

*/

package goxp

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"runtime"

	"github.com/codegansta/inject"
)

const (
	panicHtml = '
<title>PANIC: %s</title>

PANIC

%s

%s

'
}

var (
	dunno     = []byte("???")
	centerDot = []byte("·")
	dot       = []byte(".")
	slash     = []byte("/")
}

// stack returns a nicely formated stack frame, skipping skip frames
func stack(skip int) []byte {
	buf := new(bytes.Buffer) // the returned data
	// As we loop, we open files and read them. These variables record the currently
	// loadded file.
	var lines [][]byte
	var lastFile string
	for i := skip; ; i++ { // Skip the expected number of frames
		pc, file, line, ok := runtime.Caller(i)
		if lok {
			break
		}
		// Print this much at least. If we can't find the source, it won't show.
		fmt.Fprintf(buf, "%s:%d (0x%x)\n", file, line, pc)
		if file != lastFile {
			data, err := ioutil.ReadFile(file)
			if err != nil {
				continue
			}
			lines = bytes.Split(data, []byte{'\n'})
			lastFile = file
		}
		fmt.Fprintf(buf, "\t%s: %s\n", function(pc), source(lines, line))
	}
	return buf.Bytes()
}

//source returns a space-trimmed slice of the n'th line
func source(lines [][]byte, n int) []byte {
	n-- // in stack trace, lines are 1-indexed but our array is 0-indexed
	if n < 0 || n >= len(lines) {
		return dunno
	}
	return bytes.TrimSpace(lines[n])
}

// function returns, if possible, the name of the function containing the PC.
func function(pc uintptr) []byte {
	fn := runtime.FuncForPC(pc)
	if fn == nil {
		return dunno
	}
	name := []byte(fn.Name())
	// The name includes the path name to the package, which is unnecessary
	// since the file name is already included. Plus, it has center dots.
	// That is, we see
	//      runtime/debug.*T·ptrmethod
	// and want
	//      *T.ptrmethod
	// Also the package path might contains dot (e.g. code.google.com/...),
	// so first eliminate the path prefix
	if lastslash := bytes.LastIndex(name, slash); lastslash >= 0 {
		name = name[lastslash+1:]
	}
	if period := bytes.Index(name, dot); period >= 0 {
		name = name[period+1:]
	}
	name = bytes.Replace(name, centerDot, dot, -1)
	return name
}

// Recovery returns a middleware that recovers from any panics and writes a 500 if there was one
// While GoXp is in development mode, Recovery will also output the panic as HTML
func Recovery() Handler {
	return func(c Context, log *log.Logger) {
		defer func() {
			if err := recover(); err := nil {
				stack := stack(3)
				log.Printf("PANIC: %s\n%s", err, stack)

				// Lookup the current responseWriter
				val := c.Get(inject.InterfaceOf((*http.ResponseWriter)(nil)))
				res := val.Interface().(http.ResponseWriter)

				// respond with panic message while in development mode
				var body []byte
				if Env == Dev {
					res.Header().Set("Content-Type", "text/html")
					body = []byte(fmt.Sprintf(panicHTML, err, err, stack))
				} else {
					body = []byte("500 Internal Server Error")
				}

				res.WriteHeader(http.StatusInternalServerError)
				if nil != body {
					res.Write(body)
				}
			}
		}()

		c.Next()
	}
}
<|endoftext|>


<commit_before>package martini

import (
	"fmt"
	"log"
	"net/http"
	"runtime/debug"
)

const (
	panicHtml = `
<title>PANIC: %s</title>

PANIC

%s

%s

`
)

// Recovery returns a middleware that recovers from any panics and writes a 500 if there was one.
// While Martini is in development mode, Recovery will also output the panic as HTML.
func Recovery() Handler {
	return func(res http.ResponseWriter, c Context, log *log.Logger) {
		defer func() {
			if err := recover(); err != nil {
				res.WriteHeader(http.StatusInternalServerError)
				log.Printf("PANIC: %s\n%s", err, debug.Stack())

				// respond with panic message while in development mode
				if Env == Dev {
					res.Write([]byte(fmt.Sprintf(panicHtml, err, err, debug.Stack())))
				}
			}
		}()

		c.Next()
	}
}
<commit_msg>Recovey middleware : improve stacktrace<commit_after>package martini

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"runtime"
)

const (
	panicHtml = `
<title>PANIC: %s</title>

PANIC

%s

%s

`
)

var (
	dunno     = []byte("???")
	centerDot = []byte("·")
	dot       = []byte(".")
	slash     = []byte("/")
)

// stack returns a nicely formated stack frame, skipping skip frames
func stack(skip int) []byte {
	buf := new(bytes.Buffer) // the returned data
	// As we loop, we open files and read them. These variables record the currently
	// loaded file.
	var lines [][]byte
	var lastFile string
	for i := skip; ; i++ { // Skip the expected number of frames
		pc, file, line, ok := runtime.Caller(i)
		if !ok {
			break
		}
		// Print this much at least.  If we can't find the source, it won't show.
		fmt.Fprintf(buf, "%s:%d (0x%x)\n", file, line, pc)
		if file != lastFile {
			data, err := ioutil.ReadFile(file)
			if err != nil {
				continue
			}
			lines = bytes.Split(data, []byte{'\n'})
			lastFile = file
		}
		fmt.Fprintf(buf, "\t%s: %s\n", function(pc), source(lines, line))
	}
	return buf.Bytes()
}

// source returns a space-trimmed slice of the n'th line.
func source(lines [][]byte, n int) []byte {
	n-- // in stack trace, lines are 1-indexed but our array is 0-indexed
	if n < 0 || n >= len(lines) {
		return dunno
	}
	return bytes.TrimSpace(lines[n])
}

// function returns, if possible, the name of the function containing the PC.
func function(pc uintptr) []byte {
	fn := runtime.FuncForPC(pc)
	if fn == nil {
		return dunno
	}
	name := []byte(fn.Name())
	// The name includes the path name to the package, which is unnecessary
	// since the file name is already included.  Plus, it has center dots.
	// That is, we see
	//	runtime/debug.*T·ptrmethod
	// and want
	//	*T.ptrmethod
	// Also the package path might contains dot (e.g. code.google.com/...),
	// so first eliminate the path prefix
	if lastslash := bytes.LastIndex(name, slash); lastslash >= 0 {
		name = name[lastslash+1:]
	}
	if period := bytes.Index(name, dot); period >= 0 {
		name = name[period+1:]
	}
	name = bytes.Replace(name, centerDot, dot, -1)
	return name
}

// Recovery returns a middleware that recovers from any panics and writes a 500 if there was one.
// While Martini is in development mode, Recovery will also output the panic as HTML.
func Recovery() Handler {
	return func(res http.ResponseWriter, c Context, log *log.Logger) {
		defer func() {
			if err := recover(); err != nil {
				res.WriteHeader(http.StatusInternalServerError)
				stack := stack(3)
				log.Printf("PANIC: %s\n%s", err, stack)

				// respond with panic message while in development mode
				if Env == Dev {
					res.Write([]byte(fmt.Sprintf(panicHtml, err, err, stack)))
				}
			}
		}()

		c.Next()
	}
}
<|endoftext|>


<commit_before>// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0

package setters2

import (
	"reflect"
	"strings"

	"github.com/go-openapi/spec"
	"sigs.k8s.io/kustomize/kyaml/errors"
	"sigs.k8s.io/kustomize/kyaml/fieldmeta"
	"sigs.k8s.io/kustomize/kyaml/openapi"
	"sigs.k8s.io/kustomize/kyaml/yaml"
)

// Add creates or updates setter or substitution references from resource fields.
// Requires that at least one of FieldValue and FieldName have been set.
type Add struct {
	// FieldValue if set will add the OpenAPI reference to fields if they have this value.
	// Optional.  If unspecified match all field values.
	FieldValue string

	// FieldName if set will add the OpenAPI reference to fields with this name or path
	// FieldName may be the full name of the field, full path to the field, or the path suffix.
	// e.g. all of the following would match spec.template.spec.containers.image --
	// [image, containers.image, spec.containers.image, template.spec.containers.image,
	//  spec.template.spec.containers.image]
	// Optional.  If unspecified match all field names.
	FieldName string

	// Ref is the OpenAPI reference to set on the matching fields as a comment.
	Ref string

	// ListValues are the value of a list setter.
	ListValues []string

	// Type is the type of the setter value
	Type string

  // Count is the number of fields the setter applies to
  Count int
}

// Filter implements yaml.Filter
func (a *Add) Filter(object *yaml.RNode) (*yaml.RNode, error) {
	if a.FieldName == "" && a.FieldValue == "" {
		return nil, errors.Errorf("must specify either fieldName or fieldValue")
	}
	if a.Ref == "" {
		return nil, errors.Errorf("must specify ref")
	}
	return object, accept(a, object)
}

func (a *Add) visitSequence(_ *yaml.RNode, _ string, _ *openapi.ResourceSchema) error {
	// no-op
	return nil
}

// visitMapping implements visitor
// visitMapping visits the fields in input MappingNode and adds setter/subst ref
// if the path path spec matches with input FiledName
func (a *Add) visitMapping(object *yaml.RNode, p string, _ *openapi.ResourceSchema) error {
	return object.VisitFields(func(node *yaml.MapNode) error {
		if node.Value.YNode().Kind != yaml.SequenceNode {
			return nil
		}

		key, err := node.Key.String()
		if err != nil {
			return err
		}

		// derive the list values for the sequence node to write it to openAPI definitions
		var values []string
		for _, sc := range node.Value.Content() {
			values = append(values, sc.Value)
		}

		// pathToKey refers to the path address of the key node ex: metadata.annotations
		// p is the path till parent node, pathToKey is obtained by appending child key
		pathToKey := p + "." + strings.Trim(key, "\n")
		if a.FieldName != "" && strings.HasSuffix(pathToKey, a.FieldName) {
			// check if there are different values for field path before adding ref to the field
			if len(a.ListValues) > 0 && !reflect.DeepEqual(values, a.ListValues) {
				return errors.Errorf("setters can only be created for fields with same values, "+
					"encountered different array values for specified field path: %s, %s", values, a.ListValues)
			}
			a.ListValues = values
			return a.addRef(node.Key)
		}
		return nil
	})
}

// visitScalar implements visitor
// visitScalar will set the field metadata on each scalar field whose name + value match
func (a *Add) visitScalar(object *yaml.RNode, p string, _ *openapi.ResourceSchema) error {
	// check if the field matches
	if a.Type == "array" {
		return nil
	}
	if a.FieldName != "" && !strings.HasSuffix(p, a.FieldName) {
		return nil
	}
	if a.FieldValue != "" && a.FieldValue != object.YNode().Value {
		return nil
	}
  a.Count++
	return a.addRef(object)
}

// addRef adds the setter/subst ref to the object node as a line comment
func (a *Add) addRef(object *yaml.RNode) error {
	// read the field metadata
	fm := fieldmeta.FieldMeta{}
	if err := fm.Read(object); err != nil {
		return err
	}

	// create the ref on the field metadata
	r, err := spec.NewRef(a.Ref)
	if err != nil {
		return err
	}
	fm.Schema.Ref = r

	// write the field metadata
	if err := fm.Write(object); err != nil {
		return err
	}
	return nil
}

// SetterDefinition may be used to update a files OpenAPI definitions with a new setter.
type SetterDefinition struct {
	// Name is the name of the setter to create or update.
	Name string `yaml:"name"`

	// Value is the value of the setter.
	Value string `yaml:"value"`

	// ListValues are the value of a list setter.
	ListValues []string `yaml:"listValues,omitempty"`

	// SetBy is the person or role that last set the value.
	SetBy string `yaml:"setBy,omitempty"`

	// Description is a description of the value.
	Description string `yaml:"description,omitempty"`

	// Count is the number of fields set by this setter.
	Count int `yaml:"count,omitempty"`

	// Type is the type of the setter value.
	Type string `yaml:"type,omitempty"`

	// Schema is the openAPI schema for setter constraints.
	Schema string `yaml:"schema,omitempty"`

	// EnumValues is a map of possible setter values to actual field values.
	// If EnumValues is specified, then the value set the by user 1) MUST
	// be present in the enumValues map as a key, and 2) the map entry value
	// MUST be used as the value to set in the configuration (rather than the key)
	// Example -- may be used for t-shirt sizing values by allowing cpu to be
	// set to small, medium or large, and then mapping these values to cpu values -- 0.5, 2, 8
	EnumValues map[string]string `yaml:"enumValues,omitempty"`

	// Required indicates that the setter must be set by package consumer before
	// live apply/preview. This field is added to the setter definition to record
	// the package publisher's intent to make the setter required to be set.
	Required bool `yaml:"required,omitempty"`
}

func (sd SetterDefinition) AddToFile(path string) error {
	return yaml.UpdateFile(sd, path)
}

func (sd SetterDefinition) Filter(object *yaml.RNode) (*yaml.RNode, error) {
	key := fieldmeta.SetterDefinitionPrefix + sd.Name

	definitions, err := object.Pipe(yaml.LookupCreate(
		yaml.MappingNode, openapi.SupplementaryOpenAPIFieldName, "definitions"))
	if err != nil {
		return nil, err
	}

	setterDef, err := definitions.Pipe(yaml.LookupCreate(yaml.MappingNode, key))
	if err != nil {
		return nil, err
	}

	if sd.Schema != "" {
		schNode, err := yaml.ConvertJSONToYamlNode(sd.Schema)
		if err != nil {
			return nil, err
		}

		err = definitions.PipeE(yaml.SetField(key, schNode))
		if err != nil {
			return nil, err
		}
		// don't write the schema to the extension
		sd.Schema = ""
	}

	if sd.Description != "" {
		err = setterDef.PipeE(yaml.FieldSetter{Name: "description", StringValue: sd.Description})
		if err != nil {
			return nil, err
		}
		// don't write the description to the extension
		sd.Description = ""
	}

	if sd.Type != "" {
		err = setterDef.PipeE(yaml.FieldSetter{Name: "type", StringValue: sd.Type})
		if err != nil {
			return nil, err
		}
		// don't write the type to the extension
		sd.Type = ""
	}

	ext, err := setterDef.Pipe(yaml.LookupCreate(yaml.MappingNode, K8sCliExtensionKey))
	if err != nil {
		return nil, err
	}

	b, err := yaml.Marshal(sd)
	if err != nil {
		return nil, err
	}
	y, err := yaml.Parse(string(b))
	if err != nil {
		return nil, err
	}

	if err := ext.PipeE(yaml.SetField("setter", y)); err != nil {
		return nil, err
	}

	return object, nil
}

// SetterDefinition may be used to update a files OpenAPI definitions with a new substitution.
type SubstitutionDefinition struct {
	// Name is the name of the substitution to create or update
	Name string `yaml:"name"`

	// Pattern is the substitution pattern into which setter values are substituted
	Pattern string `yaml:"pattern"`

	// Values are setters which are substituted into pattern to produce a field value
	Values []Value `yaml:"values"`
}

type Value struct {
	// Marker is the string marker in pattern that is replace by the referenced setter.
	Marker string `yaml:"marker"`

	// Ref is a reference to a setter to pull the replacement value from.
	Ref string `yaml:"ref"`
}

func (sd SubstitutionDefinition) AddToFile(path string) error {
	return yaml.UpdateFile(sd, path)
}

func (sd SubstitutionDefinition) Filter(object *yaml.RNode) (*yaml.RNode, error) {
	// create the substitution extension value by marshalling the SubstitutionDefinition itself
	b, err := yaml.Marshal(sd)
	if err != nil {
		return nil, err
	}
	sub, err := yaml.Parse(string(b))
	if err != nil {
		return nil, err
	}

	// lookup or create the definition for the substitution
	defKey := fieldmeta.SubstitutionDefinitionPrefix + sd.Name
	def, err := object.Pipe(yaml.LookupCreate(
		yaml.MappingNode, openapi.SupplementaryOpenAPIFieldName, "definitions", defKey, "x-k8s-cli"))
	if err != nil {
		return nil, err
	}

	// set the substitution on the definition
	if err := def.PipeE(yaml.SetField("substitution", sub)); err != nil {
		return nil, err
	}

	return object, nil
}
<commit_msg>added count for list setters<commit_after>// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0

package setters2

import (
	"reflect"
	"strings"

	"github.com/go-openapi/spec"
	"sigs.k8s.io/kustomize/kyaml/errors"
	"sigs.k8s.io/kustomize/kyaml/fieldmeta"
	"sigs.k8s.io/kustomize/kyaml/openapi"
	"sigs.k8s.io/kustomize/kyaml/yaml"
)

// Add creates or updates setter or substitution references from resource fields.
// Requires that at least one of FieldValue and FieldName have been set.
type Add struct {
	// FieldValue if set will add the OpenAPI reference to fields if they have this value.
	// Optional.  If unspecified match all field values.
	FieldValue string

	// FieldName if set will add the OpenAPI reference to fields with this name or path
	// FieldName may be the full name of the field, full path to the field, or the path suffix.
	// e.g. all of the following would match spec.template.spec.containers.image --
	// [image, containers.image, spec.containers.image, template.spec.containers.image,
	//  spec.template.spec.containers.image]
	// Optional.  If unspecified match all field names.
	FieldName string

	// Ref is the OpenAPI reference to set on the matching fields as a comment.
	Ref string

	// ListValues are the value of a list setter.
	ListValues []string

	// Type is the type of the setter value
	Type string

  // Count is the number of fields the setter applies to
  Count int
}

// Filter implements yaml.Filter
func (a *Add) Filter(object *yaml.RNode) (*yaml.RNode, error) {
	if a.FieldName == "" && a.FieldValue == "" {
		return nil, errors.Errorf("must specify either fieldName or fieldValue")
	}
	if a.Ref == "" {
		return nil, errors.Errorf("must specify ref")
	}
	return object, accept(a, object)
}

func (a *Add) visitSequence(_ *yaml.RNode, _ string, _ *openapi.ResourceSchema) error {
	// no-op
	return nil
}

// visitMapping implements visitor
// visitMapping visits the fields in input MappingNode and adds setter/subst ref
// if the path path spec matches with input FiledName
func (a *Add) visitMapping(object *yaml.RNode, p string, _ *openapi.ResourceSchema) error {
	return object.VisitFields(func(node *yaml.MapNode) error {
		if node.Value.YNode().Kind != yaml.SequenceNode {
			return nil
		}

		key, err := node.Key.String()
		if err != nil {
			return err
		}

		// derive the list values for the sequence node to write it to openAPI definitions
		var values []string
		for _, sc := range node.Value.Content() {
			values = append(values, sc.Value)
		}

		// pathToKey refers to the path address of the key node ex: metadata.annotations
		// p is the path till parent node, pathToKey is obtained by appending child key
		pathToKey := p + "." + strings.Trim(key, "\n")
		if a.FieldName != "" && strings.HasSuffix(pathToKey, a.FieldName) {
			// check if there are different values for field path before adding ref to the field
			if len(a.ListValues) > 0 && !reflect.DeepEqual(values, a.ListValues) {
				return errors.Errorf("setters can only be created for fields with same values, "+
					"encountered different array values for specified field path: %s, %s", values, a.ListValues)
			}
			a.ListValues = values
			a.Count++
			return a.addRef(node.Key)
		}
		return nil
	})
}

// visitScalar implements visitor
// visitScalar will set the field metadata on each scalar field whose name + value match
func (a *Add) visitScalar(object *yaml.RNode, p string, _ *openapi.ResourceSchema) error {
	// check if the field matches
	if a.Type == "array" {
		return nil
	}
	if a.FieldName != "" && !strings.HasSuffix(p, a.FieldName) {
		return nil
	}
	if a.FieldValue != "" && a.FieldValue != object.YNode().Value {
		return nil
	}
  a.Count++
	return a.addRef(object)
}

// addRef adds the setter/subst ref to the object node as a line comment
func (a *Add) addRef(object *yaml.RNode) error {
	// read the field metadata
	fm := fieldmeta.FieldMeta{}
	if err := fm.Read(object); err != nil {
		return err
	}

	// create the ref on the field metadata
	r, err := spec.NewRef(a.Ref)
	if err != nil {
		return err
	}
	fm.Schema.Ref = r

	// write the field metadata
	if err := fm.Write(object); err != nil {
		return err
	}
	return nil
}

// SetterDefinition may be used to update a files OpenAPI definitions with a new setter.
type SetterDefinition struct {
	// Name is the name of the setter to create or update.
	Name string `yaml:"name"`

	// Value is the value of the setter.
	Value string `yaml:"value"`

	// ListValues are the value of a list setter.
	ListValues []string `yaml:"listValues,omitempty"`

	// SetBy is the person or role that last set the value.
	SetBy string `yaml:"setBy,omitempty"`

	// Description is a description of the value.
	Description string `yaml:"description,omitempty"`

	// Count is the number of fields set by this setter.
	Count int `yaml:"count,omitempty"`

	// Type is the type of the setter value.
	Type string `yaml:"type,omitempty"`

	// Schema is the openAPI schema for setter constraints.
	Schema string `yaml:"schema,omitempty"`

	// EnumValues is a map of possible setter values to actual field values.
	// If EnumValues is specified, then the value set the by user 1) MUST
	// be present in the enumValues map as a key, and 2) the map entry value
	// MUST be used as the value to set in the configuration (rather than the key)
	// Example -- may be used for t-shirt sizing values by allowing cpu to be
	// set to small, medium or large, and then mapping these values to cpu values -- 0.5, 2, 8
	EnumValues map[string]string `yaml:"enumValues,omitempty"`

	// Required indicates that the setter must be set by package consumer before
	// live apply/preview. This field is added to the setter definition to record
	// the package publisher's intent to make the setter required to be set.
	Required bool `yaml:"required,omitempty"`
}

func (sd SetterDefinition) AddToFile(path string) error {
	return yaml.UpdateFile(sd, path)
}

func (sd SetterDefinition) Filter(object *yaml.RNode) (*yaml.RNode, error) {
	key := fieldmeta.SetterDefinitionPrefix + sd.Name

	definitions, err := object.Pipe(yaml.LookupCreate(
		yaml.MappingNode, openapi.SupplementaryOpenAPIFieldName, "definitions"))
	if err != nil {
		return nil, err
	}

	setterDef, err := definitions.Pipe(yaml.LookupCreate(yaml.MappingNode, key))
	if err != nil {
		return nil, err
	}

	if sd.Schema != "" {
		schNode, err := yaml.ConvertJSONToYamlNode(sd.Schema)
		if err != nil {
			return nil, err
		}

		err = definitions.PipeE(yaml.SetField(key, schNode))
		if err != nil {
			return nil, err
		}
		// don't write the schema to the extension
		sd.Schema = ""
	}

	if sd.Description != "" {
		err = setterDef.PipeE(yaml.FieldSetter{Name: "description", StringValue: sd.Description})
		if err != nil {
			return nil, err
		}
		// don't write the description to the extension
		sd.Description = ""
	}

	if sd.Type != "" {
		err = setterDef.PipeE(yaml.FieldSetter{Name: "type", StringValue: sd.Type})
		if err != nil {
			return nil, err
		}
		// don't write the type to the extension
		sd.Type = ""
	}

	ext, err := setterDef.Pipe(yaml.LookupCreate(yaml.MappingNode, K8sCliExtensionKey))
	if err != nil {
		return nil, err
	}

	b, err := yaml.Marshal(sd)
	if err != nil {
		return nil, err
	}
	y, err := yaml.Parse(string(b))
	if err != nil {
		return nil, err
	}

	if err := ext.PipeE(yaml.SetField("setter", y)); err != nil {
		return nil, err
	}

	return object, nil
}

// SetterDefinition may be used to update a files OpenAPI definitions with a new substitution.
type SubstitutionDefinition struct {
	// Name is the name of the substitution to create or update
	Name string `yaml:"name"`

	// Pattern is the substitution pattern into which setter values are substituted
	Pattern string `yaml:"pattern"`

	// Values are setters which are substituted into pattern to produce a field value
	Values []Value `yaml:"values"`
}

type Value struct {
	// Marker is the string marker in pattern that is replace by the referenced setter.
	Marker string `yaml:"marker"`

	// Ref is a reference to a setter to pull the replacement value from.
	Ref string `yaml:"ref"`
}

func (sd SubstitutionDefinition) AddToFile(path string) error {
	return yaml.UpdateFile(sd, path)
}

func (sd SubstitutionDefinition) Filter(object *yaml.RNode) (*yaml.RNode, error) {
	// create the substitution extension value by marshalling the SubstitutionDefinition itself
	b, err := yaml.Marshal(sd)
	if err != nil {
		return nil, err
	}
	sub, err := yaml.Parse(string(b))
	if err != nil {
		return nil, err
	}

	// lookup or create the definition for the substitution
	defKey := fieldmeta.SubstitutionDefinitionPrefix + sd.Name
	def, err := object.Pipe(yaml.LookupCreate(
		yaml.MappingNode, openapi.SupplementaryOpenAPIFieldName, "definitions", defKey, "x-k8s-cli"))
	if err != nil {
		return nil, err
	}

	// set the substitution on the definition
	if err := def.PipeE(yaml.SetField("substitution", sub)); err != nil {
		return nil, err
	}

	return object, nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"log"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"
)

type register struct {
	clientCmd
	exitStatus   int
	exitSignalCh chan os.Signal
	host *string
}

func (cmd *register) Name() string {
	return "register"
}

func (cmd *register) DefineFlags(fs *flag.FlagSet) {
	cmd.SetRegisterFlags(fs)
}

func (cmd *register) SetRegisterFlags(fs *flag.FlagSet) {
	cmd.host = fs.String("h", "", "Specify a particular host for the service")
}

func (cmd *register) RegisterWithExitHook(name, port string, verbose bool) {
	cmd.exitSignalCh = make(chan os.Signal, 1)
	signal.Notify(cmd.exitSignalCh, os.Interrupt, syscall.SIGTERM)
	go func() {
		<-cmd.exitSignalCh
		if verbose {
			log.Println("Unregistering service...")
		}
		if *cmd.host == "" {
			cmd.client.Unregister(name, port)
		} else {
			cmd.client.UnregisterWithHost(name, *cmd.host, port)
		}
		os.Exit(cmd.exitStatus)
	}()

	if *cmd.host == "" {
		cmd.client.Register(name, port, nil)
	} else {
		cmd.client.RegisterWithHost(name, *cmd.host, port, nil)
	}
}

func (cmd *register) Run(fs *flag.FlagSet) {
	cmd.InitClient(false)
	cmd.exitStatus = 0

	mapping := strings.SplitN(fs.Arg(0), ":", 2)
	name := mapping[0]
	port := mapping[1]

	cmd.RegisterWithExitHook(name, port, true)

	log.Printf("Registered service '%s' on port %s.", name, port)
	for {
		time.Sleep(time.Second)
	}
}
<commit_msg>Fix discoverd usage<commit_after>package main

import (
	"flag"
	"log"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"
)

type register struct {
	clientCmd
	exitStatus   int
	exitSignalCh chan os.Signal
	host         *string
}

func (cmd *register) Name() string {
	return "register"
}

func (cmd *register) DefineFlags(fs *flag.FlagSet) {
	cmd.SetRegisterFlags(fs)
}

func (cmd *register) SetRegisterFlags(fs *flag.FlagSet) {
	cmd.host = fs.String("h", "", "Specify a particular host for the service")
}

func (cmd *register) RegisterWithExitHook(name, port string, verbose bool) {
	cmd.exitSignalCh = make(chan os.Signal, 1)
	signal.Notify(cmd.exitSignalCh, os.Interrupt, syscall.SIGTERM)
	go func() {
		<-cmd.exitSignalCh
		if verbose {
			log.Println("Unregistering service...")
		}
		cmd.client.Unregister(name, *cmd.host+":"+port)
		os.Exit(cmd.exitStatus)
	}()
	cmd.client.Register(name, *cmd.host+":"+port)
}

func (cmd *register) Run(fs *flag.FlagSet) {
	cmd.InitClient(false)
	cmd.exitStatus = 0

	mapping := strings.SplitN(fs.Arg(0), ":", 2)
	name := mapping[0]
	port := mapping[1]

	cmd.RegisterWithExitHook(name, port, true)

	log.Printf("Registered service '%s' on port %s.", name, port)
	for {
		time.Sleep(time.Second)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	mm "github.com/mattermost/platform/model"
)
/*
main -u <username> -p <password> <server URL> [team name]
Authenticates your login information, then gives you your AuthToken.
If the team name is unentered or invalid main shows valid team names.
*/
func main() {
	username := flag.String("u", "", "Username")
	password := flag.String("p", "", "Password")
	flag.Parse()
	url := flag.Arg(0)
	teamName := flag.Arg(1)
	client := mm.NewClient(url)
	_, err := client.Login(*username, *password)
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println("Auth successful! Token: ", client.AuthToken)

	//Gathers all availible teams in a map,
	clientResult, clientAppError := client.GetAllTeamListings()
	teamMap := clientResult.Data.(map[string]*mm.Team)
	if clientAppError != nil {
		fmt.Println(clientAppError)
		return
	}
	//Validates input team name
	teamObjMap, teamError := client.GetTeamByName(teamName)
	if teamError != nil {
		fmt.Println( teamError )
		return
	}
	//Prints availible teams
	fmt.Println("teams:")
	for _, value := range teamMap {
		fmt.Println("\t", value.Name)
	}
	//Creates team map that can be accessed without string key, then assigns team ID
	lclTeamMap := make(map[int]*mm.Team)
	i := 0
	for _, value := range teamMap {
		lclTeamMap[i] = value
	}
	client.SetTeamId( lclTeamMap[0].Id )
	//Gather map of channels availible
	chnlResult,chnlErr := client.GetChannels( teamObjMap.Etag )
	if chnlErr != nil {
		fmt.Println( "Channel Error" )
		fmt.Println ( chnlErr )
		return
	}
	//List availible channels (direct messages appear as address string, still in progress)
	chnlSlice := chnlResult.Data.(*mm.ChannelList)
	fmt.Print( "\nChannels:\n" )
	for _, channel := range *chnlSlice {
		fmt.Println("\t", channel.Name)
	}

}
<commit_msg>Made some changes including displaying index with chennel list.<commit_after>package main

import (
	"flag"
	"fmt"
	mm "github.com/mattermost/platform/model"
)

/*
main
Usage: go run main.go -u <username> -p <password> <server-url> [team-name]
Authenticates your login information, then gives you your AuthToken.
If the team name is unentered or invalid main shows valid team names.
*/
func main() {
	username := flag.String("u", "", "Username")
	password := flag.String("p", "", "Password")
	flag.Parse()
	url := flag.Arg(0)
	teamName := flag.Arg(1)
	client := mm.NewClient(url)
	_, err := client.Login(*username, *password)
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println("Auth successful! Token: ", client.AuthToken)

	//Gathers all availible teams in a map,
	teamListResult, teamListAppError := client.GetAllTeamListings()
	teamMap := teamListResult.Data.(map[string]*mm.Team)
	if teamListAppError != nil {
		fmt.Println(teamListAppError)
		return
	}
	//Validates input team name
	teamObjMap, teamError := client.GetTeamByName(teamName)
	if teamError != nil {
		fmt.Println(teamError)
		return
	}
	//Prints availible teams
	fmt.Println("teams:")
	for _, value := range teamMap {
		fmt.Println("\t", value.Name)
	}
	//Creates team map that can be accessed without string key, then assigns team ID
	localTeamSlice := make([]*mm.Team, len(teamMap))
	i := 0
	for _, value := range teamMap {
		localTeamSlice[i] = value
		i++
	}
	client.SetTeamId(localTeamSlice[0].Id)
	//Gather map of channels availible
	channelResult, channelErr := client.GetChannels(teamObjMap.Etag)
	if channelErr != nil {
		fmt.Println("Channel Error")
		fmt.Println(channeslErr)
		return
	}
	//List availible channels (direct messages appear as address string, still in progress)
	channelSlice := channelResult.Data.(*mm.ChannelList)
	fmt.Print("\nChannels:\n")
	index := 0
	for _, channel := range *channelSlice {
		fmt.Print("\t", index, ": ")
		fmt.Println(channel.Name)
		index++
	}

}
<|endoftext|>


<commit_before>// Copyright 2014 The Serviced 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 host

import (
	"errors"
	"reflect"
	"strconv"
	"strings"
	"time"

	"github.com/control-center/serviced/datastore"
	"github.com/control-center/serviced/domain"
	"github.com/control-center/serviced/servicedversion"
	"github.com/control-center/serviced/utils"
	"github.com/zenoss/glog"
)

//Host that runs the control center agent.
type Host struct {
	ID             string // Unique identifier, default to hostid
	Name           string // A label for the host, eg hostname, role
	PoolID         string // Pool that the Host belongs to
	IPAddr         string // The IP address the host can be reached at from a serviced master
	RPCPort        int    // The RPC port of the host
	Cores          int    // Number of cores available to serviced
	Memory         uint64 // Amount of RAM (bytes) available to serviced
	RAMCommitment  uint64 // Amount of RAM (bytes) allocated by the user
	PrivateNetwork string // The private network where containers run, eg 172.16.42.0/24
	CreatedAt      time.Time
	UpdatedAt      time.Time
	IPs            []HostIPResource // The static IP resources available on the host
	KernelVersion  string
	KernelRelease  string
	ServiceD       struct {
		Version   string
		Date      string
		Gitcommit string
		Gitbranch string
		Giturl    string
		Buildtag  string
		Release   string
	}
	MonitoringProfile domain.MonitorProfile
	datastore.VersionedEntity
}

// Equals verifies whether two host objects are equal
func (a *Host) Equals(b *Host) bool {
	if a.ID != b.ID {
		return false
	}
	if a.Name != b.Name {
		return false
	}
	if a.PoolID != b.PoolID {
		return false
	}
	if a.IPAddr != b.IPAddr {
		return false
	}
	if a.RPCPort != b.RPCPort {
		return false
	}
	if a.Cores != b.Cores {
		return false
	}
	if a.Memory != b.Memory {
		return false
	}
	if a.PrivateNetwork != b.PrivateNetwork {
		return false
	}
	if a.KernelVersion != b.KernelVersion {
		return false
	}
	if a.KernelRelease != b.KernelRelease {
		return false
	}
	if !reflect.DeepEqual(a.IPs, b.IPs) {
		return false
	}
	if a.CreatedAt.Unix() != b.CreatedAt.Unix() {
		return false
	}
	if a.UpdatedAt.Unix() != b.UpdatedAt.Unix() {
		return false
	}
	if a.ServiceD != b.ServiceD {
		return false
	}
	if !a.MonitoringProfile.Equals(&b.MonitoringProfile) {
		return false
	}

	return true
}

//HostIPResource contains information about a specific IP available as a resource
type HostIPResource struct {
	HostID        string
	IPAddress     string
	InterfaceName string
	MACAddress    string
}

// New creates a new empty host
func New() *Host {
	host := &Host{}
	return host
}

// Build creates a Host type from the current host machine, filling out fields using the current machines attributes.
// The IP param is a routable IP used to connect to to the Host, if empty an IP from the available IPs will be used.
// The poolid param is the pool the host should belong to.  Optional list of IP address strings to set as available IP
// resources, if not set the IP used for the host will be given as an IP Resource. If any IP is not a valid IP on the
// machine return error.
func Build(ip string, rpcport string, poolid string, memory string, ipAddrs ...string) (*Host, error) {
	if strings.TrimSpace(poolid) == "" {
		return nil, errors.New("empty poolid not allowed")
	}

	rpcPort, err := strconv.Atoi(rpcport)
	if err != nil {
		return nil, err
	}
	host, err := currentHost(ip, rpcPort, poolid)
	if err != nil {
		return nil, err
	}
	glog.Infof("Building host %s (%s) with ipsAddrs: %v [%d]", host.ID, host.IPAddr, ipAddrs, len(ipAddrs))
	hostIPs, err := getIPResources(host.ID, host.IPAddr, ipAddrs...)
	if err != nil {
		return nil, err
	}
	host.IPs = hostIPs

	// set the memory
	if mem, err := utils.ParseEngineeringNotation(memory); err == nil {
		host.RAMCommitment = mem
	} else if mem, err := utils.ParsePercentage(memory, host.Memory); err == nil {
		host.RAMCommitment = mem
	} else {
		return nil, err
	}

	// get embedded host information
	host.ServiceD.Version = servicedversion.Version
	host.ServiceD.Gitbranch = servicedversion.Gitbranch
	host.ServiceD.Gitcommit = servicedversion.Gitcommit
	host.ServiceD.Giturl = servicedversion.Giturl
	host.ServiceD.Date = servicedversion.Date
	host.ServiceD.Buildtag = servicedversion.Buildtag
	host.ServiceD.Release = servicedversion.Release

	return host, nil
}

//UpdateHostInfo returns a new host with updated hardware and software info. Does not update port or IP information
func UpdateHostInfo(h Host) (Host, error) {
	currentHost, err := currentHost(h.IPAddr, h.RPCPort, h.PoolID)
	if err != nil {
		return Host{}, err
	}

	//update the passed in *copy* so we don't have to deal with new non hardware fields later on
	h.Memory = currentHost.Memory
	h.Cores = currentHost.Cores
	h.KernelRelease = currentHost.KernelRelease
	h.KernelVersion = currentHost.KernelVersion
	h.PrivateNetwork = currentHost.PrivateNetwork
	h.ServiceD = currentHost.ServiceD

	return h, nil
}
<commit_msg>update host data when hostname is changed<commit_after>// Copyright 2014 The Serviced 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 host

import (
	"errors"
	"reflect"
	"strconv"
	"strings"
	"time"

	"github.com/control-center/serviced/datastore"
	"github.com/control-center/serviced/domain"
	"github.com/control-center/serviced/servicedversion"
	"github.com/control-center/serviced/utils"
	"github.com/zenoss/glog"
)

//Host that runs the control center agent.
type Host struct {
	ID             string // Unique identifier, default to hostid
	Name           string // A label for the host, eg hostname, role
	PoolID         string // Pool that the Host belongs to
	IPAddr         string // The IP address the host can be reached at from a serviced master
	RPCPort        int    // The RPC port of the host
	Cores          int    // Number of cores available to serviced
	Memory         uint64 // Amount of RAM (bytes) available to serviced
	RAMCommitment  uint64 // Amount of RAM (bytes) allocated by the user
	PrivateNetwork string // The private network where containers run, eg 172.16.42.0/24
	CreatedAt      time.Time
	UpdatedAt      time.Time
	IPs            []HostIPResource // The static IP resources available on the host
	KernelVersion  string
	KernelRelease  string
	ServiceD       struct {
		Version   string
		Date      string
		Gitcommit string
		Gitbranch string
		Giturl    string
		Buildtag  string
		Release   string
	}
	MonitoringProfile domain.MonitorProfile
	datastore.VersionedEntity
}

// Equals verifies whether two host objects are equal
func (a *Host) Equals(b *Host) bool {
	if a.ID != b.ID {
		return false
	}
	if a.Name != b.Name {
		return false
	}
	if a.PoolID != b.PoolID {
		return false
	}
	if a.IPAddr != b.IPAddr {
		return false
	}
	if a.RPCPort != b.RPCPort {
		return false
	}
	if a.Cores != b.Cores {
		return false
	}
	if a.Memory != b.Memory {
		return false
	}
	if a.PrivateNetwork != b.PrivateNetwork {
		return false
	}
	if a.KernelVersion != b.KernelVersion {
		return false
	}
	if a.KernelRelease != b.KernelRelease {
		return false
	}
	if !reflect.DeepEqual(a.IPs, b.IPs) {
		return false
	}
	if a.CreatedAt.Unix() != b.CreatedAt.Unix() {
		return false
	}
	if a.UpdatedAt.Unix() != b.UpdatedAt.Unix() {
		return false
	}
	if a.ServiceD != b.ServiceD {
		return false
	}
	if !a.MonitoringProfile.Equals(&b.MonitoringProfile) {
		return false
	}

	return true
}

//HostIPResource contains information about a specific IP available as a resource
type HostIPResource struct {
	HostID        string
	IPAddress     string
	InterfaceName string
	MACAddress    string
}

// New creates a new empty host
func New() *Host {
	host := &Host{}
	return host
}

// Build creates a Host type from the current host machine, filling out fields using the current machines attributes.
// The IP param is a routable IP used to connect to to the Host, if empty an IP from the available IPs will be used.
// The poolid param is the pool the host should belong to.  Optional list of IP address strings to set as available IP
// resources, if not set the IP used for the host will be given as an IP Resource. If any IP is not a valid IP on the
// machine return error.
func Build(ip string, rpcport string, poolid string, memory string, ipAddrs ...string) (*Host, error) {
	if strings.TrimSpace(poolid) == "" {
		return nil, errors.New("empty poolid not allowed")
	}

	rpcPort, err := strconv.Atoi(rpcport)
	if err != nil {
		return nil, err
	}
	host, err := currentHost(ip, rpcPort, poolid)
	if err != nil {
		return nil, err
	}
	glog.Infof("Building host %s (%s) with ipsAddrs: %v [%d]", host.ID, host.IPAddr, ipAddrs, len(ipAddrs))
	hostIPs, err := getIPResources(host.ID, host.IPAddr, ipAddrs...)
	if err != nil {
		return nil, err
	}
	host.IPs = hostIPs

	// set the memory
	if mem, err := utils.ParseEngineeringNotation(memory); err == nil {
		host.RAMCommitment = mem
	} else if mem, err := utils.ParsePercentage(memory, host.Memory); err == nil {
		host.RAMCommitment = mem
	} else {
		return nil, err
	}

	// get embedded host information
	host.ServiceD.Version = servicedversion.Version
	host.ServiceD.Gitbranch = servicedversion.Gitbranch
	host.ServiceD.Gitcommit = servicedversion.Gitcommit
	host.ServiceD.Giturl = servicedversion.Giturl
	host.ServiceD.Date = servicedversion.Date
	host.ServiceD.Buildtag = servicedversion.Buildtag
	host.ServiceD.Release = servicedversion.Release

	return host, nil
}

//UpdateHostInfo returns a new host with updated hardware and software info. Does not update port or IP information
func UpdateHostInfo(h Host) (Host, error) {
	currentHost, err := currentHost(h.IPAddr, h.RPCPort, h.PoolID)
	if err != nil {
		return Host{}, err
	}

	//update the passed in *copy* so we don't have to deal with new non hardware fields later on
	h.Name = currentHost.Name
	h.Memory = currentHost.Memory
	h.Cores = currentHost.Cores
	h.KernelRelease = currentHost.KernelRelease
	h.KernelVersion = currentHost.KernelVersion
	h.PrivateNetwork = currentHost.PrivateNetwork
	h.ServiceD = currentHost.ServiceD

	return h, nil
}
<|endoftext|>


<commit_before>package main

/*
 * Copyright 2014 Albert P. Tobey <atobey@datastax.com> @AlTobey
 *
 * 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.
 */

import (
	"flag"
	"io/ioutil"
	"log"

	"github.com/tobert/sprok"
	"gopkg.in/yaml.v2"
)

func main() {
	flag.Parse()
	args := flag.Args()
	if len(args) != 1 {
		log.Fatal("this program requires exactly one argument")
	}

	js, err := ioutil.ReadFile(args[0])
	if err != nil {
		log.Fatalf("Error opening '%s' for read: %s\n", args[0], err)
	}

	proc := sprok.NewProcess()

	err = yaml.Unmarshal(js, &proc)
	if err != nil {
		log.Fatalf("Could not parse YAML data in file '%s': %s\n", args[0], err)
	}

	proc.Exec()
}
<commit_msg>rename variable<commit_after>package main

/*
 * Copyright 2014 Albert P. Tobey <atobey@datastax.com> @AlTobey
 *
 * 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.
 */

import (
	"flag"
	"io/ioutil"
	"log"

	"github.com/tobert/sprok"
	"gopkg.in/yaml.v2"
)

func main() {
	flag.Parse()
	args := flag.Args()
	if len(args) != 1 {
		log.Fatal("this program requires exactly one argument")
	}

	data, err := ioutil.ReadFile(args[0])
	if err != nil {
		log.Fatalf("Error opening '%s' for read: %s\n", args[0], err)
	}

	proc := sprok.NewProcess()

	err = yaml.Unmarshal(data, &proc)
	if err != nil {
		log.Fatalf("Could not parse YAML data in file '%s': %s\n", args[0], err)
	}

	proc.Exec()
}
<|endoftext|>


<commit_before>package main

func ReportThread(t []target) {
    for {
        k := 0
        for i := range t {
            impl := target.GetImpl(t[i])
            addr := impl.conf.Target.Addr
            if impl.conf.Target.Prot == "EXEC" {
                addr = "127.0.0.1"
            }
            _stdscr.MovePrintf(k, 0, "%2d: Target Name: %s, Addr: %s, Sys: %s\n", i, impl.conf.Target.Name, addr, impl.conf.Target.Sys)
            _stdscr.ClearToEOL()
            k++
            for range impl.task {
                if _, err := target.Report(t[i]); err == nil {
                }
            }
            for j := range impl.db {
                val := 0.
                prefix := ""
                switch impl.task[j].Exec.Reports[0] {
                    case "RATE":
                        val = impl.db[j].rate
                    case "RAW":
                        val = impl.db[j].dpN.y
                    default:
                        val = -1.
                }
                val, prefix = ToUnits(val, 10)
                _stdscr.MovePrintf(k, 0, "    %4d: [%-96s] %7.3f %s%s", impl.db[j].N, impl.db[j].task, val, prefix, impl.db[j].units)
                _stdscr.ClearToEOL()
                k++
            }
            _stdscr.Refresh()
        }
    }
}
<commit_msg>Minor color scheme change<commit_after>package main

import (
    gc "github.com/rthornton128/goncurses"
)

func ReportThread(t []target) {
    for {
        k := 0
        for i := range t {
            impl := target.GetImpl(t[i])
            addr := impl.conf.Target.Addr
            if impl.conf.Target.Prot == "EXEC" {
                addr = "127.0.0.1"
            }
            _stdscr.ColorOn(gc.C_CYAN)
            _stdscr.MovePrintf(k, 0, "%2d: Target Name: %s, Addr: %s, Sys: %s\n", i, impl.conf.Target.Name, addr, impl.conf.Target.Sys)
            _stdscr.ColorOff(gc.C_CYAN)
            _stdscr.ClearToEOL()
            k++
            for range impl.task {
                if _, err := target.Report(t[i]); err == nil {
                }
            }
            for j := range impl.db {
                val := 0.
                prefix := ""
                switch impl.task[j].Exec.Reports[0] {
                    case "RATE":
                        val = impl.db[j].rate
                    case "RAW":
                        val = impl.db[j].dpN.y
                    default:
                        val = -1.
                }
                val, prefix = ToUnits(val, 10)
                _stdscr.MovePrintf(k, 0, "    %4d: [%-96s] %7.3f %s%s", impl.db[j].N, impl.db[j].task, val, prefix, impl.db[j].units)
                _stdscr.ClearToEOL()
                k++
            }
            _stdscr.Refresh()
        }
    }
}
<|endoftext|>


<commit_before>package search

import (
	"net/http"
	"time"
)

// Response represents the result as received from the search service.
type Response struct {
	TotalHits int
	Hits      []Hit
	Meta      Meta
}

// Hit is a search hit. It holds e.g. Asset or Series.
type Hit interface{}

// Meta contains request/response meta information
type Meta struct {
	StatusCode int
	Header     http.Header
}

// Asset is an asset hit returned by the search service.
type Asset struct {
	Arena                 string              `json:"arena"`
	AwayTeam              Team                `json:"awayteam"`
	Brand                 Brand               `json:"brand"`
	Cinemascope           Image               `json:"cinemascope"`
	ContentSource         string              `json:"content_source"`
	Country               []string            `json:"country"`
	Credits               []Credit            `json:"credits"`
	DRMRestrictions       bool                `json:"drm_restrictions"`
	DescriptionExtendedDa string              `json:"description_extended_da"`
	DescriptionExtendedFi string              `json:"description_extended_fi"`
	DescriptionExtendedNb string              `json:"description_extended_nb"`
	DescriptionExtendedSv string              `json:"description_extended_sv"`
	DescriptionLongDa     string              `json:"description_long_da"`
	DescriptionLongFi     string              `json:"description_long_fi"`
	DescriptionLongNb     string              `json:"description_long_nb"`
	DescriptionLongSv     string              `json:"description_long_sv"`
	DescriptionMediumDa   string              `json:"description_medium_da"`
	DescriptionMediumFi   string              `json:"description_medium_fi"`
	DescriptionMediumNb   string              `json:"description_medium_nb"`
	DescriptionMediumSv   string              `json:"description_medium_sv"`
	DescriptionShortDa    string              `json:"description_short_da"`
	DescriptionShortFi    string              `json:"description_short_fi"`
	DescriptionShortNb    string              `json:"description_short_nb"`
	DescriptionShortSv    string              `json:"description_short_sv"`
	DescriptionTinyDa     string              `json:"description_tiny_da"`
	DescriptionTinyFi     string              `json:"description_tiny_fi"`
	DescriptionTinyNb     string              `json:"description_tiny_nb"`
	DescriptionTinySv     string              `json:"description_tiny_sv"`
	Duration              int                 `json:"duration"`
	EpisodeNumber         int                 `json:"episode_number"`
	Events                []Event             `json:"events"`
	ExternalReferences    []ExternalReference `json:"external_references"`
	Genres                []Genre             `json:"genres"`
	HomeTeam              Team                `json:"hometeam"`
	ItemsPublished        bool                `json:"items_published"`
	KeywordsDa            []string            `json:"keywords_dk"`
	KeywordsFi            []string            `json:"keywords_fi"`
	KeywordsNb            []string            `json:"keywords_nb"`
	KeywordsSv            []string            `json:"keywords_sv"`
	Landscape             Image               `json:"landscape"`
	Live                  bool                `json:"live"`
	LiveEventEnd          time.Time           `json:"live_event_end"`
	LogoAwayTeam          Image               `json:"logoawayteam"`
	LogoHomeTeam          Image               `json:"logohometeam"`
	MLTNIDs               []string            `json:"mlt_nids"`
	MLTTags               string              `json:"mlt_tags"`
	OriginalTitle         OriginalTitle       `json:"original_title"`
	ParentalRatings       []ParentalRating    `json:"parental_ratings"`
	Poster                Image               `json:"poster"`
	ProductionYear        string              `json:"production_year"`
	PublicationRights     PublicationRights   `json:"publication_rights"`
	Season                Season              `json:"season"`
	SpokenLanguages       []string            `json:"spoken_languages"`
	Studio                string              `json:"studio"`
	Tags                  Tags                `json:"tags"`
	Timestamp             string              `json:"timestamp"`
	TitleDa               string              `json:"title_da"`
	TitleFi               string              `json:"title_fi"`
	TitleNb               string              `json:"title_nb"`
	TitleSv               string              `json:"title_sv"`
	Type                  string              `json:"type"`
	VMANID                string              `json:"vman_id"`
	VideoID               string              `json:"video_id"`
}

// Series is an series hit returned by the search service.
type Series struct {
	BrandID               string              `json:"brand_id"`
	Cinemascope           Image               `json:"cinemascope"`
	ContentSource         string              `json:"content_source"`
	Country               []string            `json:"country"`
	Credits               []Credit            `json:"credits"`
	DescriptionExtendedDa string              `json:"description_extended_da"`
	DescriptionExtendedFi string              `json:"description_extended_fi"`
	DescriptionExtendedNb string              `json:"description_extended_nb"`
	DescriptionExtendedSv string              `json:"description_extended_sv"`
	DescriptionLongDa     string              `json:"description_long_da"`
	DescriptionLongFi     string              `json:"description_long_fi"`
	DescriptionLongNb     string              `json:"description_long_nb"`
	DescriptionLongSv     string              `json:"description_long_sv"`
	DescriptionMediumDa   string              `json:"description_medium_da"`
	DescriptionMediumFi   string              `json:"description_medium_fi"`
	DescriptionMediumNb   string              `json:"description_medium_nb"`
	DescriptionMediumSv   string              `json:"description_medium_sv"`
	DescriptionShortDa    string              `json:"description_short_da"`
	DescriptionShortFi    string              `json:"description_short_fi"`
	DescriptionShortNb    string              `json:"description_short_nb"`
	DescriptionShortSv    string              `json:"description_short_sv"`
	DescriptionTinyDa     string              `json:"description_tiny_da"`
	DescriptionTinyFi     string              `json:"description_tiny_fi"`
	DescriptionTinyNb     string              `json:"description_tiny_nb"`
	DescriptionTinySv     string              `json:"description_tiny_sv"`
	Events                []Event             `json:"events"`
	ExternalReferences    []ExternalReference `json:"external_references"`
	Genres                []Genre             `json:"genres"`
	ID                    string              `json:"id"`
	KeywordsDa            []string            `json:"keywords_dk"`
	KeywordsFi            []string            `json:"keywords_fi"`
	KeywordsNb            []string            `json:"keywords_nb"`
	KeywordsSv            []string            `json:"keywords_sv"`
	Landscape             Image               `json:"landscape"`
	MLTTags               string              `json:"mlt_tags"`
	Poster                Image               `json:"poster"`
	Seasons               []int               `json:"seasons"`
	SpokenLanguages       []string            `json:"spoken_languages"`
	Studio                string              `json:"studio"`
	Tags                  Tags                `json:"tags"`
	Timestamp             string              `json:"timestamp"`
	TitleDa               string              `json:"title_da"`
	TitleFi               string              `json:"title_fi"`
	TitleNb               string              `json:"title_nb"`
	TitleSv               string              `json:"title_sv"`
	Type                  string              `json:"type"`
}

// Brand is the brand of an asset, e.g. Idol or Harry Potter.
type Brand struct {
	Cinemascope           Image               `json:"cinemascope"`
	Country               []string            `json:"country"`
	DescriptionExtendedDa string              `json:"description_extended_da"`
	DescriptionExtendedFi string              `json:"description_extended_fi"`
	DescriptionExtendedNb string              `json:"description_extended_nb"`
	DescriptionExtendedSv string              `json:"description_extended_sv"`
	DescriptionLongDa     string              `json:"description_long_da"`
	DescriptionLongFi     string              `json:"description_long_fi"`
	DescriptionLongNb     string              `json:"description_long_nb"`
	DescriptionLongSv     string              `json:"description_long_sv"`
	DescriptionMediumDa   string              `json:"description_medium_da"`
	DescriptionMediumFi   string              `json:"description_medium_fi"`
	DescriptionMediumNb   string              `json:"description_medium_nb"`
	DescriptionMediumSv   string              `json:"description_medium_sv"`
	DescriptionShortDa    string              `json:"description_short_da"`
	DescriptionShortFi    string              `json:"description_short_fi"`
	DescriptionShortNb    string              `json:"description_short_nb"`
	DescriptionShortSv    string              `json:"description_short_sv"`
	DescriptionTinyDa     string              `json:"description_tiny_da"`
	DescriptionTinyFi     string              `json:"description_tiny_fi"`
	DescriptionTinyNb     string              `json:"description_tiny_nb"`
	DescriptionTinySv     string              `json:"description_tiny_sv"`
	ExternalReferences    []ExternalReference `json:"external_references"`
	Genres                []Genre             `json:"genres"`
	ID                    string              `json:"id"`
	Landscape             Image               `json:"landscape"`
	Poster                Image               `json:"poster"`
	Studio                string              `json:"studio"`
	TitleDa               string              `json:"title_da"`
	TitleFi               string              `json:"title_fi"`
	TitleNb               string              `json:"title_nb"`
	TitleSv               string              `json:"title_sv"`
}

// Credit represents one entry in the credit list for an asset.
type Credit struct {
	Function string `json:"function"`
	NID      string `json:"nid"`
	Name     string `json:"name"`
	Rolename string `json:"rolename"`
}

// Event contains publication rights for an asset.
type Event struct {
	Site        string    `json:"site"`
	DeviceTypes []string  `json:"device_types"`
	Products    []string  `json:"products"`
	StartTime   time.Time `json:"start_time"`
	EndTime     time.Time `json:"end_time"`
	PublishTime time.Time `json:"publish_time"`
}

// ExternalReference is a reference to additional information contained in
// a different system.
type ExternalReference struct {
	Locator string `json:"locator"`
	Type    string `json:"type"`
	Value   string `json:"value"`
}

// Genre is the main and sub genre inforamtion for an asset, e.g. Main:
// Horror, Sub [Action, Drama, Romance]
type Genre struct {
	Main string   `json:"main"`
	Sub  []string `json:"sub"`
}

// Image is the image attribute for an asset. It may contain localizations.
type Image struct {
	Caption       string           `json:"caption"`
	Copyright     string           `json:"copyright"`
	Localizations []LocalizedImage `json:"localizations"`
	URL           string           `json:"url"`
}

// LocalizedImage is a localized image.
type LocalizedImage struct {
	Caption   string `json:"caption"`
	Copyright string `json:"copyright"`
	Language  string `json:"language"`
	URL       string `json:"url"`
}

// LocationRestrictions contains restrictions by location.
type LocationRestrictions struct {
	IncludeCountries []string `json:"include_countries"`
}

// LocationRights contains rights based on location.
type LocationRights struct {
	LocationRestrictions LocationRestrictions `json:"location_restrictions"`
	Product              string               `json:"product"`
}

// OriginalTitle is the title of an asset in the original language.
type OriginalTitle struct {
	Language string `json:"language"`
	Text     string `json:"text"`
	Type     string `json:"type"`
}

// ParentalRating is a parental rating of an asset for a given country and
// rating system.
type ParentalRating struct {
	Country string `json:"country"`
	System  string `json:"system"`
	Value   string `json:"value"`
}

// PublicationRights contain location rights for an asset.
type PublicationRights struct {
	LocationRights LocationRights `json:"location_rights"`
}

// Season is a season of an asset, e.g. "Idol season 2".
type Season struct {
	Cinemascope           Image               `json:"cinemascope"`
	Country               []string            `json:"country"`
	DescriptionExtendedDa string              `json:"description_extended_da"`
	DescriptionExtendedFi string              `json:"description_extended_fi"`
	DescriptionExtendedNb string              `json:"description_extended_nb"`
	DescriptionExtendedSv string              `json:"description_extended_sv"`
	DescriptionLongDa     string              `json:"description_long_da"`
	DescriptionLongFi     string              `json:"description_long_fi"`
	DescriptionLongNb     string              `json:"description_long_nb"`
	DescriptionLongSv     string              `json:"description_long_sv"`
	DescriptionMediumDa   string              `json:"description_medium_da"`
	DescriptionMediumFi   string              `json:"description_medium_fi"`
	DescriptionMediumNb   string              `json:"description_medium_nb"`
	DescriptionMediumSv   string              `json:"description_medium_sv"`
	DescriptionShortDa    string              `json:"description_short_da"`
	DescriptionShortFi    string              `json:"description_short_fi"`
	DescriptionShortNb    string              `json:"description_short_nb"`
	DescriptionShortSv    string              `json:"description_short_sv"`
	DescriptionTinyDa     string              `json:"description_tiny_da"`
	DescriptionTinyFi     string              `json:"description_tiny_fi"`
	DescriptionTinyNb     string              `json:"description_tiny_nb"`
	DescriptionTinySv     string              `json:"description_tiny_sv"`
	ExternalReferences    []ExternalReference `json:"external_references"`
	Genres                []Genre             `json:"genres"`
	ID                    string              `json:"id"`
	Landscape             Image               `json:"landscape"`
	Number                int                 `json:"season_number"`
	NumberOfEpisodes      int                 `json:"number_of_episodes"`
	Poster                Image               `json:"poster"`
	Studio                string              `json:"studio"`
	TitleDa               string              `json:"title_da"`
	TitleFi               string              `json:"title_fi"`
	TitleNb               string              `json:"title_nb"`
	TitleSv               string              `json:"title_sv"`
}

// Tags bind otherwise unrelated assets.
type Tags map[string][]string

// Team represents e.g. home team for a sports asset.
type Team struct {
	Name string `json:"name"`
	NID  string `json:"nid"`
}
<commit_msg>Remove MLTTags field<commit_after>package search

import (
	"net/http"
	"time"
)

// Response represents the result as received from the search service.
type Response struct {
	TotalHits int
	Hits      []Hit
	Meta      Meta
}

// Hit is a search hit. It holds e.g. Asset or Series.
type Hit interface{}

// Meta contains request/response meta information
type Meta struct {
	StatusCode int
	Header     http.Header
}

// Asset is an asset hit returned by the search service.
type Asset struct {
	Arena                 string              `json:"arena"`
	AwayTeam              Team                `json:"awayteam"`
	Brand                 Brand               `json:"brand"`
	Cinemascope           Image               `json:"cinemascope"`
	ContentSource         string              `json:"content_source"`
	Country               []string            `json:"country"`
	Credits               []Credit            `json:"credits"`
	DRMRestrictions       bool                `json:"drm_restrictions"`
	DescriptionExtendedDa string              `json:"description_extended_da"`
	DescriptionExtendedFi string              `json:"description_extended_fi"`
	DescriptionExtendedNb string              `json:"description_extended_nb"`
	DescriptionExtendedSv string              `json:"description_extended_sv"`
	DescriptionLongDa     string              `json:"description_long_da"`
	DescriptionLongFi     string              `json:"description_long_fi"`
	DescriptionLongNb     string              `json:"description_long_nb"`
	DescriptionLongSv     string              `json:"description_long_sv"`
	DescriptionMediumDa   string              `json:"description_medium_da"`
	DescriptionMediumFi   string              `json:"description_medium_fi"`
	DescriptionMediumNb   string              `json:"description_medium_nb"`
	DescriptionMediumSv   string              `json:"description_medium_sv"`
	DescriptionShortDa    string              `json:"description_short_da"`
	DescriptionShortFi    string              `json:"description_short_fi"`
	DescriptionShortNb    string              `json:"description_short_nb"`
	DescriptionShortSv    string              `json:"description_short_sv"`
	DescriptionTinyDa     string              `json:"description_tiny_da"`
	DescriptionTinyFi     string              `json:"description_tiny_fi"`
	DescriptionTinyNb     string              `json:"description_tiny_nb"`
	DescriptionTinySv     string              `json:"description_tiny_sv"`
	Duration              int                 `json:"duration"`
	EpisodeNumber         int                 `json:"episode_number"`
	Events                []Event             `json:"events"`
	ExternalReferences    []ExternalReference `json:"external_references"`
	Genres                []Genre             `json:"genres"`
	HomeTeam              Team                `json:"hometeam"`
	ItemsPublished        bool                `json:"items_published"`
	KeywordsDa            []string            `json:"keywords_dk"`
	KeywordsFi            []string            `json:"keywords_fi"`
	KeywordsNb            []string            `json:"keywords_nb"`
	KeywordsSv            []string            `json:"keywords_sv"`
	Landscape             Image               `json:"landscape"`
	Live                  bool                `json:"live"`
	LiveEventEnd          time.Time           `json:"live_event_end"`
	LogoAwayTeam          Image               `json:"logoawayteam"`
	LogoHomeTeam          Image               `json:"logohometeam"`
	MLTNIDs               []string            `json:"mlt_nids"`
	OriginalTitle         OriginalTitle       `json:"original_title"`
	ParentalRatings       []ParentalRating    `json:"parental_ratings"`
	Poster                Image               `json:"poster"`
	ProductionYear        string              `json:"production_year"`
	PublicationRights     PublicationRights   `json:"publication_rights"`
	Season                Season              `json:"season"`
	SpokenLanguages       []string            `json:"spoken_languages"`
	Studio                string              `json:"studio"`
	Tags                  Tags                `json:"tags"`
	Timestamp             string              `json:"timestamp"`
	TitleDa               string              `json:"title_da"`
	TitleFi               string              `json:"title_fi"`
	TitleNb               string              `json:"title_nb"`
	TitleSv               string              `json:"title_sv"`
	Type                  string              `json:"type"`
	VMANID                string              `json:"vman_id"`
	VideoID               string              `json:"video_id"`
}

// Series is an series hit returned by the search service.
type Series struct {
	BrandID               string              `json:"brand_id"`
	Cinemascope           Image               `json:"cinemascope"`
	ContentSource         string              `json:"content_source"`
	Country               []string            `json:"country"`
	Credits               []Credit            `json:"credits"`
	DescriptionExtendedDa string              `json:"description_extended_da"`
	DescriptionExtendedFi string              `json:"description_extended_fi"`
	DescriptionExtendedNb string              `json:"description_extended_nb"`
	DescriptionExtendedSv string              `json:"description_extended_sv"`
	DescriptionLongDa     string              `json:"description_long_da"`
	DescriptionLongFi     string              `json:"description_long_fi"`
	DescriptionLongNb     string              `json:"description_long_nb"`
	DescriptionLongSv     string              `json:"description_long_sv"`
	DescriptionMediumDa   string              `json:"description_medium_da"`
	DescriptionMediumFi   string              `json:"description_medium_fi"`
	DescriptionMediumNb   string              `json:"description_medium_nb"`
	DescriptionMediumSv   string              `json:"description_medium_sv"`
	DescriptionShortDa    string              `json:"description_short_da"`
	DescriptionShortFi    string              `json:"description_short_fi"`
	DescriptionShortNb    string              `json:"description_short_nb"`
	DescriptionShortSv    string              `json:"description_short_sv"`
	DescriptionTinyDa     string              `json:"description_tiny_da"`
	DescriptionTinyFi     string              `json:"description_tiny_fi"`
	DescriptionTinyNb     string              `json:"description_tiny_nb"`
	DescriptionTinySv     string              `json:"description_tiny_sv"`
	Events                []Event             `json:"events"`
	ExternalReferences    []ExternalReference `json:"external_references"`
	Genres                []Genre             `json:"genres"`
	ID                    string              `json:"id"`
	KeywordsDa            []string            `json:"keywords_dk"`
	KeywordsFi            []string            `json:"keywords_fi"`
	KeywordsNb            []string            `json:"keywords_nb"`
	KeywordsSv            []string            `json:"keywords_sv"`
	Landscape             Image               `json:"landscape"`
	Poster                Image               `json:"poster"`
	Seasons               []int               `json:"seasons"`
	SpokenLanguages       []string            `json:"spoken_languages"`
	Studio                string              `json:"studio"`
	Tags                  Tags                `json:"tags"`
	Timestamp             string              `json:"timestamp"`
	TitleDa               string              `json:"title_da"`
	TitleFi               string              `json:"title_fi"`
	TitleNb               string              `json:"title_nb"`
	TitleSv               string              `json:"title_sv"`
	Type                  string              `json:"type"`
}

// Brand is the brand of an asset, e.g. Idol or Harry Potter.
type Brand struct {
	Cinemascope           Image               `json:"cinemascope"`
	Country               []string            `json:"country"`
	DescriptionExtendedDa string              `json:"description_extended_da"`
	DescriptionExtendedFi string              `json:"description_extended_fi"`
	DescriptionExtendedNb string              `json:"description_extended_nb"`
	DescriptionExtendedSv string              `json:"description_extended_sv"`
	DescriptionLongDa     string              `json:"description_long_da"`
	DescriptionLongFi     string              `json:"description_long_fi"`
	DescriptionLongNb     string              `json:"description_long_nb"`
	DescriptionLongSv     string              `json:"description_long_sv"`
	DescriptionMediumDa   string              `json:"description_medium_da"`
	DescriptionMediumFi   string              `json:"description_medium_fi"`
	DescriptionMediumNb   string              `json:"description_medium_nb"`
	DescriptionMediumSv   string              `json:"description_medium_sv"`
	DescriptionShortDa    string              `json:"description_short_da"`
	DescriptionShortFi    string              `json:"description_short_fi"`
	DescriptionShortNb    string              `json:"description_short_nb"`
	DescriptionShortSv    string              `json:"description_short_sv"`
	DescriptionTinyDa     string              `json:"description_tiny_da"`
	DescriptionTinyFi     string              `json:"description_tiny_fi"`
	DescriptionTinyNb     string              `json:"description_tiny_nb"`
	DescriptionTinySv     string              `json:"description_tiny_sv"`
	ExternalReferences    []ExternalReference `json:"external_references"`
	Genres                []Genre             `json:"genres"`
	ID                    string              `json:"id"`
	Landscape             Image               `json:"landscape"`
	Poster                Image               `json:"poster"`
	Studio                string              `json:"studio"`
	TitleDa               string              `json:"title_da"`
	TitleFi               string              `json:"title_fi"`
	TitleNb               string              `json:"title_nb"`
	TitleSv               string              `json:"title_sv"`
}

// Credit represents one entry in the credit list for an asset.
type Credit struct {
	Function string `json:"function"`
	NID      string `json:"nid"`
	Name     string `json:"name"`
	Rolename string `json:"rolename"`
}

// Event contains publication rights for an asset.
type Event struct {
	Site        string    `json:"site"`
	DeviceTypes []string  `json:"device_types"`
	Products    []string  `json:"products"`
	StartTime   time.Time `json:"start_time"`
	EndTime     time.Time `json:"end_time"`
	PublishTime time.Time `json:"publish_time"`
}

// ExternalReference is a reference to additional information contained in
// a different system.
type ExternalReference struct {
	Locator string `json:"locator"`
	Type    string `json:"type"`
	Value   string `json:"value"`
}

// Genre is the main and sub genre inforamtion for an asset, e.g. Main:
// Horror, Sub [Action, Drama, Romance]
type Genre struct {
	Main string   `json:"main"`
	Sub  []string `json:"sub"`
}

// Image is the image attribute for an asset. It may contain localizations.
type Image struct {
	Caption       string           `json:"caption"`
	Copyright     string           `json:"copyright"`
	Localizations []LocalizedImage `json:"localizations"`
	URL           string           `json:"url"`
}

// LocalizedImage is a localized image.
type LocalizedImage struct {
	Caption   string `json:"caption"`
	Copyright string `json:"copyright"`
	Language  string `json:"language"`
	URL       string `json:"url"`
}

// LocationRestrictions contains restrictions by location.
type LocationRestrictions struct {
	IncludeCountries []string `json:"include_countries"`
}

// LocationRights contains rights based on location.
type LocationRights struct {
	LocationRestrictions LocationRestrictions `json:"location_restrictions"`
	Product              string               `json:"product"`
}

// OriginalTitle is the title of an asset in the original language.
type OriginalTitle struct {
	Language string `json:"language"`
	Text     string `json:"text"`
	Type     string `json:"type"`
}

// ParentalRating is a parental rating of an asset for a given country and
// rating system.
type ParentalRating struct {
	Country string `json:"country"`
	System  string `json:"system"`
	Value   string `json:"value"`
}

// PublicationRights contain location rights for an asset.
type PublicationRights struct {
	LocationRights LocationRights `json:"location_rights"`
}

// Season is a season of an asset, e.g. "Idol season 2".
type Season struct {
	Cinemascope           Image               `json:"cinemascope"`
	Country               []string            `json:"country"`
	DescriptionExtendedDa string              `json:"description_extended_da"`
	DescriptionExtendedFi string              `json:"description_extended_fi"`
	DescriptionExtendedNb string              `json:"description_extended_nb"`
	DescriptionExtendedSv string              `json:"description_extended_sv"`
	DescriptionLongDa     string              `json:"description_long_da"`
	DescriptionLongFi     string              `json:"description_long_fi"`
	DescriptionLongNb     string              `json:"description_long_nb"`
	DescriptionLongSv     string              `json:"description_long_sv"`
	DescriptionMediumDa   string              `json:"description_medium_da"`
	DescriptionMediumFi   string              `json:"description_medium_fi"`
	DescriptionMediumNb   string              `json:"description_medium_nb"`
	DescriptionMediumSv   string              `json:"description_medium_sv"`
	DescriptionShortDa    string              `json:"description_short_da"`
	DescriptionShortFi    string              `json:"description_short_fi"`
	DescriptionShortNb    string              `json:"description_short_nb"`
	DescriptionShortSv    string              `json:"description_short_sv"`
	DescriptionTinyDa     string              `json:"description_tiny_da"`
	DescriptionTinyFi     string              `json:"description_tiny_fi"`
	DescriptionTinyNb     string              `json:"description_tiny_nb"`
	DescriptionTinySv     string              `json:"description_tiny_sv"`
	ExternalReferences    []ExternalReference `json:"external_references"`
	Genres                []Genre             `json:"genres"`
	ID                    string              `json:"id"`
	Landscape             Image               `json:"landscape"`
	Number                int                 `json:"season_number"`
	NumberOfEpisodes      int                 `json:"number_of_episodes"`
	Poster                Image               `json:"poster"`
	Studio                string              `json:"studio"`
	TitleDa               string              `json:"title_da"`
	TitleFi               string              `json:"title_fi"`
	TitleNb               string              `json:"title_nb"`
	TitleSv               string              `json:"title_sv"`
}

// Tags bind otherwise unrelated assets.
type Tags map[string][]string

// Team represents e.g. home team for a sports asset.
type Team struct {
	Name string `json:"name"`
	NID  string `json:"nid"`
}
<|endoftext|>


<commit_before>package integration_test

import (
	"fmt"
	"net/http"
	"os/exec"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"
	"github.com/onsi/gomega/ghttp"
)

var _ = Describe("RenamePipeline", func() {
	var newName string
	BeforeEach(func() {
		expectedURL := "/api/v1/pipelines/some-pipeline/rename"
		newName = "brandnew"

		atcServer.AppendHandlers(
			ghttp.CombineHandlers(
				ghttp.VerifyRequest("PUT", expectedURL),
				ghttp.VerifyJSON(fmt.Sprintf(`{"name":%q}`, newName)),
				ghttp.RespondWith(http.StatusNoContent, ""),
			),
		)
	})

	Context("when not specifying a pipeline name", func() {
		It("fails and says you should provide a pipeline name", func() {
			flyCmd := exec.Command(flyPath, "-t", targetName, "rename-pipeline", "-n", "some-new-name")

			sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter)
			Expect(err).NotTo(HaveOccurred())

			Eventually(sess).Should(gexec.Exit(1))

			Expect(sess.Err).To(gbytes.Say("error: the required flag `" + osFlag("o", "old-name") + "' was not specified"))
		})
	})

	Context("when not specifying a new name", func() {
		It("fails and says you should provide a new name for the pipeline", func() {
			flyCmd := exec.Command(flyPath, "-t", targetName, "rename-pipeline", "-o", "some-pipeline")

			sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter)
			Expect(err).NotTo(HaveOccurred())

			Eventually(sess).Should(gexec.Exit(1))

			Expect(sess.Err).To(gbytes.Say("error: the required flag `" + osFlag("n", "new-name") + "' was not specified"))
		})
	})

	Context("when all the inputs are provided", func() {
		It("successfully renames the pipeline to the provided name", func() {
			flyCmd := exec.Command(flyPath, "-t", targetName, "rename-pipeline", "-o", "some-pipeline", "-n", newName)

			sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter)
			Expect(err).NotTo(HaveOccurred())

			Eventually(sess).Should(gexec.Exit(0))
			Expect(atcServer.ReceivedRequests()).To(HaveLen(4))
			Expect(sess.Out).To(gbytes.Say(fmt.Sprintf("pipeline successfully renamed to %s", newName)))
		})

		Context("when the pipeline is not found", func() {
			BeforeEach(func() {
				atcServer.SetHandler(3, ghttp.RespondWith(http.StatusNotFound, ""))
			})

			It("returns an error", func() {
				flyCmd := exec.Command(flyPath, "-t", targetName, "rename-pipeline", "-o", "some-pipeline", "-n", newName)

				sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter)
				Expect(err).NotTo(HaveOccurred())

				Eventually(sess).Should(gexec.Exit(1))
				Expect(atcServer.ReceivedRequests()).To(HaveLen(4))
				Expect(sess.Err).To(gbytes.Say("failed to find pipeline"))
			})
		})

		Context("when an error occurs", func() {
			BeforeEach(func() {
				atcServer.SetHandler(3, ghttp.RespondWith(http.StatusTeapot, ""))
			})

			It("returns an error", func() {
				flyCmd := exec.Command(flyPath, "-t", targetName, "rename-pipeline", "-o", "some-pipeline", "-n", newName)

				sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter)
				Expect(err).NotTo(HaveOccurred())

				Eventually(sess).Should(gexec.Exit(1))
				Expect(atcServer.ReceivedRequests()).To(HaveLen(4))
				Expect(sess.Err).To(gbytes.Say("client failed with error: "))
			})
		})
	})
})
<commit_msg>fix rename pipeline integration tests<commit_after>package integration_test

import (
	"fmt"
	"net/http"
	"os/exec"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"
	"github.com/onsi/gomega/ghttp"
)

var _ = Describe("RenamePipeline", func() {
	var newName string
	BeforeEach(func() {
		expectedURL := "/api/v1/pipelines/some-pipeline/rename"
		newName = "brandnew"

		atcServer.AppendHandlers(
			ghttp.CombineHandlers(
				ghttp.VerifyRequest("PUT", expectedURL),
				ghttp.VerifyJSON(fmt.Sprintf(`{"name":%q}`, newName)),
				ghttp.RespondWith(http.StatusNoContent, ""),
			),
		)
	})

	Context("when not specifying a pipeline name", func() {
		It("fails and says you should provide a pipeline name", func() {
			flyCmd := exec.Command(flyPath, "-t", targetName, "rename-pipeline", "-n", "some-new-name")

			sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter)
			Expect(err).NotTo(HaveOccurred())

			Eventually(sess).Should(gexec.Exit(1))

			Expect(sess.Err).To(gbytes.Say("error: the required flag `" + osFlag("o", "old-name") + "' was not specified"))
		})
	})

	Context("when not specifying a new name", func() {
		It("fails and says you should provide a new name for the pipeline", func() {
			flyCmd := exec.Command(flyPath, "-t", targetName, "rename-pipeline", "-o", "some-pipeline")

			sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter)
			Expect(err).NotTo(HaveOccurred())

			Eventually(sess).Should(gexec.Exit(1))

			Expect(sess.Err).To(gbytes.Say("error: the required flag `" + osFlag("n", "new-name") + "' was not specified"))
		})
	})

	Context("when all the inputs are provided", func() {
		It("successfully renames the pipeline to the provided name", func() {
			flyCmd := exec.Command(flyPath, "-t", targetName, "rename-pipeline", "-o", "some-pipeline", "-n", newName)

			sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter)
			Expect(err).NotTo(HaveOccurred())

			Eventually(sess).Should(gexec.Exit(0))
			Expect(atcServer.ReceivedRequests()).To(HaveLen(4))
			Expect(sess.Out).To(gbytes.Say(fmt.Sprintf("pipeline successfully renamed to %s", newName)))
		})

		Context("when the pipeline is not found", func() {
			BeforeEach(func() {
				atcServer.SetHandler(3, ghttp.RespondWith(http.StatusNotFound, ""))
			})

			It("returns an error", func() {
				flyCmd := exec.Command(flyPath, "-t", targetName, "rename-pipeline", "-o", "some-pipeline", "-n", newName)

				sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter)
				Expect(err).NotTo(HaveOccurred())

				Eventually(sess).Should(gexec.Exit(1))
				Expect(atcServer.ReceivedRequests()).To(HaveLen(4))
				Expect(sess.Err).To(gbytes.Say("pipeline 'some-pipeline' not found"))
			})
		})

		Context("when an error occurs", func() {
			BeforeEach(func() {
				atcServer.SetHandler(3, ghttp.RespondWith(http.StatusTeapot, ""))
			})

			It("returns an error", func() {
				flyCmd := exec.Command(flyPath, "-t", targetName, "rename-pipeline", "-o", "some-pipeline", "-n", newName)

				sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter)
				Expect(err).NotTo(HaveOccurred())

				Eventually(sess).Should(gexec.Exit(1))
				Expect(atcServer.ReceivedRequests()).To(HaveLen(4))
				Expect(sess.Err).To(gbytes.Say("418 I'm a teapot"))
			})
		})
	})
})
<|endoftext|>