<commit_before>package device

import (
	"fmt"

	"github.com/lxc/lxd/lxd/device/config"
	"github.com/lxc/lxd/lxd/state"
)

// devTypes defines supported top-level device type creation functions.
var devTypes = map[string]func(config.Device) device{
	"nic":        nicLoadByType,
	"infiniband": infinibandLoadByType,
	"proxy":      func(c config.Device) device { return &proxy{} },
	"gpu":        func(c config.Device) device { return &gpu{} },
	"usb":        func(c config.Device) device { return &usb{} },
}

// VolatileSetter is a function that accepts one or more key/value strings to save into the LXD
// config for this instance. It should add the volatile device name prefix to each key when saving.
type VolatileSetter func(map[string]string) error

// VolatileGetter is a function that retrieves any key/value string that exists in the LXD database
// config for this instance. It should only return keys that match the volatile device name prefix,
// and should remove the prefix before being returned.
type VolatileGetter func() map[string]string

// Device represents a device that can be added to an instance.
type Device interface {
	// CanHotPlug returns true if device can be managed whilst instance is running.
	// It also returns a slice of config fields that can be live updated. If only fields in this
	// list have changed then Update() is called rather than triggering a device remove & add.
	CanHotPlug() (bool, []string)

	// Add performs any host-side setup when a device is added to an instance.
	// It is called irrespective of whether the instance is running or not.
	Add() error

	// Start peforms any host-side configuration required to start the device for the instance.
	// This can be when a device is plugged into a running instance or the instance is starting.
	// Returns run-time configuration needed for configuring the instance with the new device.
	Start() (*RunConfig, error)

	// Register provides the ability for a device to subcribe to events that LXD can generate.
	// It is called after a device is started (after Start()) or when LXD starts.
	Register() error

	// Update performs host-side modifications for a device based on the difference between the
	// current config and previous config supplied as an argument. This called if the only
	// config fields that have changed are supplied in the list returned from CanHotPlug().
	// The function also accepts a boolean indicating whether the instance is running or not.
	Update(oldConfig config.Device, running bool) error

	// Stop performs any host-side cleanup required when a device is removed from an instance,
	// either due to unplugging it from a running instance or instance is being shutdown.
	// Returns run-time configuration needed for detaching the device from the instance.
	Stop() (*RunConfig, error)

	// Remove performs any host-side cleanup when an instance is removed from an instance.
	Remove() error
}

// device represents a sealed interface that implements Device, but also contains some internal
// setup functions for a Device that should only be called by device.New() to avoid exposing devices
// that are not in a known configured state. This is separate from the Device interface so that
// Devices created outside of the device package can be used by LXD, but ensures that any devices
// created by the device package will only be accessible after being configured properly by New().
type device interface {
	Device

	// init stores the InstanceIdentifier, daemon State and Config into device and performs any setup.
	init(InstanceIdentifier, *state.State, string, config.Device, VolatileGetter, VolatileSetter)

	// validateConfig checks Config stored by init() is valid for the instance type.
	validateConfig() error
}

// deviceCommon represents the common struct for all devices.
type deviceCommon struct {
	instance    InstanceIdentifier
	name        string
	config      map[string]string
	state       *state.State
	volatileGet func() map[string]string
	volatileSet func(map[string]string) error
}

// init stores the InstanceIdentifier, daemon state, device name and config into device.
// It also needs to be provided with volatile get and set functions for the device to allow
// persistent data to be accessed. This is implemented as part of deviceCommon so that the majority
// of devices don't need to implement it and can just embed deviceCommon.
func (d *deviceCommon) init(instance InstanceIdentifier, state *state.State, name string, conf config.Device, volatileGet VolatileGetter, volatileSet VolatileSetter) {
	d.instance = instance
	d.name = name
	d.config = conf
	d.state = state
	d.volatileGet = volatileGet
	d.volatileSet = volatileSet
}

// Add returns nil error as majority of devices don't need to do any host-side setup.
func (d *deviceCommon) Add() error {
	return nil
}

// Register returns nil error as majority of devices don't need to do any event registration.
func (d *deviceCommon) Register() error {
	return nil
}

// CanHotPlug returns true as majority of devices can be started/stopped when instance is running.
// Also returns an empty list of update fields as most devices do not support live updates.
func (d *deviceCommon) CanHotPlug() (bool, []string) {
	return true, []string{}
}

// Update returns an error as most devices do not support live updates without being restarted.
func (d *deviceCommon) Update(oldConfig config.Device, isRunning bool) error {
	return fmt.Errorf("Device does not support updates whilst started")
}

// Remove returns nil error as majority of devices don't need to do any host-side cleanup on delete.
func (d *deviceCommon) Remove() error {
	return nil
}

// New instantiates a new device struct, validates the supplied config and sets it into the device.
// If the device type is valid, but the other config validation fails then an instantiated device
// is still returned with the validation error. If an unknown device is requested or the device is
// not compatible with the instance type then an ErrUnsupportedDevType error is returned.
func New(instance InstanceIdentifier, state *state.State, name string, conf config.Device, volatileGet VolatileGetter, volatileSet VolatileSetter) (Device, error) {
	devFunc := devTypes[conf["type"]]

	// Check if top-level type is recognised, if it is known type it will return a function.
	if devFunc == nil {
		return nil, ErrUnsupportedDevType
	}

	// Run the device create function and check it succeeds.
	dev := devFunc(conf)
	if dev == nil {
		return nil, ErrUnsupportedDevType
	}

	// Init the device and run validation of supplied config.
	dev.init(instance, state, name, conf, volatileGet, volatileSet)
	err := dev.validateConfig()

	// We still return the instantiated device here, as in some scenarios the caller
	// may still want to use the device (such as when stopping or removing) even if
	// the config validation has failed.
	return dev, err
}
<commit_msg>device: Moves empty device type validation into device package<commit_after>package device

import (
	"fmt"

	"github.com/lxc/lxd/lxd/device/config"
	"github.com/lxc/lxd/lxd/state"
)

// devTypes defines supported top-level device type creation functions.
var devTypes = map[string]func(config.Device) device{
	"nic":        nicLoadByType,
	"infiniband": infinibandLoadByType,
	"proxy":      func(c config.Device) device { return &proxy{} },
	"gpu":        func(c config.Device) device { return &gpu{} },
	"usb":        func(c config.Device) device { return &usb{} },
}

// VolatileSetter is a function that accepts one or more key/value strings to save into the LXD
// config for this instance. It should add the volatile device name prefix to each key when saving.
type VolatileSetter func(map[string]string) error

// VolatileGetter is a function that retrieves any key/value string that exists in the LXD database
// config for this instance. It should only return keys that match the volatile device name prefix,
// and should remove the prefix before being returned.
type VolatileGetter func() map[string]string

// Device represents a device that can be added to an instance.
type Device interface {
	// CanHotPlug returns true if device can be managed whilst instance is running.
	// It also returns a slice of config fields that can be live updated. If only fields in this
	// list have changed then Update() is called rather than triggering a device remove & add.
	CanHotPlug() (bool, []string)

	// Add performs any host-side setup when a device is added to an instance.
	// It is called irrespective of whether the instance is running or not.
	Add() error

	// Start peforms any host-side configuration required to start the device for the instance.
	// This can be when a device is plugged into a running instance or the instance is starting.
	// Returns run-time configuration needed for configuring the instance with the new device.
	Start() (*RunConfig, error)

	// Register provides the ability for a device to subcribe to events that LXD can generate.
	// It is called after a device is started (after Start()) or when LXD starts.
	Register() error

	// Update performs host-side modifications for a device based on the difference between the
	// current config and previous config supplied as an argument. This called if the only
	// config fields that have changed are supplied in the list returned from CanHotPlug().
	// The function also accepts a boolean indicating whether the instance is running or not.
	Update(oldConfig config.Device, running bool) error

	// Stop performs any host-side cleanup required when a device is removed from an instance,
	// either due to unplugging it from a running instance or instance is being shutdown.
	// Returns run-time configuration needed for detaching the device from the instance.
	Stop() (*RunConfig, error)

	// Remove performs any host-side cleanup when an instance is removed from an instance.
	Remove() error
}

// device represents a sealed interface that implements Device, but also contains some internal
// setup functions for a Device that should only be called by device.New() to avoid exposing devices
// that are not in a known configured state. This is separate from the Device interface so that
// Devices created outside of the device package can be used by LXD, but ensures that any devices
// created by the device package will only be accessible after being configured properly by New().
type device interface {
	Device

	// init stores the InstanceIdentifier, daemon State and Config into device and performs any setup.
	init(InstanceIdentifier, *state.State, string, config.Device, VolatileGetter, VolatileSetter)

	// validateConfig checks Config stored by init() is valid for the instance type.
	validateConfig() error
}

// deviceCommon represents the common struct for all devices.
type deviceCommon struct {
	instance    InstanceIdentifier
	name        string
	config      map[string]string
	state       *state.State
	volatileGet func() map[string]string
	volatileSet func(map[string]string) error
}

// init stores the InstanceIdentifier, daemon state, device name and config into device.
// It also needs to be provided with volatile get and set functions for the device to allow
// persistent data to be accessed. This is implemented as part of deviceCommon so that the majority
// of devices don't need to implement it and can just embed deviceCommon.
func (d *deviceCommon) init(instance InstanceIdentifier, state *state.State, name string, conf config.Device, volatileGet VolatileGetter, volatileSet VolatileSetter) {
	d.instance = instance
	d.name = name
	d.config = conf
	d.state = state
	d.volatileGet = volatileGet
	d.volatileSet = volatileSet
}

// Add returns nil error as majority of devices don't need to do any host-side setup.
func (d *deviceCommon) Add() error {
	return nil
}

// Register returns nil error as majority of devices don't need to do any event registration.
func (d *deviceCommon) Register() error {
	return nil
}

// CanHotPlug returns true as majority of devices can be started/stopped when instance is running.
// Also returns an empty list of update fields as most devices do not support live updates.
func (d *deviceCommon) CanHotPlug() (bool, []string) {
	return true, []string{}
}

// Update returns an error as most devices do not support live updates without being restarted.
func (d *deviceCommon) Update(oldConfig config.Device, isRunning bool) error {
	return fmt.Errorf("Device does not support updates whilst started")
}

// Remove returns nil error as majority of devices don't need to do any host-side cleanup on delete.
func (d *deviceCommon) Remove() error {
	return nil
}

// New instantiates a new device struct, validates the supplied config and sets it into the device.
// If the device type is valid, but the other config validation fails then an instantiated device
// is still returned with the validation error. If an unknown device is requested or the device is
// not compatible with the instance type then an ErrUnsupportedDevType error is returned.
func New(instance InstanceIdentifier, state *state.State, name string, conf config.Device, volatileGet VolatileGetter, volatileSet VolatileSetter) (Device, error) {
	if conf["type"] == "" {
		return nil, fmt.Errorf("Missing device type for device '%s'", name)
	}

	devFunc := devTypes[conf["type"]]

	// Check if top-level type is recognised, if it is known type it will return a function.
	if devFunc == nil {
		return nil, ErrUnsupportedDevType
	}

	// Run the device create function and check it succeeds.
	dev := devFunc(conf)
	if dev == nil {
		return nil, ErrUnsupportedDevType
	}

	// Init the device and run validation of supplied config.
	dev.init(instance, state, name, conf, volatileGet, volatileSet)
	err := dev.validateConfig()

	// We still return the instantiated device here, as in some scenarios the caller
	// may still want to use the device (such as when stopping or removing) even if
	// the config validation has failed.
	return dev, err
}
<|endoftext|>


<commit_before>package marathon

import (
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/terraform"
)

func Provider() terraform.ResourceProvider {
	return &schema.Provider{
		Schema: map[string]*schema.Schema{
			"url": &schema.Schema{
				Type:        schema.TypeString,
				Required:    true,
				DefaultFunc: schema.EnvDefaultFunc("MARATHON_URL", nil),
				Description: "Marathon's Base HTTP URL",
			},
			"request_timeout": &schema.Schema{
				Type:        schema.TypeInt,
				Required:    true,
				Default:     10,
				Description: "'Request Timeout",
			},
		},

		ResourcesMap: map[string]*schema.Resource{
			"marathon_app": resourceMarathonApp(),
		},

		ConfigureFunc: providerConfigure,
	}
}

func providerConfigure(d *schema.ResourceData) (interface{}, error) {
	config := Config{
		Url:            d.Get("url").(string),
		RequestTimeout: d.Get("request_timeout").(int),
	}

	if err := config.loadAndValidate(); err != nil {
		return nil, err
	}

	return config.client, nil
}
<commit_msg>fix to optional<commit_after>package marathon

import (
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/terraform"
)

func Provider() terraform.ResourceProvider {
	return &schema.Provider{
		Schema: map[string]*schema.Schema{
			"url": &schema.Schema{
				Type:        schema.TypeString,
				Required:    true,
				DefaultFunc: schema.EnvDefaultFunc("MARATHON_URL", nil),
				Description: "Marathon's Base HTTP URL",
			},
			"request_timeout": &schema.Schema{
				Type:        schema.TypeInt,
				Optional:    true,
				Default:     10,
				Description: "'Request Timeout",
			},
		},

		ResourcesMap: map[string]*schema.Resource{
			"marathon_app": resourceMarathonApp(),
		},

		ConfigureFunc: providerConfigure,
	}
}

func providerConfigure(d *schema.ResourceData) (interface{}, error) {
	config := Config{
		Url:            d.Get("url").(string),
		RequestTimeout: d.Get("request_timeout").(int),
	}

	if err := config.loadAndValidate(); err != nil {
		return nil, err
	}

	return config.client, nil
}
<|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 main

import (
	"encoding/json"
	"errors"
	"fmt"
	"gopkg.in/alecthomas/kingpin.v1"
	"io/ioutil"
	"net/http"
	"org/apache/htrace/common"
	"org/apache/htrace/conf"
	"os"
)

func main() {
	// Load htraced configuration
	cnf := conf.LoadApplicationConfig()

	// Parse argv
	app := kingpin.New("htrace", "The HTrace tracing utility.")
	addr := app.Flag("addr", "Server address.").
		Default(cnf.Get(conf.HTRACE_WEB_ADDRESS)).TCP()
	version := app.Command("version", "Print the version of this program.")
	serverInfo := app.Command("serverInfo", "Print information retrieved from an htraced server.")
	findSpan := app.Command("findSpan", "Print information about a trace span with a given ID.")
	findSpanId := findSpan.Flag("id", "Span ID to find, as a signed decimal 64-bit "+
		"number").Required().Int64()
	findChildren := app.Command("findChildren", "Print out the span IDs that are children of a given span ID.")
	parentSpanId := findChildren.Flag("id", "Span ID to print children for, as a signed decimal 64-bit "+
		"number").Required().Int64()
	childLim := findChildren.Flag("lim", "Maximum number of child IDs to print.").Default("20").Int()

	// Handle operation
	switch kingpin.MustParse(app.Parse(os.Args[1:])) {
	case version.FullCommand():
		os.Exit(printVersion())
	case serverInfo.FullCommand():
		os.Exit(printServerInfo(addr.String()))
	case findSpan.FullCommand():
		os.Exit(doFindSpan(addr.String(), *findSpanId))
	case findChildren.FullCommand():
		os.Exit(doFindChildren(addr.String(), *parentSpanId, *childLim))
	}

	app.UsageErrorf(os.Stderr, "You must supply a command to run.")
}

// Print the version of the htrace binary.
func printVersion() int {
	fmt.Printf("Running htrace command version %s.\n", common.RELEASE_VERSION)
	return 0
}

// Print information retrieved from an htraced server via /serverInfo
func printServerInfo(restAddr string) int {
	buf, err := makeRestRequest(restAddr, "serverInfo")
	if err != nil {
		fmt.Printf("%s\n", err.Error())
		return 1
	}
	var info common.ServerInfo
	err = json.Unmarshal(buf, &info)
	if err != nil {
		fmt.Printf("Error: error unmarshalling response body %s: %s\n",
			string(buf), err.Error())
		return 1
	}
	fmt.Printf("HTraced server version %s\n", info.Version)
	return 0
}

// Print information about a trace span.
func doFindSpan(restAddr string, sid int64) int {
	buf, err := makeRestRequest(restAddr, fmt.Sprintf("findSid?sid=%016x", sid))
	if err != nil {
		fmt.Printf("%s\n", err.Error())
		return 1
	}
	var span common.Span
	err = json.Unmarshal(buf, &span)
	if err != nil {
		fmt.Printf("Error: error unmarshalling response body %s: %s\n",
			string(buf), err.Error())
		return 1
	}
	pbuf, err := json.MarshalIndent(span, "", "  ")
	if err != nil {
		fmt.Println("Error: error pretty-printing span to JSON: %s", err.Error())
		return 1
	}
	fmt.Printf("%s\n", string(pbuf))
	return 0
}

// Find information about the children of a span.
func doFindChildren(restAddr string, sid int64, lim int) int {
	buf, err := makeRestRequest(restAddr, fmt.Sprintf("findChildren?sid=%016x&lim=%d", sid, lim))
	if err != nil {
		fmt.Printf("%s\n", err.Error())
		return 1
	}
	var spanIds []int64
	err = json.Unmarshal(buf, &spanIds)
	if err != nil {
		fmt.Printf("Error: error unmarshalling response body %s: %s\n",
			string(buf), err.Error())
		return 1
	}
	pbuf, err := json.MarshalIndent(spanIds, "", "  ")
	if err != nil {
		fmt.Println("Error: error pretty-printing span IDs to JSON: %s", err.Error())
		return 1
	}
	fmt.Printf("%s\n", string(pbuf))
	return 0
}

// Print information retrieved from an htraced server via /serverInfo
func makeRestRequest(restAddr string, reqName string) ([]byte, error) {
	url := fmt.Sprintf("http://%s/%s", restAddr, reqName)
	req, err := http.NewRequest("GET", url, nil)
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return nil, errors.New(fmt.Sprintf("Error: error making http request to %s: %s\n", url,
			err.Error()))
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		return nil, errors.New(fmt.Sprintf("Error: got bad response status from %s: %s\n", url, resp.Status))
	}
	var body []byte
	body, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, errors.New(fmt.Sprintf("Error: error reading response body: %s\n", err.Error()))
	}
	return body, nil
}
<commit_msg>HTRACE-39. Fix compilation of cmd.go on go 1.4 (Masatake Iwasaki via Colin P. McCabe)<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 main

import (
	"encoding/json"
	"errors"
	"fmt"
	"gopkg.in/alecthomas/kingpin.v1"
	"io/ioutil"
	"net/http"
	"org/apache/htrace/common"
	"org/apache/htrace/conf"
	"os"
)

func main() {
	// Load htraced configuration
	cnf := conf.LoadApplicationConfig()

	// Parse argv
	app := kingpin.New("htrace", "The HTrace tracing utility.")
	addr := app.Flag("addr", "Server address.").
		Default(cnf.Get(conf.HTRACE_WEB_ADDRESS)).TCP()
	version := app.Command("version", "Print the version of this program.")
	serverInfo := app.Command("serverInfo", "Print information retrieved from an htraced server.")
	findSpan := app.Command("findSpan", "Print information about a trace span with a given ID.")
	findSpanId := findSpan.Flag("id", "Span ID to find, as a signed decimal 64-bit "+
		"number").Required().Int64()
	findChildren := app.Command("findChildren", "Print out the span IDs that are children of a given span ID.")
	parentSpanId := findChildren.Flag("id", "Span ID to print children for, as a signed decimal 64-bit "+
		"number").Required().Int64()
	childLim := findChildren.Flag("lim", "Maximum number of child IDs to print.").Default("20").Int()

	// Handle operation
	switch kingpin.MustParse(app.Parse(os.Args[1:])) {
	case version.FullCommand():
		os.Exit(printVersion())
	case serverInfo.FullCommand():
		os.Exit(printServerInfo((*addr).String()))
	case findSpan.FullCommand():
		os.Exit(doFindSpan((*addr).String(), *findSpanId))
	case findChildren.FullCommand():
		os.Exit(doFindChildren((*addr).String(), *parentSpanId, *childLim))
	}

	app.UsageErrorf(os.Stderr, "You must supply a command to run.")
}

// Print the version of the htrace binary.
func printVersion() int {
	fmt.Printf("Running htrace command version %s.\n", common.RELEASE_VERSION)
	return 0
}

// Print information retrieved from an htraced server via /serverInfo
func printServerInfo(restAddr string) int {
	buf, err := makeRestRequest(restAddr, "serverInfo")
	if err != nil {
		fmt.Printf("%s\n", err.Error())
		return 1
	}
	var info common.ServerInfo
	err = json.Unmarshal(buf, &info)
	if err != nil {
		fmt.Printf("Error: error unmarshalling response body %s: %s\n",
			string(buf), err.Error())
		return 1
	}
	fmt.Printf("HTraced server version %s\n", info.Version)
	return 0
}

// Print information about a trace span.
func doFindSpan(restAddr string, sid int64) int {
	buf, err := makeRestRequest(restAddr, fmt.Sprintf("findSid?sid=%016x", sid))
	if err != nil {
		fmt.Printf("%s\n", err.Error())
		return 1
	}
	var span common.Span
	err = json.Unmarshal(buf, &span)
	if err != nil {
		fmt.Printf("Error: error unmarshalling response body %s: %s\n",
			string(buf), err.Error())
		return 1
	}
	pbuf, err := json.MarshalIndent(span, "", "  ")
	if err != nil {
		fmt.Println("Error: error pretty-printing span to JSON: %s", err.Error())
		return 1
	}
	fmt.Printf("%s\n", string(pbuf))
	return 0
}

// Find information about the children of a span.
func doFindChildren(restAddr string, sid int64, lim int) int {
	buf, err := makeRestRequest(restAddr, fmt.Sprintf("findChildren?sid=%016x&lim=%d", sid, lim))
	if err != nil {
		fmt.Printf("%s\n", err.Error())
		return 1
	}
	var spanIds []int64
	err = json.Unmarshal(buf, &spanIds)
	if err != nil {
		fmt.Printf("Error: error unmarshalling response body %s: %s\n",
			string(buf), err.Error())
		return 1
	}
	pbuf, err := json.MarshalIndent(spanIds, "", "  ")
	if err != nil {
		fmt.Println("Error: error pretty-printing span IDs to JSON: %s", err.Error())
		return 1
	}
	fmt.Printf("%s\n", string(pbuf))
	return 0
}

// Print information retrieved from an htraced server via /serverInfo
func makeRestRequest(restAddr string, reqName string) ([]byte, error) {
	url := fmt.Sprintf("http://%s/%s", restAddr, reqName)
	req, err := http.NewRequest("GET", url, nil)
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return nil, errors.New(fmt.Sprintf("Error: error making http request to %s: %s\n", url,
			err.Error()))
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		return nil, errors.New(fmt.Sprintf("Error: got bad response status from %s: %s\n", url, resp.Status))
	}
	var body []byte
	body, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, errors.New(fmt.Sprintf("Error: error reading response body: %s\n", err.Error()))
	}
	return body, nil
}
<|endoftext|>


<commit_before>package main

import (
	log "github.com/Sirupsen/logrus"
	"github.com/grokify/webhook-proxy-go"
	"github.com/grokify/webhook-proxy-go/src/config"
)

func main() {
	cfg := config.Configuration{
		Port:           8080,
		EmojiURLFormat: "https://grokify.github.io/emoji/assets/images/%s.png",
		LogLevel:       log.DebugLevel}

	webhookproxy.StartServer(cfg)
}
<commit_msg>remove extra file<commit_after><|endoftext|>


<commit_before>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package ecdsa implements the Elliptic Curve Digital Signature Algorithm, as
// defined in FIPS 186-3.
//
// This implementation  derives the nonce from an AES-CTR CSPRNG keyed by
// ChopMD(256, SHA2-512(priv.D || entropy || hash)). The CSPRNG key is IRO by
// a result of Coron; the AES-CTR stream is IRO under standard assumptions.
package ecdsa

// References:
//   [NSA]: Suite B implementer's guide to FIPS 186-3,
//     http://www.nsa.gov/ia/_files/ecdsa.pdf
//   [SECG]: SECG, SEC1
//     http://www.secg.org/sec1-v2.pdf

import (
	"crypto"
	"crypto/aes"
	"crypto/cipher"
	"crypto/elliptic"
	"crypto/sha512"
	"encoding/asn1"
	"errors"
	"io"
	"math/big"
)

// A invertible implements fast inverse mod Curve.Params().N
type invertible interface {
	// Inverse returns the inverse of k in GF(P)
	Inverse(k *big.Int) *big.Int
}

// combinedMult implements fast multiplication S1*g + S2*p (g - generator, p - arbitrary point)
type combinedMult interface {
	CombinedMult(bigX, bigY *big.Int, baseScalar, scalar []byte) (x, y *big.Int)
}

const (
	aesIV = "IV for ECDSA CTR"
)

// PublicKey represents an ECDSA public key.
type PublicKey struct {
	elliptic.Curve
	X, Y *big.Int
}

// PrivateKey represents a ECDSA private key.
type PrivateKey struct {
	PublicKey
	D *big.Int
}

type ecdsaSignature struct {
	R, S *big.Int
}

// Public returns the public key corresponding to priv.
func (priv *PrivateKey) Public() crypto.PublicKey {
	return &priv.PublicKey
}

// Sign signs msg with priv, reading randomness from rand. This method is
// intended to support keys where the private part is kept in, for example, a
// hardware module. Common uses should use the Sign function in this package
// directly.
func (priv *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ([]byte, error) {
	r, s, err := Sign(rand, priv, msg)
	if err != nil {
		return nil, err
	}

	return asn1.Marshal(ecdsaSignature{r, s})
}

var one = new(big.Int).SetInt64(1)

// randFieldElement returns a random element of the field underlying the given
// curve using the procedure given in [NSA] A.2.1.
func randFieldElement(c elliptic.Curve, rand io.Reader) (k *big.Int, err error) {
	params := c.Params()
	b := make([]byte, params.BitSize/8+8)
	_, err = io.ReadFull(rand, b)
	if err != nil {
		return
	}

	k = new(big.Int).SetBytes(b)
	n := new(big.Int).Sub(params.N, one)
	k.Mod(k, n)
	k.Add(k, one)
	return
}

// GenerateKey generates a public and private key pair.
func GenerateKey(c elliptic.Curve, rand io.Reader) (*PrivateKey, error) {
	k, err := randFieldElement(c, rand)
	if err != nil {
		return nil, err
	}

	priv := new(PrivateKey)
	priv.PublicKey.Curve = c
	priv.D = k
	priv.PublicKey.X, priv.PublicKey.Y = c.ScalarBaseMult(k.Bytes())
	return priv, nil
}

// hashToInt converts a hash value to an integer. There is some disagreement
// about how this is done. [NSA] suggests that this is done in the obvious
// manner, but [SECG] truncates the hash to the bit-length of the curve order
// first. We follow [SECG] because that's what OpenSSL does. Additionally,
// OpenSSL right shifts excess bits from the number if the hash is too large
// and we mirror that too.
func hashToInt(hash []byte, c elliptic.Curve) *big.Int {
	orderBits := c.Params().N.BitLen()
	orderBytes := (orderBits + 7) / 8
	if len(hash) > orderBytes {
		hash = hash[:orderBytes]
	}

	ret := new(big.Int).SetBytes(hash)
	excess := len(hash)*8 - orderBits
	if excess > 0 {
		ret.Rsh(ret, uint(excess))
	}
	return ret
}

// fermatInverse calculates the inverse of k in GF(P) using Fermat's method.
// This has better constant-time properties than Euclid's method (implemented
// in math/big.Int.ModInverse) although math/big itself isn't strictly
// constant-time so it's not perfect.
func fermatInverse(k, N *big.Int) *big.Int {
	two := big.NewInt(2)
	nMinus2 := new(big.Int).Sub(N, two)
	return new(big.Int).Exp(k, nMinus2, N)
}

var errZeroParam = errors.New("zero parameter")

// Sign signs an arbitrary length hash (which should be the result of hashing a
// larger message) using the private key, priv. It returns the signature as a
// pair of integers. The security of the private key depends on the entropy of
// rand.
func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
	// Get max(log2(q) / 2, 256) bits of entropy from rand.
	entropylen := (priv.Curve.Params().BitSize + 7) / 16
	if entropylen > 32 {
		entropylen = 32
	}
	entropy := make([]byte, entropylen)
	_, err = io.ReadFull(rand, entropy)
	if err != nil {
		return
	}

	// Initialize an SHA-512 hash context; digest ...
	md := sha512.New()
	md.Write(priv.D.Bytes()) // the private key,
	md.Write(entropy)        // the entropy,
	md.Write(hash)           // and the input hash;
	key := md.Sum(nil)[:32]  // and compute ChopMD-256(SHA-512),
	// which is an indifferentiable MAC.

	// Create an AES-CTR instance to use as a CSPRNG.
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, nil, err
	}

	// Create a CSPRNG that xors a stream of zeros with
	// the output of the AES-CTR instance.
	csprng := cipher.StreamReader{
		R: zeroReader,
		S: cipher.NewCTR(block, []byte(aesIV)),
	}

	// See [NSA] 3.4.1
	c := priv.PublicKey.Curve
	N := c.Params().N
	if N.Sign() == 0 {
		return nil, nil, errZeroParam
	}
	var k, kInv *big.Int
	for {
		for {
			k, err = randFieldElement(c, csprng)
			if err != nil {
				r = nil
				return
			}

			if in, ok := priv.Curve.(invertible); ok {
				kInv = in.Inverse(k)
			} else {
				kInv = fermatInverse(k, N) // N != 0
			}

			r, _ = priv.Curve.ScalarBaseMult(k.Bytes())
			r.Mod(r, N)
			if r.Sign() != 0 {
				break
			}
		}

		e := hashToInt(hash, c)
		s = new(big.Int).Mul(priv.D, r)
		s.Add(s, e)
		s.Mul(s, kInv)
		s.Mod(s, N) // N != 0
		if s.Sign() != 0 {
			break
		}
	}

	return
}

// Verify verifies the signature in r, s of hash using the public key, pub. Its
// return value records whether the signature is valid.
func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
	// See [NSA] 3.4.2
	c := pub.Curve
	N := c.Params().N

	if r.Sign() <= 0 || s.Sign() <= 0 {
		return false
	}
	if r.Cmp(N) >= 0 || s.Cmp(N) >= 0 {
		return false
	}
	e := hashToInt(hash, c)

	var w *big.Int
	if in, ok := c.(invertible); ok {
		w = in.Inverse(s)
	} else {
		w = new(big.Int).ModInverse(s, N)
	}

	u1 := e.Mul(e, w)
	u1.Mod(u1, N)
	u2 := w.Mul(r, w)
	u2.Mod(u2, N)

	// Check if implements S1*g + S2*p
	var x, y *big.Int
	if opt, ok := c.(combinedMult); ok {
		x, y = opt.CombinedMult(pub.X, pub.Y, u1.Bytes(), u2.Bytes())
	} else {
		x1, y1 := c.ScalarBaseMult(u1.Bytes())
		x2, y2 := c.ScalarMult(pub.X, pub.Y, u2.Bytes())
		x, y = c.Add(x1, y1, x2, y2)
	}

	if x.Sign() == 0 && y.Sign() == 0 {
		return false
	}
	x.Mod(x, N)
	return x.Cmp(r) == 0
}

type zr struct {
	io.Reader
}

// Read replaces the contents of dst with zeros.
func (z *zr) Read(dst []byte) (n int, err error) {
	for i := range dst {
		dst[i] = 0
	}
	return len(dst), nil
}

var zeroReader = &zr{}
<commit_msg>crypto/ecdsa: Update documentation for Sign<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package ecdsa implements the Elliptic Curve Digital Signature Algorithm, as
// defined in FIPS 186-3.
//
// This implementation  derives the nonce from an AES-CTR CSPRNG keyed by
// ChopMD(256, SHA2-512(priv.D || entropy || hash)). The CSPRNG key is IRO by
// a result of Coron; the AES-CTR stream is IRO under standard assumptions.
package ecdsa

// References:
//   [NSA]: Suite B implementer's guide to FIPS 186-3,
//     http://www.nsa.gov/ia/_files/ecdsa.pdf
//   [SECG]: SECG, SEC1
//     http://www.secg.org/sec1-v2.pdf

import (
	"crypto"
	"crypto/aes"
	"crypto/cipher"
	"crypto/elliptic"
	"crypto/sha512"
	"encoding/asn1"
	"errors"
	"io"
	"math/big"
)

// A invertible implements fast inverse mod Curve.Params().N
type invertible interface {
	// Inverse returns the inverse of k in GF(P)
	Inverse(k *big.Int) *big.Int
}

// combinedMult implements fast multiplication S1*g + S2*p (g - generator, p - arbitrary point)
type combinedMult interface {
	CombinedMult(bigX, bigY *big.Int, baseScalar, scalar []byte) (x, y *big.Int)
}

const (
	aesIV = "IV for ECDSA CTR"
)

// PublicKey represents an ECDSA public key.
type PublicKey struct {
	elliptic.Curve
	X, Y *big.Int
}

// PrivateKey represents a ECDSA private key.
type PrivateKey struct {
	PublicKey
	D *big.Int
}

type ecdsaSignature struct {
	R, S *big.Int
}

// Public returns the public key corresponding to priv.
func (priv *PrivateKey) Public() crypto.PublicKey {
	return &priv.PublicKey
}

// Sign signs msg with priv, reading randomness from rand. This method is
// intended to support keys where the private part is kept in, for example, a
// hardware module. Common uses should use the Sign function in this package
// directly.
func (priv *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ([]byte, error) {
	r, s, err := Sign(rand, priv, msg)
	if err != nil {
		return nil, err
	}

	return asn1.Marshal(ecdsaSignature{r, s})
}

var one = new(big.Int).SetInt64(1)

// randFieldElement returns a random element of the field underlying the given
// curve using the procedure given in [NSA] A.2.1.
func randFieldElement(c elliptic.Curve, rand io.Reader) (k *big.Int, err error) {
	params := c.Params()
	b := make([]byte, params.BitSize/8+8)
	_, err = io.ReadFull(rand, b)
	if err != nil {
		return
	}

	k = new(big.Int).SetBytes(b)
	n := new(big.Int).Sub(params.N, one)
	k.Mod(k, n)
	k.Add(k, one)
	return
}

// GenerateKey generates a public and private key pair.
func GenerateKey(c elliptic.Curve, rand io.Reader) (*PrivateKey, error) {
	k, err := randFieldElement(c, rand)
	if err != nil {
		return nil, err
	}

	priv := new(PrivateKey)
	priv.PublicKey.Curve = c
	priv.D = k
	priv.PublicKey.X, priv.PublicKey.Y = c.ScalarBaseMult(k.Bytes())
	return priv, nil
}

// hashToInt converts a hash value to an integer. There is some disagreement
// about how this is done. [NSA] suggests that this is done in the obvious
// manner, but [SECG] truncates the hash to the bit-length of the curve order
// first. We follow [SECG] because that's what OpenSSL does. Additionally,
// OpenSSL right shifts excess bits from the number if the hash is too large
// and we mirror that too.
func hashToInt(hash []byte, c elliptic.Curve) *big.Int {
	orderBits := c.Params().N.BitLen()
	orderBytes := (orderBits + 7) / 8
	if len(hash) > orderBytes {
		hash = hash[:orderBytes]
	}

	ret := new(big.Int).SetBytes(hash)
	excess := len(hash)*8 - orderBits
	if excess > 0 {
		ret.Rsh(ret, uint(excess))
	}
	return ret
}

// fermatInverse calculates the inverse of k in GF(P) using Fermat's method.
// This has better constant-time properties than Euclid's method (implemented
// in math/big.Int.ModInverse) although math/big itself isn't strictly
// constant-time so it's not perfect.
func fermatInverse(k, N *big.Int) *big.Int {
	two := big.NewInt(2)
	nMinus2 := new(big.Int).Sub(N, two)
	return new(big.Int).Exp(k, nMinus2, N)
}

var errZeroParam = errors.New("zero parameter")

// Sign signs a hash (which should be the result of hashing a larger message)
// using the private key, priv. If the hash is longer than the bit-length of the
// private key's curve order, the hash will be truncated to that length.  It
// returns the signature as a pair of integers. The security of the private key
// depends on the entropy of rand.
func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
	// Get max(log2(q) / 2, 256) bits of entropy from rand.
	entropylen := (priv.Curve.Params().BitSize + 7) / 16
	if entropylen > 32 {
		entropylen = 32
	}
	entropy := make([]byte, entropylen)
	_, err = io.ReadFull(rand, entropy)
	if err != nil {
		return
	}

	// Initialize an SHA-512 hash context; digest ...
	md := sha512.New()
	md.Write(priv.D.Bytes()) // the private key,
	md.Write(entropy)        // the entropy,
	md.Write(hash)           // and the input hash;
	key := md.Sum(nil)[:32]  // and compute ChopMD-256(SHA-512),
	// which is an indifferentiable MAC.

	// Create an AES-CTR instance to use as a CSPRNG.
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, nil, err
	}

	// Create a CSPRNG that xors a stream of zeros with
	// the output of the AES-CTR instance.
	csprng := cipher.StreamReader{
		R: zeroReader,
		S: cipher.NewCTR(block, []byte(aesIV)),
	}

	// See [NSA] 3.4.1
	c := priv.PublicKey.Curve
	N := c.Params().N
	if N.Sign() == 0 {
		return nil, nil, errZeroParam
	}
	var k, kInv *big.Int
	for {
		for {
			k, err = randFieldElement(c, csprng)
			if err != nil {
				r = nil
				return
			}

			if in, ok := priv.Curve.(invertible); ok {
				kInv = in.Inverse(k)
			} else {
				kInv = fermatInverse(k, N) // N != 0
			}

			r, _ = priv.Curve.ScalarBaseMult(k.Bytes())
			r.Mod(r, N)
			if r.Sign() != 0 {
				break
			}
		}

		e := hashToInt(hash, c)
		s = new(big.Int).Mul(priv.D, r)
		s.Add(s, e)
		s.Mul(s, kInv)
		s.Mod(s, N) // N != 0
		if s.Sign() != 0 {
			break
		}
	}

	return
}

// Verify verifies the signature in r, s of hash using the public key, pub. Its
// return value records whether the signature is valid.
func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
	// See [NSA] 3.4.2
	c := pub.Curve
	N := c.Params().N

	if r.Sign() <= 0 || s.Sign() <= 0 {
		return false
	}
	if r.Cmp(N) >= 0 || s.Cmp(N) >= 0 {
		return false
	}
	e := hashToInt(hash, c)

	var w *big.Int
	if in, ok := c.(invertible); ok {
		w = in.Inverse(s)
	} else {
		w = new(big.Int).ModInverse(s, N)
	}

	u1 := e.Mul(e, w)
	u1.Mod(u1, N)
	u2 := w.Mul(r, w)
	u2.Mod(u2, N)

	// Check if implements S1*g + S2*p
	var x, y *big.Int
	if opt, ok := c.(combinedMult); ok {
		x, y = opt.CombinedMult(pub.X, pub.Y, u1.Bytes(), u2.Bytes())
	} else {
		x1, y1 := c.ScalarBaseMult(u1.Bytes())
		x2, y2 := c.ScalarMult(pub.X, pub.Y, u2.Bytes())
		x, y = c.Add(x1, y1, x2, y2)
	}

	if x.Sign() == 0 && y.Sign() == 0 {
		return false
	}
	x.Mod(x, N)
	return x.Cmp(r) == 0
}

type zr struct {
	io.Reader
}

// Read replaces the contents of dst with zeros.
func (z *zr) Read(dst []byte) (n int, err error) {
	for i := range dst {
		dst[i] = 0
	}
	return len(dst), nil
}

var zeroReader = &zr{}
<|endoftext|>


<commit_before>package main

import (
	"encoding/hex"
	"errors"
	"fmt"
	"github.com/uavionix/serial"
	"log"
	"unsafe"
)

/*

#cgo LDFLAGS: -ldump978

#include <stdint.h>
#include "../dump978/fec.h"

*/
import "C"

var radioSerialConfig *serial.Config
var radioSerialPort *serial.Port

func initUATRadioSerial() error {
	// Init for FEC routines.
	C.init_fec()
	// Initialize port at 2Mbaud.
	radioSerialConfig = &serial.Config{Name: "/dev/uatradio", Baud: 2000000}
	p, err := serial.OpenPort(radioSerialConfig)
	if err != nil {
		log.Printf("serial port err: %s\n", err.Error())
		return errors.New("serial port failed to initialize")
	}

	radioSerialPort = p

	// Start a goroutine to watch the serial port.
	go radioSerialPortReader()
	return nil
}

/*
	radioSerialPortReader().
	 Loop to read data from the radio serial port.
*/
var radioMagic = []byte{0x0a, 0xb0, 0xcd, 0xe0}

func radioSerialPortReader() {
	tmpBuf := make([]byte, 1024) // Read buffer.
	var buf []byte               // Message buffer.
	if radioSerialPort == nil {
		return
	}
	defer radioSerialPort.Close()
	for {
		n, err := radioSerialPort.Read(tmpBuf)
		if err != nil {
			log.Printf("serial port err, shutting down radio: %s\n", err.Error())
			return
		}
		buf = append(buf, tmpBuf[:n]...)
		bufLen := len(buf)
		var finBuf []byte   // Truncated buffer, with processed messages extracted.
		var numMessages int // Number of messages extracted.
		// Search for a suitable message to extract.
		for i := 0; i < bufLen-6; i++ {
			if (buf[i] == radioMagic[0]) && (buf[i+1] == radioMagic[1]) && (buf[i+2] == radioMagic[2]) && (buf[i+3] == radioMagic[3]) {
				// Found the magic sequence. Get the length.
				msgLen := int(uint16(buf[i+4])+(uint16(buf[i+5])<<8)) + 5 // 5 bytes for RSSI and TS.
				// Check if we've read enough to finish this message.
				if bufLen < i+6+msgLen {
					break // Wait for more of the message to come in.
				}
				// Message is long enough.
				processRadioMessage(buf[i+6 : i+6+msgLen])
				// Remove everything in the buffer before this message.
				finBuf = buf[i+6+msgLen:]
				numMessages++
			}
		}
		if numMessages > 0 {
			buf = finBuf
		}
	}
}

/*
	processRadioMessage().
	 Processes a single message from the radio. De-interleaves (when necessary), checks Reed-Solomon, passes to main process.
*/

func processRadioMessage(msg []byte) {
	log.Printf("processRadioMessage(): %d %s\n", len(msg), hex.EncodeToString(msg))

	// RSSI and message timestamp are prepended to the actual packet.

	// RSSI
	rssiRaw := int8(msg[0])
	//rssiAdjusted := int16(rssiRaw) - 132 // -132 dBm, calculated minimum RSSI.
	//rssiDump978 := int16(1000 * (10 ^ (float64(rssiAdjusted) / 20)))
	rssiDump978 := rssiRaw

	//_ := uint32(msg[1]) + (uint32(msg[2]) << 8) + (uint32(msg[3]) << 16) + (uint32(msg[4]) << 24) // Timestamp. Currently unused.

	msg = msg[5:]

	var toRelay string
	switch len(msg) {
	case 552:
		to := make([]byte, 552)
		var rs_errors int
		i := int(C.correct_uplink_frame((*C.uint8_t)(unsafe.Pointer(&msg[0])), (*C.uint8_t)(unsafe.Pointer(&to[0])), (*C.int)(unsafe.Pointer(&rs_errors))))
		toRelay = fmt.Sprintf("+%s;ss=%d;", hex.EncodeToString(to[:432]), rssiDump978)
		log.Printf("i=%d, rs_errors=%d, msg=%s\n", i, rs_errors, toRelay)
	case 48:
		to := make([]byte, 48)
		copy(to, msg)
		var rs_errors int
		i := int(C.correct_adsb_frame((*C.uint8_t)(unsafe.Pointer(&to[0])), (*C.int)(unsafe.Pointer(&rs_errors))))
		if i == 1 {
			// Short ADS-B frame.
			toRelay = fmt.Sprintf("-%s;ss=%d;", hex.EncodeToString(to[:18]), rssiDump978)
			log.Printf("i=%d, rs_errors=%d, msg=%s\n", i, rs_errors, toRelay)
		} else if i == 2 {
			// Long ADS-B frame.
			toRelay = fmt.Sprintf("-%s;ss=%d;", hex.EncodeToString(to[:34]), rssiDump978)
			log.Printf("i=%d, rs_errors=%d, msg=%s\n", i, rs_errors, toRelay)
		} else {
			log.Printf("i=%d, rs_errors=%d, msg=%s\n", i, rs_errors, hex.EncodeToString(to))
		}
	default:
		log.Printf("processRadioMessage(): unhandled message size %d\n", len(msg))
	}

	if len(toRelay) > 0 && rs_errors != 9999 {
		o, msgtype := parseInput(toRelay)
		if o != nil && msgtype != 0 {
			relayMessage(msgtype, o)
		}
	}
}
<commit_msg>Scope error fix.<commit_after>package main

import (
	"encoding/hex"
	"errors"
	"fmt"
	"github.com/uavionix/serial"
	"log"
	"unsafe"
)

/*

#cgo LDFLAGS: -ldump978

#include <stdint.h>
#include "../dump978/fec.h"

*/
import "C"

var radioSerialConfig *serial.Config
var radioSerialPort *serial.Port

func initUATRadioSerial() error {
	// Init for FEC routines.
	C.init_fec()
	// Initialize port at 2Mbaud.
	radioSerialConfig = &serial.Config{Name: "/dev/uatradio", Baud: 2000000}
	p, err := serial.OpenPort(radioSerialConfig)
	if err != nil {
		log.Printf("serial port err: %s\n", err.Error())
		return errors.New("serial port failed to initialize")
	}

	radioSerialPort = p

	// Start a goroutine to watch the serial port.
	go radioSerialPortReader()
	return nil
}

/*
	radioSerialPortReader().
	 Loop to read data from the radio serial port.
*/
var radioMagic = []byte{0x0a, 0xb0, 0xcd, 0xe0}

func radioSerialPortReader() {
	tmpBuf := make([]byte, 1024) // Read buffer.
	var buf []byte               // Message buffer.
	if radioSerialPort == nil {
		return
	}
	defer radioSerialPort.Close()
	for {
		n, err := radioSerialPort.Read(tmpBuf)
		if err != nil {
			log.Printf("serial port err, shutting down radio: %s\n", err.Error())
			return
		}
		buf = append(buf, tmpBuf[:n]...)
		bufLen := len(buf)
		var finBuf []byte   // Truncated buffer, with processed messages extracted.
		var numMessages int // Number of messages extracted.
		// Search for a suitable message to extract.
		for i := 0; i < bufLen-6; i++ {
			if (buf[i] == radioMagic[0]) && (buf[i+1] == radioMagic[1]) && (buf[i+2] == radioMagic[2]) && (buf[i+3] == radioMagic[3]) {
				// Found the magic sequence. Get the length.
				msgLen := int(uint16(buf[i+4])+(uint16(buf[i+5])<<8)) + 5 // 5 bytes for RSSI and TS.
				// Check if we've read enough to finish this message.
				if bufLen < i+6+msgLen {
					break // Wait for more of the message to come in.
				}
				// Message is long enough.
				processRadioMessage(buf[i+6 : i+6+msgLen])
				// Remove everything in the buffer before this message.
				finBuf = buf[i+6+msgLen:]
				numMessages++
			}
		}
		if numMessages > 0 {
			buf = finBuf
		}
	}
}

/*
	processRadioMessage().
	 Processes a single message from the radio. De-interleaves (when necessary), checks Reed-Solomon, passes to main process.
*/

func processRadioMessage(msg []byte) {
	log.Printf("processRadioMessage(): %d %s\n", len(msg), hex.EncodeToString(msg))

	// RSSI and message timestamp are prepended to the actual packet.

	// RSSI
	rssiRaw := int8(msg[0])
	//rssiAdjusted := int16(rssiRaw) - 132 // -132 dBm, calculated minimum RSSI.
	//rssiDump978 := int16(1000 * (10 ^ (float64(rssiAdjusted) / 20)))
	rssiDump978 := rssiRaw

	//_ := uint32(msg[1]) + (uint32(msg[2]) << 8) + (uint32(msg[3]) << 16) + (uint32(msg[4]) << 24) // Timestamp. Currently unused.

	msg = msg[5:]

	var toRelay string
	var rs_errors int
	switch len(msg) {
	case 552:
		to := make([]byte, 552)
		i := int(C.correct_uplink_frame((*C.uint8_t)(unsafe.Pointer(&msg[0])), (*C.uint8_t)(unsafe.Pointer(&to[0])), (*C.int)(unsafe.Pointer(&rs_errors))))
		toRelay = fmt.Sprintf("+%s;ss=%d;", hex.EncodeToString(to[:432]), rssiDump978)
		log.Printf("i=%d, rs_errors=%d, msg=%s\n", i, rs_errors, toRelay)
	case 48:
		to := make([]byte, 48)
		copy(to, msg)
		i := int(C.correct_adsb_frame((*C.uint8_t)(unsafe.Pointer(&to[0])), (*C.int)(unsafe.Pointer(&rs_errors))))
		if i == 1 {
			// Short ADS-B frame.
			toRelay = fmt.Sprintf("-%s;ss=%d;", hex.EncodeToString(to[:18]), rssiDump978)
			log.Printf("i=%d, rs_errors=%d, msg=%s\n", i, rs_errors, toRelay)
		} else if i == 2 {
			// Long ADS-B frame.
			toRelay = fmt.Sprintf("-%s;ss=%d;", hex.EncodeToString(to[:34]), rssiDump978)
			log.Printf("i=%d, rs_errors=%d, msg=%s\n", i, rs_errors, toRelay)
		} else {
			log.Printf("i=%d, rs_errors=%d, msg=%s\n", i, rs_errors, hex.EncodeToString(to))
		}
	default:
		log.Printf("processRadioMessage(): unhandled message size %d\n", len(msg))
	}

	if len(toRelay) > 0 && rs_errors != 9999 {
		o, msgtype := parseInput(toRelay)
		if o != nil && msgtype != 0 {
			relayMessage(msgtype, o)
		}
	}
}
<|endoftext|>


<commit_before>package api

import (
	"socialapi/models"
	"socialapi/workers/common/handler"
	"socialapi/workers/common/mux"

	"github.com/koding/metrics"
)

func AddHandlers(m *mux.Mux, metric *metrics.Metrics) {
	m.AddHandler(
		handler.Request{
			Handler:  CreateLink,
			Name:     models.ModerationChannelCreateLink,
			Type:     handler.PostRequest,
			Endpoint: "/moderation/channel/{rootId}/link",
			Metrics:  metric,
		},
	)

	m.AddHandler(
		handler.Request{
			Handler:  GetLinks,
			Name:     models.ModerationChannelGetLink,
			Type:     handler.GetRequest,
			Endpoint: "/moderation/channel/{rootId}/link",
			Metrics:  metric,
		},
	)

	m.AddHandler(
		handler.Request{
			Handler:  Blacklist,
			Name:     models.ModerationChannelDeleteLink,
			Type:     handler.PostRequest,
			Endpoint: "/moderation/channel/blacklist",
			Metrics:  metric,
		},
	)

	m.AddHandler(
		handler.Request{
			Handler:  DeleteLink,
			Name:     models.ModerationChannelDeleteLink,
			Type:     handler.DeleteRequest,
			Endpoint: "/moderation/channel/{leafId}",
			Metrics:  metric,
		},
	)
}
<commit_msg>socialapi: remove unnecessary handler definition<commit_after>package api

import (
	"socialapi/models"
	"socialapi/workers/common/handler"
	"socialapi/workers/common/mux"

	"github.com/koding/metrics"
)

func AddHandlers(m *mux.Mux, metric *metrics.Metrics) {
	m.AddHandler(
		handler.Request{
			Handler:  CreateLink,
			Name:     models.ModerationChannelCreateLink,
			Type:     handler.PostRequest,
			Endpoint: "/moderation/channel/{rootId}/link",
			Metrics:  metric,
		},
	)

	m.AddHandler(
		handler.Request{
			Handler:  GetLinks,
			Name:     models.ModerationChannelGetLink,
			Type:     handler.GetRequest,
			Endpoint: "/moderation/channel/{rootId}/link",
			Metrics:  metric,
		},
	)

	m.AddHandler(
		handler.Request{
			Handler:  Blacklist,
			Name:     models.ModerationChannelDeleteLink,
			Type:     handler.PostRequest,
			Endpoint: "/moderation/channel/blacklist",
			Metrics:  metric,
		},
	)
}
<|endoftext|>


<commit_before>package isolated

import (
	"code.cloudfoundry.org/cli/integration/helpers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
)

var _ = Describe("enable-org-isolation command", func() {
	var isolationSegmentName string
	var organizationName string

	BeforeEach(func() {
		isolationSegmentName = helpers.IsolationSegmentName()
		organizationName = helpers.NewOrgName()
	})

	Describe("help", func() {
		Context("when --help flag is set", func() {
			It("Displays command usage to output", func() {
				session := helpers.CF("enable-org-isolation", "--help")
				Eventually(session).Should(Say("NAME:"))
				Eventually(session).Should(Say("enable-org-isolation - Entitle an organization to an isolation segment"))
				Eventually(session).Should(Say("USAGE:"))
				Eventually(session).Should(Say("cf enable-org-isolation ORG_NAME SEGMENT_NAME"))
				Eventually(session).Should(Say("SEE ALSO:"))
				Eventually(session).Should(Say("create-isolation-segment, isolation-segments"))
				Eventually(session).Should(Exit(0))
			})
		})
	})

	Context("when the environment is not setup correctly", func() {
		Context("when no API endpoint is set", func() {
			BeforeEach(func() {
				helpers.UnsetAPI()
			})

			It("fails with no API endpoint set message", func() {
				session := helpers.CF("enable-org-isolation", isolationSegmentName, organizationName)
				Eventually(session).Should(Say("FAILED"))
				Eventually(session.Err).Should(Say("No API endpoint set. Use 'cf login' or 'cf api' to target an endpoint."))
				Eventually(session).Should(Exit(1))
			})
		})

		Context("when not logged in", func() {
			BeforeEach(func() {
				helpers.LogoutCF()
			})

			It("fails with not logged in message", func() {
				session := helpers.CF("enable-org-isolation", isolationSegmentName, organizationName)
				Eventually(session).Should(Say("FAILED"))
				Eventually(session.Err).Should(Say("Not logged in. Use 'cf login' to log in."))
				Eventually(session).Should(Exit(1))
			})
		})
	})

	Context("when the environment is set up correctly", func() {
		var userName string

		BeforeEach(func() {
			helpers.LoginCF()
			userName, _ = helpers.GetCredentials()
		})

		Context("when the isolation segment does not exist", func() {
			It("fails with isolation segment not found message", func() {
				session := helpers.CF("enable-org-isolation", isolationSegmentName, organizationName)
				Eventually(session).Should(Say("Enabling isolation segment %s for org %s as %s…", isolationSegmentName, organizationName, userName))
				Eventually(session).Should(Say("FAILED"))
				Eventually(session.Err).Should(Say("Isolation segment '%s' not found.", isolationSegmentName))
				Eventually(session).Should(Exit(1))
			})
		})

		Context("when the isolation segment exists", func() {
			BeforeEach(func() {
				Eventually(helpers.CF("create-isolation-segment", isolationSegmentName)).Should(Exit(0))
			})

			// TODO: Delete this and add it to cleanup script after #138303919
			AfterEach(func() {
				Eventually(helpers.CF("delete-isolation-segment", "-f", isolationSegmentName)).Should(Exit(0))
			})

			Context("when the organization does not exist", func() {
				It("fails with organization not found message", func() {
					session := helpers.CF("enable-org-isolation", isolationSegmentName, organizationName)
					Eventually(session).Should(Say("Enabling isolation segment %s for org %s as %s…", isolationSegmentName, organizationName, userName))
					Eventually(session).Should(Say("FAILED"))
					Eventually(session.Err).Should(Say("Organization '%s' not found.", organizationName))
					Eventually(session).Should(Exit(1))
				})
			})

			Context("when the organization exists", func() {
				BeforeEach(func() {
					helpers.CreateOrg(organizationName)
					helpers.TargetOrg(organizationName)
				})

				It("displays OK", func() {
					session := helpers.CF("enable-org-isolation", isolationSegmentName, organizationName)
					Eventually(session).Should(Say("Enabling isolation segment %s for org %s as %s…", isolationSegmentName, organizationName, userName))
					Eventually(session).Should(Say("OK"))
					Eventually(session).Should(Exit(0))
				})

				Context("when the isolation is already enabled", func() {
					BeforeEach(func() {
						Eventually(helpers.CF("enable-org-isolation", isolationSegmentName, organizationName)).Should(Exit(0))
					})

					It("displays OK", func() {
						session := helpers.CF("enable-org-isolation", isolationSegmentName, organizationName)
						Eventually(session).Should(Say("Enabling isolation segment %s for org %s as %s…", isolationSegmentName, organizationName, userName))
						Eventually(session).Should(Say("OK"))
						Eventually(session).Should(Exit(0))
					})
				})
			})
		})
	})
})
<commit_msg>fixed integration<commit_after>package isolated

import (
	"code.cloudfoundry.org/cli/integration/helpers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
)

var _ = Describe("enable-org-isolation command", func() {
	var isolationSegmentName string
	var organizationName string

	BeforeEach(func() {
		isolationSegmentName = helpers.IsolationSegmentName()
		organizationName = helpers.NewOrgName()
	})

	Describe("help", func() {
		Context("when --help flag is set", func() {
			It("Displays command usage to output", func() {
				session := helpers.CF("enable-org-isolation", "--help")
				Eventually(session).Should(Say("NAME:"))
				Eventually(session).Should(Say("enable-org-isolation - Entitle an organization to an isolation segment"))
				Eventually(session).Should(Say("USAGE:"))
				Eventually(session).Should(Say("cf enable-org-isolation ORG_NAME SEGMENT_NAME"))
				Eventually(session).Should(Say("SEE ALSO:"))
				Eventually(session).Should(Say("create-isolation-segment, isolation-segments"))
				Eventually(session).Should(Exit(0))
			})
		})
	})

	Context("when the environment is not setup correctly", func() {
		Context("when no API endpoint is set", func() {
			BeforeEach(func() {
				helpers.UnsetAPI()
			})

			It("fails with no API endpoint set message", func() {
				session := helpers.CF("enable-org-isolation", isolationSegmentName, organizationName)
				Eventually(session).Should(Say("FAILED"))
				Eventually(session.Err).Should(Say("No API endpoint set. Use 'cf login' or 'cf api' to target an endpoint."))
				Eventually(session).Should(Exit(1))
			})
		})

		Context("when not logged in", func() {
			BeforeEach(func() {
				helpers.LogoutCF()
			})

			It("fails with not logged in message", func() {
				session := helpers.CF("enable-org-isolation", isolationSegmentName, organizationName)
				Eventually(session).Should(Say("FAILED"))
				Eventually(session.Err).Should(Say("Not logged in. Use 'cf login' to log in."))
				Eventually(session).Should(Exit(1))
			})
		})
	})

	Context("when the environment is set up correctly", func() {
		var userName string

		BeforeEach(func() {
			helpers.LoginCF()
			userName, _ = helpers.GetCredentials()
		})

		Context("when the isolation segment does not exist", func() {
			It("fails with isolation segment not found message", func() {
				session := helpers.CF("enable-org-isolation", isolationSegmentName, organizationName)
				Eventually(session).Should(Say("Enabling isolation segment %s for org %s as %s…", isolationSegmentName, organizationName, userName))
				Eventually(session).Should(Say("FAILED"))
				Eventually(session.Err).Should(Say("Isolation segment '%s' not found.", isolationSegmentName))
				Eventually(session).Should(Exit(1))
			})
		})

		Context("when the isolation segment exists", func() {
			BeforeEach(func() {
				Eventually(helpers.CF("create-isolation-segment", isolationSegmentName)).Should(Exit(0))
			})

			// TODO: Delete this and add it to cleanup script after #138303919
			AfterEach(func() {
				Eventually(helpers.CF("delete-org", "-f", organizationName)).Should(Exit(0))
				Eventually(helpers.CF("delete-isolation-segment", "-f", isolationSegmentName)).Should(Exit(0))
			})

			Context("when the organization does not exist", func() {
				It("fails with organization not found message", func() {
					session := helpers.CF("enable-org-isolation", isolationSegmentName, organizationName)
					Eventually(session).Should(Say("Enabling isolation segment %s for org %s as %s…", isolationSegmentName, organizationName, userName))
					Eventually(session).Should(Say("FAILED"))
					Eventually(session.Err).Should(Say("Organization '%s' not found.", organizationName))
					Eventually(session).Should(Exit(1))
				})
			})

			Context("when the organization exists", func() {
				BeforeEach(func() {
					helpers.CreateOrg(organizationName)
					helpers.TargetOrg(organizationName)
				})

				It("displays OK", func() {
					session := helpers.CF("enable-org-isolation", isolationSegmentName, organizationName)
					Eventually(session).Should(Say("Enabling isolation segment %s for org %s as %s…", isolationSegmentName, organizationName, userName))
					Eventually(session).Should(Say("OK"))
					Eventually(session).Should(Exit(0))
				})

				Context("when the isolation is already enabled", func() {
					BeforeEach(func() {
						Eventually(helpers.CF("enable-org-isolation", isolationSegmentName, organizationName)).Should(Exit(0))
					})

					It("displays OK", func() {
						session := helpers.CF("enable-org-isolation", isolationSegmentName, organizationName)
						Eventually(session).Should(Say("Enabling isolation segment %s for org %s as %s…", isolationSegmentName, organizationName, userName))
						Eventually(session).Should(Say("OK"))
						Eventually(session).Should(Exit(0))
					})
				})
			})
		})
	})
})
<|endoftext|>


<commit_before>package mesos

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/CiscoCloud/mantl-api/utils/http"
	log "github.com/Sirupsen/logrus"
	"io/ioutil"
	"os"
	"strconv"
	"strings"
)

type Mesos struct {
	Principal  string
	Secret     string
	SecretPath string
	httpClient *http.HttpClient
}

type Framework struct {
	Name             string  `json:"name"`
	ID               string  `json:"id"`
	PID              string  `json:"pid"`
	Active           bool    `json:"active"`
	Hostname         string  `json:"hostname"`
	User             string  `json:"user"`
	RegisteredTime   float64 `json:"registered_time"`
	ReregisteredTime float64 `json:"reregistered_time"`
	Tasks            []*Task `json:"tasks"`
}

type State struct {
	CompletedFrameworks    []*Framework `json:"completed_frameworks"`
	Frameworks             []*Framework `json:"frameworks"`
	UnregisteredFrameworks []string     `json:"unregistered_frameworks"`
	Flags                  Flags        `json:"flags"`
}

type Flags struct {
	Authenticate       string `json:"authenticate"`
	AuthenticateSlaves string `json:"authenticate_slaves"`
}

type Task struct {
	FrameworkID string `json:"framework_id"`
	ID          string `json:"id"`
	Name        string `json:"name"`
	SlaveID     string `json:"slave_id"`
	State       string `json:"state"`
}

func NewMesos(url string, principal string, secretPath string, noVerifySsl bool) (*Mesos, error) {
	secret := readSecret(secretPath)
	httpClient, err := http.NewHttpClient(url, principal, secret, noVerifySsl)

	if err != nil {
		return nil, err
	}

	return &Mesos{
		Principal:  principal,
		Secret:     secret,
		SecretPath: secretPath,
		httpClient: httpClient,
	}, nil
}

func (m Mesos) Frameworks() ([]*Framework, error) {
	state, err := m.state()
	if err != nil {
		return []*Framework{}, err
	}

	return state.Frameworks, nil
}

func (m Mesos) CompletedFrameworks() ([]*Framework, error) {
	state, err := m.state()
	if err != nil {
		return []*Framework{}, err
	}

	return state.CompletedFrameworks, nil
}

func (m Mesos) Shutdown(frameworkId string) error {
	log.Debugf("Shutting down framework: %s", frameworkId)
	data := fmt.Sprintf("frameworkId=%s", frameworkId)
	httpReq, err := m.httpClient.Post("/master/teardown", []byte(data))
	if err != nil {
		return err
	}
	if httpReq.Response.StatusCode == 200 {
		log.Debugf(httpReq.ResponseText)
		return nil
	} else {
		responseText := httpReq.ResponseText
		return errors.New(fmt.Sprintf("Could not shutdown framework %s: %d %s", frameworkId, httpReq.Response.StatusCode, responseText))
	}
}

func (m Mesos) ShutdownFrameworkByName(name string) error {
	log.Debugf("Looking for %s framework", name)

	// find mesos framework
	fw, err := m.FindFramework(name)
	if err != nil {
		return err
	}

	if fw == nil {
		log.Debugf("Framework %s not active", name)
		return nil
	}

	// shutdown mesos framework
	return m.Shutdown(fw.ID)
}

func (m Mesos) FindFrameworks(name string) ([]*Framework, error) {
	state, err := m.state()
	if err != nil {
		return []*Framework{}, err
	}

	matching := make(map[string]*Framework)
	for _, fw := range state.Frameworks {
		if fw.Name == name && fw.Active {
			matching[fw.ID] = fw
		}
	}

	var uniqueFws []*Framework
	for _, fw := range matching {
		uniqueFws = append(uniqueFws, fw)
	}

	return uniqueFws, nil
}

func (m Mesos) FindFramework(name string) (*Framework, error) {
	fws, err := m.FindFrameworks(name)
	if err != nil {
		return nil, err
	}

	fwCount := len(fws)
	if fwCount == 0 {
		return nil, nil
	} else if fwCount > 1 {
		return nil, errors.New(fmt.Sprintf("There are %d %s frameworks.", fwCount, name))
	}

	return fws[0], nil
}

func (m Mesos) RequiresAuthentication() (bool, error) {
	state, err := m.state()
	if err != nil {
		return false, err
	}

	b, err := strconv.ParseBool(state.Flags.Authenticate)
	if err != nil {
		return false, err
	}

	return b, nil
}

func (m Mesos) state() (*State, error) {
	httpReq, err := m.httpClient.Get("/master/state.json")
	if err != nil {
		return nil, err
	}

	body := httpReq.ResponseBody
	if err != nil {
		return nil, err
	}

	state := &State{}
	err = json.Unmarshal(body, state)
	return state, err
}

func readSecret(path string) string {
	secret := ""
	if len(path) > 0 {
		if _, err := os.Stat(path); err == nil {
			data, err := ioutil.ReadFile(path)
			if err != nil {
				log.Warnf("Could not read secret from %s: %v", path, err)
			} else {
				secret = strings.TrimSpace(string(data))
			}
		} else {
			log.Warnf("Secret file %s does not exist", path)
		}
	}
	return secret
}
<commit_msg>app fails if mesos-secret-path does not exist<commit_after>package mesos

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/CiscoCloud/mantl-api/utils/http"
	log "github.com/Sirupsen/logrus"
	"io/ioutil"
	"os"
	"strconv"
	"strings"
)

type Mesos struct {
	Principal  string
	Secret     string
	SecretPath string
	httpClient *http.HttpClient
}

type Framework struct {
	Name             string  `json:"name"`
	ID               string  `json:"id"`
	PID              string  `json:"pid"`
	Active           bool    `json:"active"`
	Hostname         string  `json:"hostname"`
	User             string  `json:"user"`
	RegisteredTime   float64 `json:"registered_time"`
	ReregisteredTime float64 `json:"reregistered_time"`
	Tasks            []*Task `json:"tasks"`
}

type State struct {
	CompletedFrameworks    []*Framework `json:"completed_frameworks"`
	Frameworks             []*Framework `json:"frameworks"`
	UnregisteredFrameworks []string     `json:"unregistered_frameworks"`
	Flags                  Flags        `json:"flags"`
}

type Flags struct {
	Authenticate       string `json:"authenticate"`
	AuthenticateSlaves string `json:"authenticate_slaves"`
}

type Task struct {
	FrameworkID string `json:"framework_id"`
	ID          string `json:"id"`
	Name        string `json:"name"`
	SlaveID     string `json:"slave_id"`
	State       string `json:"state"`
}

func NewMesos(url string, principal string, secretPath string, noVerifySsl bool) (*Mesos, error) {
	secret := readSecret(secretPath)
	httpClient, err := http.NewHttpClient(url, principal, secret, noVerifySsl)

	if err != nil {
		return nil, err
	}

	return &Mesos{
		Principal:  principal,
		Secret:     secret,
		SecretPath: secretPath,
		httpClient: httpClient,
	}, nil
}

func (m Mesos) Frameworks() ([]*Framework, error) {
	state, err := m.state()
	if err != nil {
		return []*Framework{}, err
	}

	return state.Frameworks, nil
}

func (m Mesos) CompletedFrameworks() ([]*Framework, error) {
	state, err := m.state()
	if err != nil {
		return []*Framework{}, err
	}

	return state.CompletedFrameworks, nil
}

func (m Mesos) Shutdown(frameworkId string) error {
	log.Debugf("Shutting down framework: %s", frameworkId)
	data := fmt.Sprintf("frameworkId=%s", frameworkId)
	httpReq, err := m.httpClient.Post("/master/teardown", []byte(data))
	if err != nil {
		return err
	}
	if httpReq.Response.StatusCode == 200 {
		log.Debugf(httpReq.ResponseText)
		return nil
	} else {
		responseText := httpReq.ResponseText
		return errors.New(fmt.Sprintf("Could not shutdown framework %s: %d %s", frameworkId, httpReq.Response.StatusCode, responseText))
	}
}

func (m Mesos) ShutdownFrameworkByName(name string) error {
	log.Debugf("Looking for %s framework", name)

	// find mesos framework
	fw, err := m.FindFramework(name)
	if err != nil {
		return err
	}

	if fw == nil {
		log.Debugf("Framework %s not active", name)
		return nil
	}

	// shutdown mesos framework
	return m.Shutdown(fw.ID)
}

func (m Mesos) FindFrameworks(name string) ([]*Framework, error) {
	state, err := m.state()
	if err != nil {
		return []*Framework{}, err
	}

	matching := make(map[string]*Framework)
	for _, fw := range state.Frameworks {
		if fw.Name == name && fw.Active {
			matching[fw.ID] = fw
		}
	}

	var uniqueFws []*Framework
	for _, fw := range matching {
		uniqueFws = append(uniqueFws, fw)
	}

	return uniqueFws, nil
}

func (m Mesos) FindFramework(name string) (*Framework, error) {
	fws, err := m.FindFrameworks(name)
	if err != nil {
		return nil, err
	}

	fwCount := len(fws)
	if fwCount == 0 {
		return nil, nil
	} else if fwCount > 1 {
		return nil, errors.New(fmt.Sprintf("There are %d %s frameworks.", fwCount, name))
	}

	return fws[0], nil
}

func (m Mesos) RequiresAuthentication() (bool, error) {
	state, err := m.state()
	if err != nil {
		return false, err
	}

	b, err := strconv.ParseBool(state.Flags.Authenticate)
	if err != nil {
		return false, err
	}

	return b, nil
}

func (m Mesos) state() (*State, error) {
	httpReq, err := m.httpClient.Get("/master/state.json")
	if err != nil {
		return nil, err
	}

	body := httpReq.ResponseBody
	if err != nil {
		return nil, err
	}

	state := &State{}
	err = json.Unmarshal(body, state)
	return state, err
}

func readSecret(path string) string {
	secret := ""
	if len(path) > 0 {
		if _, err := os.Stat(path); err == nil {
			data, err := ioutil.ReadFile(path)
			if err != nil {
				log.Fatalf("Could not read secret from %s: %v", path, err)
			} else {
				secret = strings.TrimSpace(string(data))
			}
		} else {
			log.Fatalf("Secret file %s does not exist", path)
		}
	}
	return secret
}
<|endoftext|>


<commit_before>package service

import (
	"context"
	"encoding/base64"
	"fmt"
	"log"
	"net/http"
	"strings"

	"gopkg.in/jcmturner/gokrb5.v5/gssapi"
	"gopkg.in/jcmturner/gokrb5.v5/keytab"
)

// POTENTIAL BREAKING CHANGE notice. Context keys used will change to a name-spaced strings to avoid clashes.
// If you are using the constants service.CTXKeyAuthenticated and service.CTXKeyCredentials
// defined below when retrieving data from the request context your code will be unaffected.
// However if, for example, you are retrieving context like this: r.Context().Value(1) then
// you will need to update to replace the 1 with service.CTXKeyCredentials.
type ctxKey int

const (
	// spnegoNegTokenRespKRBAcceptCompleted - The response on successful authentication always has this header. Capturing as const so we don't have marshaling and encoding overhead.
	spnegoNegTokenRespKRBAcceptCompleted = "Negotiate oRQwEqADCgEAoQsGCSqGSIb3EgECAg=="
	// spnegoNegTokenRespReject - The response on a failed authentication always has this rejection header. Capturing as const so we don't have marshaling and encoding overhead.
	spnegoNegTokenRespReject = "Negotiate oQcwBaADCgEC"
	// CTXKeyAuthenticated is the request context key holding a boolean indicating if the request has been authenticated.
	CTXKeyAuthenticated ctxKey = 0
	// CTXKeyCredentials is the request context key holding the credentials gopkg.in/jcmturner/goidentity.v2/Identity object.
	CTXKeyCredentials ctxKey = 1
)

// SPNEGOKRB5Authenticate is a Kerberos SPNEGO authentication HTTP handler wrapper.
//
// kt - keytab for the service user
//
// ktprinc - keytab principal override for the service.
// The service looks for this principal in the keytab to use to decrypt tickets.
// If "" is passed as ktprinc then the principal will be automatically derived
// from the service name (SName) and realm in the ticket the service is trying to decrypt.
// This is often sufficient if you create the SPN in MIT KDC with: /usr/sbin/kadmin.local -q "add_principal HTTP/<fqdn>"
// When Active Directory is used for the KDC this may need to be the account name you have set the SPN against
// (setspn.exe -a "HTTP/<fqdn>" <account name>)
// If you are unsure run:
//
// klist -k <service's keytab file>
//
// and use the value from the Principal column for the keytab entry the service should use.
func SPNEGOKRB5Authenticate(f http.Handler, kt keytab.Keytab, ktprinc string, requireHostAddr bool, l *log.Logger) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		s := strings.SplitN(r.Header.Get("Authorization"), " ", 2)
		if len(s) != 2 || s[0] != "Negotiate" {
			w.Header().Set("WWW-Authenticate", "Negotiate")
			w.WriteHeader(401)
			w.Write([]byte("Unauthorised.\n"))
			return
		}
		b, err := base64.StdEncoding.DecodeString(s[1])
		if err != nil {
			rejectSPNEGO(w, l, fmt.Sprintf("%v - SPNEGO error in base64 decoding negotiation header: %v", r.RemoteAddr, err))
			return
		}
		var spnego gssapi.SPNEGO
		err = spnego.Unmarshal(b)
		if !spnego.Init {
			rejectSPNEGO(w, l, fmt.Sprintf("%v - SPNEGO negotiation token is not a NegTokenInit: %v", r.RemoteAddr, err))
			return
		}
		if !spnego.NegTokenInit.MechTypes[0].Equal(gssapi.MechTypeOIDKRB5) && !spnego.NegTokenInit.MechTypes[0].Equal(gssapi.MechTypeOIDMSLegacyKRB5) {
			rejectSPNEGO(w, l, fmt.Sprintf("%v - SPNEGO OID of MechToken is not of type KRB5", r.RemoteAddr))
			return
		}
		var mt gssapi.MechToken
		err = mt.Unmarshal(spnego.NegTokenInit.MechToken)
		if err != nil {
			rejectSPNEGO(w, l, fmt.Sprintf("%v - SPNEGO error unmarshaling MechToken: %v", r.RemoteAddr, err))
			return
		}
		if !mt.IsAPReq() {
			rejectSPNEGO(w, l, fmt.Sprintf("%v - MechToken does not contain an AP_REQ - KRB_AP_ERR_MSG_TYPE", r.RemoteAddr))
			return
		}

		if ok, creds, err := ValidateAPREQ(mt.APReq, kt, ktprinc, r.RemoteAddr, requireHostAddr); ok {
			ctx := r.Context()
			ctx = context.WithValue(ctx, CTXKeyCredentials, creds)
			ctx = context.WithValue(ctx, CTXKeyAuthenticated, true)
			if l != nil {
				l.Printf("%v %s@%s - SPNEGO authentication succeeded", r.RemoteAddr, creds.Username, creds.Realm)
			}
			spnegoResponseAcceptCompleted(w)
			f.ServeHTTP(w, r.WithContext(ctx))
		} else {
			rejectSPNEGO(w, l, fmt.Sprintf("%v - SPNEGO Kerberos authentication failed: %v", r.RemoteAddr, err))
			return
		}
	})
}

// Set the headers for a rejected SPNEGO negotiation and return an unauthorized status code.
func rejectSPNEGO(w http.ResponseWriter, l *log.Logger, logMsg string) {
	if l != nil {
		l.Println(logMsg)
	}
	spnegoResponseReject(w)
}

func spnegoResponseReject(w http.ResponseWriter) {
	w.Header().Set("WWW-Authenticate", spnegoNegTokenRespReject)
	w.WriteHeader(http.StatusUnauthorized)
	w.Write([]byte("Unauthorised.\n"))
}

func spnegoResponseAcceptCompleted(w http.ResponseWriter) {
	w.Header().Set("WWW-Authenticate", spnegoNegTokenRespKRBAcceptCompleted)
}
<commit_msg>const for best practice<commit_after>package service

import (
	"context"
	"encoding/base64"
	"fmt"
	"log"
	"net/http"
	"strings"

	"gopkg.in/jcmturner/gokrb5.v5/gssapi"
	"gopkg.in/jcmturner/gokrb5.v5/keytab"
)

// POTENTIAL BREAKING CHANGE notice. Context keys used will change to a name-spaced strings to avoid clashes.
// If you are using the constants service.CTXKeyAuthenticated and service.CTXKeyCredentials
// defined below when retrieving data from the request context your code will be unaffected.
// However if, for example, you are retrieving context like this: r.Context().Value(1) then
// you will need to update to replace the 1 with service.CTXKeyCredentials.
type ctxKey int

const (
	// spnegoNegTokenRespKRBAcceptCompleted - The response on successful authentication always has this header. Capturing as const so we don't have marshaling and encoding overhead.
	spnegoNegTokenRespKRBAcceptCompleted = "Negotiate oRQwEqADCgEAoQsGCSqGSIb3EgECAg=="
	// spnegoNegTokenRespReject - The response on a failed authentication always has this rejection header. Capturing as const so we don't have marshaling and encoding overhead.
	spnegoNegTokenRespReject = "Negotiate oQcwBaADCgEC"
	// CTXKeyAuthenticated is the request context key holding a boolean indicating if the request has been authenticated.
	CTXKeyAuthenticated ctxKey = 0
	// CTXKeyCredentials is the request context key holding the credentials gopkg.in/jcmturner/goidentity.v2/Identity object.
	CTXKeyCredentials              ctxKey = 1
	HTTPHeaderAuthResponse                = "WWW-Authenticate"
	HTTPHeaderAuthResponseValueKey        = "Negotiate"
	HTTPHeaderAuthRequest                 = "Authorization"
	UnauthorizedMsg                       = "Unauthorised.\n"
)

// SPNEGOKRB5Authenticate is a Kerberos SPNEGO authentication HTTP handler wrapper.
//
// kt - keytab for the service user
//
// ktprinc - keytab principal override for the service.
// The service looks for this principal in the keytab to use to decrypt tickets.
// If "" is passed as ktprinc then the principal will be automatically derived
// from the service name (SName) and realm in the ticket the service is trying to decrypt.
// This is often sufficient if you create the SPN in MIT KDC with: /usr/sbin/kadmin.local -q "add_principal HTTP/<fqdn>"
// When Active Directory is used for the KDC this may need to be the account name you have set the SPN against
// (setspn.exe -a "HTTP/<fqdn>" <account name>)
// If you are unsure run:
//
// klist -k <service's keytab file>
//
// and use the value from the Principal column for the keytab entry the service should use.
func SPNEGOKRB5Authenticate(f http.Handler, kt keytab.Keytab, ktprinc string, requireHostAddr bool, l *log.Logger) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		s := strings.SplitN(r.Header.Get(HTTPHeaderAuthRequest), " ", 2)
		if len(s) != 2 || s[0] != HTTPHeaderAuthResponseValueKey {
			w.Header().Set(HTTPHeaderAuthResponse, HTTPHeaderAuthResponseValueKey)
			w.WriteHeader(401)
			w.Write([]byte(UnauthorizedMsg))
			return
		}
		b, err := base64.StdEncoding.DecodeString(s[1])
		if err != nil {
			rejectSPNEGO(w, l, fmt.Sprintf("%v - SPNEGO error in base64 decoding negotiation header: %v", r.RemoteAddr, err))
			return
		}
		var spnego gssapi.SPNEGO
		err = spnego.Unmarshal(b)
		if !spnego.Init {
			rejectSPNEGO(w, l, fmt.Sprintf("%v - SPNEGO negotiation token is not a NegTokenInit: %v", r.RemoteAddr, err))
			return
		}
		if !spnego.NegTokenInit.MechTypes[0].Equal(gssapi.MechTypeOIDKRB5) && !spnego.NegTokenInit.MechTypes[0].Equal(gssapi.MechTypeOIDMSLegacyKRB5) {
			rejectSPNEGO(w, l, fmt.Sprintf("%v - SPNEGO OID of MechToken is not of type KRB5", r.RemoteAddr))
			return
		}
		var mt gssapi.MechToken
		err = mt.Unmarshal(spnego.NegTokenInit.MechToken)
		if err != nil {
			rejectSPNEGO(w, l, fmt.Sprintf("%v - SPNEGO error unmarshaling MechToken: %v", r.RemoteAddr, err))
			return
		}
		if !mt.IsAPReq() {
			rejectSPNEGO(w, l, fmt.Sprintf("%v - MechToken does not contain an AP_REQ - KRB_AP_ERR_MSG_TYPE", r.RemoteAddr))
			return
		}

		if ok, creds, err := ValidateAPREQ(mt.APReq, kt, ktprinc, r.RemoteAddr, requireHostAddr); ok {
			ctx := r.Context()
			ctx = context.WithValue(ctx, CTXKeyCredentials, creds)
			ctx = context.WithValue(ctx, CTXKeyAuthenticated, true)
			if l != nil {
				l.Printf("%v %s@%s - SPNEGO authentication succeeded", r.RemoteAddr, creds.Username, creds.Realm)
			}
			spnegoResponseAcceptCompleted(w)
			f.ServeHTTP(w, r.WithContext(ctx))
		} else {
			rejectSPNEGO(w, l, fmt.Sprintf("%v - SPNEGO Kerberos authentication failed: %v", r.RemoteAddr, err))
			return
		}
	})
}

// Set the headers for a rejected SPNEGO negotiation and return an unauthorized status code.
func rejectSPNEGO(w http.ResponseWriter, l *log.Logger, logMsg string) {
	if l != nil {
		l.Println(logMsg)
	}
	spnegoResponseReject(w)
}

func spnegoResponseReject(w http.ResponseWriter) {
	w.Header().Set(HTTPHeaderAuthResponse, spnegoNegTokenRespReject)
	w.WriteHeader(http.StatusUnauthorized)
	w.Write([]byte(UnauthorizedMsg))
}

func spnegoResponseAcceptCompleted(w http.ResponseWriter) {
	w.Header().Set(HTTPHeaderAuthResponse, spnegoNegTokenRespKRBAcceptCompleted)
}
<|endoftext|>


<commit_before>// Copyright 2014, The Serviced Authors. All rights reserved.
// Use of this source code is governed by a
// license that can be found in the LICENSE file.

// Package agent implements a service that runs on a serviced node. It is
// responsible for ensuring that a particular node is running the correct services
// and reporting the state and health of those services back to the master
// serviced.

package main

// This is the main entry point for the application. Here we parse command line
// flags and either start a service or execute command line functions.

//svc "github.com/zenoss/serviced/svc"
import (
	"github.com/zenoss/serviced"
	"github.com/zenoss/serviced/dao"
	"github.com/zenoss/serviced/dao/elasticsearch"
	"github.com/zenoss/serviced/isvcs"
	"github.com/zenoss/serviced/shell"
	"github.com/zenoss/serviced/volume"
	_ "github.com/zenoss/serviced/volume/btrfs"
	_ "github.com/zenoss/serviced/volume/rsync"
	"github.com/zenoss/serviced/web"

	"flag"
	"fmt"
	"net"
	"net/http"
	"net/rpc"
	"os"
	"os/signal"
	"os/user"
	"path"
	"strconv"
	"time"
	"syscall"

	"github.com/zenoss/glog"
)

// Store the command line options
var options struct {
	port             string
	listen           string
	master           bool
	agent            bool
	muxPort          int
	tls              bool
	keyPEMFile       string
	certPEMFile      string
	varPath          string // Directory to store data, eg isvcs & service volumes
	resourcePath     string
	zookeepers       ListOpts
	repstats         bool
	statshost        string
	statsperiod      int
	mcusername       string
	mcpasswd         string
	mount            ListOpts
	resourceperiod   int
	vfs              string
	esStartupTimeout int
	hostaliases      string
}

var agentIP string

// getEnvVarInt() returns the env var as an int value or the defaultValue if env var is unset
func getEnvVarInt(envVar string, defaultValue int) int {
	envVarValue := os.Getenv(envVar)
	if len(envVarValue) > 0 {
		if value, err := strconv.Atoi(envVarValue); err != nil {
			glog.Errorf("Could not convert env var %s:%s to integer, error:%s", envVar, envVarValue, err)
			return defaultValue
		} else {
			return value
		}
	}
	return defaultValue
}

// ensureMinimumInt sets the env var and command line flag to the given minimum if the value is less than the minimum
func ensureMinimumInt(envVar string, flagName string, minimum int) {
	theFlag := flag.Lookup(flagName)
	value, _ := strconv.Atoi(theFlag.Value.String())
	if value < minimum {
		glog.Infof("overriding flag %s:%s with minimum value of %v", flagName, theFlag.Value.String(), minimum)
		valueStr := strconv.Itoa(minimum)
		os.Setenv(envVar, valueStr)
		flag.Set(flagName, valueStr)
	} else {
		os.Setenv(envVar, theFlag.Value.String())
	}
}

// Setup flag options (static block)
func init() {
	var err error
	agentIP, err = serviced.GetIPAddress()
	if err != nil {
		panic(err)
	}

	flag.StringVar(&options.port, "port", agentIP+":4979", "port for remote serviced (example.com:8080)")
	flag.StringVar(&options.listen, "listen", ":4979", "port for local serviced (example.com:8080)")
	flag.BoolVar(&options.master, "master", false, "run in master mode, ie the control plane service")
	flag.BoolVar(&options.agent, "agent", false, "run in agent mode, ie a host in a resource pool")
	flag.IntVar(&options.muxPort, "muxport", 22250, "multiplexing port to use")
	flag.BoolVar(&options.tls, "tls", true, "enable TLS")

	varPathDefault := path.Join(os.TempDir(), "serviced")
	if len(os.Getenv("SERVICED_HOME")) > 0 {
		varPathDefault = path.Join(os.Getenv("SERVICED_HOME"), "var")
	} else {
		if user, err := user.Current(); err == nil {
			varPathDefault = path.Join(os.TempDir(), "serviced-"+user.Username, "var")
		}
	}
	flag.StringVar(&options.varPath, "varPath", varPathDefault, "path to store serviced data")

	flag.StringVar(&options.keyPEMFile, "keyfile", "", "path to private key file (defaults to compiled in private key)")
	flag.StringVar(&options.certPEMFile, "certfile", "", "path to public certificate file (defaults to compiled in public cert)")
	options.zookeepers = make(ListOpts, 0)
	flag.Var(&options.zookeepers, "zk", "Specify a zookeeper instance to connect to (e.g. -zk localhost:2181 )")
	flag.BoolVar(&options.repstats, "reportstats", false, "report container statistics")
	flag.StringVar(&options.statshost, "statshost", "127.0.0.1:8443", "host:port for container statistics")
	flag.IntVar(&options.statsperiod, "statsperiod", 5, "Period (minutes) for container statistics reporting")
	flag.StringVar(&options.mcusername, "mcusername", "scott", "Username for the Zenoss metric consumer")
	flag.StringVar(&options.mcpasswd, "mcpasswd", "tiger", "Password for the Zenoss metric consumer")
	options.mount = make(ListOpts, 0)
	flag.Var(&options.mount, "mount", "bind mount: container_image:host_path:container_path (e.g. -mount zenoss/zenoss5x:/home/zenoss/zenhome/zenoss/Products/:/opt/zenoss/Products/)")
	flag.StringVar(&options.vfs, "vfs", "rsync", "file system for container volumes")
	flag.StringVar(&options.hostaliases, "hostaliases", "", "list of aliases for this host, e.g., localhost:goldmine:goldmine.net")

	flag.IntVar(&options.esStartupTimeout, "esStartupTimeout", getEnvVarInt("ES_STARTUP_TIMEOUT", 600), "time to wait on elasticsearch startup before bailing")

	flag.Usage = func() {
		flag.PrintDefaults()
	}
}

func compareVersion(a, b []int) int {
	astr := ""
	for _, s := range a {
		astr += fmt.Sprintf("%12d", s)
	}
	bstr := ""
	for _, s := range b {
		bstr += fmt.Sprintf("%12d", s)
	}
	if astr > bstr {
		return -1
	}
	if astr < bstr {
		return 1
	}
	return 0
}

// Start the agent or master services on this host.
func startServer() {
	l, err := net.Listen("tcp", options.listen)
	if err != nil {
		glog.Fatalf("Could not bind to port %v. Is another instance running", err)
	}

	isvcs.Init()
	isvcs.Mgr.SetVolumesDir(options.varPath + "/isvcs")

	dockerVersion, err := serviced.GetDockerVersion()
	if err != nil {
		glog.Fatalf("Could not determine docker version: %s", err)
	}

	atLeast := []int{0, 7, 5}
	atMost := []int{0, 8, 1}
	if compareVersion(atLeast, dockerVersion.Client) < 0 || compareVersion(atMost, dockerVersion.Client) > 0 {
		glog.Fatal("serviced needs at least docker >= 0.7.5 or <= 0.8.1 but not 0.8.0")
	}
	if compareVersion([]int{0, 8, 0}, dockerVersion.Client) == 0 {
		glog.Fatal("serviced specifically does not support docker 0.8.0")

	}

	if _, ok := volume.Registered(options.vfs); !ok {
		glog.Fatalf("no driver registered for %s", options.vfs)
	}

	if options.master {
		var master dao.ControlPlane
		var err error
		master, err = elasticsearch.NewControlSvc("localhost", 9200, options.zookeepers, options.varPath, options.vfs)

		if err != nil {
			glog.Fatalf("Could not start ControlPlane service: %v", err)
		}
		// register the API
		glog.V(0).Infoln("registering ControlPlane service")
		rpc.RegisterName("LoadBalancer", master)
		rpc.RegisterName("ControlPlane", master)

		// TODO: Make bind port for web server optional?
		cpserver := web.NewServiceConfig(":8787", options.port, options.zookeepers, options.repstats, options.hostaliases)
		go cpserver.ServeUI()
		go cpserver.Serve()
	}
	if options.agent {
		mux := serviced.TCPMux{}

		mux.CertPEMFile = options.certPEMFile
		mux.KeyPEMFile = options.keyPEMFile
		mux.Enabled = true
		mux.Port = options.muxPort
		mux.UseTLS = options.tls

		agent, err := serviced.NewHostAgent(options.port, options.varPath, options.mount, options.vfs, options.zookeepers, mux)
		if err != nil {
			glog.Fatalf("Could not start ControlPlane agent: %v", err)
		}
		// register the API
		glog.V(0).Infoln("registering ControlPlaneAgent service")
		rpc.RegisterName("ControlPlaneAgent", agent)

		go func() {
			signalChan := make(chan os.Signal, 10)
			signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)
			<-signalChan
			glog.V(0).Info("Shutting down due to interrupt")
			err = agent.Shutdown()
			if err != nil {
				glog.V(1).Infof("Agent shutdown with error: %v", err)
			}
			isvcs.Mgr.Stop()
			os.Exit(0)
		}()

		// TODO: Integrate this server into the rpc server, or something.
		// Currently its only use is for command execution.
		go func() {
			sio := shell.NewProcessExecutorServer(options.port)
			http.ListenAndServe(":50000", sio)
		}()
	}

	rpc.HandleHTTP()

	if options.repstats {
		statsdest := fmt.Sprintf("http://%s/api/metrics/store", options.statshost)
		sr := StatsReporter{statsdest, options.mcusername, options.mcpasswd}

		glog.V(1).Infoln("Staring container statistics reporter")
		statsduration := time.Duration(options.statsperiod) * time.Minute
		go sr.Report(statsduration)
	}

	glog.V(0).Infof("Listening on %s", l.Addr().String())
	http.Serve(l, nil) // start the server
}

// main entry point of the product
func main() {

	// parse the command line flags
	flag.Parse()
	ensureMinimumInt("ES_STARTUP_TIMEOUT", "esStartupTimeout", 30)

	// are we in server mode
	if (options.master || options.agent) && len(flag.Args()) == 0 {
		startServer()
	} else {
		// we are in command line mode
		if len(flag.Args()) == 0 {
			// no arguments were give, show help
			cli := ServicedCli{}
			cli.CmdHelp(flag.Args()...)
			flag.Usage()
		} else {
			ParseCommands(flag.Args()...)
		}
	}
	glog.Flush()
}
<commit_msg>reviewed by dgarcia enable stats by defalut<commit_after>// Copyright 2014, The Serviced Authors. All rights reserved.
// Use of this source code is governed by a
// license that can be found in the LICENSE file.

// Package agent implements a service that runs on a serviced node. It is
// responsible for ensuring that a particular node is running the correct services
// and reporting the state and health of those services back to the master
// serviced.

package main

// This is the main entry point for the application. Here we parse command line
// flags and either start a service or execute command line functions.

//svc "github.com/zenoss/serviced/svc"
import (
	"github.com/zenoss/serviced"
	"github.com/zenoss/serviced/dao"
	"github.com/zenoss/serviced/dao/elasticsearch"
	"github.com/zenoss/serviced/isvcs"
	"github.com/zenoss/serviced/shell"
	"github.com/zenoss/serviced/volume"
	_ "github.com/zenoss/serviced/volume/btrfs"
	_ "github.com/zenoss/serviced/volume/rsync"
	"github.com/zenoss/serviced/web"

	"flag"
	"fmt"
	"net"
	"net/http"
	"net/rpc"
	"os"
	"os/signal"
	"os/user"
	"path"
	"strconv"
	"syscall"
	"time"

	"github.com/zenoss/glog"
)

// Store the command line options
var options struct {
	port             string
	listen           string
	master           bool
	agent            bool
	muxPort          int
	tls              bool
	keyPEMFile       string
	certPEMFile      string
	varPath          string // Directory to store data, eg isvcs & service volumes
	resourcePath     string
	zookeepers       ListOpts
	repstats         bool
	statshost        string
	statsperiod      int
	mcusername       string
	mcpasswd         string
	mount            ListOpts
	resourceperiod   int
	vfs              string
	esStartupTimeout int
	hostaliases      string
}

var agentIP string

// getEnvVarInt() returns the env var as an int value or the defaultValue if env var is unset
func getEnvVarInt(envVar string, defaultValue int) int {
	envVarValue := os.Getenv(envVar)
	if len(envVarValue) > 0 {
		if value, err := strconv.Atoi(envVarValue); err != nil {
			glog.Errorf("Could not convert env var %s:%s to integer, error:%s", envVar, envVarValue, err)
			return defaultValue
		} else {
			return value
		}
	}
	return defaultValue
}

// ensureMinimumInt sets the env var and command line flag to the given minimum if the value is less than the minimum
func ensureMinimumInt(envVar string, flagName string, minimum int) {
	theFlag := flag.Lookup(flagName)
	value, _ := strconv.Atoi(theFlag.Value.String())
	if value < minimum {
		glog.Infof("overriding flag %s:%s with minimum value of %v", flagName, theFlag.Value.String(), minimum)
		valueStr := strconv.Itoa(minimum)
		os.Setenv(envVar, valueStr)
		flag.Set(flagName, valueStr)
	} else {
		os.Setenv(envVar, theFlag.Value.String())
	}
}

// Setup flag options (static block)
func init() {
	var err error
	agentIP, err = serviced.GetIPAddress()
	if err != nil {
		panic(err)
	}

	flag.StringVar(&options.port, "port", agentIP+":4979", "port for remote serviced (example.com:8080)")
	flag.StringVar(&options.listen, "listen", ":4979", "port for local serviced (example.com:8080)")
	flag.BoolVar(&options.master, "master", false, "run in master mode, ie the control plane service")
	flag.BoolVar(&options.agent, "agent", false, "run in agent mode, ie a host in a resource pool")
	flag.IntVar(&options.muxPort, "muxport", 22250, "multiplexing port to use")
	flag.BoolVar(&options.tls, "tls", true, "enable TLS")

	varPathDefault := path.Join(os.TempDir(), "serviced")
	if len(os.Getenv("SERVICED_HOME")) > 0 {
		varPathDefault = path.Join(os.Getenv("SERVICED_HOME"), "var")
	} else {
		if user, err := user.Current(); err == nil {
			varPathDefault = path.Join(os.TempDir(), "serviced-"+user.Username, "var")
		}
	}
	flag.StringVar(&options.varPath, "varPath", varPathDefault, "path to store serviced data")

	flag.StringVar(&options.keyPEMFile, "keyfile", "", "path to private key file (defaults to compiled in private key)")
	flag.StringVar(&options.certPEMFile, "certfile", "", "path to public certificate file (defaults to compiled in public cert)")
	options.zookeepers = make(ListOpts, 0)
	flag.Var(&options.zookeepers, "zk", "Specify a zookeeper instance to connect to (e.g. -zk localhost:2181 )")
	flag.BoolVar(&options.repstats, "reportstats", true, "report container statistics")
	flag.StringVar(&options.statshost, "statshost", "127.0.0.1:8443", "host:port for container statistics")
	flag.IntVar(&options.statsperiod, "statsperiod", 5, "Period (minutes) for container statistics reporting")
	flag.StringVar(&options.mcusername, "mcusername", "scott", "Username for the Zenoss metric consumer")
	flag.StringVar(&options.mcpasswd, "mcpasswd", "tiger", "Password for the Zenoss metric consumer")
	options.mount = make(ListOpts, 0)
	flag.Var(&options.mount, "mount", "bind mount: container_image:host_path:container_path (e.g. -mount zenoss/zenoss5x:/home/zenoss/zenhome/zenoss/Products/:/opt/zenoss/Products/)")
	flag.StringVar(&options.vfs, "vfs", "rsync", "file system for container volumes")
	flag.StringVar(&options.hostaliases, "hostaliases", "", "list of aliases for this host, e.g., localhost:goldmine:goldmine.net")

	flag.IntVar(&options.esStartupTimeout, "esStartupTimeout", getEnvVarInt("ES_STARTUP_TIMEOUT", 600), "time to wait on elasticsearch startup before bailing")

	flag.Usage = func() {
		flag.PrintDefaults()
	}
}

func compareVersion(a, b []int) int {
	astr := ""
	for _, s := range a {
		astr += fmt.Sprintf("%12d", s)
	}
	bstr := ""
	for _, s := range b {
		bstr += fmt.Sprintf("%12d", s)
	}
	if astr > bstr {
		return -1
	}
	if astr < bstr {
		return 1
	}
	return 0
}

// Start the agent or master services on this host.
func startServer() {
	l, err := net.Listen("tcp", options.listen)
	if err != nil {
		glog.Fatalf("Could not bind to port %v. Is another instance running", err)
	}

	isvcs.Init()
	isvcs.Mgr.SetVolumesDir(options.varPath + "/isvcs")

	dockerVersion, err := serviced.GetDockerVersion()
	if err != nil {
		glog.Fatalf("Could not determine docker version: %s", err)
	}

	atLeast := []int{0, 7, 5}
	atMost := []int{0, 8, 1}
	if compareVersion(atLeast, dockerVersion.Client) < 0 || compareVersion(atMost, dockerVersion.Client) > 0 {
		glog.Fatal("serviced needs at least docker >= 0.7.5 or <= 0.8.1 but not 0.8.0")
	}
	if compareVersion([]int{0, 8, 0}, dockerVersion.Client) == 0 {
		glog.Fatal("serviced specifically does not support docker 0.8.0")

	}

	if _, ok := volume.Registered(options.vfs); !ok {
		glog.Fatalf("no driver registered for %s", options.vfs)
	}

	if options.master {
		var master dao.ControlPlane
		var err error
		master, err = elasticsearch.NewControlSvc("localhost", 9200, options.zookeepers, options.varPath, options.vfs)

		if err != nil {
			glog.Fatalf("Could not start ControlPlane service: %v", err)
		}
		// register the API
		glog.V(0).Infoln("registering ControlPlane service")
		rpc.RegisterName("LoadBalancer", master)
		rpc.RegisterName("ControlPlane", master)

		// TODO: Make bind port for web server optional?
		cpserver := web.NewServiceConfig(":8787", options.port, options.zookeepers, options.repstats, options.hostaliases)
		go cpserver.ServeUI()
		go cpserver.Serve()
	}
	if options.agent {
		mux := serviced.TCPMux{}

		mux.CertPEMFile = options.certPEMFile
		mux.KeyPEMFile = options.keyPEMFile
		mux.Enabled = true
		mux.Port = options.muxPort
		mux.UseTLS = options.tls

		agent, err := serviced.NewHostAgent(options.port, options.varPath, options.mount, options.vfs, options.zookeepers, mux)
		if err != nil {
			glog.Fatalf("Could not start ControlPlane agent: %v", err)
		}
		// register the API
		glog.V(0).Infoln("registering ControlPlaneAgent service")
		rpc.RegisterName("ControlPlaneAgent", agent)

		go func() {
			signalChan := make(chan os.Signal, 10)
			signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)
			<-signalChan
			glog.V(0).Info("Shutting down due to interrupt")
			err = agent.Shutdown()
			if err != nil {
				glog.V(1).Infof("Agent shutdown with error: %v", err)
			}
			isvcs.Mgr.Stop()
			os.Exit(0)
		}()

		// TODO: Integrate this server into the rpc server, or something.
		// Currently its only use is for command execution.
		go func() {
			sio := shell.NewProcessExecutorServer(options.port)
			http.ListenAndServe(":50000", sio)
		}()
	}

	rpc.HandleHTTP()

	if options.repstats {
		statsdest := fmt.Sprintf("http://%s/api/metrics/store", options.statshost)
		sr := StatsReporter{statsdest, options.mcusername, options.mcpasswd}

		glog.V(1).Infoln("Staring container statistics reporter")
		statsduration := time.Duration(options.statsperiod) * time.Minute
		go sr.Report(statsduration)
	}

	glog.V(0).Infof("Listening on %s", l.Addr().String())
	http.Serve(l, nil) // start the server
}

// main entry point of the product
func main() {

	// parse the command line flags
	flag.Parse()
	ensureMinimumInt("ES_STARTUP_TIMEOUT", "esStartupTimeout", 30)

	// are we in server mode
	if (options.master || options.agent) && len(flag.Args()) == 0 {
		startServer()
	} else {
		// we are in command line mode
		if len(flag.Args()) == 0 {
			// no arguments were give, show help
			cli := ServicedCli{}
			cli.CmdHelp(flag.Args()...)
			flag.Usage()
		} else {
			ParseCommands(flag.Args()...)
		}
	}
	glog.Flush()
}
<|endoftext|>