<commit_before>package main

import (
	"io"
	"os"
	"strings"
	"time"

	"github.com/spf13/cobra"

	"github.com/lxc/lxd/client"
	"github.com/lxc/lxd/lxc/utils"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/api"
	cli "github.com/lxc/lxd/shared/cmd"
	"github.com/lxc/lxd/shared/i18n"
)

type cmdExport struct {
	global *cmdGlobal

	flagContainerOnly    bool
	flagOptimizedStorage bool
}

func (c *cmdExport) Command() *cobra.Command {
	cmd := &cobra.Command{}
	cmd.Use = i18n.G("export [<remote>:]<container> [target] [--container-only] [--optimized-storage]")
	cmd.Short = i18n.G("Export container backups")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Export containers as backup tarballs.`))
	cmd.Example = cli.FormatSection("", i18n.G(
		`lxc export u1 backup0.tar.xz
    Download a backup tarball of the u1 container.`))

	cmd.RunE = c.Run
	cmd.Flags().BoolVar(&c.flagContainerOnly, "container-only", false,
		i18n.G("Whether or not to only backup the container (without snapshots)"))
	cmd.Flags().BoolVar(&c.flagOptimizedStorage, "optimized-storage", false,
		i18n.G("Use storage driver optimized format (can only be restored on a similar pool)"))

	return cmd
}

func (c *cmdExport) Run(cmd *cobra.Command, args []string) error {
	conf := c.global.conf

	// Sanity checks
	exit, err := c.global.CheckArgs(cmd, args, 1, 2)
	if exit {
		return err
	}

	// Connect to LXD
	remote, name, err := conf.ParseRemote(args[0])
	if err != nil {
		return err
	}

	d, err := conf.GetContainerServer(remote)
	if err != nil {
		return err
	}

	req := api.ContainerBackupsPost{
		Name:             "",
		ExpiryDate:       time.Now().Add(30 * time.Minute),
		ContainerOnly:    c.flagContainerOnly,
		OptimizedStorage: c.flagOptimizedStorage,
	}

	op, err := d.CreateContainerBackup(name, req)
	if err != nil {
		return err
	}

	// Wait until backup is done
	err = op.Wait()
	if err != nil {
		return err
	}

	// Get name of backup
	backupName := strings.TrimPrefix(op.Get().Resources["backups"][0],
		"/1.0/backups/")

	defer func() {
		// Delete backup after we're done
		op, _ = d.DeleteContainerBackup(name, backupName)
		op.Wait()
	}()

	var targetName string
	if len(args) > 1 {
		targetName = args[1]
	} else {
		targetName = "backup.tar.xz"
	}

	target, err := os.Create(shared.HostPath(targetName))
	if err != nil {
		return err
	}
	defer target.Close()

	// Prepare the download request
	progress := utils.ProgressRenderer{Format: i18n.G("Exporting the backup: %s")}
	backupFileRequest := lxd.BackupFileRequest{
		BackupFile:      io.WriteSeeker(target),
		ProgressHandler: progress.UpdateProgress,
	}

	// Export tarball
	_, err = d.GetContainerBackupFile(name, backupName, &backupFileRequest)
	if err != nil {
		os.Remove(targetName)
		progress.Done("")
		return err
	}

	progress.Done(i18n.G("Backup exported successfully!"))
	return nil
}
<commit_msg>lxc/export: Don't crash on failure to delete backup<commit_after>package main

import (
	"io"
	"os"
	"strings"
	"time"

	"github.com/spf13/cobra"

	"github.com/lxc/lxd/client"
	"github.com/lxc/lxd/lxc/utils"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/api"
	cli "github.com/lxc/lxd/shared/cmd"
	"github.com/lxc/lxd/shared/i18n"
)

type cmdExport struct {
	global *cmdGlobal

	flagContainerOnly    bool
	flagOptimizedStorage bool
}

func (c *cmdExport) Command() *cobra.Command {
	cmd := &cobra.Command{}
	cmd.Use = i18n.G("export [<remote>:]<container> [target] [--container-only] [--optimized-storage]")
	cmd.Short = i18n.G("Export container backups")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Export containers as backup tarballs.`))
	cmd.Example = cli.FormatSection("", i18n.G(
		`lxc export u1 backup0.tar.xz
    Download a backup tarball of the u1 container.`))

	cmd.RunE = c.Run
	cmd.Flags().BoolVar(&c.flagContainerOnly, "container-only", false,
		i18n.G("Whether or not to only backup the container (without snapshots)"))
	cmd.Flags().BoolVar(&c.flagOptimizedStorage, "optimized-storage", false,
		i18n.G("Use storage driver optimized format (can only be restored on a similar pool)"))

	return cmd
}

func (c *cmdExport) Run(cmd *cobra.Command, args []string) error {
	conf := c.global.conf

	// Sanity checks
	exit, err := c.global.CheckArgs(cmd, args, 1, 2)
	if exit {
		return err
	}

	// Connect to LXD
	remote, name, err := conf.ParseRemote(args[0])
	if err != nil {
		return err
	}

	d, err := conf.GetContainerServer(remote)
	if err != nil {
		return err
	}

	req := api.ContainerBackupsPost{
		Name:             "",
		ExpiryDate:       time.Now().Add(30 * time.Minute),
		ContainerOnly:    c.flagContainerOnly,
		OptimizedStorage: c.flagOptimizedStorage,
	}

	op, err := d.CreateContainerBackup(name, req)
	if err != nil {
		return err
	}

	// Wait until backup is done
	err = op.Wait()
	if err != nil {
		return err
	}

	// Get name of backup
	backupName := strings.TrimPrefix(op.Get().Resources["backups"][0],
		"/1.0/backups/")

	defer func() {
		// Delete backup after we're done
		op, err = d.DeleteContainerBackup(name, backupName)
		if err == nil {
			op.Wait()
		}
	}()

	var targetName string
	if len(args) > 1 {
		targetName = args[1]
	} else {
		targetName = "backup.tar.xz"
	}

	target, err := os.Create(shared.HostPath(targetName))
	if err != nil {
		return err
	}
	defer target.Close()

	// Prepare the download request
	progress := utils.ProgressRenderer{Format: i18n.G("Exporting the backup: %s")}
	backupFileRequest := lxd.BackupFileRequest{
		BackupFile:      io.WriteSeeker(target),
		ProgressHandler: progress.UpdateProgress,
	}

	// Export tarball
	_, err = d.GetContainerBackupFile(name, backupName, &backupFileRequest)
	if err != nil {
		os.Remove(targetName)
		progress.Done("")
		return err
	}

	progress.Done(i18n.G("Backup exported successfully!"))
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"fmt"
	"net/http"
	"strings"

	"github.com/lxc/lxd/lxd/db"
	"github.com/lxc/lxd/lxd/response"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/logger"
)

var eventTypes = []string{"logging", "operation", "lifecycle"}

var eventsCmd = APIEndpoint{
	Path: "events",

	Get: APIEndpointAction{Handler: eventsGet, AccessHandler: allowAuthenticated},
}

type eventsServe struct {
	req *http.Request
	d   *Daemon
}

func (r *eventsServe) Render(w http.ResponseWriter) error {
	return eventsSocket(r.d, r.req, w)
}

func (r *eventsServe) String() string {
	return "event handler"
}

func eventsSocket(d *Daemon, r *http.Request, w http.ResponseWriter) error {
	project := projectParam(r)
	types := strings.Split(r.FormValue("type"), ",")
	if len(types) == 1 && types[0] == "" {
		types = eventTypes
	}

	// Validate event types.
	for _, entry := range types {
		if !shared.StringInSlice(entry, eventTypes) {
			response.BadRequest(fmt.Errorf("'%s' isn't a supported event type", entry)).Render(w)
			return nil
		}
	}

	// Upgrade the connection to websocket
	c, err := shared.WebsocketUpgrader.Upgrade(w, r, nil)
	if err != nil {
		return err
	}
	defer c.Close() // This ensures the go routine below is ended when this function ends.

	// Get the current local serverName and store it for the events
	// We do that now to avoid issues with changes to the name and to limit
	// the number of DB access to just one per connection
	var serverName string
	err = d.cluster.Transaction(func(tx *db.ClusterTx) error {
		serverName, err = tx.GetLocalNodeName()
		return err
	})
	if err != nil {
		return err
	}

	// If this request is an internal one initiated by another node wanting
	// to watch the events on this node, set the listener to broadcast only
	// local events.
	listener, err := d.events.AddListener(project, c, types, serverName, isClusterNotification(r))
	if err != nil {
		return err
	}

	logger.Debugf("New event listener: %s", listener.ID())

	// Create a cancellable context from the request context. Once the request has been upgraded
	// to a websocket the request's context doesn't appear to be cancelled when the client
	// disconnects (even though its documented as such). But we wrap the request's context here
	// anyway just in case its fixed in the future.
	ctx, cancel := context.WithCancel(r.Context())

	// Instead of relying on the request's context to be cancelled when the client connection
	// is closed (see above), we instead enter into a repeat read loop of the connection in
	// order to detect when the client connection is closed. This should be fine as for the
	// events route there is no expectation to read any useful data from the client.
	go func() {
		for {
			_, _, err := c.NextReader()
			if err != nil {
				// Client read error (likely premature close), so cancel context.
				cancel()
				return
			}
		}
	}()

	listener.Wait(ctx)
	logger.Debugf("Event listener finished: %s", listener.ID())

	return nil
}

func eventsGet(d *Daemon, r *http.Request) response.Response {
	return &eventsServe{req: r, d: d}
}
<commit_msg>lxd/events: Prevent logging access to non-admin<commit_after>package main

import (
	"context"
	"fmt"
	"net/http"
	"strings"

	"github.com/lxc/lxd/lxd/db"
	"github.com/lxc/lxd/lxd/response"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/logger"
)

var eventTypes = []string{"logging", "operation", "lifecycle"}

var eventsCmd = APIEndpoint{
	Path: "events",

	Get: APIEndpointAction{Handler: eventsGet, AccessHandler: allowAuthenticated},
}

type eventsServe struct {
	req *http.Request
	d   *Daemon
}

func (r *eventsServe) Render(w http.ResponseWriter) error {
	return eventsSocket(r.d, r.req, w)
}

func (r *eventsServe) String() string {
	return "event handler"
}

func eventsSocket(d *Daemon, r *http.Request, w http.ResponseWriter) error {
	project := projectParam(r)
	types := strings.Split(r.FormValue("type"), ",")
	if len(types) == 1 && types[0] == "" {
		types = eventTypes
	}

	// Validate event types.
	for _, entry := range types {
		if !shared.StringInSlice(entry, eventTypes) {
			response.BadRequest(fmt.Errorf("'%s' isn't a supported event type", entry)).Render(w)
			return nil
		}
	}

	if shared.StringInSlice("logging", types) && !d.userIsAdmin(r) {
		response.Forbidden(nil).Render(w)
		return nil
	}

	// Upgrade the connection to websocket
	c, err := shared.WebsocketUpgrader.Upgrade(w, r, nil)
	if err != nil {
		return err
	}
	defer c.Close() // This ensures the go routine below is ended when this function ends.

	// Get the current local serverName and store it for the events
	// We do that now to avoid issues with changes to the name and to limit
	// the number of DB access to just one per connection
	var serverName string
	err = d.cluster.Transaction(func(tx *db.ClusterTx) error {
		serverName, err = tx.GetLocalNodeName()
		return err
	})
	if err != nil {
		return err
	}

	// If this request is an internal one initiated by another node wanting
	// to watch the events on this node, set the listener to broadcast only
	// local events.
	listener, err := d.events.AddListener(project, c, types, serverName, isClusterNotification(r))
	if err != nil {
		return err
	}

	logger.Debugf("New event listener: %s", listener.ID())

	// Create a cancellable context from the request context. Once the request has been upgraded
	// to a websocket the request's context doesn't appear to be cancelled when the client
	// disconnects (even though its documented as such). But we wrap the request's context here
	// anyway just in case its fixed in the future.
	ctx, cancel := context.WithCancel(r.Context())

	// Instead of relying on the request's context to be cancelled when the client connection
	// is closed (see above), we instead enter into a repeat read loop of the connection in
	// order to detect when the client connection is closed. This should be fine as for the
	// events route there is no expectation to read any useful data from the client.
	go func() {
		for {
			_, _, err := c.NextReader()
			if err != nil {
				// Client read error (likely premature close), so cancel context.
				cancel()
				return
			}
		}
	}()

	listener.Wait(ctx)
	logger.Debugf("Event listener finished: %s", listener.ID())

	return nil
}

func eventsGet(d *Daemon, r *http.Request) response.Response {
	return &eventsServe{req: r, d: d}
}
<|endoftext|>


<commit_before>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2018 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package cloud

import (
	"encoding/json"
	"fmt"
	"math"
	"sort"
	"strconv"
	"time"

	"github.com/loadimpact/k6/lib/metrics"
	"github.com/loadimpact/k6/lib/netext"
	"github.com/loadimpact/k6/stats"
)

const DataTypeSingle = "Point"
const DataTypeMap = "Points"
const DataTypeAggregatedHTTPReqs = "AggregatedPoints"

// Timestamp is used for sending times encoded as microsecond UNIX timestamps to the cloud servers
type Timestamp time.Time

// MarshalJSON encodes the microsecond UNIX timestamps as strings because JavaScripts doesn't have actual integers and tends to round big numbers
func (ct Timestamp) MarshalJSON() ([]byte, error) {
	return []byte(`"` + strconv.FormatInt(time.Time(ct).UnixNano()/1000, 10) + `"`), nil
}

// UnmarshalJSON decodes the string-enclosed microsecond timestamp back into the proper time.Time alias
func (ct *Timestamp) UnmarshalJSON(p []byte) error {
	var s string
	if err := json.Unmarshal(p, &s); err != nil {
		return err
	}
	microSecs, err := strconv.ParseInt(s, 10, 64)
	if err != nil {
		return err
	}
	*ct = Timestamp(time.Unix(microSecs/1000000, (microSecs%1000000)*1000))
	return nil
}

// Sample is the generic struct that contains all types of data that we send to the cloud.
type Sample struct {
	Type   string      `json:"type"`
	Metric string      `json:"metric"`
	Data   interface{} `json:"data"`
}

// UnmarshalJSON decodes the Data into the corresponding struct
func (ct *Sample) UnmarshalJSON(p []byte) error {
	var tmpSample struct {
		Type   string          `json:"type"`
		Metric string          `json:"metric"`
		Data   json.RawMessage `json:"data"`
	}
	if err := json.Unmarshal(p, &tmpSample); err != nil {
		return err
	}
	s := Sample{
		Type:   tmpSample.Type,
		Metric: tmpSample.Metric,
	}

	switch tmpSample.Type {
	case DataTypeSingle:
		s.Data = new(SampleDataSingle)
	case DataTypeMap:
		s.Data = new(SampleDataMap)
	case DataTypeAggregatedHTTPReqs:
		s.Data = new(SampleDataAggregatedHTTPReqs)
	default:
		return fmt.Errorf("Unknown sample type '%s'", tmpSample.Type)
	}

	if err := json.Unmarshal(tmpSample.Data, &s.Data); err != nil {
		return err
	}

	*ct = s
	return nil
}

// SampleDataSingle is used in all simple un-aggregated single-value samples.
type SampleDataSingle struct {
	Time  Timestamp         `json:"time"`
	Type  stats.MetricType  `json:"type"`
	Tags  *stats.SampleTags `json:"tags,omitempty"`
	Value float64           `json:"value"`
}

// SampleDataMap is used by samples that contain multiple values, currently
// that's only iteration metrics (`iter_li_all`) and unaggregated HTTP
// requests (`http_req_li_all`).
type SampleDataMap struct {
	Time   Timestamp          `json:"time"`
	Type   stats.MetricType   `json:"type"`
	Tags   *stats.SampleTags  `json:"tags,omitempty"`
	Values map[string]float64 `json:"values,omitempty"`
}

// NewSampleFromTrail just creates a ready-to-send Sample instance
// directly from a netext.Trail.
func NewSampleFromTrail(trail *netext.Trail) *Sample {
	return &Sample{
		Type:   DataTypeMap,
		Metric: "http_req_li_all",
		Data: &SampleDataMap{
			Time: Timestamp(trail.GetTime()),
			Tags: trail.GetTags(),
			Values: map[string]float64{
				metrics.HTTPReqs.Name:        1,
				metrics.HTTPReqDuration.Name: stats.D(trail.Duration),

				metrics.HTTPReqBlocked.Name:        stats.D(trail.Blocked),
				metrics.HTTPReqConnecting.Name:     stats.D(trail.Connecting),
				metrics.HTTPReqTLSHandshaking.Name: stats.D(trail.TLSHandshaking),
				metrics.HTTPReqSending.Name:        stats.D(trail.Sending),
				metrics.HTTPReqWaiting.Name:        stats.D(trail.Waiting),
				metrics.HTTPReqReceiving.Name:      stats.D(trail.Receiving),
			},
		},
	}
}

// SampleDataAggregatedHTTPReqs is used in aggregated samples for HTTP requests.
type SampleDataAggregatedHTTPReqs struct {
	Time   Timestamp         `json:"time"`
	Type   string            `json:"type"`
	Count  uint64            `json:"count"`
	Tags   *stats.SampleTags `json:"tags,omitempty"`
	Values struct {
		Duration       AggregatedMetric `json:"http_req_duration"`
		Blocked        AggregatedMetric `json:"http_req_blocked"`
		Connecting     AggregatedMetric `json:"http_req_connecting"`
		TLSHandshaking AggregatedMetric `json:"http_req_tls_handshaking"`
		Sending        AggregatedMetric `json:"http_req_sending"`
		Waiting        AggregatedMetric `json:"http_req_waiting"`
		Receiving      AggregatedMetric `json:"http_req_receiving"`
	} `json:"values"`
}

// Add updates all agregated values with the supplied trail data
func (sdagg *SampleDataAggregatedHTTPReqs) Add(trail *netext.Trail) {
	sdagg.Count++
	sdagg.Values.Duration.Add(trail.Duration)
	sdagg.Values.Blocked.Add(trail.Blocked)
	sdagg.Values.Connecting.Add(trail.Connecting)
	sdagg.Values.TLSHandshaking.Add(trail.TLSHandshaking)
	sdagg.Values.Sending.Add(trail.Sending)
	sdagg.Values.Waiting.Add(trail.Waiting)
	sdagg.Values.Receiving.Add(trail.Receiving)
}

// CalcAverages calculates and sets all `Avg` properties in the `Values` struct
func (sdagg *SampleDataAggregatedHTTPReqs) CalcAverages() {
	count := float64(sdagg.Count)
	sdagg.Values.Duration.Calc(count)
	sdagg.Values.Blocked.Calc(count)
	sdagg.Values.Connecting.Calc(count)
	sdagg.Values.TLSHandshaking.Calc(count)
	sdagg.Values.Sending.Calc(count)
	sdagg.Values.Waiting.Calc(count)
	sdagg.Values.Receiving.Calc(count)
}

// AggregatedMetric is used to store aggregated information for a
// particular metric in an SampleDataAggregatedMap.
type AggregatedMetric struct {
	// Used by Add() to keep working state
	minD time.Duration
	maxD time.Duration
	sumD time.Duration
	// Updated by Calc() and used in the JSON output
	Min float64 `json:"min"`
	Max float64 `json:"max"`
	Avg float64 `json:"avg"`
}

// Add the new duration to the internal sum and update Min and Max if necessary
func (am *AggregatedMetric) Add(t time.Duration) {
	if am.sumD == 0 || am.minD > t {
		am.minD = t
	}
	if am.maxD < t {
		am.maxD = t
	}
	am.sumD += t
}

// Calc populates the float fields for min and max and calulates the average value
func (am *AggregatedMetric) Calc(count float64) {
	am.Min = stats.D(am.minD)
	am.Max = stats.D(am.maxD)
	am.Avg = stats.D(am.sumD) / count
}

type aggregationBucket map[*stats.SampleTags][]*netext.Trail

type durations []time.Duration

func (d durations) Len() int           { return len(d) }
func (d durations) Swap(i, j int)      { d[i], d[j] = d[j], d[i] }
func (d durations) Less(i, j int) bool { return d[i] < d[j] }

// This is currently used only for benchmark comparisons and tests.
func (d durations) SortGetNormalBounds(radius, iqrLowerCoef, iqrUpperCoef float64) (min, max time.Duration) {
	if len(d) == 0 {
		return
	}
	sort.Sort(d)
	last := float64(len(d) - 1)
	radius = math.Min(0.5, radius)
	q1 := d[int(last*(0.5-radius))]
	q3 := d[int(last*(0.5+radius))]
	iqr := float64(q3 - q1)
	min = q1 - time.Duration(iqrLowerCoef*iqr)
	max = q3 + time.Duration(iqrUpperCoef*iqr)
	return
}

// Reworked and translated in Go from:
// https://github.com/haifengl/smile/blob/master/math/src/main/java/smile/sort/QuickSelect.java
// Originally Copyright (c) 2010 Haifeng Li
// Licensed under the Apache License, Version 2.0
func (d durations) quickSelect(k int) time.Duration {
	n := len(d)
	l := 0
	ir := n - 1

	var a time.Duration
	var i, j, mid int
	for {
		if ir <= l+1 {
			if ir == l+1 && d[ir] < d[l] {
				d.Swap(l, ir)
			}
			return d[k]
		}
		mid = (l + ir) >> 1
		d.Swap(mid, l+1)
		if d[l] > d[ir] {
			d.Swap(l, ir)
		}
		if d[l+1] > d[ir] {
			d.Swap(l+1, ir)
		}
		if d[l] > d[l+1] {
			d.Swap(l, l+1)
		}
		i = l + 1
		j = ir
		a = d[l+1]
		for {
			for i++; d[i] < a; i++ {
			}
			for j--; d[j] > a; j-- {
			}

			if j < i {
				break
			}
			d.Swap(i, j)
		}
		d[l+1] = d[j]
		d[j] = a
		if j >= k {
			ir = j - 1
		}
		if j <= k {
			l = i
		}
	}
}

// Uses Quickselect to avoid sorting the whole slice
// https://en.wikipedia.org/wiki/Quickselect
func (d durations) SelectGetNormalBounds(radius, iqrLowerCoef, iqrUpperCoef float64) (min, max time.Duration) {
	if len(d) == 0 {
		return
	}
	radius = math.Min(0.5, radius)
	last := float64(len(d) - 1)

	q1 := d.quickSelect(int(last * (0.5 - radius)))
	q3 := d.quickSelect(int(last * (0.5 + radius)))

	iqr := float64(q3 - q1)
	min = q1 - time.Duration(iqrLowerCoef*iqr)
	max = q3 + time.Duration(iqrUpperCoef*iqr)
	return
}
<commit_msg>Implement Artem's suggestion for quickselect simplification<commit_after>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2018 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package cloud

import (
	"encoding/json"
	"fmt"
	"math"
	"sort"
	"strconv"
	"time"

	"github.com/loadimpact/k6/lib/metrics"
	"github.com/loadimpact/k6/lib/netext"
	"github.com/loadimpact/k6/stats"
)

const DataTypeSingle = "Point"
const DataTypeMap = "Points"
const DataTypeAggregatedHTTPReqs = "AggregatedPoints"

// Timestamp is used for sending times encoded as microsecond UNIX timestamps to the cloud servers
type Timestamp time.Time

// MarshalJSON encodes the microsecond UNIX timestamps as strings because JavaScripts doesn't have actual integers and tends to round big numbers
func (ct Timestamp) MarshalJSON() ([]byte, error) {
	return []byte(`"` + strconv.FormatInt(time.Time(ct).UnixNano()/1000, 10) + `"`), nil
}

// UnmarshalJSON decodes the string-enclosed microsecond timestamp back into the proper time.Time alias
func (ct *Timestamp) UnmarshalJSON(p []byte) error {
	var s string
	if err := json.Unmarshal(p, &s); err != nil {
		return err
	}
	microSecs, err := strconv.ParseInt(s, 10, 64)
	if err != nil {
		return err
	}
	*ct = Timestamp(time.Unix(microSecs/1000000, (microSecs%1000000)*1000))
	return nil
}

// Sample is the generic struct that contains all types of data that we send to the cloud.
type Sample struct {
	Type   string      `json:"type"`
	Metric string      `json:"metric"`
	Data   interface{} `json:"data"`
}

// UnmarshalJSON decodes the Data into the corresponding struct
func (ct *Sample) UnmarshalJSON(p []byte) error {
	var tmpSample struct {
		Type   string          `json:"type"`
		Metric string          `json:"metric"`
		Data   json.RawMessage `json:"data"`
	}
	if err := json.Unmarshal(p, &tmpSample); err != nil {
		return err
	}
	s := Sample{
		Type:   tmpSample.Type,
		Metric: tmpSample.Metric,
	}

	switch tmpSample.Type {
	case DataTypeSingle:
		s.Data = new(SampleDataSingle)
	case DataTypeMap:
		s.Data = new(SampleDataMap)
	case DataTypeAggregatedHTTPReqs:
		s.Data = new(SampleDataAggregatedHTTPReqs)
	default:
		return fmt.Errorf("Unknown sample type '%s'", tmpSample.Type)
	}

	if err := json.Unmarshal(tmpSample.Data, &s.Data); err != nil {
		return err
	}

	*ct = s
	return nil
}

// SampleDataSingle is used in all simple un-aggregated single-value samples.
type SampleDataSingle struct {
	Time  Timestamp         `json:"time"`
	Type  stats.MetricType  `json:"type"`
	Tags  *stats.SampleTags `json:"tags,omitempty"`
	Value float64           `json:"value"`
}

// SampleDataMap is used by samples that contain multiple values, currently
// that's only iteration metrics (`iter_li_all`) and unaggregated HTTP
// requests (`http_req_li_all`).
type SampleDataMap struct {
	Time   Timestamp          `json:"time"`
	Type   stats.MetricType   `json:"type"`
	Tags   *stats.SampleTags  `json:"tags,omitempty"`
	Values map[string]float64 `json:"values,omitempty"`
}

// NewSampleFromTrail just creates a ready-to-send Sample instance
// directly from a netext.Trail.
func NewSampleFromTrail(trail *netext.Trail) *Sample {
	return &Sample{
		Type:   DataTypeMap,
		Metric: "http_req_li_all",
		Data: &SampleDataMap{
			Time: Timestamp(trail.GetTime()),
			Tags: trail.GetTags(),
			Values: map[string]float64{
				metrics.HTTPReqs.Name:        1,
				metrics.HTTPReqDuration.Name: stats.D(trail.Duration),

				metrics.HTTPReqBlocked.Name:        stats.D(trail.Blocked),
				metrics.HTTPReqConnecting.Name:     stats.D(trail.Connecting),
				metrics.HTTPReqTLSHandshaking.Name: stats.D(trail.TLSHandshaking),
				metrics.HTTPReqSending.Name:        stats.D(trail.Sending),
				metrics.HTTPReqWaiting.Name:        stats.D(trail.Waiting),
				metrics.HTTPReqReceiving.Name:      stats.D(trail.Receiving),
			},
		},
	}
}

// SampleDataAggregatedHTTPReqs is used in aggregated samples for HTTP requests.
type SampleDataAggregatedHTTPReqs struct {
	Time   Timestamp         `json:"time"`
	Type   string            `json:"type"`
	Count  uint64            `json:"count"`
	Tags   *stats.SampleTags `json:"tags,omitempty"`
	Values struct {
		Duration       AggregatedMetric `json:"http_req_duration"`
		Blocked        AggregatedMetric `json:"http_req_blocked"`
		Connecting     AggregatedMetric `json:"http_req_connecting"`
		TLSHandshaking AggregatedMetric `json:"http_req_tls_handshaking"`
		Sending        AggregatedMetric `json:"http_req_sending"`
		Waiting        AggregatedMetric `json:"http_req_waiting"`
		Receiving      AggregatedMetric `json:"http_req_receiving"`
	} `json:"values"`
}

// Add updates all agregated values with the supplied trail data
func (sdagg *SampleDataAggregatedHTTPReqs) Add(trail *netext.Trail) {
	sdagg.Count++
	sdagg.Values.Duration.Add(trail.Duration)
	sdagg.Values.Blocked.Add(trail.Blocked)
	sdagg.Values.Connecting.Add(trail.Connecting)
	sdagg.Values.TLSHandshaking.Add(trail.TLSHandshaking)
	sdagg.Values.Sending.Add(trail.Sending)
	sdagg.Values.Waiting.Add(trail.Waiting)
	sdagg.Values.Receiving.Add(trail.Receiving)
}

// CalcAverages calculates and sets all `Avg` properties in the `Values` struct
func (sdagg *SampleDataAggregatedHTTPReqs) CalcAverages() {
	count := float64(sdagg.Count)
	sdagg.Values.Duration.Calc(count)
	sdagg.Values.Blocked.Calc(count)
	sdagg.Values.Connecting.Calc(count)
	sdagg.Values.TLSHandshaking.Calc(count)
	sdagg.Values.Sending.Calc(count)
	sdagg.Values.Waiting.Calc(count)
	sdagg.Values.Receiving.Calc(count)
}

// AggregatedMetric is used to store aggregated information for a
// particular metric in an SampleDataAggregatedMap.
type AggregatedMetric struct {
	// Used by Add() to keep working state
	minD time.Duration
	maxD time.Duration
	sumD time.Duration
	// Updated by Calc() and used in the JSON output
	Min float64 `json:"min"`
	Max float64 `json:"max"`
	Avg float64 `json:"avg"`
}

// Add the new duration to the internal sum and update Min and Max if necessary
func (am *AggregatedMetric) Add(t time.Duration) {
	if am.sumD == 0 || am.minD > t {
		am.minD = t
	}
	if am.maxD < t {
		am.maxD = t
	}
	am.sumD += t
}

// Calc populates the float fields for min and max and calulates the average value
func (am *AggregatedMetric) Calc(count float64) {
	am.Min = stats.D(am.minD)
	am.Max = stats.D(am.maxD)
	am.Avg = stats.D(am.sumD) / count
}

type aggregationBucket map[*stats.SampleTags][]*netext.Trail

type durations []time.Duration

func (d durations) Len() int           { return len(d) }
func (d durations) Swap(i, j int)      { d[i], d[j] = d[j], d[i] }
func (d durations) Less(i, j int) bool { return d[i] < d[j] }

// This is currently used only for benchmark comparisons and tests.
func (d durations) SortGetNormalBounds(radius, iqrLowerCoef, iqrUpperCoef float64) (min, max time.Duration) {
	if len(d) == 0 {
		return
	}
	sort.Sort(d)
	last := float64(len(d) - 1)
	radius = math.Min(0.5, radius)
	q1 := d[int(last*(0.5-radius))]
	q3 := d[int(last*(0.5+radius))]
	iqr := float64(q3 - q1)
	min = q1 - time.Duration(iqrLowerCoef*iqr)
	max = q3 + time.Duration(iqrUpperCoef*iqr)
	return
}

// Reworked and translated in Go from:
// https://github.com/haifengl/smile/blob/master/math/src/main/java/smile/sort/QuickSelect.java
// Originally Copyright (c) 2010 Haifeng Li
// Licensed under the Apache License, Version 2.0
//
// This could potentially be implemented as a standalone function
// that only depends on the sort.Interface methods, but that would
// probably introduce some performance overhead because of the
// dynamic dispatch.
func (d durations) quickSelect(k int) time.Duration {
	n := len(d)
	l := 0
	ir := n - 1

	var i, j, mid int
	for {
		if ir <= l+1 {
			if ir == l+1 && d[ir] < d[l] {
				d.Swap(l, ir)
			}
			return d[k]
		}
		mid = (l + ir) >> 1
		d.Swap(mid, l+1)
		if d[l] > d[ir] {
			d.Swap(l, ir)
		}
		if d[l+1] > d[ir] {
			d.Swap(l+1, ir)
		}
		if d[l] > d[l+1] {
			d.Swap(l, l+1)
		}
		i = l + 1
		j = ir
		for {
			for i++; d[i] < d[l+1]; i++ {
			}
			for j--; d[j] > d[l+1]; j-- {
			}
			if j < i {
				break
			}
			d.Swap(i, j)
		}
		d.Swap(l+1, j)
		if j >= k {
			ir = j - 1
		}
		if j <= k {
			l = i
		}
	}
}

// Uses Quickselect to avoid sorting the whole slice
// https://en.wikipedia.org/wiki/Quickselect
func (d durations) SelectGetNormalBounds(radius, iqrLowerCoef, iqrUpperCoef float64) (min, max time.Duration) {
	if len(d) == 0 {
		return
	}
	radius = math.Min(0.5, radius)
	last := float64(len(d) - 1)

	q1 := d.quickSelect(int(last * (0.5 - radius)))
	q3 := d.quickSelect(int(last * (0.5 + radius)))

	iqr := float64(q3 - q1)
	min = q1 - time.Duration(iqrLowerCoef*iqr)
	max = q3 + time.Duration(iqrUpperCoef*iqr)
	return
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"regexp"
	"strings"
	"testing"
)

func testcmd(cmd string) (string, error) {
	fmt.Println("(T) " + cmd)
	switch {
	case cmd == "sudo ls -a1F /mnt/sda1/var/lib/docker/vfs/dir":
		return currenttest.vs.ls(), nil
	case cmd == "docker ps -aq --no-trunc":
		return "", nil
	case strings.HasPrefix(cmd, "docker inspect -f '{{ .Name }},{{ range $key, $value := .Volumes }}{{ $key }},{{ $value }}##~#{{ end }}' "):
		return "", nil
	case strings.HasPrefix(cmd, "sudo rm /mnt/sda1/var/lib/docker/vfs/dir/"):
		deleted := cmd[len("sudo rm /mnt/sda1/var/lib/docker/vfs/dir/"):]
		deletions = append(deletions, deleted)
		return "", nil
	case strings.HasPrefix(cmd, "sudo readlink /mnt/sda1/var/lib/docker/vfs/dir/"):
		if strings.Contains(cmd, ",nonexistent") {
			return "", errors.New("non-existent linked folder")
		}
		r := regexp.MustCompile(`.*\$([^#]+)###.*`)
		ss := r.FindStringSubmatch(cmd)
		if len(ss) == 2 {
			folder := ss[1]
			folder = folder + strings.Repeat("1", 64-len(folder))
			return folder, nil
		}
		return "", nil
	case strings.HasPrefix(cmd, "sudo ls /mnt/sda1/var/lib/docker/vfs/dir/"):
		if cmd == "sudo ls /mnt/sda1/var/lib/docker/vfs/dir/" {
			return "", errors.New("non-ls linked folder")
		}
		return "", nil
	default:
		currentT.Fatalf("test '%s': unknown command!\n", cmd)
		return fmt.Sprintf("test '%s'", cmd), errors.New("unknown command")
	}
}

type volspecs []string
type Test struct {
	title string
	vs    volspecs
	res   []int
	strs  []string
}

func (vs volspecs) ls() string {
	if len(vs) == 0 {
		return ""
	}
	res := ""
	for i, spec := range vs {
		if strings.HasSuffix(spec, "/") {
			spec = spec[:len(spec)-1]
			res = res + spec + strings.Repeat(fmt.Sprintf("%d", i), 64-len(spec)) + "/\n"
		}
		if strings.HasSuffix(spec, "@") {
			mp := "." + strings.Replace(spec, ";", "###", -1)
			mp = strings.Replace(mp, "/", ",#,", -1)
			res = res + mp + "\n"
		}
	}
	return res
}

var deletions = []string{}
var tests = []Test{
	Test{"empty vfs", []string{}, []int{0, 0, 0, 0, 0}, []string{}},
	Test{"two volumes", []string{"fa/", "fb/"}, []int{0, 0, 2, 2, 0}, []string{}},
	Test{"Invalid (ill-formed) markers must be deleted", []string{"cainv/path/a@"}, []int{0, 0, 0, 0, -1}, []string{}},
	Test{"Invalid (no readlink) markers must be deleted", []string{"ca;/path/nonexistenta@", "cb;/path/nonexistentb@"}, []int{0, 0, 0, 0, -2}, []string{}},
	Test{"Invalid (no ls) markers must be deleted", []string{"ca;/path/nolsa@", "cb;/path/nolsb@"}, []int{0, 0, 0, 0, -2}, []string{}},
	Test{"Invalid (no vdir) markers must be deleted", []string{"ca$novdira;/path/nolsa@", "cb$novdirb;/path/nolsb@"}, []int{0, 0, 0, 0, -2}, []string{}},
	Test{"two valid markers", []string{"ca$fa;/path/vola@", "cb$fb;/path/volb@"}, []int{0, 0, 0, 0, 2}, []string{"marker 'fa11111'<ca$fa->/path/vola>", "marker 'fb11111'<cb$fb->/path/volb>"}},
}
var currenttest Test
var currentT *testing.T

// TestContainers test different vfs scenarios
func TestContainers(t *testing.T) {
	cmd = testcmd
	currentT = t
	for i, test := range tests {
		currenttest = test
		deletions = []string{}
		fmt.Println("------ vvv " + test.title + " vvv ------")
		main()
		tc := Containers()
		toc := OrphanedContainers()
		tv := Volumes()
		tov := OrphanedVolumes()
		tm := Markers()
		if len(tc) != test.res[0] {
			t.Errorf("Test %d: '%s' expected '%d' containers, got '%d'", i+1, test.title, test.res[0], len(tc))
		}
		if len(toc) != test.res[1] {
			t.Errorf("Test %d: '%s' expected '%d' orphaned containers, got '%d'", i+1, test.title, test.res[1], len(toc))
		}
		if len(tv) != test.res[2] {
			t.Errorf("Test %d: '%s' expected '%d' volumes, got '%d'", i+1, test.title, test.res[2], len(tv))
		}
		if len(tov) != test.res[3] {
			t.Errorf("Test %d: '%s' expected '%d' orphaned volumes, got '%d'", i+1, test.title, test.res[3], len(tov))
		}
		if nbmarkers(tm) != test.res[4] {
			t.Errorf("Test %d: '%s' expected '%d' markers, got '%d'", i+1, test.title, test.res[4], nbmarkers(tm))
		}
		if i == 6 && tm[0].String() != "marker 'fa11111'<ca$fa->/path/vola>" {
			t.Errorf("Test %d: '%s' expected marker '%s', got '%s'", i+1, test.title, "marker 'fa11111'<ca$fa->/path/vola>", tm[0].String())
		}
		fmt.Println("------ ^^^ " + test.title + " ^^^ ------")
		fmt.Println("----------")
	}
}

func nbmarkers(tm markers) int {
	res := len(tm)
	for _, d := range deletions {
		if strings.HasPrefix(d, ".") {
			res = res - 1
		}
	}
	return res
}
<commit_msg>gcl_test.go: test markers String() values<commit_after>package main

import (
	"errors"
	"fmt"
	"regexp"
	"strings"
	"testing"
)

func testcmd(cmd string) (string, error) {
	fmt.Println("(T) " + cmd)
	switch {
	case cmd == "sudo ls -a1F /mnt/sda1/var/lib/docker/vfs/dir":
		return currenttest.vs.ls(), nil
	case cmd == "docker ps -aq --no-trunc":
		return "", nil
	case strings.HasPrefix(cmd, "docker inspect -f '{{ .Name }},{{ range $key, $value := .Volumes }}{{ $key }},{{ $value }}##~#{{ end }}' "):
		return "", nil
	case strings.HasPrefix(cmd, "sudo rm /mnt/sda1/var/lib/docker/vfs/dir/"):
		deleted := cmd[len("sudo rm /mnt/sda1/var/lib/docker/vfs/dir/"):]
		deletions = append(deletions, deleted)
		return "", nil
	case strings.HasPrefix(cmd, "sudo readlink /mnt/sda1/var/lib/docker/vfs/dir/"):
		if strings.Contains(cmd, ",nonexistent") {
			return "", errors.New("non-existent linked folder")
		}
		r := regexp.MustCompile(`.*\$([^#]+)###.*`)
		ss := r.FindStringSubmatch(cmd)
		if len(ss) == 2 {
			folder := ss[1]
			folder = folder + strings.Repeat("1", 64-len(folder))
			return folder, nil
		}
		return "", nil
	case strings.HasPrefix(cmd, "sudo ls /mnt/sda1/var/lib/docker/vfs/dir/"):
		if cmd == "sudo ls /mnt/sda1/var/lib/docker/vfs/dir/" {
			return "", errors.New("non-ls linked folder")
		}
		return "", nil
	default:
		currentT.Fatalf("test '%s': unknown command!\n", cmd)
		return fmt.Sprintf("test '%s'", cmd), errors.New("unknown command")
	}
}

type volspecs []string
type Test struct {
	title string
	vs    volspecs
	res   []int
	strs  []string
}

func (vs volspecs) ls() string {
	if len(vs) == 0 {
		return ""
	}
	res := ""
	for i, spec := range vs {
		if strings.HasSuffix(spec, "/") {
			spec = spec[:len(spec)-1]
			res = res + spec + strings.Repeat(fmt.Sprintf("%d", i), 64-len(spec)) + "/\n"
		}
		if strings.HasSuffix(spec, "@") {
			mp := "." + strings.Replace(spec, ";", "###", -1)
			mp = strings.Replace(mp, "/", ",#,", -1)
			res = res + mp + "\n"
		}
	}
	return res
}

var deletions = []string{}
var tests = []Test{
	Test{"empty vfs", []string{}, []int{0, 0, 0, 0, 0}, []string{}},
	Test{"two volumes", []string{"fa/", "fb/"}, []int{0, 0, 2, 2, 0}, []string{}},
	Test{"Invalid (ill-formed) markers must be deleted", []string{"cainv/path/a@"}, []int{0, 0, 0, 0, -1}, []string{}},
	Test{"Invalid (no readlink) markers must be deleted", []string{"ca;/path/nonexistenta@", "cb;/path/nonexistentb@"}, []int{0, 0, 0, 0, -2}, []string{}},
	Test{"Invalid (no ls) markers must be deleted", []string{"ca;/path/nolsa@", "cb;/path/nolsb@"}, []int{0, 0, 0, 0, -2}, []string{}},
	Test{"Invalid (no vdir) markers must be deleted", []string{"ca$novdira;/path/nolsa@", "cb$novdirb;/path/nolsb@"}, []int{0, 0, 0, 0, -2}, []string{}},
	Test{"two valid markers", []string{"ca$fa;/path/vola@", "cb$fb;/path/volb@"}, []int{0, 0, 0, 0, 2}, []string{"marker 'fa11111'<ca$fa->/path/vola>", "marker 'fb11111'<cb$fb->/path/volb>"}},
}
var currenttest Test
var currentT *testing.T

// TestContainers test different vfs scenarios
func TestContainers(t *testing.T) {
	cmd = testcmd
	currentT = t
	for i, test := range tests {
		currenttest = test
		deletions = []string{}
		fmt.Println("------ vvv " + test.title + " vvv ------")
		main()
		tc := Containers()
		toc := OrphanedContainers()
		tv := Volumes()
		tov := OrphanedVolumes()
		tm := Markers()
		if len(tc) != test.res[0] {
			t.Errorf("Test %d: '%s' expected '%d' containers, got '%d'", i+1, test.title, test.res[0], len(tc))
		}
		if len(toc) != test.res[1] {
			t.Errorf("Test %d: '%s' expected '%d' orphaned containers, got '%d'", i+1, test.title, test.res[1], len(toc))
		}
		if len(tv) != test.res[2] {
			t.Errorf("Test %d: '%s' expected '%d' volumes, got '%d'", i+1, test.title, test.res[2], len(tv))
		}
		if len(tov) != test.res[3] {
			t.Errorf("Test %d: '%s' expected '%d' orphaned volumes, got '%d'", i+1, test.title, test.res[3], len(tov))
		}
		if nbmarkers(tm) != test.res[4] {
			t.Errorf("Test %d: '%s' expected '%d' markers, got '%d'", i+1, test.title, test.res[4], nbmarkers(tm))
		}

		for _, m := range tm {
			ms := m.String()
			check(ms, "marker", &test, t, i)
		}
		/*
			if i == 6 && tm[0].String() != "marker 'fa11111'<ca$fa->/path/vola>" {
				t.Errorf("Test %d: '%s' expected marker '%s', got '%s'", i+1, test.title, "marker 'fa11111'<ca$fa->/path/vola>", tm[0].String())
			}*/
		fmt.Println("------ ^^^ " + test.title + " ^^^ ------")
		fmt.Println("----------")
	}
}

func check(s string, tmsg string, test *Test, t *testing.T, i int) {
	found := false
	for _, tms := range test.strs {
		if s == tms {
			found = true
			break
		}
	}
	if !found {
		t.Errorf("Test %d: '%s' expected %s '%s', not found", i+1, test.title, tmsg, s)
	}

}

func nbmarkers(tm markers) int {
	res := len(tm)
	for _, d := range deletions {
		if strings.HasPrefix(d, ".") {
			res = res - 1
		}
	}
	return res
}
<|endoftext|>


<commit_before>package main

import (
	"os/exec"
	"reflect"
	"regexp"
	"strings"
	"testing"
)

func TestNewMatcher(t *testing.T) {
	expr := "a[bc](def)"
	m, err := NewMatcher(expr)
	if err != nil {
		t.Errorf("NewMatcher(%q) returns %q, want nil",
			expr, err)
	}

	expect, err := regexp.Compile(expr)
	if err != nil {
		t.Errorf("regexp.Compile(%q) returns %q, want nil",
			expr, err)
	}
	actual := m.re
	if !reflect.DeepEqual(actual, expect) {
		t.Errorf("got %q, want %q", actual, expect)
	}
}

func TestMatch(t *testing.T) {
	expr := `\d+`
	m, err := NewMatcher(expr)
	if err != nil {
		t.Errorf("NewMatcher(%q) returns %q, want nil",
			expr, err)
	}

	src1 := "xxx123"
	expect1 := true
	actual1 := m.MatchString(src1)
	if expect1 != actual1 {
		t.Errorf("MatchString(%q) = %v, want %v",
			expr, actual1, expect1)
	}

	src2 := "xxxabc"
	expect2 := false
	actual2 := m.MatchString(src2)
	if expect2 != actual2 {
		t.Errorf("MatchString(%q) = %v, want %v",
			expr, actual2, expect2)
	}
}

func TestNewProcessor(t *testing.T) {
	name := "mkdir"
	if _, err := exec.LookPath(name); err != nil {
		t.Skipf("%q: doesn't exist", name)
	}
	p, err := NewProcessor(name)
	if err != nil {
		t.Errorf("NewMatcher(%q) returns %q, want nil",
			name, err)
	}

	expect := exec.Command(name)
	actual := p.cmd
	if !reflect.DeepEqual(actual, expect) {
		t.Errorf("NewProcessor(%q).cmd = %v, want %v",
			name, actual, expect)
	}
}

func TestProcess(t *testing.T) {
	name, arg := "sed", "s/false/true/g"
	if _, err := exec.LookPath(name); err != nil {
		t.Skipf("%q: doesn't exist", name)
	}
	p, err := NewProcessor(name, arg)
	if err != nil {
		t.Errorf("NewProcessor(%q, %q) returns %q, want nil",
			name, arg, err)
	}

	expect := []string{"true", "true", "true", "nil"}
	actual := []string{"true", "false", "false", "nil"}
	if err = p.Process(actual); err != nil {
		t.Errorf("NewProcessor(%q, %q).Process(%q) returns %q, want nil",
			name, arg, actual, err)
	}
	if !reflect.DeepEqual(actual, expect) {
		t.Errorf("got %q, want %q", actual, expect)
	}
}

func TestNewLines(t *testing.T) {
	expect := &Lines{
		lines:          []string{},
		matchedLines:   []string{},
		matchedIndexes: make(map[int]bool),
	}
	actual := NewLines()
	if !reflect.DeepEqual(actual, expect) {
		t.Errorf("got %v, want %v", actual, expect)
	}
}

func TestLoadLines(t *testing.T) {
	expr := `\d+`
	m, err := NewMatcher(expr)
	if err != nil {
		t.Errorf("NewMatcher(%q) returns %q, want nil",
			expr, err)
	}
	src := strings.NewReader(`
abc
123
def
456
789
ghi
jkl
mno
`[1:])
	expect := &Lines{
		lines:          []string{"abc", "123", "def", "456", "789", "ghi", "jkl", "mno"},
		matchedLines:   []string{"123", "456", "789"},
		matchedIndexes: map[int]bool{1: true, 3: true, 4: true},
	}
	actual := NewLines()
	if err = actual.LoadLines(src, m); err != nil {
		t.Errorf("NewLines(%v).LoadLines(%v) returns %q, want nil",
			m, src, err)
	}
	if !reflect.DeepEqual(actual, expect) {
		t.Errorf("got %v, want %v", actual, expect)
	}
}
<commit_msg>Add test for Lines.Flush<commit_after>package main

import (
	"bytes"
	"os/exec"
	"reflect"
	"regexp"
	"strings"
	"testing"
)

func TestNewMatcher(t *testing.T) {
	expr := "a[bc](def)"
	m, err := NewMatcher(expr)
	if err != nil {
		t.Errorf("NewMatcher(%q) returns %q, want nil",
			expr, err)
	}

	expect, err := regexp.Compile(expr)
	if err != nil {
		t.Errorf("regexp.Compile(%q) returns %q, want nil",
			expr, err)
	}
	actual := m.re
	if !reflect.DeepEqual(actual, expect) {
		t.Errorf("got %q, want %q", actual, expect)
	}
}

func TestMatch(t *testing.T) {
	expr := `\d+`
	m, err := NewMatcher(expr)
	if err != nil {
		t.Errorf("NewMatcher(%q) returns %q, want nil",
			expr, err)
	}

	src1 := "xxx123"
	expect1 := true
	actual1 := m.MatchString(src1)
	if expect1 != actual1 {
		t.Errorf("MatchString(%q) = %v, want %v",
			expr, actual1, expect1)
	}

	src2 := "xxxabc"
	expect2 := false
	actual2 := m.MatchString(src2)
	if expect2 != actual2 {
		t.Errorf("MatchString(%q) = %v, want %v",
			expr, actual2, expect2)
	}
}

func TestNewProcessor(t *testing.T) {
	name := "mkdir"
	if _, err := exec.LookPath(name); err != nil {
		t.Skipf("%q: doesn't exist", name)
	}
	p, err := NewProcessor(name)
	if err != nil {
		t.Errorf("NewMatcher(%q) returns %q, want nil",
			name, err)
	}

	expect := exec.Command(name)
	actual := p.cmd
	if !reflect.DeepEqual(actual, expect) {
		t.Errorf("NewProcessor(%q).cmd = %v, want %v",
			name, actual, expect)
	}
}

func TestProcess(t *testing.T) {
	name, arg := "sed", "s/false/true/g"
	if _, err := exec.LookPath(name); err != nil {
		t.Skipf("%q: doesn't exist", name)
	}
	p, err := NewProcessor(name, arg)
	if err != nil {
		t.Errorf("NewProcessor(%q, %q) returns %q, want nil",
			name, arg, err)
	}

	expect := []string{"true", "true", "true", "nil"}
	actual := []string{"true", "false", "false", "nil"}
	if err = p.Process(actual); err != nil {
		t.Errorf("NewProcessor(%q, %q).Process(%q) returns %q, want nil",
			name, arg, actual, err)
	}
	if !reflect.DeepEqual(actual, expect) {
		t.Errorf("got %q, want %q", actual, expect)
	}
}

func TestNewLines(t *testing.T) {
	expect := &Lines{
		lines:          []string{},
		matchedLines:   []string{},
		matchedIndexes: make(map[int]bool),
	}
	actual := NewLines()
	if !reflect.DeepEqual(actual, expect) {
		t.Errorf("got %v, want %v", actual, expect)
	}
}

func TestLoadLines(t *testing.T) {
	expr := `\d+`
	m, err := NewMatcher(expr)
	if err != nil {
		t.Errorf("NewMatcher(%q) returns %q, want nil",
			expr, err)
	}
	src := strings.NewReader(`
abc
123
def
456
789
ghi
jkl
mno
`[1:])
	expect := &Lines{
		lines:          []string{"abc", "123", "def", "456", "789", "ghi", "jkl", "mno"},
		matchedLines:   []string{"123", "456", "789"},
		matchedIndexes: map[int]bool{1: true, 3: true, 4: true},
	}
	actual := NewLines()
	if err = actual.LoadLines(src, m); err != nil {
		t.Errorf("NewLines(%v).LoadLines(%v) returns %q, want nil",
			m, src, err)
	}
	if !reflect.DeepEqual(actual, expect) {
		t.Errorf("got %v, want %v", actual, expect)
	}
}

func TestFlush(t *testing.T) {
	name, arg := "sed", "s/.*/true/"
	if _, err := exec.LookPath(name); err != nil {
		t.Skipf("%q: doesn't exist", name)
	}
	p, err := NewProcessor(name, arg)
	if err != nil {
		t.Errorf("NewProcessor(%q, %q) returns %q, want nil",
			name, arg, err)
	}
	l := &Lines{
		lines:          []string{"true", "false", "false", "true", "nil", "true", "false"},
		matchedLines:   []string{"false", "false", "false"},
		matchedIndexes: map[int]bool{1: true, 2: true, 6: true},
	}

	out := bytes.NewBuffer(make([]byte, 0))
	if l.Flush(out, p); err != nil {
	}
	expect := `
true
true
true
true
nil
true
true
`[1:]
	actual := out.String()
	if !reflect.DeepEqual(actual, expect) {
		t.Errorf("got %q, want %q", actual, expect)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"runtime"
	"strconv"
	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
	"github.com/opencontainers/specs"
	"github.com/syndtr/gocapability/capability"
)

var generateFlags = []cli.Flag{
	cli.StringFlag{Name: "rootfs", Usage: "path to the rootfs"},
	cli.BoolFlag{Name: "read-only", Usage: "make the container's rootfs read-only"},
	cli.StringFlag{Name: "hostname", Value: "acme", Usage: "hostname value for the container"},
	cli.IntFlag{Name: "uid", Usage: "uid for the process"},
	cli.IntFlag{Name: "gid", Usage: "gid for the process"},
	cli.StringSliceFlag{Name: "groups", Usage: "supplementary groups for the process"},
	cli.StringSliceFlag{Name: "cap-add", Usage: "add capabilities"},
	cli.StringSliceFlag{Name: "cap-drop", Usage: "drop capabilities"},
	cli.StringFlag{Name: "network", Usage: "network namespace"},
	cli.StringFlag{Name: "mount", Usage: "mount namespace"},
	cli.StringFlag{Name: "pid", Usage: "pid namespace"},
	cli.StringFlag{Name: "ipc", Usage: "ipc namespace"},
	cli.StringFlag{Name: "uts", Usage: "uts namespace"},
	cli.StringFlag{Name: "selinux-label", Usage: "process selinux label"},
}

var (
	defaultCaps = []string{
		"CAP_AUDIT_WRITE",
		"CAP_KILL",
		"CAP_NET_BIND_SERVICE",
	}
)

var generateCommand = cli.Command{
	Name:  "generate",
	Usage: "generate a OCI spec file",
	Flags: generateFlags,
	Action: func(context *cli.Context) {
		spec, rspec := getDefaultTemplate()
		err := modify(&spec, &rspec, context)
		if err != nil {
			logrus.Fatal(err)
		}
		cName := "config.json"
		rName := "runtime.json"
		data, err := json.MarshalIndent(&spec, "", "\t")
		if err != nil {
			logrus.Fatal(err)
		}
		if err := ioutil.WriteFile(cName, data, 0666); err != nil {
			logrus.Fatal(err)
		}
		rdata, err := json.MarshalIndent(&rspec, "", "\t")
		if err != nil {
			logrus.Fatal(err)
		}
		if err := ioutil.WriteFile(rName, rdata, 0666); err != nil {
			logrus.Fatal(err)
		}
	},
}

func modify(spec *specs.LinuxSpec, rspec *specs.LinuxRuntimeSpec, context *cli.Context) error {
	spec.Root.Path = context.String("rootfs")
	spec.Root.Readonly = context.Bool("read-only")
	spec.Hostname = context.String("hostname")
	spec.Process.User.UID = int32(context.Int("uid"))
	spec.Process.User.GID = int32(context.Int("gid"))
	rspec.Linux.SelinuxProcessLabel = context.String("selinux-label")

	groups := context.StringSlice("groups")
	if groups != nil {
		for _, g := range groups {
			groupId, err := strconv.Atoi(g)
			if err != nil {
				return err
			}
			spec.Process.User.AdditionalGids = append(spec.Process.User.AdditionalGids, int32(groupId))
		}
	}

	if err := setupCapabilities(spec, rspec, context); err != nil {
		return err
	}
	setupNamespaces(spec, rspec, context)

	return nil
}

func setupCapabilities(spec *specs.LinuxSpec, rspec *specs.LinuxRuntimeSpec, context *cli.Context) error {
	capMappings := make(map[string]bool)
	for _, cap := range capability.List() {
		key := strings.ToUpper(cap.String())
		capMappings[key] = true
	}

	addedCapsMap := make(map[string]bool)
	for _, cap := range defaultCaps {
		addedCapsMap[cap] = true
	}

	addCapList := make([]string, len(defaultCaps))
	copy(addCapList, defaultCaps)
	addCaps := context.StringSlice("cap-add")
	for _, c := range addCaps {
		if !capMappings[c] {
			return fmt.Errorf("Invalid value passed for adding capability")
		}
		cp := fmt.Sprintf("CAP_%s", c)
		if !addedCapsMap[cp] {
			addCapList = append(addCapList, cp)
			addedCapsMap[cp] = true
		}
	}
	dropCaps := context.StringSlice("cap-drop")
	dropCapsMap := make(map[string]bool)
	for _, c := range dropCaps {
		if !capMappings[c] {
			return fmt.Errorf("Invalid value passed for dropping capability")
		}
		cp := fmt.Sprintf("CAP_%s", c)
		dropCapsMap[cp] = true
	}

	var finalCapList []string
	for _, c := range addCapList {
		if !dropCapsMap[c] {
			finalCapList = append(finalCapList, c)
		}
	}
	spec.Linux.Capabilities = finalCapList
	return nil
}

func mapStrToNamespace(ns string, path string) specs.Namespace {
	switch ns {
	case "network":
		return specs.Namespace{Type: specs.NetworkNamespace, Path: path}
	case "pid":
		return specs.Namespace{Type: specs.PIDNamespace, Path: path}
	case "mount":
		return specs.Namespace{Type: specs.MountNamespace, Path: path}
	case "ipc":
		return specs.Namespace{Type: specs.IPCNamespace, Path: path}
	case "uts":
		return specs.Namespace{Type: specs.UTSNamespace, Path: path}
	case "user":
		return specs.Namespace{Type: specs.UserNamespace, Path: path}
	default:
		logrus.Fatalf("Should not reach here!")
	}
	return specs.Namespace{}
}

func setupNamespaces(spec *specs.LinuxSpec, rspec *specs.LinuxRuntimeSpec, context *cli.Context) {
	namespaces := []string{"network", "pid", "mount", "ipc", "uts"}
	var linuxNs []specs.Namespace
	for _, nsName := range namespaces {
		nsPath := context.String(nsName)
		if nsPath == "host" {
			continue
		}
		ns := mapStrToNamespace(nsName, nsPath)
		linuxNs = append(linuxNs, ns)
	}
	rspec.Linux.Namespaces = linuxNs
}

func getDefaultTemplate() (specs.LinuxSpec, specs.LinuxRuntimeSpec) {
	spec := specs.LinuxSpec{
		Spec: specs.Spec{
			Version: specs.Version,
			Platform: specs.Platform{
				OS:   runtime.GOOS,
				Arch: runtime.GOARCH,
			},
			Root: specs.Root{
				Path:     "",
				Readonly: false,
			},
			Process: specs.Process{
				Terminal: true,
				User:     specs.User{},
				Args: []string{
					"sh",
				},
				Env: []string{
					"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
					"TERM=xterm",
				},
			},
			Hostname: "shell",
			Mounts: []specs.MountPoint{
				{
					Name: "proc",
					Path: "/proc",
				},
				{
					Name: "dev",
					Path: "/dev",
				},
				{
					Name: "devpts",
					Path: "/dev/pts",
				},
				{
					Name: "shm",
					Path: "/dev/shm",
				},
				{
					Name: "mqueue",
					Path: "/dev/mqueue",
				},
				{
					Name: "sysfs",
					Path: "/sys",
				},
				{
					Name: "cgroup",
					Path: "/sys/fs/cgroup",
				},
			},
		},
		Linux: specs.Linux{
			Capabilities: []string{
				"CAP_AUDIT_WRITE",
				"CAP_KILL",
				"CAP_NET_BIND_SERVICE",
			},
		},
	}
	rspec := specs.LinuxRuntimeSpec{
		RuntimeSpec: specs.RuntimeSpec{
			Mounts: map[string]specs.Mount{
				"proc": {
					Type:    "proc",
					Source:  "proc",
					Options: nil,
				},
				"dev": {
					Type:    "tmpfs",
					Source:  "tmpfs",
					Options: []string{"nosuid", "strictatime", "mode=755", "size=65536k"},
				},
				"devpts": {
					Type:    "devpts",
					Source:  "devpts",
					Options: []string{"nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620", "gid=5"},
				},
				"shm": {
					Type:    "tmpfs",
					Source:  "shm",
					Options: []string{"nosuid", "noexec", "nodev", "mode=1777", "size=65536k"},
				},
				"mqueue": {
					Type:    "mqueue",
					Source:  "mqueue",
					Options: []string{"nosuid", "noexec", "nodev"},
				},
				"sysfs": {
					Type:    "sysfs",
					Source:  "sysfs",
					Options: []string{"nosuid", "noexec", "nodev"},
				},
				"cgroup": {
					Type:    "cgroup",
					Source:  "cgroup",
					Options: []string{"nosuid", "noexec", "nodev", "relatime", "ro"},
				},
			},
		},
		Linux: specs.LinuxRuntime{
			Namespaces: []specs.Namespace{
				{
					Type: "pid",
				},
				{
					Type: "network",
				},
				{
					Type: "ipc",
				},
				{
					Type: "uts",
				},
				{
					Type: "mount",
				},
			},
			Rlimits: []specs.Rlimit{
				{
					Type: "RLIMIT_NOFILE",
					Hard: uint64(1024),
					Soft: uint64(1024),
				},
			},
			Devices: []specs.Device{
				{
					Type:        'c',
					Path:        "/dev/null",
					Major:       1,
					Minor:       3,
					Permissions: "rwm",
					FileMode:    0666,
					UID:         0,
					GID:         0,
				},
				{
					Type:        'c',
					Path:        "/dev/random",
					Major:       1,
					Minor:       8,
					Permissions: "rwm",
					FileMode:    0666,
					UID:         0,
					GID:         0,
				},
				{
					Type:        'c',
					Path:        "/dev/full",
					Major:       1,
					Minor:       7,
					Permissions: "rwm",
					FileMode:    0666,
					UID:         0,
					GID:         0,
				},
				{
					Type:        'c',
					Path:        "/dev/tty",
					Major:       5,
					Minor:       0,
					Permissions: "rwm",
					FileMode:    0666,
					UID:         0,
					GID:         0,
				},
				{
					Type:        'c',
					Path:        "/dev/zero",
					Major:       1,
					Minor:       5,
					Permissions: "rwm",
					FileMode:    0666,
					UID:         0,
					GID:         0,
				},
				{
					Type:        'c',
					Path:        "/dev/urandom",
					Major:       1,
					Minor:       9,
					Permissions: "rwm",
					FileMode:    0666,
					UID:         0,
					GID:         0,
				},
			},
			Resources: &specs.Resources{
				Memory: specs.Memory{
					Swappiness: -1,
				},
			},
			Seccomp: specs.Seccomp{
				DefaultAction: "SCMP_ACT_ALLOW",
				Syscalls:      []*specs.Syscall{},
			},
		},
	}
	return spec, rspec
}
<commit_msg>Add support for privileged mode<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"runtime"
	"strconv"
	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
	"github.com/opencontainers/specs"
	"github.com/syndtr/gocapability/capability"
)

var generateFlags = []cli.Flag{
	cli.StringFlag{Name: "rootfs", Usage: "path to the rootfs"},
	cli.BoolFlag{Name: "read-only", Usage: "make the container's rootfs read-only"},
	cli.BoolFlag{Name: "privileged", Usage: "enabled privileged container settings"},
	cli.StringFlag{Name: "hostname", Value: "acme", Usage: "hostname value for the container"},
	cli.IntFlag{Name: "uid", Usage: "uid for the process"},
	cli.IntFlag{Name: "gid", Usage: "gid for the process"},
	cli.StringSliceFlag{Name: "groups", Usage: "supplementary groups for the process"},
	cli.StringSliceFlag{Name: "cap-add", Usage: "add capabilities"},
	cli.StringSliceFlag{Name: "cap-drop", Usage: "drop capabilities"},
	cli.StringFlag{Name: "network", Usage: "network namespace"},
	cli.StringFlag{Name: "mount", Usage: "mount namespace"},
	cli.StringFlag{Name: "pid", Usage: "pid namespace"},
	cli.StringFlag{Name: "ipc", Usage: "ipc namespace"},
	cli.StringFlag{Name: "uts", Usage: "uts namespace"},
	cli.StringFlag{Name: "selinux-label", Usage: "process selinux label"},
}

var (
	defaultCaps = []string{
		"CAP_AUDIT_WRITE",
		"CAP_KILL",
		"CAP_NET_BIND_SERVICE",
	}
)

var generateCommand = cli.Command{
	Name:  "generate",
	Usage: "generate a OCI spec file",
	Flags: generateFlags,
	Action: func(context *cli.Context) {
		spec, rspec := getDefaultTemplate()
		err := modify(&spec, &rspec, context)
		if err != nil {
			logrus.Fatal(err)
		}
		cName := "config.json"
		rName := "runtime.json"
		data, err := json.MarshalIndent(&spec, "", "\t")
		if err != nil {
			logrus.Fatal(err)
		}
		if err := ioutil.WriteFile(cName, data, 0666); err != nil {
			logrus.Fatal(err)
		}
		rdata, err := json.MarshalIndent(&rspec, "", "\t")
		if err != nil {
			logrus.Fatal(err)
		}
		if err := ioutil.WriteFile(rName, rdata, 0666); err != nil {
			logrus.Fatal(err)
		}
	},
}

func modify(spec *specs.LinuxSpec, rspec *specs.LinuxRuntimeSpec, context *cli.Context) error {
	spec.Root.Path = context.String("rootfs")
	spec.Root.Readonly = context.Bool("read-only")
	spec.Hostname = context.String("hostname")
	spec.Process.User.UID = int32(context.Int("uid"))
	spec.Process.User.GID = int32(context.Int("gid"))
	rspec.Linux.SelinuxProcessLabel = context.String("selinux-label")

	groups := context.StringSlice("groups")
	if groups != nil {
		for _, g := range groups {
			groupId, err := strconv.Atoi(g)
			if err != nil {
				return err
			}
			spec.Process.User.AdditionalGids = append(spec.Process.User.AdditionalGids, int32(groupId))
		}
	}

	if err := setupCapabilities(spec, rspec, context); err != nil {
		return err
	}
	setupNamespaces(spec, rspec, context)

	return nil
}

func setupCapabilities(spec *specs.LinuxSpec, rspec *specs.LinuxRuntimeSpec, context *cli.Context) error {
	var finalCapList []string

	// Add all capabilities in privileged mode.
	privileged := context.Bool("privileged")
	if privileged {
		for _, cap := range capability.List() {
			finalCapList = append(finalCapList, fmt.Sprintf("CAP_%s", strings.ToUpper(cap.String())))
		}
		spec.Linux.Capabilities = finalCapList
		return nil
	}

	capMappings := make(map[string]bool)
	for _, cap := range capability.List() {
		key := strings.ToUpper(cap.String())
		capMappings[key] = true
	}

	addedCapsMap := make(map[string]bool)
	for _, cap := range defaultCaps {
		addedCapsMap[cap] = true
	}

	addCapList := make([]string, len(defaultCaps))
	copy(addCapList, defaultCaps)
	addCaps := context.StringSlice("cap-add")
	for _, c := range addCaps {
		if !capMappings[c] {
			return fmt.Errorf("Invalid value passed for adding capability")
		}
		cp := fmt.Sprintf("CAP_%s", c)
		if !addedCapsMap[cp] {
			addCapList = append(addCapList, cp)
			addedCapsMap[cp] = true
		}
	}
	dropCaps := context.StringSlice("cap-drop")
	dropCapsMap := make(map[string]bool)
	for _, c := range dropCaps {
		if !capMappings[c] {
			return fmt.Errorf("Invalid value passed for dropping capability")
		}
		cp := fmt.Sprintf("CAP_%s", c)
		dropCapsMap[cp] = true
	}

	for _, c := range addCapList {
		if !dropCapsMap[c] {
			finalCapList = append(finalCapList, c)
		}
	}
	spec.Linux.Capabilities = finalCapList
	return nil
}

func mapStrToNamespace(ns string, path string) specs.Namespace {
	switch ns {
	case "network":
		return specs.Namespace{Type: specs.NetworkNamespace, Path: path}
	case "pid":
		return specs.Namespace{Type: specs.PIDNamespace, Path: path}
	case "mount":
		return specs.Namespace{Type: specs.MountNamespace, Path: path}
	case "ipc":
		return specs.Namespace{Type: specs.IPCNamespace, Path: path}
	case "uts":
		return specs.Namespace{Type: specs.UTSNamespace, Path: path}
	case "user":
		return specs.Namespace{Type: specs.UserNamespace, Path: path}
	default:
		logrus.Fatalf("Should not reach here!")
	}
	return specs.Namespace{}
}

func setupNamespaces(spec *specs.LinuxSpec, rspec *specs.LinuxRuntimeSpec, context *cli.Context) {
	namespaces := []string{"network", "pid", "mount", "ipc", "uts"}
	var linuxNs []specs.Namespace
	for _, nsName := range namespaces {
		nsPath := context.String(nsName)
		if nsPath == "host" {
			continue
		}
		ns := mapStrToNamespace(nsName, nsPath)
		linuxNs = append(linuxNs, ns)
	}
	rspec.Linux.Namespaces = linuxNs
}

func getDefaultTemplate() (specs.LinuxSpec, specs.LinuxRuntimeSpec) {
	spec := specs.LinuxSpec{
		Spec: specs.Spec{
			Version: specs.Version,
			Platform: specs.Platform{
				OS:   runtime.GOOS,
				Arch: runtime.GOARCH,
			},
			Root: specs.Root{
				Path:     "",
				Readonly: false,
			},
			Process: specs.Process{
				Terminal: true,
				User:     specs.User{},
				Args: []string{
					"sh",
				},
				Env: []string{
					"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
					"TERM=xterm",
				},
			},
			Hostname: "shell",
			Mounts: []specs.MountPoint{
				{
					Name: "proc",
					Path: "/proc",
				},
				{
					Name: "dev",
					Path: "/dev",
				},
				{
					Name: "devpts",
					Path: "/dev/pts",
				},
				{
					Name: "shm",
					Path: "/dev/shm",
				},
				{
					Name: "mqueue",
					Path: "/dev/mqueue",
				},
				{
					Name: "sysfs",
					Path: "/sys",
				},
				{
					Name: "cgroup",
					Path: "/sys/fs/cgroup",
				},
			},
		},
		Linux: specs.Linux{
			Capabilities: []string{
				"CAP_AUDIT_WRITE",
				"CAP_KILL",
				"CAP_NET_BIND_SERVICE",
			},
		},
	}
	rspec := specs.LinuxRuntimeSpec{
		RuntimeSpec: specs.RuntimeSpec{
			Mounts: map[string]specs.Mount{
				"proc": {
					Type:    "proc",
					Source:  "proc",
					Options: nil,
				},
				"dev": {
					Type:    "tmpfs",
					Source:  "tmpfs",
					Options: []string{"nosuid", "strictatime", "mode=755", "size=65536k"},
				},
				"devpts": {
					Type:    "devpts",
					Source:  "devpts",
					Options: []string{"nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620", "gid=5"},
				},
				"shm": {
					Type:    "tmpfs",
					Source:  "shm",
					Options: []string{"nosuid", "noexec", "nodev", "mode=1777", "size=65536k"},
				},
				"mqueue": {
					Type:    "mqueue",
					Source:  "mqueue",
					Options: []string{"nosuid", "noexec", "nodev"},
				},
				"sysfs": {
					Type:    "sysfs",
					Source:  "sysfs",
					Options: []string{"nosuid", "noexec", "nodev"},
				},
				"cgroup": {
					Type:    "cgroup",
					Source:  "cgroup",
					Options: []string{"nosuid", "noexec", "nodev", "relatime", "ro"},
				},
			},
		},
		Linux: specs.LinuxRuntime{
			Namespaces: []specs.Namespace{
				{
					Type: "pid",
				},
				{
					Type: "network",
				},
				{
					Type: "ipc",
				},
				{
					Type: "uts",
				},
				{
					Type: "mount",
				},
			},
			Rlimits: []specs.Rlimit{
				{
					Type: "RLIMIT_NOFILE",
					Hard: uint64(1024),
					Soft: uint64(1024),
				},
			},
			Devices: []specs.Device{
				{
					Type:        'c',
					Path:        "/dev/null",
					Major:       1,
					Minor:       3,
					Permissions: "rwm",
					FileMode:    0666,
					UID:         0,
					GID:         0,
				},
				{
					Type:        'c',
					Path:        "/dev/random",
					Major:       1,
					Minor:       8,
					Permissions: "rwm",
					FileMode:    0666,
					UID:         0,
					GID:         0,
				},
				{
					Type:        'c',
					Path:        "/dev/full",
					Major:       1,
					Minor:       7,
					Permissions: "rwm",
					FileMode:    0666,
					UID:         0,
					GID:         0,
				},
				{
					Type:        'c',
					Path:        "/dev/tty",
					Major:       5,
					Minor:       0,
					Permissions: "rwm",
					FileMode:    0666,
					UID:         0,
					GID:         0,
				},
				{
					Type:        'c',
					Path:        "/dev/zero",
					Major:       1,
					Minor:       5,
					Permissions: "rwm",
					FileMode:    0666,
					UID:         0,
					GID:         0,
				},
				{
					Type:        'c',
					Path:        "/dev/urandom",
					Major:       1,
					Minor:       9,
					Permissions: "rwm",
					FileMode:    0666,
					UID:         0,
					GID:         0,
				},
			},
			Resources: &specs.Resources{
				Memory: specs.Memory{
					Swappiness: -1,
				},
			},
			Seccomp: specs.Seccomp{
				DefaultAction: "SCMP_ACT_ALLOW",
				Syscalls:      []*specs.Syscall{},
			},
		},
	}
	return spec, rspec
}
<|endoftext|>


<commit_before>package opencensus

import (
	"context"
	"encoding/base64"
	"github.com/devigned/tab"
	oct "go.opencensus.io/trace"
	"go.opencensus.io/trace/propagation"
)

func init() {
	tab.Register(new(Trace))
}

const (
	propagationKey = "_oc_prop"
)

type (
	// Trace is the implementation of the OpenCensus trace abstraction
	Trace struct{}

	// Span is the implementation of the OpenCensus Span abstraction
	Span struct {
		span *oct.Span
	}
)

// StartSpan starts a new child span of the current span in the context. If
// there is no span in the context, creates a new trace and span.
//
// Returned context contains the newly created span. You can use it to
// propagate the returned span in process.
func (t *Trace) StartSpan(ctx context.Context, operationName string, opts ...interface{}) (context.Context, tab.Spanner) {
	ctx, span := oct.StartSpan(ctx, operationName, toOCOption(opts...)...)
	return ctx, &Span{span: span}
}

// StartSpanWithRemoteParent starts a new child span of the span from the given parent.
//
// If the incoming context contains a parent, it ignores. StartSpanWithRemoteParent is
// preferred for cases where the parent is propagated via an incoming request.
//
// Returned context contains the newly created span. You can use it to
// propagate the returned span in process.
func (t *Trace) StartSpanWithRemoteParent(ctx context.Context, operationName string, carrier tab.Carrier, opts ...interface{}) (context.Context, tab.Spanner) {
	keysValues := carrier.GetKeyValues()
	if val, ok := keysValues[propagationKey]; ok {
		// check if bin and extract
		if bin, ok := val.([]byte); ok {
			if sc, ok := propagation.FromBinary(bin); ok {
				ctx, span := oct.StartSpanWithRemoteParent(ctx, operationName, sc)
				return ctx, &Span{span: span}
			}
		}

		// check if string and expect base64 encoded
		if strVal, ok := val.(string); ok {
			if decoded, err := base64.StdEncoding.DecodeString(strVal); err != nil {
				if sc, ok := propagation.FromBinary(decoded); ok {
					ctx, span := oct.StartSpanWithRemoteParent(ctx, operationName, sc)
					return ctx, &Span{span: span}
				}
			}
		}
	}

	return t.StartSpan(ctx, operationName)
}

// FromContext returns the Span stored in a context, or nil if there isn't one.
func (t *Trace) FromContext(ctx context.Context) tab.Spanner {
	sp := oct.FromContext(ctx)
	return &Span{span: sp}
}

// NewContext returns a new context with the given Span attached.
func (t *Trace) NewContext(ctx context.Context, span tab.Spanner) context.Context {
	if sp, ok := span.InternalSpan().(*oct.Span); ok {
		return oct.NewContext(ctx, sp)
	}
	return ctx
}

// AddAttributes sets attributes in the span.
//
// Existing attributes whose keys appear in the attributes parameter are overwritten.
func (s *Span) AddAttributes(attributes ...tab.Attribute) {
	s.span.AddAttributes(attributesToOCAttributes(attributes...)...)
}

// End ends the span
func (s *Span) End() {
	s.span.End()
}

// Logger returns a trace.Logger for the span
func (s *Span) Logger() tab.Logger {
	return &tab.SpanLogger{Span: s}
}

// Inject propagation key onto the carrier
func (s *Span) Inject(carrier tab.Carrier) error {
	spanBin := propagation.Binary(s.span.SpanContext())
	encodedSpan := base64.StdEncoding.EncodeToString(spanBin)
	carrier.Set(propagationKey, encodedSpan)
	return nil
}

// InternalSpan returns the real implementation of the Span
func (s *Span) InternalSpan() interface{} {
	return s.span
}

func toOCOption(opts ...interface{}) []oct.StartOption {
	var ocStartOptions []oct.StartOption
	for _, opt := range opts {
		if o, ok := opt.(oct.StartOption); ok {
			ocStartOptions = append(ocStartOptions, o)
		}
	}
	return ocStartOptions
}

func attributesToOCAttributes(attributes ...tab.Attribute) []oct.Attribute {
	var ocAttributes []oct.Attribute
	for _, attr := range attributes {
		switch attr.Value.(type) {
		case int64:
			ocAttributes = append(ocAttributes, oct.Int64Attribute(attr.Key, attr.Value.(int64)))
		case string:
			ocAttributes = append(ocAttributes, oct.StringAttribute(attr.Key, attr.Value.(string)))
		case bool:
			ocAttributes = append(ocAttributes, oct.BoolAttribute(attr.Key, attr.Value.(bool)))
		}
	}
	return ocAttributes
}
<commit_msg>if no error then proceed<commit_after>package opencensus

import (
	"context"
	"encoding/base64"
	"github.com/devigned/tab"
	oct "go.opencensus.io/trace"
	"go.opencensus.io/trace/propagation"
)

func init() {
	tab.Register(new(Trace))
}

const (
	propagationKey = "_oc_prop"
)

type (
	// Trace is the implementation of the OpenCensus trace abstraction
	Trace struct{}

	// Span is the implementation of the OpenCensus Span abstraction
	Span struct {
		span *oct.Span
	}
)

// StartSpan starts a new child span of the current span in the context. If
// there is no span in the context, creates a new trace and span.
//
// Returned context contains the newly created span. You can use it to
// propagate the returned span in process.
func (t *Trace) StartSpan(ctx context.Context, operationName string, opts ...interface{}) (context.Context, tab.Spanner) {
	ctx, span := oct.StartSpan(ctx, operationName, toOCOption(opts...)...)
	return ctx, &Span{span: span}
}

// StartSpanWithRemoteParent starts a new child span of the span from the given parent.
//
// If the incoming context contains a parent, it ignores. StartSpanWithRemoteParent is
// preferred for cases where the parent is propagated via an incoming request.
//
// Returned context contains the newly created span. You can use it to
// propagate the returned span in process.
func (t *Trace) StartSpanWithRemoteParent(ctx context.Context, operationName string, carrier tab.Carrier, opts ...interface{}) (context.Context, tab.Spanner) {
	keysValues := carrier.GetKeyValues()
	if val, ok := keysValues[propagationKey]; ok {
		// check if bin and extract
		if bin, ok := val.([]byte); ok {
			if sc, ok := propagation.FromBinary(bin); ok {
				ctx, span := oct.StartSpanWithRemoteParent(ctx, operationName, sc)
				return ctx, &Span{span: span}
			}
		}

		// check if string and expect base64 encoded
		if strVal, ok := val.(string); ok {
			if decoded, err := base64.StdEncoding.DecodeString(strVal); err == nil {
				if sc, ok := propagation.FromBinary(decoded); ok {
					ctx, span := oct.StartSpanWithRemoteParent(ctx, operationName, sc)
					return ctx, &Span{span: span}
				}
			}
		}
	}

	return t.StartSpan(ctx, operationName)
}

// FromContext returns the Span stored in a context, or nil if there isn't one.
func (t *Trace) FromContext(ctx context.Context) tab.Spanner {
	sp := oct.FromContext(ctx)
	return &Span{span: sp}
}

// NewContext returns a new context with the given Span attached.
func (t *Trace) NewContext(ctx context.Context, span tab.Spanner) context.Context {
	if sp, ok := span.InternalSpan().(*oct.Span); ok {
		return oct.NewContext(ctx, sp)
	}
	return ctx
}

// AddAttributes sets attributes in the span.
//
// Existing attributes whose keys appear in the attributes parameter are overwritten.
func (s *Span) AddAttributes(attributes ...tab.Attribute) {
	s.span.AddAttributes(attributesToOCAttributes(attributes...)...)
}

// End ends the span
func (s *Span) End() {
	s.span.End()
}

// Logger returns a trace.Logger for the span
func (s *Span) Logger() tab.Logger {
	return &tab.SpanLogger{Span: s}
}

// Inject propagation key onto the carrier
func (s *Span) Inject(carrier tab.Carrier) error {
	spanBin := propagation.Binary(s.span.SpanContext())
	encodedSpan := base64.StdEncoding.EncodeToString(spanBin)
	carrier.Set(propagationKey, encodedSpan)
	return nil
}

// InternalSpan returns the real implementation of the Span
func (s *Span) InternalSpan() interface{} {
	return s.span
}

func toOCOption(opts ...interface{}) []oct.StartOption {
	var ocStartOptions []oct.StartOption
	for _, opt := range opts {
		if o, ok := opt.(oct.StartOption); ok {
			ocStartOptions = append(ocStartOptions, o)
		}
	}
	return ocStartOptions
}

func attributesToOCAttributes(attributes ...tab.Attribute) []oct.Attribute {
	var ocAttributes []oct.Attribute
	for _, attr := range attributes {
		switch attr.Value.(type) {
		case int64:
			ocAttributes = append(ocAttributes, oct.Int64Attribute(attr.Key, attr.Value.(int64)))
		case string:
			ocAttributes = append(ocAttributes, oct.StringAttribute(attr.Key, attr.Value.(string)))
		case bool:
			ocAttributes = append(ocAttributes, oct.BoolAttribute(attr.Key, attr.Value.(bool)))
		}
	}
	return ocAttributes
}
<|endoftext|>


<commit_before>package operator

import (
	"github.com/bahadley/esp/log"
)

const flushType = "F"

var (
	// Invariant:  Tupls are in descending order by SensorTuple.Timestamp.
	window []*SensorTuple

	// Length of window.
	bufSz uint32
	// Number of tuples that will compose the aggregate calculation.
	aggSz uint32
)

func windowInsert(msg []byte) error {
	newTuple, err := Unmarshal(msg)
	if err != nil {
		log.Warning.Printf("Failed to unmarshal tuple: %s", msg)
		return err
	}

	agg := false
	avg := 0.0

	inserted := insert(newTuple)
	if !inserted {
		log.Warning.Printf("Sensor %s tuple %d not inserted",
			newTuple.Sensor, newTuple.Timestamp)
	}

	if newTuple.Type == flushType {
		avg, agg = flush()
	} else {
		if inserted && window[bufSz-1] != nil {
			// Tuple was inserted and the window is full.
			avg = aggregate()
			agg = true
		}
	}

	if agg {
		aggTuple, err := Marshal(newTuple.Sensor, avg)
		if err != nil {
			log.Warning.Printf("Failed to marshal aggregate tuple for sensor: %s",
				newTuple.Sensor)
		} else {
			EgressChan <- aggTuple
		}
	}

	return nil
}

func insert(tmp *SensorTuple) bool {
	inserted := false

	if window[0] == nil {
		// This case only occurs for the very first tuple received by the operator.
		// Handling this special case simplifies the remaining logic.
		window[0] = tmp
		inserted = true
	} else {
		for idx, st := range window {
			if inserted ||
				(!inserted && st != nil && tmp.Timestamp > st.Timestamp) {
				// Insert the new tuple and shift the subsequent tuples towards
				// the back of the window.  The last tuple will fall off if the
				// window is full.
				window[idx] = tmp
				tmp = st
				inserted = true
			}
		}
	}

	return inserted
}

func aggregate() float64 {
	// Calculate the aggregation and flush the tuples that were used.
	sum := 0.0

	for idx := bufSz - aggSz; idx < bufSz; idx++ {
		sum += window[idx].Data
		window[idx] = nil
	}

	return RoundDecimal(sum/float64(aggSz), 2)
}

func flush() (float64, bool) {
	// Calculate the aggregation and flush all the tuples.
	// Take the aggregation from the front of the window in a flush.
	agg := true
	sum := 0.0

	for idx := uint32(0); idx < bufSz; idx++ {
		if idx < aggSz && window[idx] == nil {
			agg = false
		} else if idx < aggSz {
			sum += window[idx].Data
		}
		window[idx] = nil
	}

	return RoundDecimal(sum/float64(aggSz), 2), agg
}

func init() {
	bufSz = WindowSize()
	aggSz = AggregateSize()

	if bufSz < aggSz {
		log.Error.Fatalf("Invalid environment variables: %s < %s",
			envWinSz, envAggSz)
	}

	window = make([]*SensorTuple, bufSz)
}
<commit_msg>Fixed weakness in tuple insert logic that would keep some out-of-order tuples from getting inserted<commit_after>package operator

import (
	"github.com/bahadley/esp/log"
)

const flushType = "F"

var (
	// Invariant:  Tupls are in descending order by SensorTuple.Timestamp.
	window []*SensorTuple

	// Length of window.
	bufSz uint32
	// Number of tuples that will compose the aggregate calculation.
	aggSz uint32
)

func windowInsert(msg []byte) error {
	newTuple, err := Unmarshal(msg)
	if err != nil {
		log.Warning.Printf("Failed to unmarshal tuple: %s", msg)
		return err
	}

	agg := false
	avg := 0.0

	inserted := insert(newTuple)
	if !inserted {
		log.Warning.Printf("Sensor %s tuple %d not inserted",
			newTuple.Sensor, newTuple.Timestamp)
	}

	if newTuple.Type == flushType {
		avg, agg = flush()
	} else {
		if inserted && window[bufSz-1] != nil {
			// Tuple was inserted and the window is full.
			avg = aggregate()
			agg = true
		}
	}

	if agg {
		aggTuple, err := Marshal(newTuple.Sensor, avg)
		if err != nil {
			log.Warning.Printf("Failed to marshal aggregate tuple for sensor: %s",
				newTuple.Sensor)
		} else {
			EgressChan <- aggTuple
		}
	}

	return nil
}

func insert(tmp *SensorTuple) bool {
	inserted := false

	for idx, st := range window {
		if inserted ||
			(!inserted && st != nil && tmp.Timestamp > st.Timestamp) {
			// Insert the new tuple and shift the subsequent tuples towards
			// the back of the window.  The last tuple will fall off if the
			// window is full.
			window[idx] = tmp
			tmp = st
			inserted = true
		} else if !inserted && st == nil {
			// Window is currently empty and this is the first arriving tuple, or ...
			// Out of order arrival and there is room at the back of the window.
			window[idx] = tmp
			inserted = true
			break
		}
	}

	return inserted
}

func aggregate() float64 {
	// Calculate the aggregation and flush the tuples that were used.
	sum := 0.0

	for idx := bufSz - aggSz; idx < bufSz; idx++ {
		sum += window[idx].Data
		window[idx] = nil
	}

	return RoundDecimal(sum/float64(aggSz), 2)
}

func flush() (float64, bool) {
	// Calculate the aggregation and flush all the tuples.
	// Take the aggregation from the front of the window in a flush.
	agg := true
	sum := 0.0

	for idx := uint32(0); idx < bufSz; idx++ {
		if idx < aggSz && window[idx] == nil {
			agg = false
		} else if idx < aggSz {
			sum += window[idx].Data
		}
		window[idx] = nil
	}

	return RoundDecimal(sum/float64(aggSz), 2), agg
}

func init() {
	bufSz = WindowSize()
	aggSz = AggregateSize()

	if bufSz < aggSz {
		log.Error.Fatalf("Invalid environment variables: %s < %s",
			envWinSz, envAggSz)
	}

	window = make([]*SensorTuple, bufSz)
}
<|endoftext|>


<commit_before>// Package options implements common options recognized by veyron implementations.
//
// Below are the common options required of all veyron implementations.  Let's
// say we have functions MyFuncA and MyFuncB in package demo:
//
//   package demo
//   func MyFuncA(a, b, c int, opts ...MyFuncAOpt)
//   func MyFuncB(opts ...MyFuncBOpt)
//
//   type MyFuncAOpt interface {
//     DemoMyFuncAOpt()
//   }
//   type MyFuncBOpt interface {
//     DemoMyFuncBOpt()
//   }
//
// The MyFuncAOpt interface is used solely to constrain the types of options
// that MyFuncA accepts, and ditto for MyFuncBOpt and MyFuncB.  In order to
// enable an option to be accepted by a particular function, you simply add a
// no-op function definition with the appropriate name.  An example:
//
//   type Foo int
//   func (Foo) DemoMyFuncAOpt() {}
//   func (Foo) DemoMyFuncBOpt() {}
//
//   type Bar string
//   func (Bar) DemoMyFuncBOpt() {}
//
// Foo is accepted by both demo.MyFuncA and demo.MyFuncB, while Bar is only
// accepted by demo.MyFuncB.  The methods defined for each option essentially
// act as annotations telling us which functions will accept them.
//
// Go stipulates that methods may only be attached to named types, and the type
// may not be an interface.  E.g.
//
//   // BAD: can't attach methods to named interfaces.
//   type Bad interface{}
//   func (Bad) DemoMyFuncAOpt() {}
//
//   // GOOD: wrap the interface in a named struct.
//   type Good struct { val interface{} }
//
//   func (Good) DemoMyFuncAOpt() {}
//
// These options can then be passed to the function as so:
//   MyFuncA(a, b, c, Foo(1), Good{object})
package options

import (
	"time"

	"veyron.io/veyron/veyron2"
	"veyron.io/veyron/veyron2/ipc/stream"
	"veyron.io/veyron/veyron2/naming"
	"veyron.io/veyron/veyron2/security"
)

// RuntimePrincipal represents the principal to be used by the runtime.
//
// It wraps the security.Principal interface so that functions representing
// option annotations can be added.
type RuntimePrincipal struct{ security.Principal }

func (RuntimePrincipal) ROpt() {}

// RuntimeID represents the identity to be used by the runtime.
//
// It wraps the security.PrivateID interface so that functions representing
// option annotations can be added.
type RuntimeID struct{ security.PrivateID }

func (RuntimeID) ROpt() {}

// TODO(ashankar): Remove this once the transition to the new model is complete
type ForceNewSecurityModel struct{}

func (ForceNewSecurityModel) ROpt() {}

// LocalID represents the PublicID to be used by the local end of an IPC.
//
// It wraps the security.PrivateID interface so that functions representing
// option annotations can be added.
type LocalID struct{ security.PublicID }

func (LocalID) IPCClientOpt() {}
func (LocalID) IPCServerOpt() {}

// RemoteID specifies a pattern identifying the set of valid remote identities for
// a call.
type RemoteID security.BlessingPattern

func (RemoteID) IPCCallOpt() {}

// VCSecurityLevel represents the level of confidentiality of data transmitted
// and received over a VC.
type VCSecurityLevel int

func (VCSecurityLevel) IPCClientOpt()         {}
func (VCSecurityLevel) IPCServerOpt()         {}
func (VCSecurityLevel) IPCStreamVCOpt()       {}
func (VCSecurityLevel) IPCStreamListenerOpt() {}

const (
	// All user data transmitted over the VC is encrypted and can be interpreted only
	// by processes at the two ends of the VC.
	// This is the default level.
	VCSecurityConfidential VCSecurityLevel = 0
	// Data is transmitted over the VC in plain text and there is no authentication.
	VCSecurityNone VCSecurityLevel = 1
)

// Discharge wraps the security.Discharge interface so that we can
// add functions representing the option annotations.
type Discharge struct{ security.Discharge }

func (Discharge) IPCCallOpt() {}

// RetryTimeout is the duration during which we will retry starting
// an RPC call.  Zero means don't retry.
type RetryTimeout time.Duration

func (RetryTimeout) IPCCallOpt() {}

// NoResolve specifies that the RPC call should not further Resolve the name.
type NoResolve bool

func (NoResolve) IPCCallOpt() {}

// StreamManager wraps the stream.Manager interface so that we can add
// functions representing the option annotations.
type StreamManager struct{ stream.Manager }

func (StreamManager) IPCClientOpt() {}

// Namespace wraps the naming.Namespace interface so that we can add
// functions representing the option annotations.
type Namespace struct{ naming.Namespace }

func (Namespace) IPCClientOpt() {}
func (Namespace) IPCServerOpt() {}

// NamespaceRoots wraps an array of strings so that we specify the root
// of the Namespace when initializing the runtime.
type NamespaceRoots []string

func (NamespaceRoots) ROpt() {}

// Profile wraps the veyron2.Profile interface so that we can add
// functions representing the option annotations
type Profile struct{ veyron2.Profile }

func (Profile) ROpt() {}

// RuntimeName wraps the name of the runtime so that we can add
// functions representing the option annotations
type RuntimeName string

func (RuntimeName) ROpt() {}

// GoogleRuntime is the RuntimeName option to use to force the Google runtime
// implementation.
const GoogleRuntime RuntimeName = "google"

// Create a server that will be used to serve a MountTable. This server
// cannot be used for any other purpose.
type ServesMountTable bool

func (ServesMountTable) IPCServerOpt() {}

// DebugAuthorizer specifies the authorizer that controls access to framework
// provided debug objects on this server.
type DebugAuthorizer struct{ security.Authorizer }

func (DebugAuthorizer) IPCServerOpt() {}
<commit_msg>veyron/runtimes/google/rt: Use the new security model by default.<commit_after>// Package options implements common options recognized by veyron implementations.
//
// Below are the common options required of all veyron implementations.  Let's
// say we have functions MyFuncA and MyFuncB in package demo:
//
//   package demo
//   func MyFuncA(a, b, c int, opts ...MyFuncAOpt)
//   func MyFuncB(opts ...MyFuncBOpt)
//
//   type MyFuncAOpt interface {
//     DemoMyFuncAOpt()
//   }
//   type MyFuncBOpt interface {
//     DemoMyFuncBOpt()
//   }
//
// The MyFuncAOpt interface is used solely to constrain the types of options
// that MyFuncA accepts, and ditto for MyFuncBOpt and MyFuncB.  In order to
// enable an option to be accepted by a particular function, you simply add a
// no-op function definition with the appropriate name.  An example:
//
//   type Foo int
//   func (Foo) DemoMyFuncAOpt() {}
//   func (Foo) DemoMyFuncBOpt() {}
//
//   type Bar string
//   func (Bar) DemoMyFuncBOpt() {}
//
// Foo is accepted by both demo.MyFuncA and demo.MyFuncB, while Bar is only
// accepted by demo.MyFuncB.  The methods defined for each option essentially
// act as annotations telling us which functions will accept them.
//
// Go stipulates that methods may only be attached to named types, and the type
// may not be an interface.  E.g.
//
//   // BAD: can't attach methods to named interfaces.
//   type Bad interface{}
//   func (Bad) DemoMyFuncAOpt() {}
//
//   // GOOD: wrap the interface in a named struct.
//   type Good struct { val interface{} }
//
//   func (Good) DemoMyFuncAOpt() {}
//
// These options can then be passed to the function as so:
//   MyFuncA(a, b, c, Foo(1), Good{object})
package options

import (
	"time"

	"veyron.io/veyron/veyron2"
	"veyron.io/veyron/veyron2/ipc/stream"
	"veyron.io/veyron/veyron2/naming"
	"veyron.io/veyron/veyron2/security"
)

// RuntimePrincipal represents the principal to be used by the runtime.
//
// It wraps the security.Principal interface so that functions representing
// option annotations can be added.
type RuntimePrincipal struct{ security.Principal }

func (RuntimePrincipal) ROpt() {}

// RuntimeID represents the identity to be used by the runtime.
//
// It wraps the security.PrivateID interface so that functions representing
// option annotations can be added.
type RuntimeID struct{ security.PrivateID }

func (RuntimeID) ROpt() {}

// TODO(ashankar): Remove. DEPRECATED HAS NO EFFECT
type ForceNewSecurityModel struct{}

func (ForceNewSecurityModel) ROpt() {}

// LocalID represents the PublicID to be used by the local end of an IPC.
//
// It wraps the security.PrivateID interface so that functions representing
// option annotations can be added.
type LocalID struct{ security.PublicID }

func (LocalID) IPCClientOpt() {}
func (LocalID) IPCServerOpt() {}

// RemoteID specifies a pattern identifying the set of valid remote identities for
// a call.
type RemoteID security.BlessingPattern

func (RemoteID) IPCCallOpt() {}

// VCSecurityLevel represents the level of confidentiality of data transmitted
// and received over a VC.
type VCSecurityLevel int

func (VCSecurityLevel) IPCClientOpt()         {}
func (VCSecurityLevel) IPCServerOpt()         {}
func (VCSecurityLevel) IPCStreamVCOpt()       {}
func (VCSecurityLevel) IPCStreamListenerOpt() {}

const (
	// All user data transmitted over the VC is encrypted and can be interpreted only
	// by processes at the two ends of the VC.
	// This is the default level.
	VCSecurityConfidential VCSecurityLevel = 0
	// Data is transmitted over the VC in plain text and there is no authentication.
	VCSecurityNone VCSecurityLevel = 1
)

// Discharge wraps the security.Discharge interface so that we can
// add functions representing the option annotations.
type Discharge struct{ security.Discharge }

func (Discharge) IPCCallOpt() {}

// RetryTimeout is the duration during which we will retry starting
// an RPC call.  Zero means don't retry.
type RetryTimeout time.Duration

func (RetryTimeout) IPCCallOpt() {}

// NoResolve specifies that the RPC call should not further Resolve the name.
type NoResolve bool

func (NoResolve) IPCCallOpt() {}

// StreamManager wraps the stream.Manager interface so that we can add
// functions representing the option annotations.
type StreamManager struct{ stream.Manager }

func (StreamManager) IPCClientOpt() {}

// Namespace wraps the naming.Namespace interface so that we can add
// functions representing the option annotations.
type Namespace struct{ naming.Namespace }

func (Namespace) IPCClientOpt() {}
func (Namespace) IPCServerOpt() {}

// NamespaceRoots wraps an array of strings so that we specify the root
// of the Namespace when initializing the runtime.
type NamespaceRoots []string

func (NamespaceRoots) ROpt() {}

// Profile wraps the veyron2.Profile interface so that we can add
// functions representing the option annotations
type Profile struct{ veyron2.Profile }

func (Profile) ROpt() {}

// RuntimeName wraps the name of the runtime so that we can add
// functions representing the option annotations
type RuntimeName string

func (RuntimeName) ROpt() {}

// GoogleRuntime is the RuntimeName option to use to force the Google runtime
// implementation.
const GoogleRuntime RuntimeName = "google"

// Create a server that will be used to serve a MountTable. This server
// cannot be used for any other purpose.
type ServesMountTable bool

func (ServesMountTable) IPCServerOpt() {}

// DebugAuthorizer specifies the authorizer that controls access to framework
// provided debug objects on this server.
type DebugAuthorizer struct{ security.Authorizer }

func (DebugAuthorizer) IPCServerOpt() {}
<|endoftext|>


<commit_before>// The options package includes some default option parsers for the
// requests package.
package options

import (
	"errors"
	"reflect"
)

var (
	ErrRequiredMissing = errors.New("Required value has nil input")
	ErrValueImmutable  = errors.New("Value is immutable once set")
)

// changeReceiver is just a clone of requests.ChangeReceiver, since we can't
// import requests in this package.
type changeReceiver interface {
	Receive(interface{}) (bool, error)
}

// receiver is a clone of requests.Receiver, similar to changeReceiver.
type receiver interface {
	Receive(interface{}) error
}

func isPtrOrInter(t reflect.Type) bool {
	return t.Kind() == reflect.Ptr || t.Kind() == reflect.Interface
}

// zeroOrEqual checks whether orig is either the zero value of its type or
// loosely equal to value.  The main utility here is that zeroOrEqual(4.0, 4)
// will return true, as will zeroOrEqual(new(int64), float32(0)).
func zeroOrEqual(orig, value interface{}) bool {
	origType := reflect.TypeOf(orig)
	if orig == reflect.Zero(origType).Interface() {
		return true
	}
	origVal := reflect.New(origType).Elem()
	origVal.Set(reflect.ValueOf(orig))
	compareValue := reflect.ValueOf(value)
	for !compareValue.Type().ConvertibleTo(origType) && isPtrOrInter(origType) {
		if origVal.IsNil() {
			if origVal.Kind() != reflect.Ptr {
				// Can't initialize
				return false
			}
			origVal.Set(reflect.New(origType.Elem()))
		}
		origVal = origVal.Elem()
		origType = origType.Elem()
	}
	if compareValue.Type().ConvertibleTo(origType) {
		compareValue = compareValue.Convert(origType)
	}
	return origVal.Interface() == compareValue.Interface()
}

// Required is an option func that ensures a non-nil value was passed
// along in the request.  It does not ensure that the value is
// non-empty.
func Required(orig, value interface{}, fromRequest bool, optionValue string) (interface{}, error) {
	if optionValue == "true" {
		if fromRequest {
			if value == nil || value == reflect.Zero(reflect.TypeOf(orig)).Interface() {
				return nil, ErrRequiredMissing
			}
		} else {
			if orig == reflect.Zero(reflect.TypeOf(orig)).Interface() {
				return nil, ErrRequiredMissing
			}
		}
	}
	return value, nil
}

// Default is an option func that sets a default value for a field.
// If its value is non-empty, it will use the following logic to
// decide what to return:
//
// If fromRequest is false, then the default will be returned if orig
// is equal to its zero value.
//
// If fromRequest is true, then the default will be returned if value
// is nil.
//
// In all other cases, value will be returned.
func Default(orig, value interface{}, fromRequest bool, optionValue string) (interface{}, error) {
	if optionValue != "" {
		// optionValue is always a string type, but we'll leave it up
		// to the calling code to perform conversion to orig's type.
		useDefault := false
		if fromRequest {
			useDefault = value == nil
		} else {
			useDefault = orig == reflect.Zero(reflect.TypeOf(orig)).Interface()
		}
		if useDefault {
			return optionValue, nil
		}
	}
	return value, nil
}

// Immutable is an option func that ensures that a value is not
// modified after being set.  It will return an error if orig is
// non-empty and does not match the new value from the request.
func Immutable(orig, value interface{}, fromRequest bool, optionValue string) (interface{}, error) {
	if optionValue == "true" && fromRequest {
		if _, ok := orig.(receiver); ok {
			return nil, errors.New("Receiver types cannot be immutable.  " +
				"See ChangeReceiver for a supported alternative.")
		}
		if !zeroOrEqual(orig, value) {
			if changeReceiver, ok := orig.(changeReceiver); ok {
				changed, err := changeReceiver.Receive(value)
				if err != nil {
					return nil, err
				}
				if changed {
					return nil, ErrValueImmutable
				}
				return value, nil
			}
			return nil, ErrValueImmutable
		}
	}
	return value, nil
}
<commit_msg>Avoid calling reflect.Zero on a nil value<commit_after>// The options package includes some default option parsers for the
// requests package.
package options

import (
	"errors"
	"reflect"
)

var (
	ErrRequiredMissing = errors.New("Required value has nil input")
	ErrValueImmutable  = errors.New("Value is immutable once set")
)

// changeReceiver is just a clone of requests.ChangeReceiver, since we can't
// import requests in this package.
type changeReceiver interface {
	Receive(interface{}) (bool, error)
}

// receiver is a clone of requests.Receiver, similar to changeReceiver.
type receiver interface {
	Receive(interface{}) error
}

func isPtrOrInter(t reflect.Type) bool {
	return t.Kind() == reflect.Ptr || t.Kind() == reflect.Interface
}

// zeroOrEqual checks whether orig is either the zero value of its type or
// loosely equal to value.  The main utility here is that zeroOrEqual(4.0, 4)
// will return true, as will zeroOrEqual(new(int64), float32(0)).
func zeroOrEqual(orig, value interface{}) bool {
	origType := reflect.TypeOf(orig)
	if orig == reflect.Zero(origType).Interface() {
		return true
	}
	origVal := reflect.New(origType).Elem()
	origVal.Set(reflect.ValueOf(orig))
	compareValue := reflect.ValueOf(value)
	for !compareValue.Type().ConvertibleTo(origType) && isPtrOrInter(origType) {
		if origVal.IsNil() {
			if origVal.Kind() != reflect.Ptr {
				// Can't initialize
				return false
			}
			origVal.Set(reflect.New(origType.Elem()))
		}
		origVal = origVal.Elem()
		origType = origType.Elem()
	}
	if compareValue.Type().ConvertibleTo(origType) {
		compareValue = compareValue.Convert(origType)
	}
	return origVal.Interface() == compareValue.Interface()
}

// Required is an option func that ensures a non-nil value was passed
// along in the request.  It does not ensure that the value is
// non-empty.
func Required(orig, value interface{}, fromRequest bool, optionValue string) (interface{}, error) {
	if optionValue == "true" {
		if fromRequest {
			if value == nil || value == reflect.Zero(reflect.TypeOf(orig)).Interface() {
				return nil, ErrRequiredMissing
			}
		} else {
			if orig == reflect.Zero(reflect.TypeOf(orig)).Interface() {
				return nil, ErrRequiredMissing
			}
		}
	}
	return value, nil
}

// Default is an option func that sets a default value for a field.
// If its value is non-empty, it will use the following logic to
// decide what to return:
//
// If fromRequest is false, then the default will be returned if orig
// is equal to its zero value.
//
// If fromRequest is true, then the default will be returned if value
// is nil.
//
// In all other cases, value will be returned.
func Default(orig, value interface{}, fromRequest bool, optionValue string) (interface{}, error) {
	if optionValue != "" {
		// optionValue is always a string type, but we'll leave it up
		// to the calling code to perform conversion to orig's type.
		useDefault := false
		if fromRequest {
			useDefault = value == nil
		} else {
			useDefault = orig == nil || orig == reflect.Zero(reflect.TypeOf(orig)).Interface()
		}
		if useDefault {
			return optionValue, nil
		}
	}
	return value, nil
}

// Immutable is an option func that ensures that a value is not
// modified after being set.  It will return an error if orig is
// non-empty and does not match the new value from the request.
func Immutable(orig, value interface{}, fromRequest bool, optionValue string) (interface{}, error) {
	if optionValue == "true" && fromRequest {
		if _, ok := orig.(receiver); ok {
			return nil, errors.New("Receiver types cannot be immutable.  " +
				"See ChangeReceiver for a supported alternative.")
		}
		if !zeroOrEqual(orig, value) {
			if changeReceiver, ok := orig.(changeReceiver); ok {
				changed, err := changeReceiver.Receive(value)
				if err != nil {
					return nil, err
				}
				if changed {
					return nil, ErrValueImmutable
				}
				return value, nil
			}
			return nil, ErrValueImmutable
		}
	}
	return value, nil
}
<|endoftext|>


<commit_before>package server

// Server is custom server.
type Server struct {
	host string
	port int
}

// Host sets server's host.
func Host(host string) func(s *Server) {
	return func(s *Server) {
		s.host = host
	}
}

// Port sets server's port.
func Port(port int) Option {
	return func(s *Server) {
		s.port = port
	}
}

// Option handle server option.
type Option func(s *Server)

// New creates new server.
func New(options ...Option) *Server {
	srv := &Server{}
	for _, o := range options {
		o(srv)
	}
	return srv
}
<commit_msg>options/server: Host returns Option<commit_after>package server

// Server is custom server.
type Server struct {
	host string
	port int
}

// Host sets server's host.
func Host(host string) Option {
	return func(s *Server) {
		s.host = host
	}
}

// Port sets server's port.
func Port(port int) Option {
	return func(s *Server) {
		s.port = port
	}
}

// Option handle server option.
type Option func(s *Server)

// New creates new server.
func New(options ...Option) *Server {
	srv := &Server{}
	for _, o := range options {
		o(srv)
	}
	return srv
}
<|endoftext|>