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

package scanner

import (
	"go/scanner";
	"go/token";
	"strings";
	"testing";
)

const /* class */ (
	special = iota;
	literal;
	operator;
	keyword;
)

func tokenclass(tok token.Token) int {
	switch {
	case tok.IsLiteral(): return literal;
	case tok.IsOperator(): return operator;
	case tok.IsKeyword(): return keyword;
	}
	return special;
}

type elt struct {
	tok token.Token;
	lit string;
	class int;
}

var tokens = [...]elt{
	// Special tokens
	elt{ token.COMMENT, "/* a comment */", special },
	elt{ token.COMMENT, "// a comment \n", special },

	// Identifiers and basic type literals
	elt{ token.IDENT, "foobar", literal },
	elt{ token.IDENT, "a۰۱۸", literal },
	elt{ token.IDENT, "foo६४", literal },
	elt{ token.IDENT, "bar９８７６", literal },
	elt{ token.INT, "0", literal },
	elt{ token.INT, "01234567", literal },
	elt{ token.INT, "0xcafebabe", literal },
	elt{ token.FLOAT, "0.", literal },
	elt{ token.FLOAT, ".0", literal },
	elt{ token.FLOAT, "3.14159265", literal },
	elt{ token.FLOAT, "1e0", literal },
	elt{ token.FLOAT, "1e+100", literal },
	elt{ token.FLOAT, "1e-100", literal },
	elt{ token.FLOAT, "2.71828e-1000", literal },
	elt{ token.CHAR, "'a'", literal },
	elt{ token.CHAR, "'\\000'", literal },
	elt{ token.CHAR, "'\\xFF'", literal },
	elt{ token.CHAR, "'\\uff16'", literal },
	elt{ token.CHAR, "'\\U0000ff16'", literal },
	elt{ token.STRING, "`foobar`", literal },
	elt{ token.STRING, "`" `foo
	                        bar` "`", literal },

	// Operators and delimitors
	elt{ token.ADD, "+", operator },
	elt{ token.SUB, "-", operator },
	elt{ token.MUL, "*", operator },
	elt{ token.QUO, "/", operator },
	elt{ token.REM, "%", operator },

	elt{ token.AND, "&", operator },
	elt{ token.OR, "|", operator },
	elt{ token.XOR, "^", operator },
	elt{ token.SHL, "<<", operator },
	elt{ token.SHR, ">>", operator },
	elt{ token.AND_NOT, "&^", operator },

	elt{ token.ADD_ASSIGN, "+=", operator },
	elt{ token.SUB_ASSIGN, "-=", operator },
	elt{ token.MUL_ASSIGN, "*=", operator },
	elt{ token.QUO_ASSIGN, "/=", operator },
	elt{ token.REM_ASSIGN, "%=", operator },

	elt{ token.AND_ASSIGN, "&=", operator },
	elt{ token.OR_ASSIGN, "|=", operator },
	elt{ token.XOR_ASSIGN, "^=", operator },
	elt{ token.SHL_ASSIGN, "<<=", operator },
	elt{ token.SHR_ASSIGN, ">>=", operator },
	elt{ token.AND_NOT_ASSIGN, "&^=", operator },

	elt{ token.LAND, "&&", operator },
	elt{ token.LOR, "||", operator },
	elt{ token.ARROW, "<-", operator },
	elt{ token.INC, "++", operator },
	elt{ token.DEC, "--", operator },

	elt{ token.EQL, "==", operator },
	elt{ token.LSS, "<", operator },
	elt{ token.GTR, ">", operator },
	elt{ token.ASSIGN, "=", operator },
	elt{ token.NOT, "!", operator },

	elt{ token.NEQ, "!=", operator },
	elt{ token.LEQ, "<=", operator },
	elt{ token.GEQ, ">=", operator },
	elt{ token.DEFINE, ":=", operator },
	elt{ token.ELLIPSIS, "...", operator },

	elt{ token.LPAREN, "(", operator },
	elt{ token.LBRACK, "[", operator },
	elt{ token.LBRACE, "{", operator },
	elt{ token.COMMA, ",", operator },
	elt{ token.PERIOD, ".", operator },

	elt{ token.RPAREN, ")", operator },
	elt{ token.RBRACK, "]", operator },
	elt{ token.RBRACE, "}", operator },
	elt{ token.SEMICOLON, ";", operator },
	elt{ token.COLON, ":", operator },

	// Keywords
	elt{ token.BREAK, "break", keyword },
	elt{ token.CASE, "case", keyword },
	elt{ token.CHAN, "chan", keyword },
	elt{ token.CONST, "const", keyword },
	elt{ token.CONTINUE, "continue", keyword },

	elt{ token.DEFAULT, "default", keyword },
	elt{ token.DEFER, "defer", keyword },
	elt{ token.ELSE, "else", keyword },
	elt{ token.FALLTHROUGH, "fallthrough", keyword },
	elt{ token.FOR, "for", keyword },

	elt{ token.FUNC, "func", keyword },
	elt{ token.GO, "go", keyword },
	elt{ token.GOTO, "goto", keyword },
	elt{ token.IF, "if", keyword },
	elt{ token.IMPORT, "import", keyword },

	elt{ token.INTERFACE, "interface", keyword },
	elt{ token.MAP, "map", keyword },
	elt{ token.PACKAGE, "package", keyword },
	elt{ token.RANGE, "range", keyword },
	elt{ token.RETURN, "return", keyword },

	elt{ token.SELECT, "select", keyword },
	elt{ token.STRUCT, "struct", keyword },
	elt{ token.SWITCH, "switch", keyword },
	elt{ token.TYPE, "type", keyword },
	elt{ token.VAR, "var", keyword },
}

const whitespace = "  \t  \n\n\n";  // to separate tokens

type TestErrorHandler struct {
	t *testing.T
}

func (h *TestErrorHandler) Error(pos token.Position, msg string) {
	h.t.Errorf("Error() called (msg = %s)", msg);
}

func NewlineCount(s string) int {
	n := 0;
	for i := 0; i < len(s); i++ {
		if s[i] == '\n' {
			n++;
		}
	}
	return n;
}

// Verify that calling Scan() provides the correct results.
func TestScan(t *testing.T) {
	// make source
	var src string;
	for i, e := range tokens {
		src += e.lit + whitespace;
	}
	whitespace_linecount := NewlineCount(whitespace);

	// verify scan
	index := 0;
	eloc := token.Position{0, 1, 1};
	nerrors := scanner.Tokenize(strings.Bytes(src), &TestErrorHandler{t}, scanner.ScanComments,
		func (pos token.Position, tok token.Token, litb []byte) bool {
			e := elt{token.EOF, "", special};
			if index < len(tokens) {
				e = tokens[index];
			}
			lit := string(litb);
			if tok == token.EOF {
				lit = "<EOF>";
				eloc.Column = 0;
			}
			if pos.Offset != eloc.Offset {
				t.Errorf("bad position for %s: got %d, expected %d", lit, pos.Offset, eloc.Offset);
			}
			if pos.Line != eloc.Line {
				t.Errorf("bad line for %s: got %d, expected %d", lit, pos.Line, eloc.Line);
			}
			if pos.Column!= eloc.Column {
				t.Errorf("bad column for %s: got %d, expected %d", lit, pos.Column, eloc.Column);
			}
			if tok != e.tok {
				t.Errorf("bad token for %s: got %s, expected %s", lit, tok.String(), e.tok.String());
			}
			if e.tok.IsLiteral() && lit != e.lit {
				t.Errorf("bad literal for %s: got %s, expected %s", lit, lit, e.lit);
			}
			if tokenclass(tok) != e.class {
				t.Errorf("bad class for %s: got %d, expected %d", lit, tokenclass(tok), e.class);
			}
			eloc.Offset += len(lit) + len(whitespace);
			eloc.Line += NewlineCount(lit) + whitespace_linecount;
			index++;
			return tok != token.EOF;
		}
	);
	if nerrors != 0 {
		t.Errorf("found %d errors", nerrors);
	}
}

// Verify that initializing the same scanner more then once works correctly.
func TestInit(t *testing.T) {
	var s scanner.Scanner;

	// 1st init
	s.Init(strings.Bytes("if true { }"), nil, 0);
	s.Scan();  // if
	s.Scan();  // true
	pos, tok, lit := s.Scan();  // {
	if tok != token.LBRACE {
		t.Errorf("bad token: got %s, expected %s", tok.String(), token.LBRACE);
	}

	// 2nd init
	s.Init(strings.Bytes("go true { ]"), nil, 0);
	pos, tok, lit = s.Scan();  // go
	if tok != token.GO {
		t.Errorf("bad token: got %s, expected %s", tok.String(), token.GO);
	}

	if s.ErrorCount != 0 {
		t.Errorf("found %d errors", s.ErrorCount);
	}
}

func TestIllegalChars(t *testing.T) {
	var s scanner.Scanner;

	const src = "*?*$*@*";
	s.Init(strings.Bytes(src), &TestErrorHandler{t}, scanner.AllowIllegalChars);
	for offs, ch := range src {
		pos, tok, lit := s.Scan();
		if pos.Offset != offs {
			t.Errorf("bad position for %s: got %d, expected %d", string(lit), pos.Offset, offs);
		}
		if tok == token.ILLEGAL && string(lit) != string(ch) {
			t.Errorf("bad token: got %s, expected %s", string(lit), string(ch));
		}
	}

	if s.ErrorCount != 0 {
		t.Errorf("found %d errors", s.ErrorCount);
	}
}
<commit_msg>fix to scanner_test after change to //-style comment token<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package scanner

import (
	"go/scanner";
	"go/token";
	"strings";
	"testing";
)

const /* class */ (
	special = iota;
	literal;
	operator;
	keyword;
)

func tokenclass(tok token.Token) int {
	switch {
	case tok.IsLiteral(): return literal;
	case tok.IsOperator(): return operator;
	case tok.IsKeyword(): return keyword;
	}
	return special;
}

type elt struct {
	tok token.Token;
	lit string;
	class int;
}

var tokens = [...]elt{
	// Special tokens
	elt{ token.COMMENT, "/* a comment */", special },
	elt{ token.COMMENT, "// a comment \n", special },

	// Identifiers and basic type literals
	elt{ token.IDENT, "foobar", literal },
	elt{ token.IDENT, "a۰۱۸", literal },
	elt{ token.IDENT, "foo६४", literal },
	elt{ token.IDENT, "bar９８７６", literal },
	elt{ token.INT, "0", literal },
	elt{ token.INT, "01234567", literal },
	elt{ token.INT, "0xcafebabe", literal },
	elt{ token.FLOAT, "0.", literal },
	elt{ token.FLOAT, ".0", literal },
	elt{ token.FLOAT, "3.14159265", literal },
	elt{ token.FLOAT, "1e0", literal },
	elt{ token.FLOAT, "1e+100", literal },
	elt{ token.FLOAT, "1e-100", literal },
	elt{ token.FLOAT, "2.71828e-1000", literal },
	elt{ token.CHAR, "'a'", literal },
	elt{ token.CHAR, "'\\000'", literal },
	elt{ token.CHAR, "'\\xFF'", literal },
	elt{ token.CHAR, "'\\uff16'", literal },
	elt{ token.CHAR, "'\\U0000ff16'", literal },
	elt{ token.STRING, "`foobar`", literal },
	elt{ token.STRING, "`" `foo
	                        bar` "`", literal },

	// Operators and delimitors
	elt{ token.ADD, "+", operator },
	elt{ token.SUB, "-", operator },
	elt{ token.MUL, "*", operator },
	elt{ token.QUO, "/", operator },
	elt{ token.REM, "%", operator },

	elt{ token.AND, "&", operator },
	elt{ token.OR, "|", operator },
	elt{ token.XOR, "^", operator },
	elt{ token.SHL, "<<", operator },
	elt{ token.SHR, ">>", operator },
	elt{ token.AND_NOT, "&^", operator },

	elt{ token.ADD_ASSIGN, "+=", operator },
	elt{ token.SUB_ASSIGN, "-=", operator },
	elt{ token.MUL_ASSIGN, "*=", operator },
	elt{ token.QUO_ASSIGN, "/=", operator },
	elt{ token.REM_ASSIGN, "%=", operator },

	elt{ token.AND_ASSIGN, "&=", operator },
	elt{ token.OR_ASSIGN, "|=", operator },
	elt{ token.XOR_ASSIGN, "^=", operator },
	elt{ token.SHL_ASSIGN, "<<=", operator },
	elt{ token.SHR_ASSIGN, ">>=", operator },
	elt{ token.AND_NOT_ASSIGN, "&^=", operator },

	elt{ token.LAND, "&&", operator },
	elt{ token.LOR, "||", operator },
	elt{ token.ARROW, "<-", operator },
	elt{ token.INC, "++", operator },
	elt{ token.DEC, "--", operator },

	elt{ token.EQL, "==", operator },
	elt{ token.LSS, "<", operator },
	elt{ token.GTR, ">", operator },
	elt{ token.ASSIGN, "=", operator },
	elt{ token.NOT, "!", operator },

	elt{ token.NEQ, "!=", operator },
	elt{ token.LEQ, "<=", operator },
	elt{ token.GEQ, ">=", operator },
	elt{ token.DEFINE, ":=", operator },
	elt{ token.ELLIPSIS, "...", operator },

	elt{ token.LPAREN, "(", operator },
	elt{ token.LBRACK, "[", operator },
	elt{ token.LBRACE, "{", operator },
	elt{ token.COMMA, ",", operator },
	elt{ token.PERIOD, ".", operator },

	elt{ token.RPAREN, ")", operator },
	elt{ token.RBRACK, "]", operator },
	elt{ token.RBRACE, "}", operator },
	elt{ token.SEMICOLON, ";", operator },
	elt{ token.COLON, ":", operator },

	// Keywords
	elt{ token.BREAK, "break", keyword },
	elt{ token.CASE, "case", keyword },
	elt{ token.CHAN, "chan", keyword },
	elt{ token.CONST, "const", keyword },
	elt{ token.CONTINUE, "continue", keyword },

	elt{ token.DEFAULT, "default", keyword },
	elt{ token.DEFER, "defer", keyword },
	elt{ token.ELSE, "else", keyword },
	elt{ token.FALLTHROUGH, "fallthrough", keyword },
	elt{ token.FOR, "for", keyword },

	elt{ token.FUNC, "func", keyword },
	elt{ token.GO, "go", keyword },
	elt{ token.GOTO, "goto", keyword },
	elt{ token.IF, "if", keyword },
	elt{ token.IMPORT, "import", keyword },

	elt{ token.INTERFACE, "interface", keyword },
	elt{ token.MAP, "map", keyword },
	elt{ token.PACKAGE, "package", keyword },
	elt{ token.RANGE, "range", keyword },
	elt{ token.RETURN, "return", keyword },

	elt{ token.SELECT, "select", keyword },
	elt{ token.STRUCT, "struct", keyword },
	elt{ token.SWITCH, "switch", keyword },
	elt{ token.TYPE, "type", keyword },
	elt{ token.VAR, "var", keyword },
}

const whitespace = "  \t  \n\n\n";  // to separate tokens

type TestErrorHandler struct {
	t *testing.T
}

func (h *TestErrorHandler) Error(pos token.Position, msg string) {
	h.t.Errorf("Error() called (msg = %s)", msg);
}

func NewlineCount(s string) int {
	n := 0;
	for i := 0; i < len(s); i++ {
		if s[i] == '\n' {
			n++;
		}
	}
	return n;
}

// Verify that calling Scan() provides the correct results.
func TestScan(t *testing.T) {
	// make source
	var src string;
	for i, e := range tokens {
		src += e.lit + whitespace;
	}
	whitespace_linecount := NewlineCount(whitespace);

	// verify scan
	index := 0;
	eloc := token.Position{0, 1, 1};
	nerrors := scanner.Tokenize(strings.Bytes(src), &TestErrorHandler{t}, scanner.ScanComments,
		func (pos token.Position, tok token.Token, litb []byte) bool {
			e := elt{token.EOF, "", special};
			if index < len(tokens) {
				e = tokens[index];
			}
			lit := string(litb);
			if tok == token.EOF {
				lit = "<EOF>";
				eloc.Column = 0;
			}
			if pos.Offset != eloc.Offset {
				t.Errorf("bad position for %s: got %d, expected %d", lit, pos.Offset, eloc.Offset);
			}
			if pos.Line != eloc.Line {
				t.Errorf("bad line for %s: got %d, expected %d", lit, pos.Line, eloc.Line);
			}
			if pos.Column!= eloc.Column {
				t.Errorf("bad column for %s: got %d, expected %d", lit, pos.Column, eloc.Column);
			}
			if tok != e.tok {
				t.Errorf("bad token for %s: got %s, expected %s", lit, tok.String(), e.tok.String());
			}
			if e.tok.IsLiteral() && lit != e.lit {
				t.Errorf("bad literal for %s: got %s, expected %s", lit, lit, e.lit);
			}
			if tokenclass(tok) != e.class {
				t.Errorf("bad class for %s: got %d, expected %d", lit, tokenclass(tok), e.class);
			}
			eloc.Offset += len(lit) + len(whitespace);
			eloc.Line += NewlineCount(lit) + whitespace_linecount;
			if tok == token.COMMENT && litb[1] == '/' {
				// correct for unaccounted '/n' in //-style comment
				eloc.Offset++;
				eloc.Line++;
			}
			index++;
			return tok != token.EOF;
		}
	);
	if nerrors != 0 {
		t.Errorf("found %d errors", nerrors);
	}
}

// Verify that initializing the same scanner more then once works correctly.
func TestInit(t *testing.T) {
	var s scanner.Scanner;

	// 1st init
	s.Init(strings.Bytes("if true { }"), nil, 0);
	s.Scan();  // if
	s.Scan();  // true
	pos, tok, lit := s.Scan();  // {
	if tok != token.LBRACE {
		t.Errorf("bad token: got %s, expected %s", tok.String(), token.LBRACE);
	}

	// 2nd init
	s.Init(strings.Bytes("go true { ]"), nil, 0);
	pos, tok, lit = s.Scan();  // go
	if tok != token.GO {
		t.Errorf("bad token: got %s, expected %s", tok.String(), token.GO);
	}

	if s.ErrorCount != 0 {
		t.Errorf("found %d errors", s.ErrorCount);
	}
}

func TestIllegalChars(t *testing.T) {
	var s scanner.Scanner;

	const src = "*?*$*@*";
	s.Init(strings.Bytes(src), &TestErrorHandler{t}, scanner.AllowIllegalChars);
	for offs, ch := range src {
		pos, tok, lit := s.Scan();
		if pos.Offset != offs {
			t.Errorf("bad position for %s: got %d, expected %d", string(lit), pos.Offset, offs);
		}
		if tok == token.ILLEGAL && string(lit) != string(ch) {
			t.Errorf("bad token: got %s, expected %s", string(lit), string(ch));
		}
	}

	if s.ErrorCount != 0 {
		t.Errorf("found %d errors", s.ErrorCount);
	}
}
<|endoftext|>


<commit_before>package cdp_test

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"

	"github.com/mafredri/cdp"
	"github.com/mafredri/cdp/rpcc"
)

// LogCodec captures the output from writing RPC requests and reading
// responses on the connection. It implements rpcc.Codec via
// WriteRequest and ReadResponse.
type LogCodec struct{ conn io.ReadWriter }

// WriteRequest marshals v into a buffer, writes its contents onto the
// connection and logs it.
func (c *LogCodec) WriteRequest(req *rpcc.Request) error {
	var buf bytes.Buffer
	if err := json.NewEncoder(&buf).Encode(req); err != nil {
		return err
	}
	_, err := c.conn.Write(buf.Bytes())
	if err != nil {
		return err
	}
	fmt.Printf("SEND: %s", buf.Bytes())
	return nil
}

// ReadResponse unmarshals from the connection into v whilst echoing
// what is read into a buffer for logging.
func (c *LogCodec) ReadResponse(resp *rpcc.Response) error {
	var buf bytes.Buffer
	if err := json.NewDecoder(io.TeeReader(c.conn, &buf)).Decode(resp); err != nil {
		return err
	}
	fmt.Printf("RECV: %s\n", buf.String())
	return nil
}

func Example_logging() {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	newLogCodec := func(conn io.ReadWriter) rpcc.Codec {
		return &LogCodec{conn: conn}
	}
	conn, err := rpcc.Dial("ws://"+TestSockSrv+"/example_logging", rpcc.WithCodec(newLogCodec))
	if err != nil {
		fmt.Println(err)
	}
	defer conn.Close()

	c := cdp.NewClient(conn)

	if err = c.Network.Enable(ctx, nil); err != nil {
		fmt.Println(err)
	}
	// Output:
	// SEND: {"id":1,"method":"Network.enable"}
	// RECV: {"id":1,"result":{}}
}
<commit_msg>Fix output race in logging example<commit_after>package cdp_test

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"

	"github.com/mafredri/cdp"
	"github.com/mafredri/cdp/rpcc"
)

// LogCodec captures the output from writing RPC requests and reading
// responses on the connection. It implements rpcc.Codec via
// WriteRequest and ReadResponse.
type LogCodec struct{ conn io.ReadWriter }

// WriteRequest marshals v into a buffer, writes its contents onto the
// connection and logs it.
func (c *LogCodec) WriteRequest(req *rpcc.Request) error {
	var buf bytes.Buffer
	if err := json.NewEncoder(&buf).Encode(req); err != nil {
		return err
	}
	fmt.Printf("SEND: %s", buf.Bytes())
	_, err := c.conn.Write(buf.Bytes())
	if err != nil {
		return err
	}
	return nil
}

// ReadResponse unmarshals from the connection into v whilst echoing
// what is read into a buffer for logging.
func (c *LogCodec) ReadResponse(resp *rpcc.Response) error {
	var buf bytes.Buffer
	if err := json.NewDecoder(io.TeeReader(c.conn, &buf)).Decode(resp); err != nil {
		return err
	}
	fmt.Printf("RECV: %s\n", buf.String())
	return nil
}

func Example_logging() {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	newLogCodec := func(conn io.ReadWriter) rpcc.Codec {
		return &LogCodec{conn: conn}
	}
	conn, err := rpcc.Dial("ws://"+TestSockSrv+"/example_logging", rpcc.WithCodec(newLogCodec))
	if err != nil {
		fmt.Println(err)
	}
	defer conn.Close()

	c := cdp.NewClient(conn)

	if err = c.Network.Enable(ctx, nil); err != nil {
		fmt.Println(err)
	}
	// Output:
	// SEND: {"id":1,"method":"Network.enable"}
	// RECV: {"id":1,"result":{}}
}
<|endoftext|>


<commit_before>package server

import (
	"context"
	"fmt"

	client "github.com/pachyderm/pachyderm/src/client"
	"github.com/pachyderm/pachyderm/src/client/enterprise"
	"github.com/pachyderm/pachyderm/src/client/pps"
	"github.com/pachyderm/pachyderm/src/server/pkg/deploy/assets"

	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/resource"
	"k8s.io/kubernetes/pkg/api/unversioned"
	"k8s.io/kubernetes/pkg/util/intstr"
)

// Parameters used when creating the kubernetes replication controller in charge
// of a job or pipeline's workers
type workerOptions struct {
	rcName string // Name of the replication controller managing workers

	userImage        string            // The user's pipeline/job image
	labels           map[string]string // k8s labels attached to the RC and workers
	annotations      map[string]string // k8s annotations attached to the RC and workers
	parallelism      int32             // Number of replicas the RC maintains
	cacheSize        string            // Size of cache that sidecar uses
	resourceRequests *api.ResourceList // Resources requested by pipeline/job pods
	resourceLimits   *api.ResourceList // Resources requested by pipeline/job pods
	workerEnv        []api.EnvVar      // Environment vars set in the user container
	volumes          []api.Volume      // Volumes that we expose to the user container
	volumeMounts     []api.VolumeMount // Paths where we mount each volume in 'volumes'

	// Secrets that we mount in the worker container (e.g. for reading/writing to
	// s3)
	imagePullSecrets []api.LocalObjectReference
	service          *pps.Service
}

func (a *apiServer) workerPodSpec(options *workerOptions) (api.PodSpec, error) {
	pullPolicy := a.workerImagePullPolicy
	if pullPolicy == "" {
		pullPolicy = "IfNotPresent"
	}
	sidecarEnv := []api.EnvVar{{
		Name:  "BLOCK_CACHE_BYTES",
		Value: options.cacheSize,
	}, {
		Name:  "PFS_CACHE_SIZE",
		Value: "16",
	}, {
		Name:  "PACH_ROOT",
		Value: a.storageRoot,
	}, {
		Name:  "STORAGE_BACKEND",
		Value: a.storageBackend,
	}}
	// This only happens in local deployment.  We want the workers to be
	// able to read from/write to the hostpath volume as well.
	storageVolumeName := "pach-disk"
	var sidecarVolumeMounts []api.VolumeMount
	if a.storageHostPath != "" {
		options.volumes = append(options.volumes, api.Volume{
			Name: storageVolumeName,
			VolumeSource: api.VolumeSource{
				HostPath: &api.HostPathVolumeSource{
					Path: a.storageHostPath,
				},
			},
		})

		sidecarVolumeMounts = []api.VolumeMount{
			{
				Name:      storageVolumeName,
				MountPath: a.storageRoot,
			},
		}
	}
	userVolumeMounts := options.volumeMounts
	secretVolume, secretMount := assets.GetSecretVolumeAndMount(a.storageBackend)
	options.volumes = append(options.volumes, secretVolume)
	options.volumeMounts = append(options.volumeMounts, secretMount)
	sidecarVolumeMounts = append(sidecarVolumeMounts, secretMount)
	userVolumeMounts = append(userVolumeMounts, secretMount)

	// Explicitly set CPU and MEM requests to zero because some cloud
	// providers set their own defaults which are usually not what we want.
	cpuZeroQuantity := resource.MustParse("0")
	memZeroQuantity := resource.MustParse("0M")
	memSidecarQuantity := resource.MustParse(options.cacheSize)

	options.volumes = append(options.volumes, api.Volume{
		Name: "docker",
		VolumeSource: api.VolumeSource{
			HostPath: &api.HostPathVolumeSource{
				Path: "/var/run/docker.sock",
			},
		},
	})
	userVolumeMounts = append(userVolumeMounts, api.VolumeMount{
		Name:      "docker",
		MountPath: "/var/run/docker.sock",
	})
	zeroVal := int64(0)
	workerImage := a.workerImage
	pachClient, err := a.getPachClient()
	if err != nil {
		return api.PodSpec{}, err
	}
	resp, err := pachClient.Enterprise.GetState(context.Background(), &enterprise.GetStateRequest{})
	if err != nil {
		return api.PodSpec{}, err
	}
	if resp.State != enterprise.State_ACTIVE {
		workerImage = assets.AddRegistry("", workerImage)
	}
	podSpec := api.PodSpec{
		InitContainers: []api.Container{
			{
				Name:            "init",
				Image:           workerImage,
				Command:         []string{"/pach/worker.sh"},
				ImagePullPolicy: api.PullPolicy(pullPolicy),
				Env:             options.workerEnv,
				VolumeMounts:    options.volumeMounts,
			},
		},
		Containers: []api.Container{
			{
				Name:    client.PPSWorkerUserContainerName,
				Image:   options.userImage,
				Command: []string{"/pach-bin/guest.sh"},
				SecurityContext: &api.SecurityContext{
					Privileged: &trueVal, // god is this dumb
				},
				ImagePullPolicy: api.PullPolicy(pullPolicy),
				Env:             options.workerEnv,
				Resources: api.ResourceRequirements{
					Requests: map[api.ResourceName]resource.Quantity{
						api.ResourceCPU:    cpuZeroQuantity,
						api.ResourceMemory: memZeroQuantity,
					},
				},
				VolumeMounts: userVolumeMounts,
			},
			{
				Name:            client.PPSWorkerSidecarContainerName,
				Image:           a.workerSidecarImage,
				Command:         []string{"/pachd", "--mode", "sidecar"},
				ImagePullPolicy: api.PullPolicy(pullPolicy),
				Env:             sidecarEnv,
				VolumeMounts:    sidecarVolumeMounts,
				Resources: api.ResourceRequirements{
					Requests: map[api.ResourceName]resource.Quantity{
						api.ResourceCPU:    cpuZeroQuantity,
						api.ResourceMemory: memSidecarQuantity,
					},
				},
			},
		},
		RestartPolicy:                 "Always",
		Volumes:                       options.volumes,
		ImagePullSecrets:              options.imagePullSecrets,
		TerminationGracePeriodSeconds: &zeroVal,
		SecurityContext:               &api.PodSecurityContext{RunAsUser: &zeroVal},
	}
	resourceRequirements := api.ResourceRequirements{}
	if options.resourceRequests != nil {
		resourceRequirements.Requests = *options.resourceRequests
	}
	if options.resourceLimits != nil {
		resourceRequirements.Limits = *options.resourceLimits
	}
	podSpec.Containers[0].Resources = resourceRequirements
	return podSpec, nil
}

func (a *apiServer) getWorkerOptions(pipelineName string, rcName string,
	parallelism int32, resourceRequests *api.ResourceList, resourceLimits *api.ResourceList, transform *pps.Transform,
	cacheSize string, service *pps.Service) *workerOptions {
	labels := labels(rcName)
	userImage := transform.Image
	if userImage == "" {
		userImage = DefaultUserImage
	}

	var workerEnv []api.EnvVar
	for name, value := range transform.Env {
		workerEnv = append(
			workerEnv,
			api.EnvVar{
				Name:  name,
				Value: value,
			},
		)
	}
	// We use Kubernetes' "Downward API" so the workers know their IP
	// addresses, which they will then post on etcd so the job managers
	// can discover the workers.
	workerEnv = append(workerEnv, api.EnvVar{
		Name: client.PPSWorkerIPEnv,
		ValueFrom: &api.EnvVarSource{
			FieldRef: &api.ObjectFieldSelector{
				APIVersion: "v1",
				FieldPath:  "status.podIP",
			},
		},
	})
	workerEnv = append(workerEnv, api.EnvVar{
		Name: client.PPSPodNameEnv,
		ValueFrom: &api.EnvVarSource{
			FieldRef: &api.ObjectFieldSelector{
				APIVersion: "v1",
				FieldPath:  "metadata.name",
			},
		},
	})
	// Set the etcd prefix env
	workerEnv = append(workerEnv, api.EnvVar{
		Name:  client.PPSEtcdPrefixEnv,
		Value: a.etcdPrefix,
	})
	// Pass along the namespace
	workerEnv = append(workerEnv, api.EnvVar{
		Name:  client.PPSNamespaceEnv,
		Value: a.namespace,
	})

	var volumes []api.Volume
	var volumeMounts []api.VolumeMount
	for _, secret := range transform.Secrets {
		if secret.MountPath != "" {
			volumes = append(volumes, api.Volume{
				Name: secret.Name,
				VolumeSource: api.VolumeSource{
					Secret: &api.SecretVolumeSource{
						SecretName: secret.Name,
					},
				},
			})
			volumeMounts = append(volumeMounts, api.VolumeMount{
				Name:      secret.Name,
				MountPath: secret.MountPath,
			})
		}
		if secret.EnvVar != "" {
			workerEnv = append(workerEnv, api.EnvVar{
				Name: secret.EnvVar,
				ValueFrom: &api.EnvVarSource{
					SecretKeyRef: &api.SecretKeySelector{
						LocalObjectReference: api.LocalObjectReference{
							Name: secret.Name,
						},
						Key: secret.Key,
					},
				},
			})
		}
	}

	volumes = append(volumes, api.Volume{
		Name: "pach-bin",
		VolumeSource: api.VolumeSource{
			EmptyDir: &api.EmptyDirVolumeSource{},
		},
	})
	volumeMounts = append(volumeMounts, api.VolumeMount{
		Name:      "pach-bin",
		MountPath: "/pach-bin",
	})

	volumes = append(volumes, api.Volume{
		Name: client.PPSWorkerVolume,
		VolumeSource: api.VolumeSource{
			EmptyDir: &api.EmptyDirVolumeSource{},
		},
	})
	volumeMounts = append(volumeMounts, api.VolumeMount{
		Name:      client.PPSWorkerVolume,
		MountPath: client.PPSScratchSpace,
	})
	if resourceRequests != nil && resourceRequests.NvidiaGPU() != nil && !resourceRequests.NvidiaGPU().IsZero() {
		volumes = append(volumes, api.Volume{
			Name: "root-lib",
			VolumeSource: api.VolumeSource{
				HostPath: &api.HostPathVolumeSource{
					Path: "/usr/lib",
				},
			},
		})
		volumeMounts = append(volumeMounts, api.VolumeMount{
			Name:      "root-lib",
			MountPath: "/rootfs/usr/lib",
		})
	}
	var imagePullSecrets []api.LocalObjectReference
	for _, secret := range transform.ImagePullSecrets {
		imagePullSecrets = append(imagePullSecrets, api.LocalObjectReference{Name: secret})
	}
	if a.imagePullSecret != "" {
		imagePullSecrets = append(imagePullSecrets, api.LocalObjectReference{Name: a.imagePullSecret})
	}

	annotations := map[string]string{"pipelineName": pipelineName}
	if a.iamRole != "" {
		annotations["iam.amazonaws.com/role"] = a.iamRole
	}

	return &workerOptions{
		rcName:           rcName,
		labels:           labels,
		annotations:      annotations,
		parallelism:      int32(parallelism),
		resourceRequests: resourceRequests,
		resourceLimits:   resourceLimits,
		userImage:        userImage,
		workerEnv:        workerEnv,
		volumes:          volumes,
		volumeMounts:     volumeMounts,
		imagePullSecrets: imagePullSecrets,
		cacheSize:        cacheSize,
		service:          service,
	}
}

func (a *apiServer) createWorkerRc(options *workerOptions) error {
	podSpec, err := a.workerPodSpec(options)
	if err != nil {
		return err
	}
	rc := &api.ReplicationController{
		TypeMeta: unversioned.TypeMeta{
			Kind:       "ReplicationController",
			APIVersion: "v1",
		},
		ObjectMeta: api.ObjectMeta{
			Name:        options.rcName,
			Labels:      options.labels,
			Annotations: options.annotations,
		},
		Spec: api.ReplicationControllerSpec{
			Selector: options.labels,
			Replicas: options.parallelism,
			Template: &api.PodTemplateSpec{
				ObjectMeta: api.ObjectMeta{
					Name:        options.rcName,
					Labels:      options.labels,
					Annotations: options.annotations,
				},
				Spec: podSpec,
			},
		},
	}
	if _, err := a.kubeClient.ReplicationControllers(a.namespace).Create(rc); err != nil {
		if !isAlreadyExistsErr(err) {
			return err
		}
	}

	service := &api.Service{
		TypeMeta: unversioned.TypeMeta{
			Kind:       "Service",
			APIVersion: "v1",
		},
		ObjectMeta: api.ObjectMeta{
			Name:   options.rcName,
			Labels: options.labels,
		},
		Spec: api.ServiceSpec{
			Selector: options.labels,
			Ports: []api.ServicePort{
				{
					Port: client.PPSWorkerPort,
					Name: "grpc-port",
				},
			},
		},
	}
	if _, err := a.kubeClient.Services(a.namespace).Create(service); err != nil {
		if !isAlreadyExistsErr(err) {
			return err
		}
	}

	if options.service != nil {
		service := &api.Service{
			TypeMeta: unversioned.TypeMeta{
				Kind:       "Service",
				APIVersion: "v1",
			},
			ObjectMeta: api.ObjectMeta{
				Name:   options.rcName + "-user",
				Labels: options.labels,
			},
			Spec: api.ServiceSpec{
				Selector: options.labels,
				Type:     api.ServiceTypeNodePort,
				Ports: []api.ServicePort{
					{
						Port:       options.service.ExternalPort,
						TargetPort: intstr.FromInt(int(options.service.InternalPort)),
						Name:       "user-port",
						NodePort:   options.service.ExternalPort,
					},
				},
			},
		}
		if _, err := a.kubeClient.Services(a.namespace).Create(service); err != nil {
			if !isAlreadyExistsErr(err) {
				return err
			}
		}
	}

	return nil
}
<commit_msg>No, use limits on GPU<commit_after>package server

import (
	"context"
	"fmt"

	client "github.com/pachyderm/pachyderm/src/client"
	"github.com/pachyderm/pachyderm/src/client/enterprise"
	"github.com/pachyderm/pachyderm/src/client/pps"
	"github.com/pachyderm/pachyderm/src/server/pkg/deploy/assets"

	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/resource"
	"k8s.io/kubernetes/pkg/api/unversioned"
	"k8s.io/kubernetes/pkg/util/intstr"
)

// Parameters used when creating the kubernetes replication controller in charge
// of a job or pipeline's workers
type workerOptions struct {
	rcName string // Name of the replication controller managing workers

	userImage        string            // The user's pipeline/job image
	labels           map[string]string // k8s labels attached to the RC and workers
	annotations      map[string]string // k8s annotations attached to the RC and workers
	parallelism      int32             // Number of replicas the RC maintains
	cacheSize        string            // Size of cache that sidecar uses
	resourceRequests *api.ResourceList // Resources requested by pipeline/job pods
	resourceLimits   *api.ResourceList // Resources requested by pipeline/job pods
	workerEnv        []api.EnvVar      // Environment vars set in the user container
	volumes          []api.Volume      // Volumes that we expose to the user container
	volumeMounts     []api.VolumeMount // Paths where we mount each volume in 'volumes'

	// Secrets that we mount in the worker container (e.g. for reading/writing to
	// s3)
	imagePullSecrets []api.LocalObjectReference
	service          *pps.Service
}

func (a *apiServer) workerPodSpec(options *workerOptions) (api.PodSpec, error) {
	pullPolicy := a.workerImagePullPolicy
	if pullPolicy == "" {
		pullPolicy = "IfNotPresent"
	}
	sidecarEnv := []api.EnvVar{{
		Name:  "BLOCK_CACHE_BYTES",
		Value: options.cacheSize,
	}, {
		Name:  "PFS_CACHE_SIZE",
		Value: "16",
	}, {
		Name:  "PACH_ROOT",
		Value: a.storageRoot,
	}, {
		Name:  "STORAGE_BACKEND",
		Value: a.storageBackend,
	}}
	// This only happens in local deployment.  We want the workers to be
	// able to read from/write to the hostpath volume as well.
	storageVolumeName := "pach-disk"
	var sidecarVolumeMounts []api.VolumeMount
	if a.storageHostPath != "" {
		options.volumes = append(options.volumes, api.Volume{
			Name: storageVolumeName,
			VolumeSource: api.VolumeSource{
				HostPath: &api.HostPathVolumeSource{
					Path: a.storageHostPath,
				},
			},
		})

		sidecarVolumeMounts = []api.VolumeMount{
			{
				Name:      storageVolumeName,
				MountPath: a.storageRoot,
			},
		}
	}
	userVolumeMounts := options.volumeMounts
	secretVolume, secretMount := assets.GetSecretVolumeAndMount(a.storageBackend)
	options.volumes = append(options.volumes, secretVolume)
	options.volumeMounts = append(options.volumeMounts, secretMount)
	sidecarVolumeMounts = append(sidecarVolumeMounts, secretMount)
	userVolumeMounts = append(userVolumeMounts, secretMount)

	// Explicitly set CPU and MEM requests to zero because some cloud
	// providers set their own defaults which are usually not what we want.
	cpuZeroQuantity := resource.MustParse("0")
	memZeroQuantity := resource.MustParse("0M")
	memSidecarQuantity := resource.MustParse(options.cacheSize)

	options.volumes = append(options.volumes, api.Volume{
		Name: "docker",
		VolumeSource: api.VolumeSource{
			HostPath: &api.HostPathVolumeSource{
				Path: "/var/run/docker.sock",
			},
		},
	})
	userVolumeMounts = append(userVolumeMounts, api.VolumeMount{
		Name:      "docker",
		MountPath: "/var/run/docker.sock",
	})
	zeroVal := int64(0)
	workerImage := a.workerImage
	pachClient, err := a.getPachClient()
	if err != nil {
		return api.PodSpec{}, err
	}
	resp, err := pachClient.Enterprise.GetState(context.Background(), &enterprise.GetStateRequest{})
	if err != nil {
		return api.PodSpec{}, err
	}
	if resp.State != enterprise.State_ACTIVE {
		workerImage = assets.AddRegistry("", workerImage)
	}
	podSpec := api.PodSpec{
		InitContainers: []api.Container{
			{
				Name:            "init",
				Image:           workerImage,
				Command:         []string{"/pach/worker.sh"},
				ImagePullPolicy: api.PullPolicy(pullPolicy),
				Env:             options.workerEnv,
				VolumeMounts:    options.volumeMounts,
			},
		},
		Containers: []api.Container{
			{
				Name:    client.PPSWorkerUserContainerName,
				Image:   options.userImage,
				Command: []string{"/pach-bin/guest.sh"},
				SecurityContext: &api.SecurityContext{
					Privileged: &trueVal, // god is this dumb
				},
				ImagePullPolicy: api.PullPolicy(pullPolicy),
				Env:             options.workerEnv,
				Resources: api.ResourceRequirements{
					Requests: map[api.ResourceName]resource.Quantity{
						api.ResourceCPU:    cpuZeroQuantity,
						api.ResourceMemory: memZeroQuantity,
					},
				},
				VolumeMounts: userVolumeMounts,
			},
			{
				Name:            client.PPSWorkerSidecarContainerName,
				Image:           a.workerSidecarImage,
				Command:         []string{"/pachd", "--mode", "sidecar"},
				ImagePullPolicy: api.PullPolicy(pullPolicy),
				Env:             sidecarEnv,
				VolumeMounts:    sidecarVolumeMounts,
				Resources: api.ResourceRequirements{
					Requests: map[api.ResourceName]resource.Quantity{
						api.ResourceCPU:    cpuZeroQuantity,
						api.ResourceMemory: memSidecarQuantity,
					},
				},
			},
		},
		RestartPolicy:                 "Always",
		Volumes:                       options.volumes,
		ImagePullSecrets:              options.imagePullSecrets,
		TerminationGracePeriodSeconds: &zeroVal,
		SecurityContext:               &api.PodSecurityContext{RunAsUser: &zeroVal},
	}
	resourceRequirements := api.ResourceRequirements{}
	if options.resourceRequests != nil {
		resourceRequirements.Requests = *options.resourceRequests
	}
	if options.resourceLimits != nil {
		resourceRequirements.Limits = *options.resourceLimits
	}
	podSpec.Containers[0].Resources = resourceRequirements
	return podSpec, nil
}

func (a *apiServer) getWorkerOptions(pipelineName string, rcName string,
	parallelism int32, resourceRequests *api.ResourceList, resourceLimits *api.ResourceList, transform *pps.Transform,
	cacheSize string, service *pps.Service) *workerOptions {
	labels := labels(rcName)
	userImage := transform.Image
	if userImage == "" {
		userImage = DefaultUserImage
	}

	var workerEnv []api.EnvVar
	for name, value := range transform.Env {
		workerEnv = append(
			workerEnv,
			api.EnvVar{
				Name:  name,
				Value: value,
			},
		)
	}
	// We use Kubernetes' "Downward API" so the workers know their IP
	// addresses, which they will then post on etcd so the job managers
	// can discover the workers.
	workerEnv = append(workerEnv, api.EnvVar{
		Name: client.PPSWorkerIPEnv,
		ValueFrom: &api.EnvVarSource{
			FieldRef: &api.ObjectFieldSelector{
				APIVersion: "v1",
				FieldPath:  "status.podIP",
			},
		},
	})
	workerEnv = append(workerEnv, api.EnvVar{
		Name: client.PPSPodNameEnv,
		ValueFrom: &api.EnvVarSource{
			FieldRef: &api.ObjectFieldSelector{
				APIVersion: "v1",
				FieldPath:  "metadata.name",
			},
		},
	})
	// Set the etcd prefix env
	workerEnv = append(workerEnv, api.EnvVar{
		Name:  client.PPSEtcdPrefixEnv,
		Value: a.etcdPrefix,
	})
	// Pass along the namespace
	workerEnv = append(workerEnv, api.EnvVar{
		Name:  client.PPSNamespaceEnv,
		Value: a.namespace,
	})

	var volumes []api.Volume
	var volumeMounts []api.VolumeMount
	for _, secret := range transform.Secrets {
		if secret.MountPath != "" {
			volumes = append(volumes, api.Volume{
				Name: secret.Name,
				VolumeSource: api.VolumeSource{
					Secret: &api.SecretVolumeSource{
						SecretName: secret.Name,
					},
				},
			})
			volumeMounts = append(volumeMounts, api.VolumeMount{
				Name:      secret.Name,
				MountPath: secret.MountPath,
			})
		}
		if secret.EnvVar != "" {
			workerEnv = append(workerEnv, api.EnvVar{
				Name: secret.EnvVar,
				ValueFrom: &api.EnvVarSource{
					SecretKeyRef: &api.SecretKeySelector{
						LocalObjectReference: api.LocalObjectReference{
							Name: secret.Name,
						},
						Key: secret.Key,
					},
				},
			})
		}
	}

	volumes = append(volumes, api.Volume{
		Name: "pach-bin",
		VolumeSource: api.VolumeSource{
			EmptyDir: &api.EmptyDirVolumeSource{},
		},
	})
	volumeMounts = append(volumeMounts, api.VolumeMount{
		Name:      "pach-bin",
		MountPath: "/pach-bin",
	})

	volumes = append(volumes, api.Volume{
		Name: client.PPSWorkerVolume,
		VolumeSource: api.VolumeSource{
			EmptyDir: &api.EmptyDirVolumeSource{},
		},
	})
	volumeMounts = append(volumeMounts, api.VolumeMount{
		Name:      client.PPSWorkerVolume,
		MountPath: client.PPSScratchSpace,
	})
	if resourceLimits != nil && resourceLimits.NvidiaGPU() != nil && !resourceLimits.NvidiaGPU().IsZero() {
		volumes = append(volumes, api.Volume{
			Name: "root-lib",
			VolumeSource: api.VolumeSource{
				HostPath: &api.HostPathVolumeSource{
					Path: "/usr/lib",
				},
			},
		})
		volumeMounts = append(volumeMounts, api.VolumeMount{
			Name:      "root-lib",
			MountPath: "/rootfs/usr/lib",
		})
	}
	var imagePullSecrets []api.LocalObjectReference
	for _, secret := range transform.ImagePullSecrets {
		imagePullSecrets = append(imagePullSecrets, api.LocalObjectReference{Name: secret})
	}
	if a.imagePullSecret != "" {
		imagePullSecrets = append(imagePullSecrets, api.LocalObjectReference{Name: a.imagePullSecret})
	}

	annotations := map[string]string{"pipelineName": pipelineName}
	if a.iamRole != "" {
		annotations["iam.amazonaws.com/role"] = a.iamRole
	}

	return &workerOptions{
		rcName:           rcName,
		labels:           labels,
		annotations:      annotations,
		parallelism:      int32(parallelism),
		resourceRequests: resourceRequests,
		resourceLimits:   resourceLimits,
		userImage:        userImage,
		workerEnv:        workerEnv,
		volumes:          volumes,
		volumeMounts:     volumeMounts,
		imagePullSecrets: imagePullSecrets,
		cacheSize:        cacheSize,
		service:          service,
	}
}

func (a *apiServer) createWorkerRc(options *workerOptions) error {
	podSpec, err := a.workerPodSpec(options)
	if err != nil {
		return err
	}
	rc := &api.ReplicationController{
		TypeMeta: unversioned.TypeMeta{
			Kind:       "ReplicationController",
			APIVersion: "v1",
		},
		ObjectMeta: api.ObjectMeta{
			Name:        options.rcName,
			Labels:      options.labels,
			Annotations: options.annotations,
		},
		Spec: api.ReplicationControllerSpec{
			Selector: options.labels,
			Replicas: options.parallelism,
			Template: &api.PodTemplateSpec{
				ObjectMeta: api.ObjectMeta{
					Name:        options.rcName,
					Labels:      options.labels,
					Annotations: options.annotations,
				},
				Spec: podSpec,
			},
		},
	}
	if _, err := a.kubeClient.ReplicationControllers(a.namespace).Create(rc); err != nil {
		if !isAlreadyExistsErr(err) {
			return err
		}
	}

	service := &api.Service{
		TypeMeta: unversioned.TypeMeta{
			Kind:       "Service",
			APIVersion: "v1",
		},
		ObjectMeta: api.ObjectMeta{
			Name:   options.rcName,
			Labels: options.labels,
		},
		Spec: api.ServiceSpec{
			Selector: options.labels,
			Ports: []api.ServicePort{
				{
					Port: client.PPSWorkerPort,
					Name: "grpc-port",
				},
			},
		},
	}
	if _, err := a.kubeClient.Services(a.namespace).Create(service); err != nil {
		if !isAlreadyExistsErr(err) {
			return err
		}
	}

	if options.service != nil {
		service := &api.Service{
			TypeMeta: unversioned.TypeMeta{
				Kind:       "Service",
				APIVersion: "v1",
			},
			ObjectMeta: api.ObjectMeta{
				Name:   options.rcName + "-user",
				Labels: options.labels,
			},
			Spec: api.ServiceSpec{
				Selector: options.labels,
				Type:     api.ServiceTypeNodePort,
				Ports: []api.ServicePort{
					{
						Port:       options.service.ExternalPort,
						TargetPort: intstr.FromInt(int(options.service.InternalPort)),
						Name:       "user-port",
						NodePort:   options.service.ExternalPort,
					},
				},
			},
		}
		if _, err := a.kubeClient.Services(a.namespace).Create(service); err != nil {
			if !isAlreadyExistsErr(err) {
				return err
			}
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package directfio_test

import (
	"bytes"
	"os"
	"testing"

	"log"
	"time"

	"io/ioutil"

	fio "github.com/rancher/sparse-tools/directfio"
	"syscall"
)

func tempFileName() string {
	// Make a temporary file name
	f, err := ioutil.TempFile("", "fio_test")
	if err != nil {
		log.Fatal("Failed to make temp file", err)
	}
	defer f.Close()
	return f.Name()
}

func cleanup(path string) {
	// Cleanup
	err := os.Remove(path)
	if err != nil {
		log.Fatal("Failed to remove file", path, err)
	}
}

func fillData(data []byte, start int) {
	for i := 0; i < len(data); i++ {
		data[i] = byte(start + i)
	}
}

func TestDirectFileIO1(t *testing.T) {
	blocks := 4

	// Init data
	data1 := fio.AllocateAligned(blocks * fio.BlockSize)
	fillData(data1, 0)

	path := tempFileName()
	{
		// Write
		f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|syscall.O_DIRECT, 0644)
		if err != nil {
			t.Fatal("Failed to OpenFile for write", err)
		}
		defer f.Close()

		_, err = f.WriteAt(data1, int64(blocks*fio.BlockSize))
		if err != nil {
			t.Fatal("Failed to write", err)
		}
	}

	data2 := fio.AllocateAligned(blocks * fio.BlockSize)
	{
		// Read
		f, err := os.OpenFile(path, os.O_RDONLY|syscall.O_DIRECT, 0)
		if err != nil {
			t.Fatal("Failed to OpenFile for read", err)
		}
		defer f.Close()

		_, err = f.ReadAt(data2, int64(blocks*fio.BlockSize))
		if err != nil {
			t.Fatal("Failed to read", err)
		}
	}

	// Check
	if !bytes.Equal(data1, data2) {
		t.Fatal("Read not the same as written")
	}

	cleanup(path)
}

func TestDirectFileIO2(t *testing.T) {
	blocks := 4

	// Init data
	data1 := make([]byte, blocks*fio.BlockSize)
	fillData(data1, 0)

	path := tempFileName()
	{
		// Write
		f, err := fio.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0644)
		if err != nil {
			t.Fatal("Failed to OpenFile for write", err)
		}
		defer f.Close()

		_, err = fio.WriteAt(f, data1, int64(blocks*fio.BlockSize))
		if err != nil {
			t.Fatal("Failed to write", err)
		}
	}

	data2 := make([]byte, blocks*fio.BlockSize)
	{
		// Read
		f, err := fio.OpenFile(path, os.O_RDONLY, 0)
		if err != nil {
			t.Fatal("Failed to OpenFile for read", err)
		}
		defer f.Close()

		_, err = fio.ReadAt(f, data2, int64(blocks*fio.BlockSize))
		if err != nil {
			t.Fatal("Failed to read", err)
		}
	}

	// Check
	if !bytes.Equal(data1, data2) {
		t.Fatal("Read not the same as written")
	}

	cleanup(path)
}

const fileSize = int64(512) /*MB*/ << 20

const FileMode = os.O_RDWR

func write(b *testing.B, path string, done chan<- bool, batchSize int, offset, size int64) {
	data := fio.AllocateAligned(batchSize)
	fillData(data, 0)

	f, err := os.OpenFile(path, syscall.O_DIRECT|FileMode, 0)
	if err != nil {
		b.Fatal("Failed to OpenFile for write", err)
	}
	defer f.Close()

	for pos := offset; pos < offset+size; pos += int64(batchSize) {
		_, err = f.WriteAt(data, pos)
		if err != nil {
			b.Fatal("Failed to write", err)
		}
	}
	done <- true
}

func read(b *testing.B, path string, done chan<- bool, batchSize int, offset, size int64) {
	data := fio.AllocateAligned(batchSize)

	f, err := os.OpenFile(path, syscall.O_DIRECT|FileMode, 0)
	if err != nil {
		b.Fatal("Failed to OpenFile for read", err)
	}
	defer f.Close()

	for pos := offset; pos < offset+size; pos += int64(batchSize) {
		_, err = f.ReadAt(data, pos)
		if err != nil {
			b.Fatal("Failed to read", err)
		}
	}
	done <- true
}

func writeUnaligned(b *testing.B, path string, done chan<- bool, batchSize int, offset, size int64) {
	data := make([]byte, batchSize)
	fillData(data, 0)

	f, err := fio.OpenFile(path, FileMode, 0)
	if err != nil {
		b.Fatal("Failed to OpenFile for write", err)
	}
	defer f.Close()

	for pos := offset; pos < offset+size; pos += int64(batchSize) {
		_, err = fio.WriteAt(f, data, pos)
		if err != nil {
			b.Fatal("Failed to write", err)
		}
	}
	done <- true
}

func readUnaligned(b *testing.B, path string, done chan<- bool, batchSize int, offset, size int64) {
	data := make([]byte, batchSize)

	f, err := fio.OpenFile(path, FileMode, 0)
	if err != nil {
		b.Fatal("Failed to OpenFile for read", err)
	}
	defer f.Close()

	for pos := offset; pos < offset+size; pos += int64(batchSize) {
		_, err = fio.ReadAt(f, data, pos)
		if err != nil {
			b.Fatal("Failed to read", err)
		}
	}
	done <- true
}

func ioTest(title string, b *testing.B, path string, threads, batch int, io func(b *testing.B, path string, done chan<- bool, batchSize int, offset, size int64)) {
	done := make(chan bool, threads)
	chunkSize := fileSize / int64(threads)

	start := time.Now().UnixNano()
	ioSize := batch * fio.BlockSize
	for i := 0; i < threads; i++ {
		go io(b, path, done, ioSize, int64(i)*chunkSize, chunkSize)
	}
	for i := 0; i < threads; i++ {
		<-done
	}
	stop := time.Now().UnixNano()
	log.Println(title, ":", threads, "(threads) batch=", batch, "(blocks)", "thruput=", 1000000000*fileSize/(1<<20)/(stop-start), "(MB/s)")
}

func BenchmarkIO8(b *testing.B) {
	path := tempFileName()

	f, err := os.OpenFile(path, os.O_CREATE|FileMode, 0644)
	if err != nil {
		b.Fatal("Failed to OpenFile for write", err)
	}
	defer f.Close()
	f.Truncate(fileSize)

	for batch := 32; batch >= 1; batch >>= 1 {
		log.Println("")
		for threads := 1; threads <= 8; threads <<= 1 {
			ioTest("write", b, path, threads, batch, write)
			ioTest(" read", b, path, threads, batch, read)
		}
	}

	cleanup(path)
}

func BenchmarkIO8u(b *testing.B) {
	path := tempFileName()

	f, err := os.OpenFile(path, os.O_CREATE|FileMode, 0644)
	if err != nil {
		b.Fatal("Failed to OpenFile for write", err)
	}
	defer f.Close()
	f.Truncate(fileSize)

	for batch := 32; batch >= 1; batch >>= 1 {
		log.Println("")
		for threads := 1; threads <= 8; threads <<= 1 {
			ioTest("unaligned write", b, path, threads, batch, writeUnaligned)
			ioTest(" unaligned read", b, path, threads, batch, readUnaligned)
		}
	}

	cleanup(path)
}
<commit_msg>test: directfio: added pilot write and tweaked output<commit_after>package directfio_test

import (
	"bytes"
	"os"
	"testing"

	"log"
	"time"

	"io/ioutil"

	"syscall"

	fio "github.com/rancher/sparse-tools/directfio"
)

func tempFileName() string {
	// Make a temporary file name
	f, err := ioutil.TempFile(".", "fio_test")
	if err != nil {
		log.Fatal("Failed to make temp file", err)
	}
	defer f.Close()
	return f.Name()
}

func cleanup(path string) {
	// Cleanup
	err := os.Remove(path)
	if err != nil {
		log.Fatal("Failed to remove file", path, err)
	}
}

func fillData(data []byte, start int) {
	for i := 0; i < len(data); i++ {
		data[i] = byte(start + i)
	}
}

func TestDirectFileIO1(t *testing.T) {
	blocks := 4

	// Init data
	data1 := fio.AllocateAligned(blocks * fio.BlockSize)
	fillData(data1, 0)

	path := tempFileName()
	{
		// Write
		f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|syscall.O_DIRECT, 0644)
		if err != nil {
			t.Fatal("Failed to OpenFile for write", err)
		}
		defer f.Close()

		_, err = f.WriteAt(data1, int64(blocks*fio.BlockSize))
		if err != nil {
			t.Fatal("Failed to write", err)
		}
	}

	data2 := fio.AllocateAligned(blocks * fio.BlockSize)
	{
		// Read
		f, err := os.OpenFile(path, os.O_RDONLY|syscall.O_DIRECT, 0)
		if err != nil {
			t.Fatal("Failed to OpenFile for read", err)
		}
		defer f.Close()

		_, err = f.ReadAt(data2, int64(blocks*fio.BlockSize))
		if err != nil {
			t.Fatal("Failed to read", err)
		}
	}

	// Check
	if !bytes.Equal(data1, data2) {
		t.Fatal("Read not the same as written")
	}

	cleanup(path)
}

func TestDirectFileIO2(t *testing.T) {
	blocks := 4

	// Init data
	data1 := make([]byte, blocks*fio.BlockSize)
	fillData(data1, 0)

	path := tempFileName()
	{
		// Write
		f, err := fio.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0644)
		if err != nil {
			t.Fatal("Failed to OpenFile for write", err)
		}
		defer f.Close()

		_, err = fio.WriteAt(f, data1, int64(blocks*fio.BlockSize))
		if err != nil {
			t.Fatal("Failed to write", err)
		}
	}

	data2 := make([]byte, blocks*fio.BlockSize)
	{
		// Read
		f, err := fio.OpenFile(path, os.O_RDONLY, 0)
		if err != nil {
			t.Fatal("Failed to OpenFile for read", err)
		}
		defer f.Close()

		_, err = fio.ReadAt(f, data2, int64(blocks*fio.BlockSize))
		if err != nil {
			t.Fatal("Failed to read", err)
		}
	}

	// Check
	if !bytes.Equal(data1, data2) {
		t.Fatal("Read not the same as written")
	}

	cleanup(path)
}

const fileSize = int64(1) /*GB*/ << 30

const FileMode = os.O_RDWR

func write(b *testing.B, path string, done chan<- bool, batchSize int, offset, size int64) {
	data := fio.AllocateAligned(batchSize)
	fillData(data, 0)

	f, err := os.OpenFile(path, syscall.O_DIRECT|FileMode, 0)
	if err != nil {
		b.Fatal("Failed to OpenFile for write", err)
	}
	defer f.Close()

	for pos := offset; pos < offset+size; pos += int64(batchSize) {
		_, err = f.WriteAt(data, pos)
		if err != nil {
			b.Fatal("Failed to write", err)
		}
	}
	done <- true
}

func read(b *testing.B, path string, done chan<- bool, batchSize int, offset, size int64) {
	data := fio.AllocateAligned(batchSize)

	f, err := os.OpenFile(path, syscall.O_DIRECT|FileMode, 0)
	if err != nil {
		b.Fatal("Failed to OpenFile for read", err)
	}
	defer f.Close()

	for pos := offset; pos < offset+size; pos += int64(batchSize) {
		_, err = f.ReadAt(data, pos)
		if err != nil {
			b.Fatal("Failed to read", err)
		}
	}
	done <- true
}

func writeUnaligned(b *testing.B, path string, done chan<- bool, batchSize int, offset, size int64) {
	data := make([]byte, batchSize)
	fillData(data, 0)

	f, err := fio.OpenFile(path, FileMode, 0)
	if err != nil {
		b.Fatal("Failed to OpenFile for write", err)
	}
	defer f.Close()

	for pos := offset; pos < offset+size; pos += int64(batchSize) {
		_, err = fio.WriteAt(f, data, pos)
		if err != nil {
			b.Fatal("Failed to write", err)
		}
	}
	done <- true
}

func readUnaligned(b *testing.B, path string, done chan<- bool, batchSize int, offset, size int64) {
	data := make([]byte, batchSize)

	f, err := fio.OpenFile(path, FileMode, 0)
	if err != nil {
		b.Fatal("Failed to OpenFile for read", err)
	}
	defer f.Close()

	for pos := offset; pos < offset+size; pos += int64(batchSize) {
		_, err = fio.ReadAt(f, data, pos)
		if err != nil {
			b.Fatal("Failed to read", err)
		}
	}
	done <- true
}

func ioTest(title string, b *testing.B, path string, threads, batch int, io func(b *testing.B, path string, done chan<- bool, batchSize int, offset, size int64)) {
	done := make(chan bool, threads)
	chunkSize := fileSize / int64(threads)

	start := time.Now().UnixNano()
	ioSize := batch * fio.BlockSize
	for i := 0; i < threads; i++ {
		go io(b, path, done, ioSize, int64(i)*chunkSize, chunkSize)
	}
	for i := 0; i < threads; i++ {
		<-done
	}
	stop := time.Now().UnixNano()
	if len(title) > 0 {
		log.Println(title, ":", threads, "(threads) batch=", batch, "(blocks)", "thruput=", 1000000*fileSize/(1<<20)/((stop-start)/1000), "(MB/s)")
	}
}

func BenchmarkIO8(b *testing.B) {
	path := tempFileName()

	f, err := os.OpenFile(path, os.O_CREATE|FileMode, 0644)
	if err != nil {
		b.Fatal("Failed to OpenFile for write", err)
	}
	defer f.Close()
	f.Truncate(fileSize)
	log.Println("")
	ioTest("pilot write", b, path, 8, 32, write)

	for batch := 32; batch >= 1; batch >>= 1 {
		log.Println("")
		for threads := 1; threads <= 8; threads <<= 1 {
			ioTest("write", b, path, threads, batch, write)
		}
		for threads := 1; threads <= 8; threads <<= 1 {
			ioTest(" read", b, path, threads, batch, read)
		}
	}

	cleanup(path)
}

func BenchmarkIO8u(b *testing.B) {
	path := tempFileName()

	f, err := os.OpenFile(path, os.O_CREATE|FileMode, 0644)
	if err != nil {
		b.Fatal("Failed to OpenFile for write", err)
	}
	defer f.Close()
	f.Truncate(fileSize)
	log.Println("")
	ioTest("pilot write", b, path, 8, 32, writeUnaligned)

	for batch := 32; batch >= 1; batch >>= 1 {
		log.Println("")
		for threads := 1; threads <= 8; threads <<= 1 {
			ioTest("unaligned write", b, path, threads, batch, writeUnaligned)
		}
		for threads := 1; threads <= 8; threads <<= 1 {
			ioTest(" unaligned read", b, path, threads, batch, readUnaligned)
		}
	}

	cleanup(path)
}
<|endoftext|>


<commit_before>package restarts

import (
	"fmt"
	"math/rand"
	"sync"
	"time"

	"github.com/hashicorp/nomad/nomad/structs"
	"github.com/hashicorp/nomad/plugins/drivers"
)

const (
	// jitter is the percent of jitter added to restart delays.
	jitter = 0.25

	ReasonNoRestartsAllowed   = "Policy allows no restarts"
	ReasonUnrecoverableErrror = "Error was unrecoverable"
	ReasonWithinPolicy        = "Restart within policy"
	ReasonDelay               = "Exceeded allowed attempts, applying a delay"
)

func NewRestartTracker(policy *structs.RestartPolicy, jobType string, tlc *structs.TaskLifecycleConfig) *RestartTracker {
	onSuccess := jobType != structs.JobTypeBatch
	if tlc != nil && tlc.Hook == structs.TaskLifecycleHookPrestart {
		onSuccess = tlc.Sidecar
	}

	return &RestartTracker{
		startTime: time.Now(),
		onSuccess: onSuccess,
		policy:    policy,
		rand:      rand.New(rand.NewSource(time.Now().Unix())),
	}
}

type RestartTracker struct {
	exitRes          *drivers.ExitResult
	startErr         error
	killed           bool      // Whether the task has been killed
	restartTriggered bool      // Whether the task has been signalled to be restarted
	failure          bool      // Whether a failure triggered the restart
	count            int       // Current number of attempts.
	onSuccess        bool      // Whether to restart on successful exit code.
	startTime        time.Time // When the interval began
	reason           string    // The reason for the last state
	policy           *structs.RestartPolicy
	rand             *rand.Rand
	lock             sync.Mutex
}

// SetPolicy updates the policy used to determine restarts.
func (r *RestartTracker) SetPolicy(policy *structs.RestartPolicy) {
	r.lock.Lock()
	defer r.lock.Unlock()
	r.policy = policy
}

// GetPolicy returns a copy of the policy used to determine restarts.
func (r *RestartTracker) GetPolicy() *structs.RestartPolicy {
	r.lock.Lock()
	defer r.lock.Unlock()
	return r.policy.Copy()
}

// SetStartError is used to mark the most recent start error. If starting was
// successful the error should be nil.
func (r *RestartTracker) SetStartError(err error) *RestartTracker {
	r.lock.Lock()
	defer r.lock.Unlock()
	r.startErr = err
	r.failure = true
	return r
}

// SetExitResult is used to mark the most recent wait result.
func (r *RestartTracker) SetExitResult(res *drivers.ExitResult) *RestartTracker {
	r.lock.Lock()
	defer r.lock.Unlock()
	r.exitRes = res
	r.failure = true
	return r
}

// SetRestartTriggered is used to mark that the task has been signalled to be
// restarted. Setting the failure to true restarts according to the restart
// policy. When failure is false the task is restarted without considering the
// restart policy.
func (r *RestartTracker) SetRestartTriggered(failure bool) *RestartTracker {
	r.lock.Lock()
	defer r.lock.Unlock()
	if failure {
		r.failure = true
	} else {
		r.restartTriggered = true
	}
	return r
}

// SetKilled is used to mark that the task has been killed.
func (r *RestartTracker) SetKilled() *RestartTracker {
	r.lock.Lock()
	defer r.lock.Unlock()
	r.killed = true
	return r
}

// GetReason returns a human-readable description for the last state returned by
// GetState.
func (r *RestartTracker) GetReason() string {
	r.lock.Lock()
	defer r.lock.Unlock()
	return r.reason
}

// GetCount returns the current restart count
func (r *RestartTracker) GetCount() int {
	r.lock.Lock()
	defer r.lock.Unlock()
	return r.count
}

// GetState returns the tasks next state given the set exit code and start
// error. One of the following states are returned:
// * TaskRestarting - Task should be restarted
// * TaskNotRestarting - Task should not be restarted and has exceeded its
//   restart policy.
// * TaskTerminated - Task has terminated successfully and does not need a
//   restart.
//
// If TaskRestarting is returned, the duration is how long to wait until
// starting the task again.
func (r *RestartTracker) GetState() (string, time.Duration) {
	r.lock.Lock()
	defer r.lock.Unlock()

	// Clear out the existing state
	defer func() {
		r.startErr = nil
		r.exitRes = nil
		r.restartTriggered = false
		r.failure = false
		r.killed = false
	}()

	// Hot path if task was killed
	if r.killed {
		r.reason = ""
		return structs.TaskKilled, 0
	}

	// Hot path if a restart was triggered
	if r.restartTriggered {
		r.reason = ""
		return structs.TaskRestarting, 0
	}

	// Hot path if no attempts are expected
	if r.policy.Attempts == 0 {
		r.reason = ReasonNoRestartsAllowed

		// If the task does not restart on a successful exit code and
		// the exit code was successful: terminate.
		if !r.onSuccess && r.exitRes != nil && r.exitRes.Successful() {
			return structs.TaskTerminated, 0
		}

		// Task restarts even on a successful exit code but no restarts
		// allowed.
		return structs.TaskNotRestarting, 0
	}

	// Check if we have entered a new interval.
	end := r.startTime.Add(r.policy.Interval)
	now := time.Now()
	if now.After(end) {
		r.count = 0
		r.startTime = now
	}

	r.count++

	// Handle restarts due to failures
	if !r.failure {
		return "", 0
	}

	if r.startErr != nil {
		// If the error is not recoverable, do not restart.
		if !structs.IsRecoverable(r.startErr) {
			r.reason = ReasonUnrecoverableErrror
			return structs.TaskNotRestarting, 0
		}
	} else if r.exitRes != nil {
		// If the task started successfully and restart on success isn't specified,
		// don't restart but don't mark as failed.
		if r.exitRes.Successful() && !r.onSuccess {
			r.reason = "Restart unnecessary as task terminated successfully"
			return structs.TaskTerminated, 0
		}
	}

	// If this task has been restarted due to failures more times
	// than the restart policy allows within an interval fail
	// according to the restart policy's mode.
	if r.count > r.policy.Attempts {
		if r.policy.Mode == structs.RestartPolicyModeFail {
			r.reason = fmt.Sprintf(
				`Exceeded allowed attempts %d in interval %v and mode is "fail"`,
				r.policy.Attempts, r.policy.Interval)
			return structs.TaskNotRestarting, 0
		} else {
			r.reason = ReasonDelay
			return structs.TaskRestarting, r.getDelay()
		}
	}

	r.reason = ReasonWithinPolicy
	return structs.TaskRestarting, r.jitter()
}

// getDelay returns the delay time to enter the next interval.
func (r *RestartTracker) getDelay() time.Duration {
	end := r.startTime.Add(r.policy.Interval)
	now := time.Now()
	return end.Sub(now)
}

// jitter returns the delay time plus a jitter.
func (r *RestartTracker) jitter() time.Duration {
	// Get the delay and ensure it is valid.
	d := r.policy.Delay.Nanoseconds()
	if d == 0 {
		d = 1
	}

	j := float64(r.rand.Int63n(d)) * jitter
	return time.Duration(d + int64(j))
}
<commit_msg>client: don't restart poststart sidecars on success<commit_after>package restarts

import (
	"fmt"
	"math/rand"
	"sync"
	"time"

	"github.com/hashicorp/nomad/nomad/structs"
	"github.com/hashicorp/nomad/plugins/drivers"
)

const (
	// jitter is the percent of jitter added to restart delays.
	jitter = 0.25

	ReasonNoRestartsAllowed   = "Policy allows no restarts"
	ReasonUnrecoverableErrror = "Error was unrecoverable"
	ReasonWithinPolicy        = "Restart within policy"
	ReasonDelay               = "Exceeded allowed attempts, applying a delay"
)

func NewRestartTracker(policy *structs.RestartPolicy, jobType string, tlc *structs.TaskLifecycleConfig) *RestartTracker {
	// Batch jobs should not restart if they exit successfully
	onSuccess := jobType != structs.JobTypeBatch

	// Prestart sidecars should get restarted on success
	if tlc != nil && tlc.Hook == structs.TaskLifecycleHookPrestart {
		onSuccess = tlc.Sidecar
	}

	// Poststart sidecars should get restarted on success
	if tlc != nil && tlc.Hook == structs.TaskLifecycleHookPoststart {
		onSuccess = tlc.Sidecar
	}

	return &RestartTracker{
		startTime: time.Now(),
		onSuccess: onSuccess,
		policy:    policy,
		rand:      rand.New(rand.NewSource(time.Now().Unix())),
	}
}

type RestartTracker struct {
	exitRes          *drivers.ExitResult
	startErr         error
	killed           bool      // Whether the task has been killed
	restartTriggered bool      // Whether the task has been signalled to be restarted
	failure          bool      // Whether a failure triggered the restart
	count            int       // Current number of attempts.
	onSuccess        bool      // Whether to restart on successful exit code.
	startTime        time.Time // When the interval began
	reason           string    // The reason for the last state
	policy           *structs.RestartPolicy
	rand             *rand.Rand
	lock             sync.Mutex
}

// SetPolicy updates the policy used to determine restarts.
func (r *RestartTracker) SetPolicy(policy *structs.RestartPolicy) {
	r.lock.Lock()
	defer r.lock.Unlock()
	r.policy = policy
}

// GetPolicy returns a copy of the policy used to determine restarts.
func (r *RestartTracker) GetPolicy() *structs.RestartPolicy {
	r.lock.Lock()
	defer r.lock.Unlock()
	return r.policy.Copy()
}

// SetStartError is used to mark the most recent start error. If starting was
// successful the error should be nil.
func (r *RestartTracker) SetStartError(err error) *RestartTracker {
	r.lock.Lock()
	defer r.lock.Unlock()
	r.startErr = err
	r.failure = true
	return r
}

// SetExitResult is used to mark the most recent wait result.
func (r *RestartTracker) SetExitResult(res *drivers.ExitResult) *RestartTracker {
	r.lock.Lock()
	defer r.lock.Unlock()
	r.exitRes = res
	r.failure = true
	return r
}

// SetRestartTriggered is used to mark that the task has been signalled to be
// restarted. Setting the failure to true restarts according to the restart
// policy. When failure is false the task is restarted without considering the
// restart policy.
func (r *RestartTracker) SetRestartTriggered(failure bool) *RestartTracker {
	r.lock.Lock()
	defer r.lock.Unlock()
	if failure {
		r.failure = true
	} else {
		r.restartTriggered = true
	}
	return r
}

// SetKilled is used to mark that the task has been killed.
func (r *RestartTracker) SetKilled() *RestartTracker {
	r.lock.Lock()
	defer r.lock.Unlock()
	r.killed = true
	return r
}

// GetReason returns a human-readable description for the last state returned by
// GetState.
func (r *RestartTracker) GetReason() string {
	r.lock.Lock()
	defer r.lock.Unlock()
	return r.reason
}

// GetCount returns the current restart count
func (r *RestartTracker) GetCount() int {
	r.lock.Lock()
	defer r.lock.Unlock()
	return r.count
}

// GetState returns the tasks next state given the set exit code and start
// error. One of the following states are returned:
// * TaskRestarting - Task should be restarted
// * TaskNotRestarting - Task should not be restarted and has exceeded its
//   restart policy.
// * TaskTerminated - Task has terminated successfully and does not need a
//   restart.
//
// If TaskRestarting is returned, the duration is how long to wait until
// starting the task again.
func (r *RestartTracker) GetState() (string, time.Duration) {
	r.lock.Lock()
	defer r.lock.Unlock()

	// Clear out the existing state
	defer func() {
		r.startErr = nil
		r.exitRes = nil
		r.restartTriggered = false
		r.failure = false
		r.killed = false
	}()

	// Hot path if task was killed
	if r.killed {
		r.reason = ""
		return structs.TaskKilled, 0
	}

	// Hot path if a restart was triggered
	if r.restartTriggered {
		r.reason = ""
		return structs.TaskRestarting, 0
	}

	// Hot path if no attempts are expected
	if r.policy.Attempts == 0 {
		r.reason = ReasonNoRestartsAllowed

		// If the task does not restart on a successful exit code and
		// the exit code was successful: terminate.
		if !r.onSuccess && r.exitRes != nil && r.exitRes.Successful() {
			return structs.TaskTerminated, 0
		}

		// Task restarts even on a successful exit code but no restarts
		// allowed.
		return structs.TaskNotRestarting, 0
	}

	// Check if we have entered a new interval.
	end := r.startTime.Add(r.policy.Interval)
	now := time.Now()
	if now.After(end) {
		r.count = 0
		r.startTime = now
	}

	r.count++

	// Handle restarts due to failures
	if !r.failure {
		return "", 0
	}

	if r.startErr != nil {
		// If the error is not recoverable, do not restart.
		if !structs.IsRecoverable(r.startErr) {
			r.reason = ReasonUnrecoverableErrror
			return structs.TaskNotRestarting, 0
		}
	} else if r.exitRes != nil {
		// If the task started successfully and restart on success isn't specified,
		// don't restart but don't mark as failed.
		if r.exitRes.Successful() && !r.onSuccess {
			r.reason = "Restart unnecessary as task terminated successfully"
			return structs.TaskTerminated, 0
		}
	}

	// If this task has been restarted due to failures more times
	// than the restart policy allows within an interval fail
	// according to the restart policy's mode.
	if r.count > r.policy.Attempts {
		if r.policy.Mode == structs.RestartPolicyModeFail {
			r.reason = fmt.Sprintf(
				`Exceeded allowed attempts %d in interval %v and mode is "fail"`,
				r.policy.Attempts, r.policy.Interval)
			return structs.TaskNotRestarting, 0
		} else {
			r.reason = ReasonDelay
			return structs.TaskRestarting, r.getDelay()
		}
	}

	r.reason = ReasonWithinPolicy
	return structs.TaskRestarting, r.jitter()
}

// getDelay returns the delay time to enter the next interval.
func (r *RestartTracker) getDelay() time.Duration {
	end := r.startTime.Add(r.policy.Interval)
	now := time.Now()
	return end.Sub(now)
}

// jitter returns the delay time plus a jitter.
func (r *RestartTracker) jitter() time.Duration {
	// Get the delay and ensure it is valid.
	d := r.policy.Delay.Nanoseconds()
	if d == 0 {
		d = 1
	}

	j := float64(r.rand.Int63n(d)) * jitter
	return time.Duration(d + int64(j))
}
<|endoftext|>


<commit_before>package cloudformation

// AWSCodeBuildProject_Source AWS CloudFormation Resource (AWS::CodeBuild::Project.Source)
// See: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codebuild-project-source.html
type AWSCodeBuildProject_Source struct {

	// Auth AWS CloudFormation Property
	// Required: false
	// See: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codebuild-project-source.html#cfn-codebuild-project-source-auth
	Auth *AWSCodeBuildProject_SourceAuth `json:"Auth,omitempty"`

	// BuildSpec AWS CloudFormation Property
	// Required: false
	// See: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codebuild-project-source.html#cfn-codebuild-project-source-buildspec
	BuildSpec string `json:"BuildSpec,omitempty"`

	// Location AWS CloudFormation Property
	// Required: false
	// See: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codebuild-project-source.html#cfn-codebuild-project-source-location
	Location string `json:"Location,omitempty"`

	// Type AWS CloudFormation Property
	// Required: true
	// See: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codebuild-project-source.html#cfn-codebuild-project-source-type
	Type string `json:"Type,omitempty"`
}

// AWSCloudFormationType returns the AWS CloudFormation resource type
func (r *AWSCodeBuildProject_Source) AWSCloudFormationType() string {
	return "AWS::CodeBuild::Project.Source"
}
<commit_msg>AWS CloudFormation Update (2018-01-30)<commit_after>package cloudformation

// AWSCodeBuildProject_Source AWS CloudFormation Resource (AWS::CodeBuild::Project.Source)
// See: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codebuild-project-source.html
type AWSCodeBuildProject_Source struct {

	// Auth AWS CloudFormation Property
	// Required: false
	// See: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codebuild-project-source.html#cfn-codebuild-project-source-auth
	Auth *AWSCodeBuildProject_SourceAuth `json:"Auth,omitempty"`

	// BuildSpec AWS CloudFormation Property
	// Required: false
	// See: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codebuild-project-source.html#cfn-codebuild-project-source-buildspec
	BuildSpec string `json:"BuildSpec,omitempty"`

	// GitCloneDepth AWS CloudFormation Property
	// Required: false
	// See: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codebuild-project-source.html#cfn-codebuild-project-source-gitclonedepth
	GitCloneDepth int `json:"GitCloneDepth,omitempty"`

	// InsecureSsl AWS CloudFormation Property
	// Required: false
	// See: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codebuild-project-source.html#cfn-codebuild-project-source-insecuressl
	InsecureSsl bool `json:"InsecureSsl,omitempty"`

	// Location AWS CloudFormation Property
	// Required: false
	// See: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codebuild-project-source.html#cfn-codebuild-project-source-location
	Location string `json:"Location,omitempty"`

	// Type AWS CloudFormation Property
	// Required: true
	// See: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codebuild-project-source.html#cfn-codebuild-project-source-type
	Type string `json:"Type,omitempty"`
}

// AWSCloudFormationType returns the AWS CloudFormation resource type
func (r *AWSCodeBuildProject_Source) AWSCloudFormationType() string {
	return "AWS::CodeBuild::Project.Source"
}
<|endoftext|>


<commit_before>package collectors

import (
	"regexp"
	"strings"

	"github.com/StackExchange/scollector/metadata"
	"github.com/StackExchange/scollector/opentsdb"
	"github.com/StackExchange/wmi"
)

func init() {
	collectors = append(collectors, &IntervalCollector{F: c_windows_processes})
}

// These are silly processes but exist on my machine, will need to update KMB
var processInclusions = regexp.MustCompile("chrome|powershell|scollector|SocketServer")
var serviceInclusions = regexp.MustCompile("WinRM")

func c_windows_processes() (opentsdb.MultiDataPoint, error) {
	var dst []Win32_PerfRawData_PerfProc_Process
	var q = wmi.CreateQuery(&dst, `WHERE Name <> '_Total'`)
	err := queryWmi(q, &dst)
	if err != nil {
		return nil, err
	}

	var svc_dst []Win32_Service
	var svc_q = wmi.CreateQuery(&svc_dst, `WHERE Name <> '_Total'`)
	err = queryWmi(svc_q, &svc_dst)
	if err != nil {
		return nil, err
	}

	var iis_dst []WorkerProcess
	iis_q := wmi.CreateQuery(&iis_dst, "")
	err = queryWmiNamespace(iis_q, &iis_dst, "root\\WebAdministration")
	if err != nil {
		//Don't Return from this error since the name space might exist
		iis_dst = nil
	}

	var md opentsdb.MultiDataPoint
	for _, v := range dst {
		var name string
		service_match := false
		iis_match := false
		process_match := processInclusions.MatchString(v.Name)

		id := "0"

		if process_match {
			raw_name := strings.Split(v.Name, "#")
			name = raw_name[0]
			if len(raw_name) == 2 {
				id = raw_name[1]
			}
			// If you have a hash sign in your process name you don't deserve monitoring ;-)
			if len(raw_name) > 2 {
				continue
			}
		}

		// A Service match could "overwrite" a process match, but that is probably what we would want
		for _, svc := range svc_dst {
			if serviceInclusions.MatchString(svc.Name) {
				// It is possible the pid has gone and been reused, but I think this unlikely
				// And I'm not aware of an atomic join we could do anyways
				if svc.ProcessId == v.IDProcess {
					id = "0"
					service_match = true
					name = svc.Name
					break
				}
			}
		}

		for _, a_pool := range iis_dst {
			if a_pool.ProcessId == v.IDProcess {
				id = "0"
				iis_match = true
				name = strings.Join([]string{"iis", a_pool.AppPoolName}, "_")
				break
			}
		}

		if !(service_match || process_match || iis_match) {
			continue
		}

		Add(&md, "win.proc.elapsed_time", v.ElapsedTime, opentsdb.TagSet{"name": name, "id": id}, metadata.Unknown, metadata.None, "")
		Add(&md, "win.proc.handle_count", v.HandleCount, opentsdb.TagSet{"name": name, "id": id}, metadata.Unknown, metadata.None, "")
		Add(&md, "win.proc.io_bytes", v.IOOtherBytesPersec, opentsdb.TagSet{"name": name, "id": id, "type": "other"}, metadata.Unknown, metadata.None, "")
		Add(&md, "win.proc.io_operations", v.IOOtherOperationsPersec, opentsdb.TagSet{"name": name, "id": id, "type": "other"}, metadata.Unknown, metadata.None, "")
		Add(&md, "win.proc.io_bytes", v.IOReadBytesPersec, opentsdb.TagSet{"name": name, "id": id, "type": "read"}, metadata.Unknown, metadata.None, "")
		Add(&md, "win.proc.io_operations", v.IOReadOperationsPersec, opentsdb.TagSet{"name": name, "id": id, "type": "read"}, metadata.Unknown, metadata.None, "")
		Add(&md, "win.proc.io_bytes", v.IOWriteBytesPersec, opentsdb.TagSet{"name": name, "id": id, "type": "write"}, metadata.Unknown, metadata.None, "")
		Add(&md, "win.proc.io_operations", v.IOWriteOperationsPersec, opentsdb.TagSet{"name": name, "id": id, "type": "write"}, metadata.Unknown, metadata.None, "")
		Add(&md, "win.proc.mem.page_faults", v.PageFaultsPersec, opentsdb.TagSet{"name": name, "id": id}, metadata.Unknown, metadata.None, "")
		Add(&md, "win.proc.mem.pagefile_bytes", v.PageFileBytes, opentsdb.TagSet{"name": name, "id": id}, metadata.Unknown, metadata.None, "")
		Add(&md, "win.proc.mem.pagefile_bytes_peak", v.PageFileBytesPeak, opentsdb.TagSet{"name": name, "id": id}, metadata.Unknown, metadata.None, "")
		Add(&md, "win.proc.cpu", v.PercentPrivilegedTime, opentsdb.TagSet{"name": name, "id": id, "type": "privileged"}, metadata.Unknown, metadata.None, "")
		Add(&md, "win.proc.cpu_total", v.PercentProcessorTime, opentsdb.TagSet{"name": name, "id": id}, metadata.Unknown, metadata.None, "")
		Add(&md, "win.proc.cpu", v.PercentUserTime, opentsdb.TagSet{"name": name, "id": id, "type": "user"}, metadata.Unknown, metadata.None, "")
		Add(&md, "win.proc.mem.pool_nonpaged_bytes", v.PoolNonpagedBytes, opentsdb.TagSet{"name": name, "id": id}, metadata.Unknown, metadata.None, "")
		Add(&md, "win.proc.mem.pool_paged_bytes", v.PoolPagedBytes, opentsdb.TagSet{"name": name, "id": id}, metadata.Unknown, metadata.None, "")
		Add(&md, "win.proc.priority_base", v.PriorityBase, opentsdb.TagSet{"name": name, "id": id}, metadata.Unknown, metadata.None, "")
		Add(&md, "win.proc.private_bytes", v.PrivateBytes, opentsdb.TagSet{"name": name, "id": id}, metadata.Unknown, metadata.None, "")
		Add(&md, "win.proc.thread_count", v.ThreadCount, opentsdb.TagSet{"name": name, "id": id}, metadata.Unknown, metadata.None, "")
		Add(&md, "win.proc.mem.vm.bytes", v.VirtualBytes, opentsdb.TagSet{"name": name, "id": id}, metadata.Unknown, metadata.None, "")
		Add(&md, "win.proc.mem.vm.bytes_peak", v.VirtualBytesPeak, opentsdb.TagSet{"name": name, "id": id}, metadata.Unknown, metadata.None, "")
		Add(&md, "win.proc.mem.working_set", v.WorkingSet, opentsdb.TagSet{"name": name, "id": id}, metadata.Unknown, metadata.None, "")
		Add(&md, "win.proc.mem.working_set_peak", v.WorkingSetPeak, opentsdb.TagSet{"name": name, "id": id}, metadata.Unknown, metadata.None, "")
		Add(&md, "win.proc.mem.working_set_private", v.WorkingSetPrivate, opentsdb.TagSet{"name": name, "id": id}, metadata.Unknown, metadata.None, "")

	}
	return md, nil
}

// Actually a CIM_StatisticalInformation Struct according to Reflection
type Win32_PerfRawData_PerfProc_Process struct {
	ElapsedTime             uint64
	HandleCount             uint32
	IDProcess               uint32
	IOOtherBytesPersec      uint64
	IOOtherOperationsPersec uint64
	IOReadBytesPersec       uint64
	IOReadOperationsPersec  uint64
	IOWriteBytesPersec      uint64
	IOWriteOperationsPersec uint64
	Name                    string
	PageFaultsPersec        uint32
	PageFileBytes           uint64
	PageFileBytesPeak       uint64
	PercentPrivilegedTime   uint64
	PercentProcessorTime    uint64
	PercentUserTime         uint64
	PoolNonpagedBytes       uint32
	PoolPagedBytes          uint32
	PriorityBase            uint32
	PrivateBytes            uint64
	ThreadCount             uint32
	VirtualBytes            uint64
	VirtualBytesPeak        uint64
	WorkingSet              uint64
	WorkingSetPeak          uint64
	WorkingSetPrivate       uint64
}

//Actually a Win32_BaseServce
type Win32_Service struct {
	Name      string
	ProcessId uint32
}

type WorkerProcess struct {
	AppPoolName string
	ProcessId   uint32
}
<commit_msg>cmd/scollector: Add descriptions and fix units/type in processes_windows.go<commit_after>package collectors

import (
	"regexp"
	"strings"

	"github.com/StackExchange/scollector/metadata"
	"github.com/StackExchange/scollector/opentsdb"
	"github.com/StackExchange/wmi"
)

func init() {
	collectors = append(collectors, &IntervalCollector{F: c_windows_processes})
}

// These are silly processes but exist on my machine, will need to update KMB
var processInclusions = regexp.MustCompile("chrome|powershell|scollector|SocketServer")
var serviceInclusions = regexp.MustCompile("WinRM")

func c_windows_processes() (opentsdb.MultiDataPoint, error) {
	var dst []Win32_PerfRawData_PerfProc_Process
	var q = wmi.CreateQuery(&dst, `WHERE Name <> '_Total'`)
	err := queryWmi(q, &dst)
	if err != nil {
		return nil, err
	}

	var svc_dst []Win32_Service
	var svc_q = wmi.CreateQuery(&svc_dst, `WHERE Name <> '_Total'`)
	err = queryWmi(svc_q, &svc_dst)
	if err != nil {
		return nil, err
	}

	var iis_dst []WorkerProcess
	iis_q := wmi.CreateQuery(&iis_dst, "")
	err = queryWmiNamespace(iis_q, &iis_dst, "root\\WebAdministration")
	if err != nil {
		//Don't Return from this error since the name space might exist
		iis_dst = nil
	}

	var md opentsdb.MultiDataPoint
	for _, v := range dst {
		var name string
		service_match := false
		iis_match := false
		process_match := processInclusions.MatchString(v.Name)

		id := "0"

		if process_match {
			raw_name := strings.Split(v.Name, "#")
			name = raw_name[0]
			if len(raw_name) == 2 {
				id = raw_name[1]
			}
			// If you have a hash sign in your process name you don't deserve monitoring ;-)
			if len(raw_name) > 2 {
				continue
			}
		}

		// A Service match could "overwrite" a process match, but that is probably what we would want
		for _, svc := range svc_dst {
			if serviceInclusions.MatchString(svc.Name) {
				// It is possible the pid has gone and been reused, but I think this unlikely
				// And I'm not aware of an atomic join we could do anyways
				if svc.ProcessId == v.IDProcess {
					id = "0"
					service_match = true
					name = svc.Name
					break
				}
			}
		}

		for _, a_pool := range iis_dst {
			if a_pool.ProcessId == v.IDProcess {
				id = "0"
				iis_match = true
				name = strings.Join([]string{"iis", a_pool.AppPoolName}, "_")
				break
			}
		}

		if !(service_match || process_match || iis_match) {
			continue
		}

		Add(&md, "win.proc.elapsed_time", v.ElapsedTime, opentsdb.TagSet{"name": name, "id": id}, metadata.Counter, metadata.Second, "Elapsed time in seconds this process has been running.")
		Add(&md, "win.proc.handle_count", v.HandleCount, opentsdb.TagSet{"name": name, "id": id}, metadata.Gauge, metadata.Count, "Total number of handles the process has open across all threads.")
		Add(&md, "win.proc.io_bytes", v.IOOtherBytesPersec, opentsdb.TagSet{"name": name, "id": id, "type": "other"}, metadata.Counter, metadata.BytesPerSecond, "Rate at which the process is issuing bytes to I/O operations that don not involve data such as control operations.")
		Add(&md, "win.proc.io_operations", v.IOOtherOperationsPersec, opentsdb.TagSet{"name": name, "id": id, "type": "other"}, metadata.Counter, metadata.Operation, "Rate at which the process is issuing I/O operations that are neither a read or a write request.")
		Add(&md, "win.proc.io_bytes", v.IOReadBytesPersec, opentsdb.TagSet{"name": name, "id": id, "type": "read"}, metadata.Counter, metadata.BytesPerSecond, "Rate at which the process is reading bytes from I/O operations.")
		Add(&md, "win.proc.io_operations", v.IOReadOperationsPersec, opentsdb.TagSet{"name": name, "id": id, "type": "read"}, metadata.Counter, metadata.Operation, "Rate at which the process is issuing read I/O operations.")
		Add(&md, "win.proc.io_bytes", v.IOWriteBytesPersec, opentsdb.TagSet{"name": name, "id": id, "type": "write"}, metadata.Counter, metadata.BytesPerSecond, "Rate at which the process is writing bytes to I/O operations.")
		Add(&md, "win.proc.io_operations", v.IOWriteOperationsPersec, opentsdb.TagSet{"name": name, "id": id, "type": "write"}, metadata.Counter, metadata.Operation, "Rate at which the process is issuing write I/O operations.")
		Add(&md, "win.proc.mem.page_faults", v.PageFaultsPersec, opentsdb.TagSet{"name": name, "id": id}, metadata.Gauge, metadata.PerSecond, "Rate of page faults by the threads executing in this process.")
		Add(&md, "win.proc.mem.pagefile_bytes", v.PageFileBytes, opentsdb.TagSet{"name": name, "id": id}, metadata.Gauge, metadata.Bytes, "Current number of bytes this process has used in the paging file(s).")
		Add(&md, "win.proc.mem.pagefile_bytes_peak", v.PageFileBytesPeak, opentsdb.TagSet{"name": name, "id": id}, metadata.Gauge, metadata.Bytes, "Maximum number of bytes this process has used in the paging file(s).")
		Add(&md, "win.proc.cpu", v.PercentPrivilegedTime, opentsdb.TagSet{"name": name, "id": id, "type": "privileged"}, metadata.Counter, metadata.Pct, "Percentage of elapsed time that this thread has spent executing code in privileged mode.")
		Add(&md, "win.proc.cpu_total", v.PercentProcessorTime, opentsdb.TagSet{"name": name, "id": id}, metadata.Counter, metadata.Pct, "Percentage of elapsed time that this process's threads have spent executing code in user or privileged mode.")
		Add(&md, "win.proc.cpu", v.PercentUserTime, opentsdb.TagSet{"name": name, "id": id, "type": "user"}, metadata.Counter, metadata.Pct, "Percentage of elapsed time that this process's threads have spent executing code in user mode.")
		Add(&md, "win.proc.mem.pool_nonpaged_bytes", v.PoolNonpagedBytes, opentsdb.TagSet{"name": name, "id": id}, metadata.Gauge, metadata.Bytes, "Total number of bytes for objects that cannot be written to disk when they are not being used.")
		Add(&md, "win.proc.mem.pool_paged_bytes", v.PoolPagedBytes, opentsdb.TagSet{"name": name, "id": id}, metadata.Gauge, metadata.Bytes, "Total number of bytes for objects that can be written to disk when they are not being used.")
		Add(&md, "win.proc.priority_base", v.PriorityBase, opentsdb.TagSet{"name": name, "id": id}, metadata.Gauge, metadata.None, "Current base priority of this process. Threads within a process can raise and lower their own base priority relative to the process base priority of the process.")
		Add(&md, "win.proc.private_bytes", v.PrivateBytes, opentsdb.TagSet{"name": name, "id": id}, metadata.Gauge, metadata.Bytes, "Current number of bytes this process has allocated that cannot be shared with other processes.")
		Add(&md, "win.proc.thread_count", v.ThreadCount, opentsdb.TagSet{"name": name, "id": id}, metadata.Gauge, metadata.Count, "Number of threads currently active in this process.")
		Add(&md, "win.proc.mem.vm.bytes", v.VirtualBytes, opentsdb.TagSet{"name": name, "id": id}, metadata.Gauge, metadata.Bytes, "Current size, in bytes, of the virtual address space that the process is using.")
		Add(&md, "win.proc.mem.vm.bytes_peak", v.VirtualBytesPeak, opentsdb.TagSet{"name": name, "id": id}, metadata.Gauge, metadata.Bytes, "Maximum number of bytes of virtual address space that the process has used at any one time.")
		Add(&md, "win.proc.mem.working_set", v.WorkingSet, opentsdb.TagSet{"name": name, "id": id}, metadata.Gauge, metadata.Bytes, "Current number of bytes in the working set of this process at any point in time.")
		Add(&md, "win.proc.mem.working_set_peak", v.WorkingSetPeak, opentsdb.TagSet{"name": name, "id": id}, metadata.Gauge, metadata.Bytes, "Maximum number of bytes in the working set of this process at any point in time.")
		Add(&md, "win.proc.mem.working_set_private", v.WorkingSetPrivate, opentsdb.TagSet{"name": name, "id": id}, metadata.Gauge, metadata.Bytes, "Current number of bytes in the working set that are not shared with other processes.")

	}
	return md, nil
}

// Actually a CIM_StatisticalInformation Struct according to Reflection
type Win32_PerfRawData_PerfProc_Process struct {
	ElapsedTime             uint64
	HandleCount             uint32
	IDProcess               uint32
	IOOtherBytesPersec      uint64
	IOOtherOperationsPersec uint64
	IOReadBytesPersec       uint64
	IOReadOperationsPersec  uint64
	IOWriteBytesPersec      uint64
	IOWriteOperationsPersec uint64
	Name                    string
	PageFaultsPersec        uint32
	PageFileBytes           uint64
	PageFileBytesPeak       uint64
	PercentPrivilegedTime   uint64
	PercentProcessorTime    uint64
	PercentUserTime         uint64
	PoolNonpagedBytes       uint32
	PoolPagedBytes          uint32
	PriorityBase            uint32
	PrivateBytes            uint64
	ThreadCount             uint32
	VirtualBytes            uint64
	VirtualBytesPeak        uint64
	WorkingSet              uint64
	WorkingSetPeak          uint64
	WorkingSetPrivate       uint64
}

//Actually a Win32_BaseServce
type Win32_Service struct {
	Name      string
	ProcessId uint32
}

type WorkerProcess struct {
	AppPoolName string
	ProcessId   uint32
}
<|endoftext|>


<commit_before>/* This example show a basic menu similar to that found in the ncurses
 * examples from TLDP */

package main

import gc "code.google.com/p/goncurses"

const (
	HEIGHT = 10
	WIDTH  = 30
)

func main() {
	var active int
	menu := []string{"Choice 1", "Choice 2", "Choice 3", "Choice 4", "Exit"}

	stdscr, _ := gc.Init()
	defer gc.End()

	gc.Raw(true)
	gc.Echo(false)
	gc.Cursor(0)
	stdscr.Clear()
	stdscr.Keypad(true)

	rows, cols := stdscr.Maxyx()
	y, x := (rows-HEIGHT)/2, (cols-WIDTH)/2

	win, _ := gc.NewWindow(HEIGHT, WIDTH, y, x)
	win.Keypad(true)
	stdscr.MovePrint(0, 0,
		"Use arrow keys to go up and down, Press enter to select")
	stdscr.Refresh()

	printmenu(win, menu, active)
	gc.MouseMask(gc.M_B1_CLICKED, nil)

	for {
		ch := stdscr.GetChar()
		switch ch {
		case 'q':
			return
		case gc.KEY_UP:
			if active == 0 {
				active = len(menu) - 1
			} else {
				active -= 1
			}
		case gc.KEY_DOWN:
			if active == len(menu)-1 {
				active = 0
			} else {
				active += 1
			}
		case gc.KEY_MOUSE:
			md, _ := gc.GetMouse()
			new := getactive(x, y, md[0], md[1], menu)
			if new != -1 {
				active = new
			}
			stdscr.MovePrint(23, 0, "Choice #%d: %s selected", active+1,
				menu[active])
			stdscr.ClearToEOL()
			stdscr.Refresh()
		case gc.KEY_RETURN:
			stdscr.MovePrint(23, 0, "Choice #%d: %s selected", active+1,
				menu[active])
			stdscr.ClearToEOL()
			stdscr.Refresh()
		default:
			stdscr.MovePrint(23, 0, "Character pressed = %3d/%c", ch, ch)
			stdscr.ClearToEOL()
			stdscr.Refresh()
		}

		printmenu(win, menu, active)
	}
}

func getactive(x, y, mx, my int, menu []string) int {
	row := my - y - 2
	col := mx - x - 2

	if row < 0 || row > len(menu)-1 {
		return -1
	}

	l := menu[row]

	if col >= 0 && col < len(l) {
		return row
	}
	return -1
}

func printmenu(w gc.Window, menu []string, active int) {
	y, x := 2, 2
	w.Box(0, 0)
	for i, s := range menu {
		if i == active {
			w.AttrOn(gc.A_REVERSE)
			w.MovePrint(y+i, x, s)
			w.AttrOff(gc.A_REVERSE)
		} else {
			w.MovePrint(y+i, x, s)
		}
	}
	w.Refresh()
}
<commit_msg>Fix bug in mouse example and other improvements<commit_after>/* This example show a basic menu similar to that found in the ncurses
 * examples from TLDP */

package main

import gc "code.google.com/p/goncurses"

const (
	HEIGHT = 10
	WIDTH  = 30
)

func main() {
	var active int
	menu := []string{"Choice 1", "Choice 2", "Choice 3", "Choice 4", "Exit"}

	stdscr, _ := gc.Init()
	defer gc.End()

	gc.Raw(true)
	gc.Echo(false)
	gc.Cursor(0)
	stdscr.Clear()
	stdscr.Keypad(true)

	rows, cols := stdscr.Maxyx()
	y, x := (rows-HEIGHT)/2, (cols-WIDTH)/2

	win, _ := gc.NewWindow(HEIGHT, WIDTH, y, x)
	win.Keypad(true)
	stdscr.MovePrint(0, 0,
		"Use arrow keys to go up and down, Press enter to select")
	stdscr.Refresh()

	printmenu(win, menu, active)
	if gc.Mouse() {
		stdscr.MovePrint(3, 0, "WARN: Mouse support not detected.")
	}
	// If, for example, you are temporarily disabling the mouse or are
	// otherwise altering mouse button detection temporarily, you could
	// pass a pointer to a MouseButton object as the 2nd argument to
	// record that information. Invocation may look something like:
	// var old gc.MouseButton
	// gc.MouseMask(gc.M_ALL, &old) /* temporarily enable all mouse clicks */
	// gc.MouseMask(old, nil)		/* change it back */
	gc.MouseMask(gc.M_B1_PRESSED, nil)

	for {
		ch := stdscr.GetChar()
		switch ch {
		case 'q':
			return
		case gc.KEY_UP:
			if active == 0 {
				active = len(menu) - 1
			} else {
				active -= 1
			}
		case gc.KEY_DOWN:
			if active == len(menu)-1 {
				active = 0
			} else {
				active += 1
			}
		case gc.KEY_MOUSE:
			md, err := gc.GetMouse()
			if err != nil {
				stdscr.MovePrint(20, 0, "%s", err)
			}
			new := getactive(x, y, md[0], md[1], menu)
			if new != -1 {
				active = new
			}
			stdscr.MovePrint(23, 0, "Choice #%d: %s selected", active+1,
				menu[active])
			stdscr.ClearToEOL()
			stdscr.Refresh()
		case gc.KEY_RETURN:
			stdscr.MovePrint(23, 0, "Choice #%d: %s selected", active+1,
				menu[active])
			stdscr.ClearToEOL()
			stdscr.Refresh()
		default:
			stdscr.MovePrint(23, 0, "Character pressed = %3d/%c", ch, ch)
			stdscr.ClearToEOL()
			stdscr.Refresh()
		}

		printmenu(win, menu, active)
	}
}

func getactive(x, y, mx, my int, menu []string) int {
	row := my - y - 2
	col := mx - x - 2

	if row < 0 || row > len(menu)-1 {
		return -1
	}

	l := menu[row]

	if col >= 0 && col < len(l) {
		return row
	}
	return -1
}

func printmenu(w gc.Window, menu []string, active int) {
	y, x := 2, 2
	w.Box(0, 0)
	for i, s := range menu {
		if i == active {
			w.AttrOn(gc.A_REVERSE)
			w.MovePrint(y+i, x, s)
			w.AttrOff(gc.A_REVERSE)
		} else {
			w.MovePrint(y+i, x, s)
		}
	}
	w.Refresh()
}
<|endoftext|>