<commit_before>// +build linux

package libcontainer

import (
	"fmt"
	"io/ioutil"
	"net"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/opencontainers/runc/libcontainer/configs"
	"github.com/opencontainers/runc/libcontainer/utils"
	"github.com/vishvananda/netlink"
)

var strategies = map[string]networkStrategy{
	"veth":     &veth{},
	"loopback": &loopback{},
}

// networkStrategy represents a specific network configuration for
// a container's networking stack
type networkStrategy interface {
	create(*network, int) error
	initialize(*network) error
	detach(*configs.Network) error
	attach(*configs.Network) error
}

// getStrategy returns the specific network strategy for the
// provided type.
func getStrategy(tpe string) (networkStrategy, error) {
	s, exists := strategies[tpe]
	if !exists {
		return nil, fmt.Errorf("unknown strategy type %q", tpe)
	}
	return s, nil
}

// Returns the network statistics for the network interfaces represented by the NetworkRuntimeInfo.
func getNetworkInterfaceStats(interfaceName string) (*NetworkInterface, error) {
	out := &NetworkInterface{Name: interfaceName}
	// This can happen if the network runtime information is missing - possible if the
	// container was created by an old version of libcontainer.
	if interfaceName == "" {
		return out, nil
	}
	type netStatsPair struct {
		// Where to write the output.
		Out *uint64
		// The network stats file to read.
		File string
	}
	// Ingress for host veth is from the container. Hence tx_bytes stat on the host veth is actually number of bytes received by the container.
	netStats := []netStatsPair{
		{Out: &out.RxBytes, File: "tx_bytes"},
		{Out: &out.RxPackets, File: "tx_packets"},
		{Out: &out.RxErrors, File: "tx_errors"},
		{Out: &out.RxDropped, File: "tx_dropped"},

		{Out: &out.TxBytes, File: "rx_bytes"},
		{Out: &out.TxPackets, File: "rx_packets"},
		{Out: &out.TxErrors, File: "rx_errors"},
		{Out: &out.TxDropped, File: "rx_dropped"},
	}
	for _, netStat := range netStats {
		data, err := readSysfsNetworkStats(interfaceName, netStat.File)
		if err != nil {
			return nil, err
		}
		*(netStat.Out) = data
	}
	return out, nil
}

// Reads the specified statistics available under /sys/class/net/<EthInterface>/statistics
func readSysfsNetworkStats(ethInterface, statsFile string) (uint64, error) {
	data, err := ioutil.ReadFile(filepath.Join("/sys/class/net", ethInterface, "statistics", statsFile))
	if err != nil {
		return 0, err
	}
	return strconv.ParseUint(strings.TrimSpace(string(data)), 10, 64)
}

// loopback is a network strategy that provides a basic loopback device
type loopback struct {
}

func (l *loopback) create(n *network, nspid int) error {
	return nil
}

func (l *loopback) initialize(config *network) error {
	return netlink.LinkSetUp(&netlink.Device{LinkAttrs: netlink.LinkAttrs{Name: "lo"}})
}

func (l *loopback) attach(n *configs.Network) (err error) {
	return nil
}

func (l *loopback) detach(n *configs.Network) (err error) {
	return nil
}

// veth is a network strategy that uses a bridge and creates
// a veth pair, one that is attached to the bridge on the host and the other
// is placed inside the container's namespace
type veth struct {
}

func (v *veth) detach(n *configs.Network) (err error) {
	return netlink.LinkSetMaster(&netlink.Device{LinkAttrs: netlink.LinkAttrs{Name: n.HostInterfaceName}}, nil)
}

// attach a container network interface to an external network
func (v *veth) attach(n *configs.Network) (err error) {
	brl, err := netlink.LinkByName(n.Bridge)
	if err != nil {
		return err
	}
	br, ok := brl.(*netlink.Bridge)
	if !ok {
		return fmt.Errorf("Wrong device type %T", brl)
	}
	host, err := netlink.LinkByName(n.HostInterfaceName)
	if err != nil {
		return err
	}

	if err := netlink.LinkSetMaster(host, br); err != nil {
		return err
	}
	if err := netlink.LinkSetMTU(host, n.Mtu); err != nil {
		return err
	}
	if n.HairpinMode {
		if err := netlink.LinkSetHairpin(host, true); err != nil {
			return err
		}
	}
	if err := netlink.LinkSetUp(host); err != nil {
		return err
	}

	return nil
}

func (v *veth) create(n *network, nspid int) (err error) {
	tmpName, err := v.generateTempPeerName()
	if err != nil {
		return err
	}
	n.TempVethPeerName = tmpName
	if n.Bridge == "" {
		return fmt.Errorf("bridge is not specified")
	}
	veth := &netlink.Veth{
		LinkAttrs: netlink.LinkAttrs{
			Name:   n.HostInterfaceName,
			TxQLen: n.TxQueueLen,
		},
		PeerName: n.TempVethPeerName,
	}
	if err := netlink.LinkAdd(veth); err != nil {
		return err
	}
	defer func() {
		if err != nil {
			netlink.LinkDel(veth)
		}
	}()
	if err := v.attach(&n.Network); err != nil {
		return err
	}
	child, err := netlink.LinkByName(n.TempVethPeerName)
	if err != nil {
		return err
	}
	return netlink.LinkSetNsPid(child, nspid)
}

func (v *veth) generateTempPeerName() (string, error) {
	return utils.GenerateRandomName("veth", 7)
}

func (v *veth) initialize(config *network) error {
	peer := config.TempVethPeerName
	if peer == "" {
		return fmt.Errorf("peer is not specified")
	}
	child, err := netlink.LinkByName(peer)
	if err != nil {
		return err
	}
	if err := netlink.LinkSetDown(child); err != nil {
		return err
	}
	if err := netlink.LinkSetName(child, config.Name); err != nil {
		return err
	}
	// get the interface again after we changed the name as the index also changes.
	if child, err = netlink.LinkByName(config.Name); err != nil {
		return err
	}
	if config.MacAddress != "" {
		mac, err := net.ParseMAC(config.MacAddress)
		if err != nil {
			return err
		}
		if err := netlink.LinkSetHardwareAddr(child, mac); err != nil {
			return err
		}
	}
	ip, err := netlink.ParseAddr(config.Address)
	if err != nil {
		return err
	}
	if err := netlink.AddrAdd(child, ip); err != nil {
		return err
	}
	if config.IPv6Address != "" {
		ip6, err := netlink.ParseAddr(config.IPv6Address)
		if err != nil {
			return err
		}
		if err := netlink.AddrAdd(child, ip6); err != nil {
			return err
		}
	}
	if err := netlink.LinkSetMTU(child, config.Mtu); err != nil {
		return err
	}
	if err := netlink.LinkSetUp(child); err != nil {
		return err
	}
	if config.Gateway != "" {
		gw := net.ParseIP(config.Gateway)
		if err := netlink.RouteAdd(&netlink.Route{
			Scope:     netlink.SCOPE_UNIVERSE,
			LinkIndex: child.Attrs().Index,
			Gw:        gw,
		}); err != nil {
			return err
		}
	}
	if config.IPv6Gateway != "" {
		gw := net.ParseIP(config.IPv6Gateway)
		if err := netlink.RouteAdd(&netlink.Route{
			Scope:     netlink.SCOPE_UNIVERSE,
			LinkIndex: child.Attrs().Index,
			Gw:        gw,
		}); err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>fix minor issue<commit_after>// +build linux

package libcontainer

import (
	"fmt"
	"io/ioutil"
	"net"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/opencontainers/runc/libcontainer/configs"
	"github.com/opencontainers/runc/libcontainer/utils"
	"github.com/vishvananda/netlink"
)

var strategies = map[string]networkStrategy{
	"veth":     &veth{},
	"loopback": &loopback{},
}

// networkStrategy represents a specific network configuration for
// a container's networking stack
type networkStrategy interface {
	create(*network, int) error
	initialize(*network) error
	detach(*configs.Network) error
	attach(*configs.Network) error
}

// getStrategy returns the specific network strategy for the
// provided type.
func getStrategy(tpe string) (networkStrategy, error) {
	s, exists := strategies[tpe]
	if !exists {
		return nil, fmt.Errorf("unknown strategy type %q", tpe)
	}
	return s, nil
}

// Returns the network statistics for the network interfaces represented by the NetworkRuntimeInfo.
func getNetworkInterfaceStats(interfaceName string) (*NetworkInterface, error) {
	out := &NetworkInterface{Name: interfaceName}
	// This can happen if the network runtime information is missing - possible if the
	// container was created by an old version of libcontainer.
	if interfaceName == "" {
		return out, nil
	}
	type netStatsPair struct {
		// Where to write the output.
		Out *uint64
		// The network stats file to read.
		File string
	}
	// Ingress for host veth is from the container. Hence tx_bytes stat on the host veth is actually number of bytes received by the container.
	netStats := []netStatsPair{
		{Out: &out.RxBytes, File: "tx_bytes"},
		{Out: &out.RxPackets, File: "tx_packets"},
		{Out: &out.RxErrors, File: "tx_errors"},
		{Out: &out.RxDropped, File: "tx_dropped"},

		{Out: &out.TxBytes, File: "rx_bytes"},
		{Out: &out.TxPackets, File: "rx_packets"},
		{Out: &out.TxErrors, File: "rx_errors"},
		{Out: &out.TxDropped, File: "rx_dropped"},
	}
	for _, netStat := range netStats {
		data, err := readSysfsNetworkStats(interfaceName, netStat.File)
		if err != nil {
			return nil, err
		}
		*(netStat.Out) = data
	}
	return out, nil
}

// Reads the specified statistics available under /sys/class/net/<EthInterface>/statistics
func readSysfsNetworkStats(ethInterface, statsFile string) (uint64, error) {
	data, err := ioutil.ReadFile(filepath.Join("/sys/class/net", ethInterface, "statistics", statsFile))
	if err != nil {
		return 0, err
	}
	return strconv.ParseUint(strings.TrimSpace(string(data)), 10, 64)
}

// loopback is a network strategy that provides a basic loopback device
type loopback struct {
}

func (l *loopback) create(n *network, nspid int) error {
	return nil
}

func (l *loopback) initialize(config *network) error {
	return netlink.LinkSetUp(&netlink.Device{LinkAttrs: netlink.LinkAttrs{Name: "lo"}})
}

func (l *loopback) attach(n *configs.Network) (err error) {
	return nil
}

func (l *loopback) detach(n *configs.Network) (err error) {
	return nil
}

// veth is a network strategy that uses a bridge and creates
// a veth pair, one that is attached to the bridge on the host and the other
// is placed inside the container's namespace
type veth struct {
}

func (v *veth) detach(n *configs.Network) (err error) {
	return netlink.LinkSetMaster(&netlink.Device{LinkAttrs: netlink.LinkAttrs{Name: n.HostInterfaceName}}, nil)
}

// attach a container network interface to an external network
func (v *veth) attach(n *configs.Network) (err error) {
	brl, err := netlink.LinkByName(n.Bridge)
	if err != nil {
		return err
	}
	br, ok := brl.(*netlink.Bridge)
	if !ok {
		return fmt.Errorf("Wrong device type %T", brl)
	}
	host, err := netlink.LinkByName(n.HostInterfaceName)
	if err != nil {
		return err
	}

	if err := netlink.LinkSetMaster(host, br); err != nil {
		return err
	}
	if err := netlink.LinkSetMTU(host, n.Mtu); err != nil {
		return err
	}
	if n.HairpinMode {
		if err := netlink.LinkSetHairpin(host, true); err != nil {
			return err
		}
	}
	if err := netlink.LinkSetUp(host); err != nil {
		return err
	}

	return nil
}

func (v *veth) create(n *network, nspid int) (err error) {
	tmpName, err := v.generateTempPeerName()
	if err != nil {
		return err
	}
	n.TempVethPeerName = tmpName
	if n.Bridge == "" {
		return fmt.Errorf("bridge is not specified")
	}
	veth := &netlink.Veth{
		LinkAttrs: netlink.LinkAttrs{
			Name:   n.HostInterfaceName,
			TxQLen: n.TxQueueLen,
		},
		PeerName: n.TempVethPeerName,
	}
	if err := netlink.LinkAdd(veth); err != nil {
		return err
	}
	defer func() {
		if err != nil {
			netlink.LinkDel(veth)
		}
	}()
	if err = v.attach(&n.Network); err != nil {
		return err
	}
	child, err := netlink.LinkByName(n.TempVethPeerName)
	if err != nil {
		return err
	}
	return netlink.LinkSetNsPid(child, nspid)
}

func (v *veth) generateTempPeerName() (string, error) {
	return utils.GenerateRandomName("veth", 7)
}

func (v *veth) initialize(config *network) error {
	peer := config.TempVethPeerName
	if peer == "" {
		return fmt.Errorf("peer is not specified")
	}
	child, err := netlink.LinkByName(peer)
	if err != nil {
		return err
	}
	if err := netlink.LinkSetDown(child); err != nil {
		return err
	}
	if err := netlink.LinkSetName(child, config.Name); err != nil {
		return err
	}
	// get the interface again after we changed the name as the index also changes.
	if child, err = netlink.LinkByName(config.Name); err != nil {
		return err
	}
	if config.MacAddress != "" {
		mac, err := net.ParseMAC(config.MacAddress)
		if err != nil {
			return err
		}
		if err := netlink.LinkSetHardwareAddr(child, mac); err != nil {
			return err
		}
	}
	ip, err := netlink.ParseAddr(config.Address)
	if err != nil {
		return err
	}
	if err := netlink.AddrAdd(child, ip); err != nil {
		return err
	}
	if config.IPv6Address != "" {
		ip6, err := netlink.ParseAddr(config.IPv6Address)
		if err != nil {
			return err
		}
		if err := netlink.AddrAdd(child, ip6); err != nil {
			return err
		}
	}
	if err := netlink.LinkSetMTU(child, config.Mtu); err != nil {
		return err
	}
	if err := netlink.LinkSetUp(child); err != nil {
		return err
	}
	if config.Gateway != "" {
		gw := net.ParseIP(config.Gateway)
		if err := netlink.RouteAdd(&netlink.Route{
			Scope:     netlink.SCOPE_UNIVERSE,
			LinkIndex: child.Attrs().Index,
			Gw:        gw,
		}); err != nil {
			return err
		}
	}
	if config.IPv6Gateway != "" {
		gw := net.ParseIP(config.IPv6Gateway)
		if err := netlink.RouteAdd(&netlink.Route{
			Scope:     netlink.SCOPE_UNIVERSE,
			LinkIndex: child.Attrs().Index,
			Gw:        gw,
		}); err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright (c) Ilia Kravets, 2015. All rights reserved. PROVIDED "AS IS"
// WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. See LICENSE file for details.

package rec

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io"

	"github.com/ikravets/errs"

	"my/ev/packet"
	"my/ev/packet/bats"
	"my/ev/packet/nasdaq"
	"my/ev/sim"
)

const (
	EFHM_DEFINITION      = 0
	EFHM_TRADE           = 1
	EFHM_QUOTE           = 2
	EFHM_ORDER           = 3
	EFHM_DEFINITION_NOM  = 4
	EFHM_DEFINITION_BATS = 5
	EFHM_REFRESHED       = 100
	EFHM_STOPPED         = 101

	EFH_ORDER_BID = 1
	EFH_ORDER_ASK = -1

	EFH_SECURITY_PUT  = 0
	EFH_SECURITY_CALL = 1
)

var efhmOutputNames = [...]string{
	EFHM_DEFINITION:      "",
	EFHM_TRADE:           "TRD",
	EFHM_QUOTE:           "QUO",
	EFHM_ORDER:           "ORD",
	EFHM_DEFINITION_NOM:  "DEF_NOM",
	EFHM_DEFINITION_BATS: "DEF_BATS",
}

type efhm_header struct {
	Type           uint8
	TickCondition  uint8
	QueuePosition  uint16
	UnderlyingId   uint32
	SecurityId     uint64
	SequenceNumber uint64
	TimeStamp      uint64
}

type efhm_order struct {
	efhm_header
	TradeStatus     uint8
	OrderType       uint8
	OrderSide       int8
	_pad            byte
	Price           uint32
	Size            uint32
	AoNSize         uint32
	CustomerSize    uint32
	CustomerAoNSize uint32
	BDSize          uint32
	BDAoNSize       uint32
}

type efhm_quote struct {
	efhm_header
	TradeStatus        uint8
	_pad               [3]byte
	BidPrice           uint32
	BidSize            uint32
	BidOrderSize       uint32
	BidAoNSize         uint32
	BidCustomerSize    uint32
	BidCustomerAoNSize uint32
	BidBDSize          uint32
	BidBDAoNSize       uint32
	AskPrice           uint32
	AskSize            uint32
	AskOrderSize       uint32
	AskAoNSize         uint32
	AskCustomerSize    uint32
	AskCustomerAoNSize uint32
	AskBDSize          uint32
	AskBDAoNSize       uint32
}

type efhm_trade struct {
	efhm_header
	Price          uint32
	Size           uint32
	TradeCondition uint8
}

type efhm_definition_nom struct {
	efhm_header
	Symbol           [8]byte
	MaturityDate     uint64
	UnderlyingSymbol [16]byte
	StrikePrice      uint32
	PutOrCall        uint8
}

type efhm_definition_bats struct {
	efhm_header
	OsiSymbol [22]byte
}

func (m efhm_header) String() string {
	switch m.Type {
	case EFHM_QUOTE, EFHM_ORDER, EFHM_TRADE, EFHM_DEFINITION_NOM, EFHM_DEFINITION_BATS:
		return fmt.Sprintf("HDR{T:%d, TC:%d, QP:%d, UId:%08x, SId:%016x, SN:%d, TS:%016x} %s",
			m.Type,
			m.TickCondition,
			m.QueuePosition,
			m.UnderlyingId,
			m.SecurityId,
			m.SequenceNumber,
			m.TimeStamp,
			efhmOutputNames[m.Type],
		)
	default:
		return fmt.Sprintf("HDR{T:%d}", m.Type)
	}
}
func (m efhm_order) String() string {
	return fmt.Sprintf("%s{TS:%d, OT:%d, OS:%+d, P:%10d, S:%d, AS:%d, CS:%d, CAS:%d, BS:%d, BAS:%d}",
		m.efhm_header,
		m.TradeStatus,
		m.OrderType,
		m.OrderSide,
		m.Price,
		m.Size,
		m.AoNSize,
		m.CustomerSize,
		m.CustomerAoNSize,
		m.BDSize,
		m.BDAoNSize,
	)
}
func (m efhm_quote) String() string {
	return fmt.Sprintf("%s{TS:%d, "+
		"Bid{P:%10d, S:%d, OS:%d, AS:%d, CS:%d, CAS:%d, BS:%d, BAS:%d}, "+
		"Ask{P:%10d, S:%d, OS:%d, AS:%d, CS:%d, CAS:%d, BS:%d, BAS:%d}"+
		"}",
		m.efhm_header,
		m.TradeStatus,
		m.BidPrice,
		m.BidSize,
		m.BidOrderSize,
		m.BidAoNSize,
		m.BidCustomerSize,
		m.BidCustomerAoNSize,
		m.BidBDSize,
		m.BidBDAoNSize,
		m.AskPrice,
		m.AskSize,
		m.AskOrderSize,
		m.AskAoNSize,
		m.AskCustomerSize,
		m.AskCustomerAoNSize,
		m.AskBDSize,
		m.AskBDAoNSize,
	)
}
func (m efhm_trade) String() string {
	return fmt.Sprintf("%s{P:%10d, S:%d, TC:%d}",
		m.efhm_header,
		m.Price,
		m.Size,
		m.TradeCondition,
	)
}
func (m efhm_definition_nom) String() string {
	return fmt.Sprintf("%s{S:\"%s\" %016x, MD:%x, US:\"%s\" %016x, SP:%d, PC:%d}",
		m.efhm_header,
		trimAsciiz(m.Symbol[:]),
		binary.LittleEndian.Uint64(m.Symbol[:]),
		m.MaturityDate,
		trimAsciiz(m.UnderlyingSymbol[:]),
		binary.LittleEndian.Uint64(m.UnderlyingSymbol[:]),
		m.StrikePrice,
		m.PutOrCall,
	)
}
func (m efhm_definition_bats) String() string {
	return fmt.Sprintf("%s{OS:\"%s\"}",
		m.efhm_header,
		trimAsciiz(m.OsiSymbol[:]),
	)
}
func trimAsciiz(b []byte) []byte {
	pos := bytes.IndexByte(b, 0)
	if pos < 0 {
		return b
	}
	return b[:pos]
}

type EfhLoggerPrinter interface {
	PrintOrder(efhm_order) error
	PrintQuote(efhm_quote) error
	PrintTrade(efhm_trade) error
	PrintDefinitionNom(efhm_definition_nom) error
	PrintDefinitionBats(efhm_definition_bats) error
}

type testefhPrinter struct {
	w io.Writer
}

var _ EfhLoggerPrinter = &testefhPrinter{}

func NewTestefhPrinter(w io.Writer) EfhLoggerPrinter {
	return &testefhPrinter{w: w}
}
func (p *testefhPrinter) PrintOrder(o efhm_order) error {
	return p.print(o)
}
func (p *testefhPrinter) PrintQuote(o efhm_quote) error {
	return p.print(o)
}
func (p *testefhPrinter) PrintTrade(m efhm_trade) error {
	return p.print(m)
}
func (p *testefhPrinter) PrintDefinitionNom(m efhm_definition_nom) error {
	return p.print(m)
}
func (p *testefhPrinter) PrintDefinitionBats(m efhm_definition_bats) error {
	return p.print(m)
}
func (p *testefhPrinter) print(v interface{}) error {
	_, err := fmt.Fprintln(p.w, v)
	return err
}

type EfhLogger struct {
	TobLogger
	printer EfhLoggerPrinter
	mode    EfhLoggerOutputMode
	stream  Stream
}

var _ sim.Observer = &EfhLogger{}

func NewEfhLogger(p EfhLoggerPrinter) *EfhLogger {
	l := &EfhLogger{
		printer:   p,
		TobLogger: *NewTobLogger(),
		stream:    *NewStream(),
	}
	return l
}

type EfhLoggerOutputMode byte

const (
	EfhLoggerOutputOrders EfhLoggerOutputMode = iota
	EfhLoggerOutputQuotes
)

func (l *EfhLogger) SetOutputMode(mode EfhLoggerOutputMode) {
	l.mode = mode
}

func (l *EfhLogger) MessageArrived(idm *sim.SimMessage) {
	l.stream.MessageArrived(idm)
	l.TobLogger.MessageArrived(idm)
	switch m := l.stream.getExchangeMessage().(type) {
	case packet.TradeMessage:
		l.genUpdateTrades(m)
	case *nasdaq.IttoMessageOptionDirectory:
		l.genUpdateDefinitionsNom(m)
	case *bats.PitchMessageSymbolMapping:
		l.genUpdateDefinitionsBats(m)
	}
}

func (l *EfhLogger) AfterBookUpdate(book sim.Book, operation sim.SimOperation) {
	if l.mode == EfhLoggerOutputOrders {
		if l.TobLogger.AfterBookUpdate(book, operation, TobUpdateNew) {
			l.genUpdateOrders(l.TobLogger.bid)
			l.genUpdateOrders(l.TobLogger.ask)
		}
	} else {
		if l.TobLogger.AfterBookUpdate(book, operation, TobUpdateNewForce) {
			l.genUpdateQuotes(l.TobLogger.bid, l.TobLogger.ask)
		}
	}
}

func (l *EfhLogger) genUpdateHeaderForOption(messageType uint8, oid packet.OptionId) efhm_header {
	return efhm_header{
		Type:           messageType,
		SecurityId:     oid.ToUint64(),
		SequenceNumber: l.stream.getSeqNum(),
		TimeStamp:      l.stream.getTimestamp(),
	}
}
func (l *EfhLogger) genUpdateHeader(messageType uint8) efhm_header {
	return l.genUpdateHeaderForOption(messageType, l.TobLogger.lastOptionId)
}
func (l *EfhLogger) genUpdateOrders(tob tob) {
	if !tob.updated() {
		return
	}
	m := efhm_order{
		efhm_header: l.genUpdateHeader(EFHM_ORDER),
		Price:       uint32(tob.New.Price),
		Size:        uint32(tob.New.Size),
		OrderType:   1,
	}
	switch tob.Side {
	case packet.MarketSideBid:
		m.OrderSide = EFH_ORDER_BID
	case packet.MarketSideAsk:
		m.OrderSide = EFH_ORDER_ASK
	}
	errs.CheckE(l.printer.PrintOrder(m))
}
func (l *EfhLogger) genUpdateQuotes(bid, ask tob) {
	m := efhm_quote{
		efhm_header: l.genUpdateHeader(EFHM_QUOTE),
		BidPrice:    uint32(bid.New.Price),
		BidSize:     uint32(bid.New.Size),
		AskPrice:    uint32(ask.New.Price),
		AskSize:     uint32(ask.New.Size),
	}
	errs.CheckE(l.printer.PrintQuote(m))
}
func (l *EfhLogger) genUpdateTrades(msg packet.TradeMessage) {
	oid, price, size := msg.TradeInfo()
	m := efhm_trade{
		efhm_header: l.genUpdateHeaderForOption(EFHM_TRADE, oid),
		Price:       uint32(packet.PriceTo4Dec(price)),
		Size:        uint32(size),
	}
	errs.CheckE(l.printer.PrintTrade(m))
}
func (l *EfhLogger) genUpdateDefinitionsNom(msg *nasdaq.IttoMessageOptionDirectory) {
	m := efhm_definition_nom{
		efhm_header: l.genUpdateHeaderForOption(EFHM_DEFINITION_NOM, msg.OptionId()),
		StrikePrice: uint32(msg.StrikePrice),
	}
	year, month, day := msg.Expiration.Date()
	m.MaturityDate = uint64(day<<16 + int(month)<<8 + year%100)
	copy(m.Symbol[:], msg.Symbol)
	copy(m.UnderlyingSymbol[:], msg.UnderlyingSymbol)
	switch msg.OType {
	case 'C':
		m.PutOrCall = EFH_SECURITY_CALL
	case 'P':
		m.PutOrCall = EFH_SECURITY_PUT
	}
	errs.CheckE(l.printer.PrintDefinitionNom(m))
}
func (l *EfhLogger) genUpdateDefinitionsBats(msg *bats.PitchMessageSymbolMapping) {
	m := efhm_definition_bats{
		efhm_header: l.genUpdateHeaderForOption(EFHM_DEFINITION_BATS, msg.OptionId()),
	}
	m.efhm_header.SequenceNumber = 0
	m.efhm_header.TimeStamp = 0
	copy(m.OsiSymbol[:], msg.OsiSymbol)
	errs.CheckE(l.printer.PrintDefinitionBats(m))
}
<commit_msg>rec:EfhLogger: add MIAX definitions support<commit_after>// Copyright (c) Ilia Kravets, 2015. All rights reserved. PROVIDED "AS IS"
// WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. See LICENSE file for details.

package rec

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
	"time"

	"github.com/ikravets/errs"

	"my/ev/packet"
	"my/ev/packet/bats"
	"my/ev/packet/miax"
	"my/ev/packet/nasdaq"
	"my/ev/sim"
)

const (
	EFHM_DEFINITION      = 0
	EFHM_TRADE           = 1
	EFHM_QUOTE           = 2
	EFHM_ORDER           = 3
	EFHM_DEFINITION_NOM  = 4
	EFHM_DEFINITION_BATS = 5
	EFHM_DEFINITION_MIAX = 6
	EFHM_REFRESHED       = 100
	EFHM_STOPPED         = 101

	EFH_ORDER_BID = 1
	EFH_ORDER_ASK = -1

	EFH_SECURITY_PUT  = 0
	EFH_SECURITY_CALL = 1
)

var efhmOutputNames = [...]string{
	EFHM_DEFINITION:      "",
	EFHM_TRADE:           "TRD",
	EFHM_QUOTE:           "QUO",
	EFHM_ORDER:           "ORD",
	EFHM_DEFINITION_NOM:  "DEF_NOM",
	EFHM_DEFINITION_BATS: "DEF_BATS",
	EFHM_DEFINITION_MIAX: "DEF_MIAX",
}

type efhm_header struct {
	Type           uint8
	TickCondition  uint8
	QueuePosition  uint16
	UnderlyingId   uint32
	SecurityId     uint64
	SequenceNumber uint64
	TimeStamp      uint64
}

type efhm_order struct {
	efhm_header
	TradeStatus     uint8
	OrderType       uint8
	OrderSide       int8
	_pad            byte
	Price           uint32
	Size            uint32
	AoNSize         uint32
	CustomerSize    uint32
	CustomerAoNSize uint32
	BDSize          uint32
	BDAoNSize       uint32
}

type efhm_quote struct {
	efhm_header
	TradeStatus        uint8
	_pad               [3]byte
	BidPrice           uint32
	BidSize            uint32
	BidOrderSize       uint32
	BidAoNSize         uint32
	BidCustomerSize    uint32
	BidCustomerAoNSize uint32
	BidBDSize          uint32
	BidBDAoNSize       uint32
	AskPrice           uint32
	AskSize            uint32
	AskOrderSize       uint32
	AskAoNSize         uint32
	AskCustomerSize    uint32
	AskCustomerAoNSize uint32
	AskBDSize          uint32
	AskBDAoNSize       uint32
}

type efhm_trade struct {
	efhm_header
	Price          uint32
	Size           uint32
	TradeCondition uint8
}

type efhm_definition_nom struct {
	efhm_header
	Symbol           [8]byte
	MaturityDate     uint64
	UnderlyingSymbol [16]byte
	StrikePrice      uint32
	PutOrCall        uint8
}

type efhm_definition_bats struct {
	efhm_header
	OsiSymbol [22]byte
}

func (m efhm_header) String() string {
	switch m.Type {
	case EFHM_QUOTE, EFHM_ORDER, EFHM_TRADE, EFHM_DEFINITION_NOM, EFHM_DEFINITION_BATS, EFHM_DEFINITION_MIAX:
		return fmt.Sprintf("HDR{T:%d, TC:%d, QP:%d, UId:%08x, SId:%016x, SN:%d, TS:%016x} %s",
			m.Type,
			m.TickCondition,
			m.QueuePosition,
			m.UnderlyingId,
			m.SecurityId,
			m.SequenceNumber,
			m.TimeStamp,
			efhmOutputNames[m.Type],
		)
	default:
		return fmt.Sprintf("HDR{T:%d}", m.Type)
	}
}
func (m efhm_order) String() string {
	return fmt.Sprintf("%s{TS:%d, OT:%d, OS:%+d, P:%10d, S:%d, AS:%d, CS:%d, CAS:%d, BS:%d, BAS:%d}",
		m.efhm_header,
		m.TradeStatus,
		m.OrderType,
		m.OrderSide,
		m.Price,
		m.Size,
		m.AoNSize,
		m.CustomerSize,
		m.CustomerAoNSize,
		m.BDSize,
		m.BDAoNSize,
	)
}
func (m efhm_quote) String() string {
	return fmt.Sprintf("%s{TS:%d, "+
		"Bid{P:%10d, S:%d, OS:%d, AS:%d, CS:%d, CAS:%d, BS:%d, BAS:%d}, "+
		"Ask{P:%10d, S:%d, OS:%d, AS:%d, CS:%d, CAS:%d, BS:%d, BAS:%d}"+
		"}",
		m.efhm_header,
		m.TradeStatus,
		m.BidPrice,
		m.BidSize,
		m.BidOrderSize,
		m.BidAoNSize,
		m.BidCustomerSize,
		m.BidCustomerAoNSize,
		m.BidBDSize,
		m.BidBDAoNSize,
		m.AskPrice,
		m.AskSize,
		m.AskOrderSize,
		m.AskAoNSize,
		m.AskCustomerSize,
		m.AskCustomerAoNSize,
		m.AskBDSize,
		m.AskBDAoNSize,
	)
}
func (m efhm_trade) String() string {
	return fmt.Sprintf("%s{P:%10d, S:%d, TC:%d}",
		m.efhm_header,
		m.Price,
		m.Size,
		m.TradeCondition,
	)
}
func (m efhm_definition_nom) String() string {
	return fmt.Sprintf("%s{S:\"%s\" %016x, MD:%x, US:\"%s\" %016x, SP:%d, PC:%d}",
		m.efhm_header,
		trimAsciiz(m.Symbol[:]),
		binary.LittleEndian.Uint64(m.Symbol[:]),
		m.MaturityDate,
		trimAsciiz(m.UnderlyingSymbol[:]),
		binary.LittleEndian.Uint64(m.UnderlyingSymbol[:]),
		m.StrikePrice,
		m.PutOrCall,
	)
}
func (m efhm_definition_bats) String() string {
	return fmt.Sprintf("%s{OS:\"%s\"}",
		m.efhm_header,
		trimAsciiz(m.OsiSymbol[:]),
	)
}
func trimAsciiz(b []byte) []byte {
	pos := bytes.IndexByte(b, 0)
	if pos < 0 {
		return b
	}
	return b[:pos]
}

type EfhLoggerPrinter interface {
	PrintOrder(efhm_order) error
	PrintQuote(efhm_quote) error
	PrintTrade(efhm_trade) error
	PrintDefinitionNom(efhm_definition_nom) error
	PrintDefinitionBats(efhm_definition_bats) error
}

type testefhPrinter struct {
	w io.Writer
}

var _ EfhLoggerPrinter = &testefhPrinter{}

func NewTestefhPrinter(w io.Writer) EfhLoggerPrinter {
	return &testefhPrinter{w: w}
}
func (p *testefhPrinter) PrintOrder(o efhm_order) error {
	return p.print(o)
}
func (p *testefhPrinter) PrintQuote(o efhm_quote) error {
	return p.print(o)
}
func (p *testefhPrinter) PrintTrade(m efhm_trade) error {
	return p.print(m)
}
func (p *testefhPrinter) PrintDefinitionNom(m efhm_definition_nom) error {
	return p.print(m)
}
func (p *testefhPrinter) PrintDefinitionBats(m efhm_definition_bats) error {
	return p.print(m)
}
func (p *testefhPrinter) print(v interface{}) error {
	_, err := fmt.Fprintln(p.w, v)
	return err
}

type EfhLogger struct {
	TobLogger
	printer EfhLoggerPrinter
	mode    EfhLoggerOutputMode
	stream  Stream
}

var _ sim.Observer = &EfhLogger{}

func NewEfhLogger(p EfhLoggerPrinter) *EfhLogger {
	l := &EfhLogger{
		printer:   p,
		TobLogger: *NewTobLogger(),
		stream:    *NewStream(),
	}
	return l
}

type EfhLoggerOutputMode byte

const (
	EfhLoggerOutputOrders EfhLoggerOutputMode = iota
	EfhLoggerOutputQuotes
)

func (l *EfhLogger) SetOutputMode(mode EfhLoggerOutputMode) {
	l.mode = mode
}

func (l *EfhLogger) MessageArrived(idm *sim.SimMessage) {
	l.stream.MessageArrived(idm)
	l.TobLogger.MessageArrived(idm)
	switch m := l.stream.getExchangeMessage().(type) {
	case packet.TradeMessage:
		l.genUpdateTrades(m)
	case *nasdaq.IttoMessageOptionDirectory:
		l.genUpdateDefinitionsNom(m)
	case *bats.PitchMessageSymbolMapping:
		l.genUpdateDefinitionsBats(m)
	case *miax.TomMessageSeriesUpdate:
		l.genUpdateDefinitionsMiax(m)
	}
}

func (l *EfhLogger) AfterBookUpdate(book sim.Book, operation sim.SimOperation) {
	if l.mode == EfhLoggerOutputOrders {
		if l.TobLogger.AfterBookUpdate(book, operation, TobUpdateNew) {
			l.genUpdateOrders(l.TobLogger.bid)
			l.genUpdateOrders(l.TobLogger.ask)
		}
	} else {
		if l.TobLogger.AfterBookUpdate(book, operation, TobUpdateNewForce) {
			l.genUpdateQuotes(l.TobLogger.bid, l.TobLogger.ask)
		}
	}
}

func (l *EfhLogger) genUpdateHeaderForOption(messageType uint8, oid packet.OptionId) efhm_header {
	return efhm_header{
		Type:           messageType,
		SecurityId:     oid.ToUint64(),
		SequenceNumber: l.stream.getSeqNum(),
		TimeStamp:      l.stream.getTimestamp(),
	}
}
func (l *EfhLogger) genUpdateHeader(messageType uint8) efhm_header {
	return l.genUpdateHeaderForOption(messageType, l.TobLogger.lastOptionId)
}
func (l *EfhLogger) genUpdateOrders(tob tob) {
	if !tob.updated() {
		return
	}
	m := efhm_order{
		efhm_header: l.genUpdateHeader(EFHM_ORDER),
		Price:       uint32(tob.New.Price),
		Size:        uint32(tob.New.Size),
		OrderType:   1,
	}
	switch tob.Side {
	case packet.MarketSideBid:
		m.OrderSide = EFH_ORDER_BID
	case packet.MarketSideAsk:
		m.OrderSide = EFH_ORDER_ASK
	}
	errs.CheckE(l.printer.PrintOrder(m))
}
func (l *EfhLogger) genUpdateQuotes(bid, ask tob) {
	m := efhm_quote{
		efhm_header: l.genUpdateHeader(EFHM_QUOTE),
		BidPrice:    uint32(bid.New.Price),
		BidSize:     uint32(bid.New.Size),
		AskPrice:    uint32(ask.New.Price),
		AskSize:     uint32(ask.New.Size),
	}
	errs.CheckE(l.printer.PrintQuote(m))
}
func (l *EfhLogger) genUpdateTrades(msg packet.TradeMessage) {
	oid, price, size := msg.TradeInfo()
	m := efhm_trade{
		efhm_header: l.genUpdateHeaderForOption(EFHM_TRADE, oid),
		Price:       uint32(packet.PriceTo4Dec(price)),
		Size:        uint32(size),
	}
	errs.CheckE(l.printer.PrintTrade(m))
}
func (l *EfhLogger) genUpdateDefinitionsNom(msg *nasdaq.IttoMessageOptionDirectory) {
	m := efhm_definition_nom{
		efhm_header: l.genUpdateHeaderForOption(EFHM_DEFINITION_NOM, msg.OptionId()),
		StrikePrice: uint32(msg.StrikePrice),
	}
	year, month, day := msg.Expiration.Date()
	m.MaturityDate = uint64(day<<16 + int(month)<<8 + year%100)
	copy(m.Symbol[:], msg.Symbol)
	copy(m.UnderlyingSymbol[:], msg.UnderlyingSymbol)
	switch msg.OType {
	case 'C':
		m.PutOrCall = EFH_SECURITY_CALL
	case 'P':
		m.PutOrCall = EFH_SECURITY_PUT
	}
	errs.CheckE(l.printer.PrintDefinitionNom(m))
}
// FIXME boilerplate code left until there's guarantee that output for MIAX should have exactly the same fields as for NASDAQ
func (l *EfhLogger) genUpdateDefinitionsMiax(msg *miax.TomMessageSeriesUpdate) {
	m := efhm_definition_nom{
		efhm_header: l.genUpdateHeaderForOption(EFHM_DEFINITION_MIAX, msg.OptionId()),
		StrikePrice: uint32(msg.StrikePrice),
	}
	t, ok := time.Parse("20060102", msg.Expiration)
	errs.CheckE(ok)
	year, month, day := t.Date()
	m.MaturityDate = uint64(day<<16 + int(month)<<8 + year%100)
	copy(m.Symbol[:], msg.SecuritySymbol)
	copy(m.UnderlyingSymbol[:], msg.UnderlyingSymbol)
	switch msg.CallOrPut {
	case 'C':
		m.PutOrCall = EFH_SECURITY_CALL
	case 'P':
		m.PutOrCall = EFH_SECURITY_PUT
	}
	errs.CheckE(l.printer.PrintDefinitionNom(m))
}
func (l *EfhLogger) genUpdateDefinitionsBats(msg *bats.PitchMessageSymbolMapping) {
	m := efhm_definition_bats{
		efhm_header: l.genUpdateHeaderForOption(EFHM_DEFINITION_BATS, msg.OptionId()),
	}
	m.efhm_header.SequenceNumber = 0
	m.efhm_header.TimeStamp = 0
	copy(m.OsiSymbol[:], msg.OsiSymbol)
	errs.CheckE(l.printer.PrintDefinitionBats(m))
}
<|endoftext|>


<commit_before>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package lxc

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"launchpad.net/golxc"
	"launchpad.net/juju-core/constraints"
	"launchpad.net/juju-core/environs"
	"launchpad.net/juju-core/environs/cloudinit"
	"launchpad.net/juju-core/environs/config"
	"launchpad.net/juju-core/instance"
	"launchpad.net/juju-core/state"
	"launchpad.net/juju-core/state/api"
	"launchpad.net/loggo"
)

var logger = loggo.GetLogger("juju.container.lxc")

var (
	defaultTemplate     = "ubuntu-cloud"
	containerDir        = "/var/lib/juju/containers"
	removedContainerDir = "/var/lib/juju/removed-containers"
	lxcContainerDir     = "/var/lib/lxc"
	lxcRestartDir       = "/etc/lxc/auto"
	lxcObjectFactory    = golxc.Factory()
)

// ManagerConfig contains the initialization parameters for the ContainerManager.
type ManagerConfig struct {
	Name   string
	LogDir string
}

// ContainerManager is responsible for starting containers, and stopping and
// listing containers that it has started.  The name of the manager is used to
// namespace the lxc containers on the machine.
type ContainerManager interface {
	// StartContainer creates and starts a new lxc container for the specified machine.
	StartContainer(
		machineId, series, nonce string,
		tools *state.Tools,
		environConfig *config.Config,
		stateInfo *state.Info,
		apiInfo *api.Info) (instance.Instance, error)
	// StopContainer stops and destroyes the lxc container identified by Instance.
	StopContainer(instance.Instance) error
	// ListContainers return a list of containers that have been started by
	// this manager.
	ListContainers() ([]instance.Instance, error)
}

type containerManager struct {
	name   string
	logdir string
}

// NewContainerManager returns a manager object that can start and stop lxc
// containers. The containers that are created are namespaced by the name
// parameter.
func NewContainerManager(conf ManagerConfig) ContainerManager {
	logdir := "/var/log/juju"
	if conf.LogDir != "" {
		logdir = conf.LogDir
	}
	return &containerManager{name: conf.Name, logdir: logdir}
}

func (manager *containerManager) StartContainer(
	machineId, series, nonce string,
	tools *state.Tools,
	environConfig *config.Config,
	stateInfo *state.Info,
	apiInfo *api.Info) (instance.Instance, error) {

	name := state.MachineTag(machineId)
	if manager.name != "" {
		name = fmt.Sprintf("%s-%s", manager.name, name)
	}
	// Note here that the lxcObjectFacotry only returns a valid container
	// object, and doesn't actually construct the underlying lxc container on
	// disk.
	container := lxcObjectFactory.New(name)

	// Create the cloud-init.
	directory := jujuContainerDirectory(name)
	logger.Tracef("create directory: %s", directory)
	if err := os.MkdirAll(directory, 0755); err != nil {
		logger.Errorf("failed to create container directory: %v", err)
		return nil, err
	}
	logger.Tracef("write cloud-init")
	userDataFilename, err := writeUserData(directory, machineId, nonce, tools, environConfig, stateInfo, apiInfo)
	if err != nil {
		logger.Errorf("failed to write user data: %v", err)
		return nil, err
	}
	logger.Tracef("write the lxc.conf file")
	configFile, err := writeLxcConfig(directory, manager.logdir)
	if err != nil {
		logger.Errorf("failed to write config file: %v", err)
		return nil, err
	}
	templateParams := []string{
		"--debug",                      // Debug errors in the cloud image
		"--userdata", userDataFilename, // Our groovey cloud-init
		"--hostid", name, // Use the container name as the hostid
		"-r", series,
	}
	// Create the container.
	logger.Tracef("create the container")
	if err := container.Create(configFile, defaultTemplate, templateParams...); err != nil {
		logger.Errorf("lxc container creation failed: %v", err)
		return nil, err
	}
	// Make sure that the mount dir has been created.
	logger.Tracef("make the mount dir for the shard logs")
	if err := os.MkdirAll(internalLogDir(name), 0755); err != nil {
		logger.Errorf("failed to create internal /var/log/juju mount dir: %v", err)
		return nil, err
	}
	logger.Tracef("lxc container created")
	// Now symlink the config file into the restart directory.
	containerConfigFile := filepath.Join(lxcContainerDir, name, "config")
	linkLocation := filepath.Join(lxcRestartDir, name+".conf")
	if err := os.Symlink(containerConfigFile, linkLocation); err != nil {
		return nil, err
	}
	logger.Tracef("auto-restart link created")

	// Start the lxc container with the appropriate settings for grabbing the
	// console output and a log file.
	consoleFile := filepath.Join(directory, "console.log")
	container.SetLogFile(filepath.Join(directory, "container.log"), golxc.LogDebug)
	logger.Tracef("start the container")
	// We explicitly don't pass through the config file to the container.Start
	// method as we have passed it through at container creation time.  This
	// is necessary to get the appropriate rootfs reference without explicitly
	// setting it ourselves.
	if err = container.Start("", consoleFile); err != nil {
		logger.Errorf("container failed to start: %v", err)
		return nil, err
	}
	logger.Tracef("container started")
	return &lxcInstance{name}, nil
}

func (manager *containerManager) StopContainer(instance instance.Instance) error {
	name := string(instance.Id())
	container := lxcObjectFactory.New(name)
	if err := container.Stop(); err != nil {
		logger.Errorf("failed to stop lxc container: %v", err)
		return err
	}
	if err := container.Destroy(); err != nil {
		logger.Errorf("failed to destroy lxc container: %v", err)
		return err
	}
	// Remove the autostart symlink
	linkLocation := filepath.Join(lxcRestartDir, name+".conf")
	if err := os.Remove(linkLocation); err != nil {
		return err
	}
	logger.Tracef("auto-restart link removed")

	// Move the directory.
	logger.Tracef("create old container dir: %s", removedContainerDir)
	if err := os.MkdirAll(removedContainerDir, 0755); err != nil {
		logger.Errorf("failed to create removed container directory: %v", err)
		return err
	}
	removedDir, err := uniqueDirectory(removedContainerDir, name)
	if err != nil {
		logger.Errorf("was not able to generate a unique directory: %v", err)
		return err
	}
	if err := os.Rename(jujuContainerDirectory(name), removedDir); err != nil {
		logger.Errorf("failed to rename container directory: %v", err)
		return err
	}
	return nil
}

func (manager *containerManager) ListContainers() (result []instance.Instance, err error) {
	containers, err := lxcObjectFactory.List()
	if err != nil {
		logger.Errorf("failed getting all instances: %v", err)
		return
	}
	managerPrefix := ""
	if manager.name != "" {
		managerPrefix = fmt.Sprintf("%s-", manager.name)
	}

	for _, container := range containers {
		// Filter out those not starting with our name.
		name := container.Name()
		if !strings.HasPrefix(name, managerPrefix) {
			continue
		}
		if container.IsRunning() {
			result = append(result, &lxcInstance{name})
		}
	}
	return
}

func jujuContainerDirectory(containerName string) string {
	return filepath.Join(containerDir, containerName)
}

const internalLogDirTemplate = "%s/%s/rootfs/var/log/juju"

func internalLogDir(containerName string) string {
	return fmt.Sprintf(internalLogDirTemplate, lxcContainerDir, containerName)
}

const localConfig = `
lxc.network.type = veth
lxc.network.link = lxcbr0
lxc.network.flags = up

lxc.mount.entry=%s var/log/juju none defaults,bind 0 0
`

func writeLxcConfig(directory, logdir string) (string, error) {
	// TODO(thumper): support different network settings.
	configFilename := filepath.Join(directory, "lxc.conf")
	configContent := fmt.Sprintf(localConfig, logdir)
	if err := ioutil.WriteFile(configFilename, []byte(configContent), 0644); err != nil {
		return "", err
	}
	return configFilename, nil
}

func writeUserData(
	directory, machineId, nonce string,
	tools *state.Tools,
	environConfig *config.Config,
	stateInfo *state.Info,
	apiInfo *api.Info,
) (string, error) {
	userData, err := cloudInitUserData(machineId, nonce, tools, environConfig, stateInfo, apiInfo)
	if err != nil {
		logger.Errorf("failed to create user data: %v", err)
		return "", err
	}
	userDataFilename := filepath.Join(directory, "cloud-init")
	if err := ioutil.WriteFile(userDataFilename, userData, 0644); err != nil {
		logger.Errorf("failed to write user data: %v", err)
		return "", err
	}
	return userDataFilename, nil
}

func cloudInitUserData(
	machineId, nonce string,
	tools *state.Tools,
	environConfig *config.Config,
	stateInfo *state.Info,
	apiInfo *api.Info,
) ([]byte, error) {
	machineConfig := &cloudinit.MachineConfig{
		MachineId:            machineId,
		MachineNonce:         nonce,
		MachineContainerType: instance.LXC,
		StateInfo:            stateInfo,
		APIInfo:              apiInfo,
		DataDir:              "/var/lib/juju",
		Tools:                tools,
	}
	if err := environs.FinishMachineConfig(machineConfig, environConfig, constraints.Value{}); err != nil {
		return nil, err
	}
	cloudConfig, err := cloudinit.New(machineConfig)
	if err != nil {
		return nil, err
	}
	data, err := cloudConfig.Render()
	if err != nil {
		return nil, err
	}
	return data, nil
}

// uniqueDirectory returns "path/name" if that directory doesn't exist.  If it
// does, the method starts appending .1, .2, etc until a unique name is found.
func uniqueDirectory(path, name string) (string, error) {
	dir := filepath.Join(path, name)
	_, err := os.Stat(dir)
	if os.IsNotExist(err) {
		return dir, nil
	}
	for i := 1; ; i++ {
		dir := filepath.Join(path, fmt.Sprintf("%s.%d", name, i))
		_, err := os.Stat(dir)
		if os.IsNotExist(err) {
			return dir, nil
		} else if err != nil {
			return "", err
		}
	}
	panic("unreachable")
}
<commit_msg>make a function.<commit_after>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package lxc

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"launchpad.net/golxc"
	"launchpad.net/juju-core/constraints"
	"launchpad.net/juju-core/environs"
	"launchpad.net/juju-core/environs/cloudinit"
	"launchpad.net/juju-core/environs/config"
	"launchpad.net/juju-core/instance"
	"launchpad.net/juju-core/state"
	"launchpad.net/juju-core/state/api"
	"launchpad.net/loggo"
)

var logger = loggo.GetLogger("juju.container.lxc")

var (
	defaultTemplate     = "ubuntu-cloud"
	containerDir        = "/var/lib/juju/containers"
	removedContainerDir = "/var/lib/juju/removed-containers"
	lxcContainerDir     = "/var/lib/lxc"
	lxcRestartDir       = "/etc/lxc/auto"
	lxcObjectFactory    = golxc.Factory()
)

// ManagerConfig contains the initialization parameters for the ContainerManager.
type ManagerConfig struct {
	Name   string
	LogDir string
}

// ContainerManager is responsible for starting containers, and stopping and
// listing containers that it has started.  The name of the manager is used to
// namespace the lxc containers on the machine.
type ContainerManager interface {
	// StartContainer creates and starts a new lxc container for the specified machine.
	StartContainer(
		machineId, series, nonce string,
		tools *state.Tools,
		environConfig *config.Config,
		stateInfo *state.Info,
		apiInfo *api.Info) (instance.Instance, error)
	// StopContainer stops and destroyes the lxc container identified by Instance.
	StopContainer(instance.Instance) error
	// ListContainers return a list of containers that have been started by
	// this manager.
	ListContainers() ([]instance.Instance, error)
}

type containerManager struct {
	name   string
	logdir string
}

// NewContainerManager returns a manager object that can start and stop lxc
// containers. The containers that are created are namespaced by the name
// parameter.
func NewContainerManager(conf ManagerConfig) ContainerManager {
	logdir := "/var/log/juju"
	if conf.LogDir != "" {
		logdir = conf.LogDir
	}
	return &containerManager{name: conf.Name, logdir: logdir}
}

func (manager *containerManager) StartContainer(
	machineId, series, nonce string,
	tools *state.Tools,
	environConfig *config.Config,
	stateInfo *state.Info,
	apiInfo *api.Info) (instance.Instance, error) {

	name := state.MachineTag(machineId)
	if manager.name != "" {
		name = fmt.Sprintf("%s-%s", manager.name, name)
	}
	// Note here that the lxcObjectFacotry only returns a valid container
	// object, and doesn't actually construct the underlying lxc container on
	// disk.
	container := lxcObjectFactory.New(name)

	// Create the cloud-init.
	directory := jujuContainerDirectory(name)
	logger.Tracef("create directory: %s", directory)
	if err := os.MkdirAll(directory, 0755); err != nil {
		logger.Errorf("failed to create container directory: %v", err)
		return nil, err
	}
	logger.Tracef("write cloud-init")
	userDataFilename, err := writeUserData(directory, machineId, nonce, tools, environConfig, stateInfo, apiInfo)
	if err != nil {
		logger.Errorf("failed to write user data: %v", err)
		return nil, err
	}
	logger.Tracef("write the lxc.conf file")
	configFile, err := writeLxcConfig(directory, manager.logdir)
	if err != nil {
		logger.Errorf("failed to write config file: %v", err)
		return nil, err
	}
	templateParams := []string{
		"--debug",                      // Debug errors in the cloud image
		"--userdata", userDataFilename, // Our groovey cloud-init
		"--hostid", name, // Use the container name as the hostid
		"-r", series,
	}
	// Create the container.
	logger.Tracef("create the container")
	if err := container.Create(configFile, defaultTemplate, templateParams...); err != nil {
		logger.Errorf("lxc container creation failed: %v", err)
		return nil, err
	}
	// Make sure that the mount dir has been created.
	logger.Tracef("make the mount dir for the shard logs")
	if err := os.MkdirAll(internalLogDir(name), 0755); err != nil {
		logger.Errorf("failed to create internal /var/log/juju mount dir: %v", err)
		return nil, err
	}
	logger.Tracef("lxc container created")
	// Now symlink the config file into the restart directory.
	containerConfigFile := filepath.Join(lxcContainerDir, name, "config")
	if err := os.Symlink(containerConfigFile, restartSymlink(name)); err != nil {
		return nil, err
	}
	logger.Tracef("auto-restart link created")

	// Start the lxc container with the appropriate settings for grabbing the
	// console output and a log file.
	consoleFile := filepath.Join(directory, "console.log")
	container.SetLogFile(filepath.Join(directory, "container.log"), golxc.LogDebug)
	logger.Tracef("start the container")
	// We explicitly don't pass through the config file to the container.Start
	// method as we have passed it through at container creation time.  This
	// is necessary to get the appropriate rootfs reference without explicitly
	// setting it ourselves.
	if err = container.Start("", consoleFile); err != nil {
		logger.Errorf("container failed to start: %v", err)
		return nil, err
	}
	logger.Tracef("container started")
	return &lxcInstance{name}, nil
}

func (manager *containerManager) StopContainer(instance instance.Instance) error {
	name := string(instance.Id())
	container := lxcObjectFactory.New(name)
	if err := container.Stop(); err != nil {
		logger.Errorf("failed to stop lxc container: %v", err)
		return err
	}
	if err := container.Destroy(); err != nil {
		logger.Errorf("failed to destroy lxc container: %v", err)
		return err
	}
	// Remove the autostart symlink
	if err := os.Remove(restartSymlink(name)); err != nil {
		return err
	}
	logger.Tracef("auto-restart link removed")

	// Move the directory.
	logger.Tracef("create old container dir: %s", removedContainerDir)
	if err := os.MkdirAll(removedContainerDir, 0755); err != nil {
		logger.Errorf("failed to create removed container directory: %v", err)
		return err
	}
	removedDir, err := uniqueDirectory(removedContainerDir, name)
	if err != nil {
		logger.Errorf("was not able to generate a unique directory: %v", err)
		return err
	}
	if err := os.Rename(jujuContainerDirectory(name), removedDir); err != nil {
		logger.Errorf("failed to rename container directory: %v", err)
		return err
	}
	return nil
}

func (manager *containerManager) ListContainers() (result []instance.Instance, err error) {
	containers, err := lxcObjectFactory.List()
	if err != nil {
		logger.Errorf("failed getting all instances: %v", err)
		return
	}
	managerPrefix := ""
	if manager.name != "" {
		managerPrefix = fmt.Sprintf("%s-", manager.name)
	}

	for _, container := range containers {
		// Filter out those not starting with our name.
		name := container.Name()
		if !strings.HasPrefix(name, managerPrefix) {
			continue
		}
		if container.IsRunning() {
			result = append(result, &lxcInstance{name})
		}
	}
	return
}

func jujuContainerDirectory(containerName string) string {
	return filepath.Join(containerDir, containerName)
}

const internalLogDirTemplate = "%s/%s/rootfs/var/log/juju"

func internalLogDir(containerName string) string {
	return fmt.Sprintf(internalLogDirTemplate, lxcContainerDir, containerName)
}

func restartSymlink(name string) string {
	return filepath.Join(lxcRestartDir, name+".conf")
}

const localConfig = `
lxc.network.type = veth
lxc.network.link = lxcbr0
lxc.network.flags = up

lxc.mount.entry=%s var/log/juju none defaults,bind 0 0
`

func writeLxcConfig(directory, logdir string) (string, error) {
	// TODO(thumper): support different network settings.
	configFilename := filepath.Join(directory, "lxc.conf")
	configContent := fmt.Sprintf(localConfig, logdir)
	if err := ioutil.WriteFile(configFilename, []byte(configContent), 0644); err != nil {
		return "", err
	}
	return configFilename, nil
}

func writeUserData(
	directory, machineId, nonce string,
	tools *state.Tools,
	environConfig *config.Config,
	stateInfo *state.Info,
	apiInfo *api.Info,
) (string, error) {
	userData, err := cloudInitUserData(machineId, nonce, tools, environConfig, stateInfo, apiInfo)
	if err != nil {
		logger.Errorf("failed to create user data: %v", err)
		return "", err
	}
	userDataFilename := filepath.Join(directory, "cloud-init")
	if err := ioutil.WriteFile(userDataFilename, userData, 0644); err != nil {
		logger.Errorf("failed to write user data: %v", err)
		return "", err
	}
	return userDataFilename, nil
}

func cloudInitUserData(
	machineId, nonce string,
	tools *state.Tools,
	environConfig *config.Config,
	stateInfo *state.Info,
	apiInfo *api.Info,
) ([]byte, error) {
	machineConfig := &cloudinit.MachineConfig{
		MachineId:            machineId,
		MachineNonce:         nonce,
		MachineContainerType: instance.LXC,
		StateInfo:            stateInfo,
		APIInfo:              apiInfo,
		DataDir:              "/var/lib/juju",
		Tools:                tools,
	}
	if err := environs.FinishMachineConfig(machineConfig, environConfig, constraints.Value{}); err != nil {
		return nil, err
	}
	cloudConfig, err := cloudinit.New(machineConfig)
	if err != nil {
		return nil, err
	}
	data, err := cloudConfig.Render()
	if err != nil {
		return nil, err
	}
	return data, nil
}

// uniqueDirectory returns "path/name" if that directory doesn't exist.  If it
// does, the method starts appending .1, .2, etc until a unique name is found.
func uniqueDirectory(path, name string) (string, error) {
	dir := filepath.Join(path, name)
	_, err := os.Stat(dir)
	if os.IsNotExist(err) {
		return dir, nil
	}
	for i := 1; ; i++ {
		dir := filepath.Join(path, fmt.Sprintf("%s.%d", name, i))
		_, err := os.Stat(dir)
		if os.IsNotExist(err) {
			return dir, nil
		} else if err != nil {
			return "", err
		}
	}
	panic("unreachable")
}
<|endoftext|>


<commit_before>// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements.  See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You 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 runnerlib contains utilities for submitting Go pipelines
// to a Beam model runner.
package runnerlib

import (
	"context"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"sync/atomic"

	"github.com/apache/beam/sdks/go/pkg/beam/log"
)

// IsWorkerCompatibleBinary returns the path to itself and true if running
// a linux-amd64 binary that can directly be used as a worker binary.
func IsWorkerCompatibleBinary() (string, bool) {
	if runtime.GOOS == "linux" && runtime.GOARCH == "amd64" {
		return os.Args[0], true
	}
	return "", false
}

var unique int32

// BuildTempWorkerBinary creates a local worker binary in the tmp directory
// for linux/amd64. Caller responsible for deleting the binary.
func BuildTempWorkerBinary(ctx context.Context) (string, error) {
	id := atomic.AddInt32(&unique, 1)
	filename := filepath.Join(os.TempDir(), fmt.Sprintf("worker-%v-%v", id, time.Now().UnixNano()))
	if err := BuildWorkerBinary(ctx, filename); err != nil {
		return "", err
	}
	return filename, nil
}

// BuildWorkerBinary creates a local worker binary for linux/amd64. It finds the filename
// by examining the call stack. We want the user entry (*), for example:
//
//   /Users/herohde/go/src/github.com/apache/beam/sdks/go/pkg/beam/runners/beamexec/main.go (skip: 2)
// * /Users/herohde/go/src/github.com/apache/beam/sdks/go/examples/wordcount/wordcount.go (skip: 3)
//   /usr/local/go/src/runtime/proc.go (skip: 4)      // not always present
//   /usr/local/go/src/runtime/asm_amd64.s (skip: 4 or 5)
func BuildWorkerBinary(ctx context.Context, filename string) error {
	program := ""
	for i := 3; ; i++ {
		_, file, _, ok := runtime.Caller(i)
		if !ok || !strings.HasSuffix(file, ".go") || strings.HasSuffix(file, "runtime/proc.go") {
			break
		}
		program = file
	}
	if !strings.HasSuffix(program, ".go") {
		return fmt.Errorf("could not detect user main")
	}

	log.Infof(ctx, "Cross-compiling %v as %v", program, filename)

	// Cross-compile given go program. Not awesome.
	build := []string{"go", "build", "-o", filename, program}

	cmd := exec.Command(build[0], build[1:]...)
	cmd.Env = append(os.Environ(), "GOOS=linux", "GOARCH=amd64")
	if out, err := cmd.CombinedOutput(); err != nil {
		return fmt.Errorf("failed to cross-compile %v: %v\n%v", program, err, out)
	}
	return nil
}
<commit_msg>Revert worker compatible binary check since its failing on some systems<commit_after>// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements.  See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You 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 runnerlib contains utilities for submitting Go pipelines
// to a Beam model runner.
package runnerlib

import (
	"context"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"sync/atomic"

	"github.com/apache/beam/sdks/go/pkg/beam/log"
)

// IsWorkerCompatibleBinary returns the path to itself and true if running
// a linux-amd64 binary that can directly be used as a worker binary.
func IsWorkerCompatibleBinary() (string, bool) {
	return "", false
}

var unique int32

// BuildTempWorkerBinary creates a local worker binary in the tmp directory
// for linux/amd64. Caller responsible for deleting the binary.
func BuildTempWorkerBinary(ctx context.Context) (string, error) {
	id := atomic.AddInt32(&unique, 1)
	filename := filepath.Join(os.TempDir(), fmt.Sprintf("worker-%v-%v", id, time.Now().UnixNano()))
	if err := BuildWorkerBinary(ctx, filename); err != nil {
		return "", err
	}
	return filename, nil
}

// BuildWorkerBinary creates a local worker binary for linux/amd64. It finds the filename
// by examining the call stack. We want the user entry (*), for example:
//
//   /Users/herohde/go/src/github.com/apache/beam/sdks/go/pkg/beam/runners/beamexec/main.go (skip: 2)
// * /Users/herohde/go/src/github.com/apache/beam/sdks/go/examples/wordcount/wordcount.go (skip: 3)
//   /usr/local/go/src/runtime/proc.go (skip: 4)      // not always present
//   /usr/local/go/src/runtime/asm_amd64.s (skip: 4 or 5)
func BuildWorkerBinary(ctx context.Context, filename string) error {
	program := ""
	for i := 3; ; i++ {
		_, file, _, ok := runtime.Caller(i)
		if !ok || !strings.HasSuffix(file, ".go") || strings.HasSuffix(file, "runtime/proc.go") {
			break
		}
		program = file
	}
	if !strings.HasSuffix(program, ".go") {
		return fmt.Errorf("could not detect user main")
	}

	log.Infof(ctx, "Cross-compiling %v as %v", program, filename)

	// Cross-compile given go program. Not awesome.
	build := []string{"go", "build", "-o", filename, program}

	cmd := exec.Command(build[0], build[1:]...)
	cmd.Env = append(os.Environ(), "GOOS=linux", "GOARCH=amd64")
	if out, err := cmd.CombinedOutput(); err != nil {
		return fmt.Errorf("failed to cross-compile %v: %v\n%v", program, err, out)
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"math/rand"
	"regexp"
	"strings"
	"text/template"
	"time"

	"github.com/mattn/go-xmpp"
	log "github.com/sirupsen/logrus"
	"github.com/spf13/viper"
)

var (
	cdsbot    *botClient
	xmlRegexp = regexp.MustCompile(`<\/[\w\-][^><]*>|<[\w\-][^><]*\/>`)
)

const resource = "cds"
const waitTimeOnError = 5 * time.Second

type botClient struct {
	creation               time.Time
	XMPPClient             *xmpp.Client
	admins                 []string
	nbXMPPErrors           int
	nbXMPPErrorsAfterRetry int
	nbXMPPSent             int
	nbXMPPAnswers          int
	nbRenew                int
	chats                  chan xmpp.Chat
}

func getBotClient() (*botClient, error) {
	xClient, err := getNewXMPPClient()
	if err != nil {
		log.Errorf("getClient >> error with getNewXMPPClient err:%s", err)
		return nil, err
	}

	instance := &botClient{
		XMPPClient: xClient,
		admins:     strings.Split(viper.GetString("admin_cds2xmpp"), ","),
	}

	log.Infof("admin configured:%+v", viper.GetString("admin_cds2xmpp"))

	return instance, nil
}

func (bot *botClient) born() {
	bot.creation = time.Now().UTC()
	rand.Seed(time.Now().Unix())

	if viper.GetString("admin_conference") != "" {
		conferences = append(conferences, viper.GetString("admin_conference"))
	}

	bot.chats = make(chan xmpp.Chat)
	go bot.sendToXMPP()

	bot.helloWorld()

	go bot.receive()
	go do()

	for {
		sendInitialPresence(bot.XMPPClient)
		time.Sleep(10 * time.Second)
		bot.sendPresencesOnConfs()
		time.Sleep(20 * time.Second)
	}
}

func (bot *botClient) helloWorld() {
	for _, a := range bot.admins {
		log.Infof("helloWorld >> sending hello world to %s", a)

		bot.chats <- xmpp.Chat{
			Remote: a,
			Type:   "chat",
			Text:   fmt.Sprintf("Hi, I'm CDS2XMPP, what a good day to be alive. /cds cds2xmpp status for more information"),
		}
	}
}

const status = `
CDS2XMPP Status

Started:{{.creation}} since {{.since}}
Admin: {{.admin}}

XMPP:
- sent: {{.sent}}, errors: {{.nbXMPPErrors}}, errors after retry: {{.nbXMPPErrorsAfterRetry}}
- renew: {{.nbRenew}}

----
Bot:
- answers: {{.nbXMPPAnswers}}

`

func (bot *botClient) getStatus() string {

	data := map[string]string{
		"creation":               fmt.Sprintf("%s", cdsbot.creation),
		"since":                  fmt.Sprintf("%s", time.Now().Sub(cdsbot.creation)),
		"admin":                  viper.GetString("admin_cds2xmpp"),
		"sent":                   fmt.Sprintf("%d", bot.nbXMPPSent),
		"nbXMPPErrors":           fmt.Sprintf("%d", bot.nbXMPPErrors),
		"nbXMPPErrorsAfterRetry": fmt.Sprintf("%d", bot.nbXMPPErrorsAfterRetry),
		"nbRenew":                fmt.Sprintf("%d", bot.nbRenew),
		"nbXMPPAnswers":          fmt.Sprintf("%d", bot.nbXMPPAnswers),
	}

	t, errp := template.New("status").Parse(status)
	if errp != nil {
		log.Errorf("getStatus> Error:%s", errp.Error())
		return "Error while prepare status:" + errp.Error()
	}

	var buffer bytes.Buffer
	if err := t.Execute(&buffer, data); err != nil {
		log.Errorf("getStatus> Error:%s", errp.Error())
		return "Error while prepare status (execute):" + err.Error()
	}

	return buffer.String()
}

func (bot *botClient) sendPresencesOnConfs() error {
	bot.nbRenew++
	for _, c := range conferences {
		bot.XMPPClient.JoinMUCNoHistory(c, resource)
	}
	return nil
}

func (bot *botClient) sendToXMPP() {
	for {
		chat := <-bot.chats
		if isXML(chat.Text) {
			cdsbot.XMPPClient.SendHtml(chat)
		} else {
			cdsbot.XMPPClient.Send(chat)
		}
		time.Sleep(time.Duration(viper.GetInt("xmpp_delay")) * time.Second)
	}
}

// XML is detected if presence of tags like </foo> or <foo/>
// This means that
 is not detected as XML, but
 is
func isXML(text string) bool {
	return len(xmlRegexp.FindAllString(text, -1)) > 0
}

func (bot *botClient) receive() {
	for {
		chat, err := bot.XMPPClient.Recv()
		if err != nil {
			if !strings.Contains(err.Error(), "EOF") {
				log.Errorf("receive >> err: %s", err)

				log.Warn("We will try to get a new XMPP client now to fix this error")
				newXMPPClient, errGetNewXMPPClient := getNewXMPPClient()
				if errGetNewXMPPClient != nil {
					log.Errorf("XMPP Client renewal >> error with getNewXMPPClient errGetNewXMPPClient:%s", errGetNewXMPPClient)
				} else {
					log.Info("Reconnection successful, replace the old client with the new one")
					bot.XMPPClient = newXMPPClient
				}

				// In any case, wait 10 seconds between each retry to avoid spamming logs and connection retries
				time.Sleep(waitTimeOnError)
			}
		}
		isError := false
		switch v := chat.(type) {
		case xmpp.Chat:
			if v.Remote != "" {
				if v.Type == "error" {

					isError = true
					log.Errorf("receive> msg error from xmpp :%+v\n", v)

					if !strings.HasSuffix(v.Text, " [cds2xmppRetry]") {
						bot.nbXMPPErrors++
						go cdsbot.sendRetry(v)
					} else {
						bot.nbXMPPErrorsAfterRetry++
					}
				} else {
					log.Debugf("receive> msg from xmpp :%+v\n", v)
				}
			}

			if !isError {
				bot.receiveMsg(v)
			}
		}
	}
}

func (bot *botClient) sendRetry(v xmpp.Chat) {
	time.Sleep(60 * time.Second)
	bot.chats <- xmpp.Chat{
		Remote: v.Remote,
		Type:   getTypeChat(v.Remote),
		Text:   v.Text + " [cds2xmppRetry]",
	}
}

func getTypeChat(s string) string {
	if strings.Contains(s, "@conference") {
		return typeGroupChat
	}
	return typeChat
}

func (bot *botClient) receiveMsg(chat xmpp.Chat) {
	log.Debugf("receiveMsg >> enter remote:%s text:%s", chat.Remote, chat.Text)
	if time.Now().Add(-10*time.Second).Unix() < bot.creation.Unix() {
		log.Debugf("receiveMsg >> exit, bot is starting... ")
		return
	}

	if strings.HasPrefix(chat.Text, "cds, ") || strings.HasPrefix(chat.Text, "/cds ") {
		log.Infof("receiveMsg for cdsbot >> %s from remote:%s stamp:%s", chat.Text, chat.Remote, chat.Stamp)
		bot.answer(chat)
	}

}
<commit_msg>fix(contrib/cds2xmpp): add reconnect (#3566)<commit_after>package main

import (
	"bytes"
	"fmt"
	"math/rand"
	"regexp"
	"strings"
	"text/template"
	"time"

	"github.com/mattn/go-xmpp"
	log "github.com/sirupsen/logrus"
	"github.com/spf13/viper"
)

var (
	cdsbot    *botClient
	xmlRegexp = regexp.MustCompile(`<\/[\w\-][^><]*>|<[\w\-][^><]*\/>`)
)

const resource = "cds"
const waitTimeOnError = 5 * time.Second

type botClient struct {
	creation               time.Time
	XMPPClient             *xmpp.Client
	admins                 []string
	nbXMPPErrors           int
	nbXMPPErrorsAfterRetry int
	nbXMPPSent             int
	nbXMPPAnswers          int
	nbRenew                int
	chats                  chan xmpp.Chat
}

func getBotClient() (*botClient, error) {
	xClient, err := getNewXMPPClient()
	if err != nil {
		log.Errorf("getClient >> error with getNewXMPPClient err:%s", err)
		return nil, err
	}

	instance := &botClient{
		XMPPClient: xClient,
		admins:     strings.Split(viper.GetString("admin_cds2xmpp"), ","),
	}

	log.Infof("admin configured:%+v", viper.GetString("admin_cds2xmpp"))

	return instance, nil
}

func (bot *botClient) born() {
	bot.creation = time.Now().UTC()
	rand.Seed(time.Now().Unix())

	bot.chats = make(chan xmpp.Chat)
	go bot.sendToXMPP()

	bot.helloWorld()

	go bot.receive()

	for {
		if err := sendInitialPresence(bot.XMPPClient); err != nil {
			log.Errorf("born - sendInitialPresence >> error: %v", err)
			bot.reconnectXMPPClient()
		}
		time.Sleep(10 * time.Second)

		if err := bot.sendPresencesOnConfs(); err != nil {
			log.Errorf("born - sendPresencesOnConfs >> error: %v", err)
		}
		time.Sleep(20 * time.Second)
	}
}

func (bot *botClient) helloWorld() {
	for _, a := range bot.admins {
		log.Infof("helloWorld >> sending hello world to %s", a)

		bot.chats <- xmpp.Chat{
			Remote: a,
			Type:   "chat",
			Text:   fmt.Sprintf("Hi, I'm CDS2XMPP, what a good day to be alive. /cds cds2xmpp status for more information"),
		}
	}
}

const status = `
CDS2XMPP Status

Started:{{.creation}} since {{.since}}
Admin: {{.admin}}

XMPP:
- sent: {{.sent}}, errors: {{.nbXMPPErrors}}, errors after retry: {{.nbXMPPErrorsAfterRetry}}
- renew: {{.nbRenew}}

----
Bot:
- answers: {{.nbXMPPAnswers}}

`

func (bot *botClient) getStatus() string {

	data := map[string]string{
		"creation":               fmt.Sprintf("%s", cdsbot.creation),
		"since":                  fmt.Sprintf("%s", time.Now().Sub(cdsbot.creation)),
		"admin":                  viper.GetString("admin_cds2xmpp"),
		"sent":                   fmt.Sprintf("%d", bot.nbXMPPSent),
		"nbXMPPErrors":           fmt.Sprintf("%d", bot.nbXMPPErrors),
		"nbXMPPErrorsAfterRetry": fmt.Sprintf("%d", bot.nbXMPPErrorsAfterRetry),
		"nbRenew":                fmt.Sprintf("%d", bot.nbRenew),
		"nbXMPPAnswers":          fmt.Sprintf("%d", bot.nbXMPPAnswers),
	}

	t, errp := template.New("status").Parse(status)
	if errp != nil {
		log.Errorf("getStatus> Error:%s", errp.Error())
		return "Error while prepare status:" + errp.Error()
	}

	var buffer bytes.Buffer
	if err := t.Execute(&buffer, data); err != nil {
		log.Errorf("getStatus> Error:%s", errp.Error())
		return "Error while prepare status (execute):" + err.Error()
	}

	return buffer.String()
}

func (bot *botClient) sendPresencesOnConfs() error {
	bot.nbRenew++
	for _, c := range conferences {
		bot.XMPPClient.JoinMUCNoHistory(c, resource)
	}
	return nil
}

func (bot *botClient) sendToXMPP() {
	for {
		chat := <-bot.chats
		if isXML(chat.Text) {
			cdsbot.XMPPClient.SendHtml(chat)
		} else {
			cdsbot.XMPPClient.Send(chat)
		}
		time.Sleep(time.Duration(viper.GetInt("xmpp_delay")) * time.Second)
	}
}

// XML is detected if presence of tags like </foo> or <foo/>
// This means that
 is not detected as XML, but
 is
func isXML(text string) bool {
	return len(xmlRegexp.FindAllString(text, -1)) > 0
}

func (bot *botClient) receive() {
	for {
		chat, err := bot.XMPPClient.Recv()
		if err != nil {
			if !strings.Contains(err.Error(), "EOF") {
				log.Errorf("receive >> err: %s", err)
				bot.reconnectXMPPClient()
			} else {
				// FIXME: This log (and the else block) are here to troubleshoot potential connexion problems
				// If this log here shows that we can have connection problems not handled by the code below,
				// we will need to apply the same fix as below to renew the XMPP client
				// Else, we will be able to remove this log securely
				// Until then, keep it here to troubleshoot potential connection problems
				log.Errorf("receive >> err WITH EOF: %v", err)
				time.Sleep(waitTimeOnError)
			}
		}
		isError := false
		switch v := chat.(type) {
		case xmpp.Chat:
			if v.Remote != "" {
				if v.Type == "error" {

					isError = true
					log.Errorf("receive> msg error from xmpp :%+v\n", v)

					if !strings.HasSuffix(v.Text, " [cds2xmppRetry]") {
						bot.nbXMPPErrors++
						go cdsbot.sendRetry(v)
					} else {
						bot.nbXMPPErrorsAfterRetry++
					}
				} else {
					log.Debugf("receive> msg from xmpp :%+v\n", v)
				}
			}

			if !isError {
				bot.receiveMsg(v)
			}
		}
	}
}

func (bot *botClient) sendRetry(v xmpp.Chat) {
	time.Sleep(60 * time.Second)
	bot.chats <- xmpp.Chat{
		Remote: v.Remote,
		Type:   getTypeChat(v.Remote),
		Text:   v.Text + " [cds2xmppRetry]",
	}
}

func getTypeChat(s string) string {
	if strings.Contains(s, "@conference") {
		return typeGroupChat
	}
	return typeChat
}

func (bot *botClient) receiveMsg(chat xmpp.Chat) {
	log.Debugf("receiveMsg >> enter remote:%s text:%s", chat.Remote, chat.Text)
	if time.Now().Add(-10*time.Second).Unix() < bot.creation.Unix() {
		log.Debugf("receiveMsg >> exit, bot is starting... ")
		return
	}

	if strings.HasPrefix(chat.Text, "cds, ") || strings.HasPrefix(chat.Text, "/cds ") {
		log.Infof("receiveMsg for cdsbot >> %s from remote:%s stamp:%s", chat.Text, chat.Remote, chat.Stamp)
		bot.answer(chat)
	}

}

func (bot *botClient) reconnectXMPPClient() {
	log.Warn("We will try to get a new XMPP client now to fix this error")
	newXMPPClient, err := getNewXMPPClient()
	if err != nil {
		log.Errorf("XMPP Client renewal >> error with getNewXMPPClient err:%s", err)
	} else {
		log.Info("Reconnection successful, replace the old client with the new one")
		bot.XMPPClient = newXMPPClient
	}

	// Wait 10 seconds between each retry after an error to avoid spamming logs and connection retries
	time.Sleep(waitTimeOnError)
}
<|endoftext|>


<commit_before>package controllers

import (
	"net/http"
	"strings"

	"github.com/byuoitav/av-api/helpers"
	"github.com/byuoitav/av-api/packages/fusion"
	"github.com/byuoitav/av-api/packages/hateoas"
	"github.com/labstack/echo"
)

func isRoomAvailable(room fusion.Room) (fusion.Room, error) {
	available, err := helpers.IsRoomAvailable(room)
	if err != nil {
		return fusion.Room{}, err
	}

	room.Available = available

	return room, nil
}

// GetAllRooms returns a list of all rooms Crestron Fusion knows about
func GetAllRooms(c echo.Context) error {
	allRooms, err := fusion.GetAllRooms()
	if err != nil {
		return c.JSON(http.StatusBadRequest, helpers.ReturnError(err))
	}

	// Add HATEOAS links
	for i := range allRooms.Rooms {
		links, err := hateoas.AddLinks(c, []string{strings.Replace(allRooms.Rooms[i].Name, " ", "-", -1)})
		if err != nil {
			return c.JSON(http.StatusBadRequest, helpers.ReturnError(err))
		}

		allRooms.Rooms[i].Links = links
	}

	return c.JSON(http.StatusOK, allRooms)
}

// GetRoomByName get a room from Fusion using only its name
func GetRoomByName(c echo.Context) error {
	room, err := fusion.GetRoomByName(c.Param("room"))
	if err != nil {
		return c.JSON(http.StatusBadRequest, helpers.ReturnError(err))
	}

	links, err := hateoas.AddLinks(c, []string{c.Param("building"), c.Param("room")})
	if err != nil {
		return c.JSON(http.StatusBadRequest, helpers.ReturnError(err))
	}

	room.Links = links

	health, err := helpers.GetHealth(room.Address)
	if err != nil {
		return c.JSON(http.StatusBadRequest, helpers.ReturnError(err))
	}

	room.Health = health

	room, err = isRoomAvailable(room)
	if err != nil {
		return c.JSON(http.StatusBadRequest, helpers.ReturnError(err))
	}

	return c.JSON(http.StatusOK, room)
}

// GetAllRoomsByBuilding pulls room information from fusion by building designator
func GetAllRoomsByBuilding(c echo.Context) error {
	allRooms, err := fusion.GetAllRooms()
	if err != nil {
		return c.JSON(http.StatusBadRequest, helpers.ReturnError(err))
	}

	// Remove rooms that are not in the asked-for building
	for i := len(allRooms.Rooms) - 1; i >= 0; i-- {
		roomBuilding := strings.Split(allRooms.Rooms[i].Name, " ")

		if roomBuilding[0] != c.Param("building") {
			allRooms.Rooms = append(allRooms.Rooms[:i], allRooms.Rooms[i+1:]...)
		}
	}

	// Add HATEOAS links
	for i := range allRooms.Rooms {
		room := strings.Split(allRooms.Rooms[i].Name, " ")

		links, err := hateoas.AddLinks(c, []string{c.Param("building"), room[1]})
		if err != nil {
			return c.JSON(http.StatusBadRequest, helpers.ReturnError(err))
		}

		allRooms.Rooms[i].Links = links
	}

	return c.JSON(http.StatusOK, allRooms)
}

// GetRoomByNameAndBuilding is almost identical to GetRoomByName
func GetRoomByNameAndBuilding(c echo.Context) error {
	room, err := fusion.GetRoomByNameAndBuilding(c.Param("building"), c.Param("room"))
	if err != nil {
		return c.JSON(http.StatusBadRequest, helpers.ReturnError(err))
	}

	// Add HATEOAS links
	links, err := hateoas.AddLinks(c, []string{c.Param("building"), c.Param("room")})
	if err != nil {
		return c.JSON(http.StatusBadRequest, helpers.ReturnError(err))
	}

	room.Links = links

	// Add HATEOAS links for signals
	for i := range room.Signals {
		links, err := hateoas.AddLinks(c, []string{c.Param("building"), c.Param("room"), room.Signals[i].Name})
		if err != nil {
			return c.JSON(http.StatusBadRequest, helpers.ReturnError(err))
		}

		room.Signals[i].Links = links
	}

	health, err := helpers.GetHealth(room.Address)
	if err != nil {
		return c.JSON(http.StatusBadRequest, helpers.ReturnError(err))
	}

	room.Health = health

	room, err = isRoomAvailable(room)
	if err != nil {
		return c.JSON(http.StatusBadRequest, helpers.ReturnError(err))
	}

	return c.JSON(http.StatusOK, room)
}

func GetAllSignalsByRoomAndBuilding(c echo.Context) error {
	room, err := fusion.GetAllSignalsByRoomAndBuilding(c.Param("building"), c.Param("room"))
	if err != nil {
		return c.JSON(http.StatusBadRequest, helpers.ReturnError(err))
	}

	// Add HATEOAS links
	for i := range room.Signals {
		links, err := hateoas.AddLinks(c, []string{c.Param("building"), c.Param("room"), room.Signals[i].Name})
		if err != nil {
			return c.JSON(http.StatusBadRequest, helpers.ReturnError(err))
		}

		room.Signals[i].Links = links
	}

	return c.JSON(http.StatusOK, room)
}

func GetSignalByRoomAndBuilding(c echo.Context) error {
	room, err := fusion.GetSignalByRoomAndBuilding(c.Param("building"), c.Param("room"), c.Param("signal"))
	if err != nil {
		return c.JSON(http.StatusBadRequest, helpers.ReturnError(err))
	}

	return c.JSON(http.StatusOK, room)
}
<commit_msg>Manually adding a preceding slash<commit_after>package controllers

import (
	"net/http"
	"strings"

	"github.com/byuoitav/av-api/helpers"
	"github.com/byuoitav/av-api/packages/fusion"
	"github.com/byuoitav/av-api/packages/hateoas"
	"github.com/labstack/echo"
)

func isRoomAvailable(room fusion.Room) (fusion.Room, error) {
	available, err := helpers.IsRoomAvailable(room)
	if err != nil {
		return fusion.Room{}, err
	}

	room.Available = available

	return room, nil
}

// GetAllRooms returns a list of all rooms Crestron Fusion knows about
func GetAllRooms(c echo.Context) error {
	allRooms, err := fusion.GetAllRooms()
	if err != nil {
		return c.JSON(http.StatusBadRequest, helpers.ReturnError(err))
	}

	// Add HATEOAS links
	for i := range allRooms.Rooms {
		links, err := hateoas.AddLinks(c, []string{strings.Replace(allRooms.Rooms[i].Name, " ", "-", -1)})
		if err != nil {
			return c.JSON(http.StatusBadRequest, helpers.ReturnError(err))
		}

		allRooms.Rooms[i].Links = links
	}

	return c.JSON(http.StatusOK, allRooms)
}

// GetRoomByName get a room from Fusion using only its name
func GetRoomByName(c echo.Context) error {
	room, err := fusion.GetRoomByName(c.Param("room"))
	if err != nil {
		return c.JSON(http.StatusBadRequest, helpers.ReturnError(err))
	}

	links, err := hateoas.AddLinks(c, []string{c.Param("building"), c.Param("room")})
	if err != nil {
		return c.JSON(http.StatusBadRequest, helpers.ReturnError(err))
	}

	room.Links = links

	health, err := helpers.GetHealth(room.Address)
	if err != nil {
		return c.JSON(http.StatusBadRequest, helpers.ReturnError(err))
	}

	room.Health = health

	room, err = isRoomAvailable(room)
	if err != nil {
		return c.JSON(http.StatusBadRequest, helpers.ReturnError(err))
	}

	return c.JSON(http.StatusOK, room)
}

// GetAllRoomsByBuilding pulls room information from fusion by building designator
func GetAllRoomsByBuilding(c echo.Context) error {
	allRooms, err := fusion.GetAllRooms()
	if err != nil {
		return c.JSON(http.StatusBadRequest, helpers.ReturnError(err))
	}

	// Remove rooms that are not in the asked-for building
	for i := len(allRooms.Rooms) - 1; i >= 0; i-- {
		roomBuilding := strings.Split(allRooms.Rooms[i].Name, " ")

		if roomBuilding[0] != c.Param("building") {
			allRooms.Rooms = append(allRooms.Rooms[:i], allRooms.Rooms[i+1:]...)
		}
	}

	// Add HATEOAS links
	for i := range allRooms.Rooms {
		room := strings.Split(allRooms.Rooms[i].Name, " ")

		links, err := hateoas.AddLinks(c, []string{c.Param("building"), room[1]})
		if err != nil {
			return c.JSON(http.StatusBadRequest, helpers.ReturnError(err))
		}

		allRooms.Rooms[i].Links = links
	}

	return c.JSON(http.StatusOK, allRooms)
}

// GetRoomByNameAndBuilding is almost identical to GetRoomByName
func GetRoomByNameAndBuilding(c echo.Context) error {
	room, err := fusion.GetRoomByNameAndBuilding(c.Param("building"), c.Param("room"))
	if err != nil {
		return c.JSON(http.StatusBadRequest, helpers.ReturnError(err))
	}

	// Add HATEOAS links
	links, err := hateoas.AddLinks(c, []string{c.Param("building"), c.Param("room")})
	if err != nil {
		return c.JSON(http.StatusBadRequest, helpers.ReturnError(err))
	}

	room.Links = links

	// Add HATEOAS links for signals
	for i := range room.Signals {
		links, err := hateoas.AddLinks(c, []string{c.Param("building"), c.Param("room"), "/" + room.Signals[i].Name})
		if err != nil {
			return c.JSON(http.StatusBadRequest, helpers.ReturnError(err))
		}

		room.Signals[i].Links = links
	}

	health, err := helpers.GetHealth(room.Address)
	if err != nil {
		return c.JSON(http.StatusBadRequest, helpers.ReturnError(err))
	}

	room.Health = health

	room, err = isRoomAvailable(room)
	if err != nil {
		return c.JSON(http.StatusBadRequest, helpers.ReturnError(err))
	}

	return c.JSON(http.StatusOK, room)
}

func GetAllSignalsByRoomAndBuilding(c echo.Context) error {
	room, err := fusion.GetAllSignalsByRoomAndBuilding(c.Param("building"), c.Param("room"))
	if err != nil {
		return c.JSON(http.StatusBadRequest, helpers.ReturnError(err))
	}

	// Add HATEOAS links
	for i := range room.Signals {
		links, err := hateoas.AddLinks(c, []string{c.Param("building"), c.Param("room"), room.Signals[i].Name})
		if err != nil {
			return c.JSON(http.StatusBadRequest, helpers.ReturnError(err))
		}

		room.Signals[i].Links = links
	}

	return c.JSON(http.StatusOK, room)
}

func GetSignalByRoomAndBuilding(c echo.Context) error {
	room, err := fusion.GetSignalByRoomAndBuilding(c.Param("building"), c.Param("room"), c.Param("signal"))
	if err != nil {
		return c.JSON(http.StatusBadRequest, helpers.ReturnError(err))
	}

	return c.JSON(http.StatusOK, room)
}
<|endoftext|>


<commit_before>package certificateutils

import (
	"encoding/json"
	"fmt"

	"nimona.io/pkg/context"
	"nimona.io/pkg/crypto"
	"nimona.io/pkg/errors"
	"nimona.io/pkg/network"
	"nimona.io/pkg/object"
	"nimona.io/pkg/objectstore"
)

func WaitForCertificateResponse(
	ctx context.Context,
	net network.Network,
	csr *object.CertificateRequest,
) <-chan *object.CertificateResponse {
	ch := make(chan *object.CertificateResponse)
	go func() {
		sub := net.Subscribe(
			network.FilterByObjectType(
				new(object.CertificateResponse).Type(),
			),
		)
		subCh := sub.Channel()
		defer sub.Cancel()
		defer close(ch)
		for {
			select {
			case <-ctx.Done():
				return
			case env := <-subCh:
				csrRes := &object.CertificateResponse{}
				if csrRes == nil {
					return
				}
				b, _ := json.MarshalIndent(env.Payload, "", "  ")
				fmt.Println(string(b))
				if err := csrRes.FromObject(env.Payload); err != nil {
					continue
				}
				// if csrRes.Request.Nonce != csr.Nonce {
				// 	continue
				// }
				select {
				case ch <- csrRes:
				default:
				}
				return
			}
		}
	}()
	return ch
}

func FindCertificateResponseForPeer(
	ctx context.Context,
	str objectstore.Store,
	peerPublicKey crypto.PublicKey,
) (*object.CertificateResponse, error) {
	rdr, err := str.GetByType(
		new(object.CertificateResponse).Type(),
	)
	if err != nil {
		return nil, err
	}
	for {
		obj, err := rdr.Read()
		if err != nil {
			break
		}
		c := &object.CertificateResponse{}
		if err := c.FromObject(obj); err != nil {
			return nil, err
		}
		if c.Certificate.Subject.Equals(peerPublicKey) {
			return c, nil
		}
	}
	return nil, errors.Error("not found")
}
<commit_msg>chore(certificateutils): remove unused code<commit_after>package certificateutils

import (
	"encoding/json"
	"fmt"

	"nimona.io/pkg/context"
	"nimona.io/pkg/crypto"
	"nimona.io/pkg/errors"
	"nimona.io/pkg/network"
	"nimona.io/pkg/object"
	"nimona.io/pkg/objectstore"
)

func WaitForCertificateResponse(
	ctx context.Context,
	net network.Network,
	csr *object.CertificateRequest,
) <-chan *object.CertificateResponse {
	ch := make(chan *object.CertificateResponse)
	go func() {
		sub := net.Subscribe(
			network.FilterByObjectType(
				new(object.CertificateResponse).Type(),
			),
		)
		subCh := sub.Channel()
		defer sub.Cancel()
		defer close(ch)
		for {
			select {
			case <-ctx.Done():
				return
			case env := <-subCh:
				csrRes := &object.CertificateResponse{}
				if csrRes == nil {
					return
				}
				b, _ := json.MarshalIndent(env.Payload, "", "  ")
				fmt.Println(string(b))
				if err := csrRes.FromObject(env.Payload); err != nil {
					continue
				}
				select {
				case ch <- csrRes:
				default:
				}
				return
			}
		}
	}()
	return ch
}

func FindCertificateResponseForPeer(
	ctx context.Context,
	str objectstore.Store,
	peerPublicKey crypto.PublicKey,
) (*object.CertificateResponse, error) {
	rdr, err := str.GetByType(
		new(object.CertificateResponse).Type(),
	)
	if err != nil {
		return nil, err
	}
	for {
		obj, err := rdr.Read()
		if err != nil {
			break
		}
		c := &object.CertificateResponse{}
		if err := c.FromObject(obj); err != nil {
			return nil, err
		}
		if c.Certificate.Subject.Equals(peerPublicKey) {
			return c, nil
		}
	}
	return nil, errors.Error("not found")
}
<|endoftext|>


<commit_before>package commands

import (
	"flag"
	"os"

	"github.com/codegangsta/cli"
	"github.com/fatih/color"
	"github.com/grafana/grafana/pkg/cmd/grafana-cli/logger"
	"github.com/grafana/grafana/pkg/services/sqlstore"
	"github.com/grafana/grafana/pkg/setting"
)

func runDbCommand(command func(commandLine CommandLine) error) func(context *cli.Context) {
	return func(context *cli.Context) {
		cmd := &contextCommandLine{context}

		cfg := setting.NewCfg()
		cfg.Load(&setting.CommandLineArgs{
			Config:   cmd.String("config"),
			HomePath: cmd.String("homepath"),
			Args:     flag.Args(),
		})

		engine := &sqlstore.SqlStore{}
		engine.Cfg = cfg
		engine.Init()

		if err := command(cmd); err != nil {
			logger.Errorf("\n%s: ", color.RedString("Error"))
			logger.Errorf("%s\n\n", err)

			cmd.ShowHelp()
			os.Exit(1)
		} else {
			logger.Info("\n\n")
		}
	}
}

func runPluginCommand(command func(commandLine CommandLine) error) func(context *cli.Context) {
	return func(context *cli.Context) {

		cmd := &contextCommandLine{context}
		if err := command(cmd); err != nil {
			logger.Errorf("\n%s: ", color.RedString("Error"))
			logger.Errorf("%s %s\n\n", color.RedString("✗"), err)

			cmd.ShowHelp()
			os.Exit(1)
		} else {
			logger.Info("\nRestart grafana after installing plugins . <service grafana-server restart>\n\n")
		}
	}
}

var pluginCommands = []cli.Command{
	{
		Name:   "install",
		Usage:  "install <plugin id> <plugin version (optional)>",
		Action: runPluginCommand(installCommand),
	}, {
		Name:   "list-remote",
		Usage:  "list remote available plugins",
		Action: runPluginCommand(listremoteCommand),
	}, {
		Name:   "list-versions",
		Usage:  "list-versions <plugin id>",
		Action: runPluginCommand(listversionsCommand),
	}, {
		Name:    "update",
		Usage:   "update <plugin id>",
		Aliases: []string{"upgrade"},
		Action:  runPluginCommand(upgradeCommand),
	}, {
		Name:    "update-all",
		Aliases: []string{"upgrade-all"},
		Usage:   "update all your installed plugins",
		Action:  runPluginCommand(upgradeAllCommand),
	}, {
		Name:   "ls",
		Usage:  "list all installed plugins",
		Action: runPluginCommand(lsCommand),
	}, {
		Name:    "uninstall",
		Aliases: []string{"remove"},
		Usage:   "uninstall <plugin id>",
		Action:  runPluginCommand(removeCommand),
	},
}

var adminCommands = []cli.Command{
	{
		Name:   "reset-admin-password",
		Usage:  "reset-admin-password <new password>",
		Action: runDbCommand(resetPasswordCommand),
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "homepath",
				Usage: "path to grafana install/home path, defaults to working directory",
			},
			cli.StringFlag{
				Name:  "config",
				Usage: "path to config file",
			},
		},
	},
}

var Commands = []cli.Command{
	{
		Name:        "plugins",
		Usage:       "Manage plugins for grafana",
		Subcommands: pluginCommands,
	},
	{
		Name:        "admin",
		Usage:       "Grafana admin commands",
		Subcommands: adminCommands,
	},
}
<commit_msg>cli: fix init of bus<commit_after>package commands

import (
	"flag"
	"os"

	"github.com/codegangsta/cli"
	"github.com/fatih/color"
	"github.com/grafana/grafana/pkg/bus"
	"github.com/grafana/grafana/pkg/cmd/grafana-cli/logger"
	"github.com/grafana/grafana/pkg/services/sqlstore"
	"github.com/grafana/grafana/pkg/setting"
)

func runDbCommand(command func(commandLine CommandLine) error) func(context *cli.Context) {
	return func(context *cli.Context) {
		cmd := &contextCommandLine{context}

		cfg := setting.NewCfg()
		cfg.Load(&setting.CommandLineArgs{
			Config:   cmd.String("config"),
			HomePath: cmd.String("homepath"),
			Args:     flag.Args(),
		})

		engine := &sqlstore.SqlStore{}
		engine.Cfg = cfg
		engine.Bus = bus.GetBus()
		engine.Init()

		if err := command(cmd); err != nil {
			logger.Errorf("\n%s: ", color.RedString("Error"))
			logger.Errorf("%s\n\n", err)

			cmd.ShowHelp()
			os.Exit(1)
		} else {
			logger.Info("\n\n")
		}
	}
}

func runPluginCommand(command func(commandLine CommandLine) error) func(context *cli.Context) {
	return func(context *cli.Context) {

		cmd := &contextCommandLine{context}
		if err := command(cmd); err != nil {
			logger.Errorf("\n%s: ", color.RedString("Error"))
			logger.Errorf("%s %s\n\n", color.RedString("✗"), err)

			cmd.ShowHelp()
			os.Exit(1)
		} else {
			logger.Info("\nRestart grafana after installing plugins . <service grafana-server restart>\n\n")
		}
	}
}

var pluginCommands = []cli.Command{
	{
		Name:   "install",
		Usage:  "install <plugin id> <plugin version (optional)>",
		Action: runPluginCommand(installCommand),
	}, {
		Name:   "list-remote",
		Usage:  "list remote available plugins",
		Action: runPluginCommand(listremoteCommand),
	}, {
		Name:   "list-versions",
		Usage:  "list-versions <plugin id>",
		Action: runPluginCommand(listversionsCommand),
	}, {
		Name:    "update",
		Usage:   "update <plugin id>",
		Aliases: []string{"upgrade"},
		Action:  runPluginCommand(upgradeCommand),
	}, {
		Name:    "update-all",
		Aliases: []string{"upgrade-all"},
		Usage:   "update all your installed plugins",
		Action:  runPluginCommand(upgradeAllCommand),
	}, {
		Name:   "ls",
		Usage:  "list all installed plugins",
		Action: runPluginCommand(lsCommand),
	}, {
		Name:    "uninstall",
		Aliases: []string{"remove"},
		Usage:   "uninstall <plugin id>",
		Action:  runPluginCommand(removeCommand),
	},
}

var adminCommands = []cli.Command{
	{
		Name:   "reset-admin-password",
		Usage:  "reset-admin-password <new password>",
		Action: runDbCommand(resetPasswordCommand),
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "homepath",
				Usage: "path to grafana install/home path, defaults to working directory",
			},
			cli.StringFlag{
				Name:  "config",
				Usage: "path to config file",
			},
		},
	},
}

var Commands = []cli.Command{
	{
		Name:        "plugins",
		Usage:       "Manage plugins for grafana",
		Subcommands: pluginCommands,
	},
	{
		Name:        "admin",
		Usage:       "Grafana admin commands",
		Subcommands: adminCommands,
	},
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Rook Authors. All rights reserved.

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 mon

import (
	"strconv"

	"github.com/pkg/errors"
	"github.com/rook/rook/pkg/operator/k8sutil"
	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/intstr"
)

func (c *Cluster) createService(mon *monConfig) (string, error) {
	labels := c.getLabels(mon.DaemonName, false, "", true)
	svcDef := &v1.Service{
		ObjectMeta: metav1.ObjectMeta{
			Name:   mon.ResourceName,
			Labels: labels,
		},
		Spec: v1.ServiceSpec{
			Ports: []v1.ServicePort{
				{
					Name: "tcp-msgr1",
					Port: mon.Port,
					// --public-bind-addr=IP with no IP:port has the mon listen on port 6789
					// regardless of what port the mon advertises (--public-addr) to the outside.
					TargetPort: intstr.FromInt(int(DefaultMsgr1Port)),
					Protocol:   v1.ProtocolTCP,
				},
			},
			Selector: labels,
		},
	}
	k8sutil.SetOwnerRef(&svcDef.ObjectMeta, &c.ownerRef)

	// If deploying Nautilus or newer we need a new port for the monitor service
	addServicePort(svcDef, "tcp-msgr2", DefaultMsgr2Port)

	s, err := k8sutil.CreateOrUpdateService(c.context.Clientset, c.Namespace, svcDef)
	if err != nil {
		return "", errors.Wrapf(err, "failed to create service for mon %s", mon.DaemonName)
	}

	if s == nil {
		logger.Errorf("service ip not found for mon %q. if this is not a unit test, this is an error", mon.ResourceName)
		return "", nil
	}

	// mon endpoint are not actually like, they remain with the mgrs1 format
	// however it's interesting to show that monitors can be addressed via 2 different ports
	// in the end the service has msgr1 and msgr2 ports configured so it's not entirely wrong
	logger.Infof("mon %q endpoint are [v2:%s:%s,v1:%s:%d]", mon.DaemonName, s.Spec.ClusterIP, strconv.Itoa(int(DefaultMsgr2Port)), s.Spec.ClusterIP, mon.Port)

	return s.Spec.ClusterIP, nil
}
<commit_msg>ceph: during upgrade service selector cannot be changed<commit_after>/*
Copyright 2016 The Rook Authors. All rights reserved.

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 mon

import (
	"strconv"

	"github.com/pkg/errors"
	"github.com/rook/rook/pkg/operator/k8sutil"
	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/intstr"
)

func (c *Cluster) createService(mon *monConfig) (string, error) {
	svcDef := &v1.Service{
		ObjectMeta: metav1.ObjectMeta{
			Name:   mon.ResourceName,
			Labels: c.getLabels(mon.DaemonName, false, "", true),
		},
		Spec: v1.ServiceSpec{
			Ports: []v1.ServicePort{
				{
					Name: "tcp-msgr1",
					Port: mon.Port,
					// --public-bind-addr=IP with no IP:port has the mon listen on port 6789
					// regardless of what port the mon advertises (--public-addr) to the outside.
					TargetPort: intstr.FromInt(int(DefaultMsgr1Port)),
					Protocol:   v1.ProtocolTCP,
				},
			},
			Selector: c.getLabels(mon.DaemonName, false, "", false),
		},
	}
	k8sutil.SetOwnerRef(&svcDef.ObjectMeta, &c.ownerRef)

	// If deploying Nautilus or newer we need a new port for the monitor service
	addServicePort(svcDef, "tcp-msgr2", DefaultMsgr2Port)

	s, err := k8sutil.CreateOrUpdateService(c.context.Clientset, c.Namespace, svcDef)
	if err != nil {
		return "", errors.Wrapf(err, "failed to create service for mon %s", mon.DaemonName)
	}

	if s == nil {
		logger.Errorf("service ip not found for mon %q. if this is not a unit test, this is an error", mon.ResourceName)
		return "", nil
	}

	// mon endpoint are not actually like, they remain with the mgrs1 format
	// however it's interesting to show that monitors can be addressed via 2 different ports
	// in the end the service has msgr1 and msgr2 ports configured so it's not entirely wrong
	logger.Infof("mon %q endpoint are [v2:%s:%s,v1:%s:%d]", mon.DaemonName, s.Spec.ClusterIP, strconv.Itoa(int(DefaultMsgr2Port)), s.Spec.ClusterIP, mon.Port)

	return s.Spec.ClusterIP, nil
}
<|endoftext|>