<commit_before>package storage

import (
	"os"
	"testing"

	"config"
	pb "datamodel/protobuf"

	"github.com/golang/protobuf/proto"

	"utils"
)

func createDom(id string) *pb.Domain {
	dom := new(pb.Domain)
	dom.Name = utils.Stringp(id)
	types := []pb.SketchType{pb.SketchType_MEMB, pb.SketchType_FREQ, pb.SketchType_RANK, pb.SketchType_CARD}
	for _, ty := range types {
		sketch := &pb.Sketch{}
		sketch.Name = dom.Name
		sketch.Type = &ty
		sketch.Properties = &pb.SketchProperties{
			Size:           utils.Int64p(100),
			MaxUniqueItems: utils.Int64p(10),
		}
		dom.Sketches = append(dom.Sketches, sketch)
	}
	return dom
}

func createSketch(id string, typ pb.SketchType) *pb.Sketch {
	sketch := &pb.Sketch{}
	sketch.Name = utils.Stringp(id)
	sketch.Type = &typ
	sketch.Properties = &pb.SketchProperties{
		Size:           utils.Int64p(100),
		MaxUniqueItems: utils.Int64p(10),
	}
	return sketch
}

func TestCreateDeleteDom(t *testing.T) {
	config.Reset()
	utils.SetupTests()
	defer utils.TearDownTests()

	_ = os.Remove("test.log")

	aof := NewAOF("test.log")

	dom := createDom("test1")
	err := aof.AppendDomOp(CreateDom, dom)
	if err != nil {
		t.Error("Expected no error, got", err)
	}

	dom = createDom("test2")
	err = aof.AppendDomOp(CreateDom, dom)
	if err != nil {
		t.Error("Expected no error, got", err)
	}

	// Create new AOF
	aof = NewAOF("test.log")
	for {
		e, err2 := aof.Read()
		if err2 != nil {
			if err2.Error() != "EOF" {
				t.Error("Expected no error, got", err2)
			}
			break
		}
		dom := &pb.Domain{}
		err = proto.Unmarshal(e.args, dom)
		if err != nil {
			t.Error("Expected no error, got", err)
		}
	}

	dom = createDom("test3")

	if err = aof.AppendDomOp(CreateDom, dom); err != nil {
		t.Error("Expected no error, got", err)
	}

	dom = new(pb.Domain)
	dom.Name = utils.Stringp("test1")

	if err = aof.AppendDomOp(DeleteDom, dom); err != nil {
		t.Error("Expected no error, got", err)
	}

	aof = NewAOF("test.log")
	for {
		e, err := aof.Read()
		if err != nil {
			if err.Error() != "EOF" {
				t.Error("Expected no error, got", err)
			}
			break
		}
		dom := &pb.Domain{}
		err = proto.Unmarshal(e.args, dom)
		if err != nil {
			t.Error("Expected no error, got", err)
		}
	}
}

func TestCreateDeleteSketch(t *testing.T) {
	config.Reset()
	utils.SetupTests()
	defer utils.TearDownTests()

	_ = os.Remove("test.log")

	aof := NewAOF("test.log")

	sketch := createSketch("skz1", pb.SketchType_CARD)
	err := aof.AppendDomOp(CreateDom, sketch)
	if err != nil {
		t.Error("Expected no error, got", err)
	}

	sketch = createSketch("skz2", pb.SketchType_FREQ)
	err = aof.AppendDomOp(CreateDom, sketch)
	if err != nil {
		t.Error("Expected no error, got", err)
	}

	// Create new AOF
	aof = NewAOF("test.log")
	if err != nil {
		t.Error("Expected no error, got", err)
	}

	for {
		e, err2 := aof.Read()
		if err2 != nil {
			if err2.Error() != "EOF" {
				t.Error("Expected no error, got", err2)
			}
			break
		}
		sketch := &pb.Sketch{}
		err = proto.Unmarshal(e.args, sketch)
		if err != nil {
			t.Error("Expected no error, got", err)
		}
	}

	sketch = createSketch("skz3", pb.SketchType_RANK)
	err = aof.AppendDomOp(CreateDom, sketch)
	if err != nil {
		t.Error("Expected no error, got", err)
	}

	sketch = createSketch("skz1", pb.SketchType_RANK)
	if err = aof.AppendDomOp(DeleteDom, sketch); err != nil {
		t.Error("Expected no error, got", err)
	}

	addReq := &pb.AddRequest{
		Sketch: sketch,
		Values: []string{"foo", "bar", "hello", "world"},
	}
	if err = aof.AppendAddOp(addReq); err != nil {
		t.Error("Expected no error, got", err)
	}

	aof = NewAOF("test.log")
	for {
		e, err := aof.Read()
		if err != nil {
			if err.Error() != "EOF" {
				t.Error("Expected no error, got", err)
			}
			break
		}
		if e.op == Add {
			req := &pb.AddRequest{}
			err = proto.Unmarshal(e.args, req)
		} else {
			sketch := &pb.Sketch{}
			err = proto.Unmarshal(e.args, sketch)
		}
		if err != nil {
			t.Error("Expected no error, got", err)
		}
	}
}
<commit_msg>use config DataDir for aof unit tests<commit_after>package storage

import (
	"os"
	"path/filepath"
	"testing"

	"config"
	pb "datamodel/protobuf"

	"github.com/golang/protobuf/proto"

	"utils"
)

func createDom(id string) *pb.Domain {
	dom := new(pb.Domain)
	dom.Name = utils.Stringp(id)
	types := []pb.SketchType{pb.SketchType_MEMB, pb.SketchType_FREQ, pb.SketchType_RANK, pb.SketchType_CARD}
	for _, ty := range types {
		sketch := &pb.Sketch{}
		sketch.Name = dom.Name
		sketch.Type = &ty
		sketch.Properties = &pb.SketchProperties{
			Size:           utils.Int64p(100),
			MaxUniqueItems: utils.Int64p(10),
		}
		dom.Sketches = append(dom.Sketches, sketch)
	}
	return dom
}

func createSketch(id string, typ pb.SketchType) *pb.Sketch {
	sketch := &pb.Sketch{}
	sketch.Name = utils.Stringp(id)
	sketch.Type = &typ
	sketch.Properties = &pb.SketchProperties{
		Size:           utils.Int64p(100),
		MaxUniqueItems: utils.Int64p(10),
	}
	return sketch
}

func TestCreateDeleteDom(t *testing.T) {
	config.Reset()
	utils.SetupTests()
	defer utils.TearDownTests()

	path := filepath.Join(config.GetConfig().DataDir, "skizze.aof")
	aof := NewAOF(path)

	dom := createDom("test1")
	err := aof.AppendDomOp(CreateDom, dom)
	if err != nil {
		t.Error("Expected no error, got", err)
	}

	dom = createDom("test2")
	err = aof.AppendDomOp(CreateDom, dom)
	if err != nil {
		t.Error("Expected no error, got", err)
	}

	// Create new AOF
	aof = NewAOF(path)
	for {
		e, err2 := aof.Read()
		if err2 != nil {
			if err2.Error() != "EOF" {
				t.Error("Expected no error, got", err2)
			}
			break
		}
		dom := &pb.Domain{}
		err = proto.Unmarshal(e.args, dom)
		if err != nil {
			t.Error("Expected no error, got", err)
		}
	}

	dom = createDom("test3")

	if err = aof.AppendDomOp(CreateDom, dom); err != nil {
		t.Error("Expected no error, got", err)
	}

	dom = new(pb.Domain)
	dom.Name = utils.Stringp("test1")

	if err = aof.AppendDomOp(DeleteDom, dom); err != nil {
		t.Error("Expected no error, got", err)
	}

	aof = NewAOF(path)
	for {
		e, err := aof.Read()
		if err != nil {
			if err.Error() != "EOF" {
				t.Error("Expected no error, got", err)
			}
			break
		}
		dom := &pb.Domain{}
		err = proto.Unmarshal(e.args, dom)
		if err != nil {
			t.Error("Expected no error, got", err)
		}
	}
}

func TestCreateDeleteSketch(t *testing.T) {
	config.Reset()
	utils.SetupTests()
	defer utils.TearDownTests()

	_ = os.Remove("test.log")

	aof := NewAOF("test.log")

	sketch := createSketch("skz1", pb.SketchType_CARD)
	err := aof.AppendDomOp(CreateDom, sketch)
	if err != nil {
		t.Error("Expected no error, got", err)
	}

	sketch = createSketch("skz2", pb.SketchType_FREQ)
	err = aof.AppendDomOp(CreateDom, sketch)
	if err != nil {
		t.Error("Expected no error, got", err)
	}

	// Create new AOF
	aof = NewAOF("test.log")
	if err != nil {
		t.Error("Expected no error, got", err)
	}

	for {
		e, err2 := aof.Read()
		if err2 != nil {
			if err2.Error() != "EOF" {
				t.Error("Expected no error, got", err2)
			}
			break
		}
		sketch := &pb.Sketch{}
		err = proto.Unmarshal(e.args, sketch)
		if err != nil {
			t.Error("Expected no error, got", err)
		}
	}

	sketch = createSketch("skz3", pb.SketchType_RANK)
	err = aof.AppendDomOp(CreateDom, sketch)
	if err != nil {
		t.Error("Expected no error, got", err)
	}

	sketch = createSketch("skz1", pb.SketchType_RANK)
	if err = aof.AppendDomOp(DeleteDom, sketch); err != nil {
		t.Error("Expected no error, got", err)
	}

	addReq := &pb.AddRequest{
		Sketch: sketch,
		Values: []string{"foo", "bar", "hello", "world"},
	}
	if err = aof.AppendAddOp(addReq); err != nil {
		t.Error("Expected no error, got", err)
	}

	aof = NewAOF("test.log")
	for {
		e, err := aof.Read()
		if err != nil {
			if err.Error() != "EOF" {
				t.Error("Expected no error, got", err)
			}
			break
		}
		if e.op == Add {
			req := &pb.AddRequest{}
			err = proto.Unmarshal(e.args, req)
		} else {
			sketch := &pb.Sketch{}
			err = proto.Unmarshal(e.args, sketch)
		}
		if err != nil {
			t.Error("Expected no error, got", err)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"math"
	"io/ioutil"
	"encoding/binary"
	"github.com/anthonynsimon/bild/imgio"
	"github.com/anthonynsimon/bild/transform"
	"github.com/songtianyi/go-mxnet-predictor"
)

func main() {
	mb, err := ioutil.ReadFile("mean.matrix")
	if err != nil {
		panic(err)
	}
	rgb3c := make([]float32, len(mb)/4)
	for i := 0;i < len(mb)/4;i++ {
		bits := binary.LittleEndian.Uint32(mb[i*4:(i+1)*4])
		rgb3c[i] = math.Float32frombits(bits)
	}
	//fmt.Println(rgb3c[0: 100])

	filePath := "flowertest.jpg"
	img, err := imgio.Open(filePath)
	if err != nil {
		panic(err)
	}

	resized := transform.Resize(img, 299, 299, transform.Linear)
	//fmt.Println(resized)
	_, err = mxnet.CvtImageTo1DArray(resized, rgb3c)
	if err != nil {
		panic(err)
	}
	fmt.Println()
	//fmt.Println(res)

	symbol, err := ioutil.ReadFile("./102flowers-symbol.json")
	if err != nil {
		panic(err)
	}
	params, err := ioutil.ReadFile("./102flowers-0260.params")
	if err != nil {
		panic(err)
	}

	p, err := mxnet.CreatePredictor(symbol, params, mxnet.Device{mxnet.CPU_DEVICE, 0}, []mxnet.InputNode{{Key: "data", Shape: []uint32{1, 3, 299, 299}}})
	if err != nil {
		panic(err)
	}
	//if err := p.SetInput("data", res); err != nil {
	//	panic(err)
	//}
	fmt.Println(p)
}
<commit_msg>change example file path<commit_after>package main

import (
	"fmt"
	"math"
	"io/ioutil"
	"encoding/binary"
	"github.com/anthonynsimon/bild/imgio"
	"github.com/anthonynsimon/bild/transform"
	"github.com/songtianyi/go-mxnet-predictor"
)

func main() {
	mb, err := ioutil.ReadFile("mean.matrix")
	if err != nil {
		panic(err)
	}
	rgb3c := make([]float32, len(mb)/4)
	for i := 0;i < len(mb)/4;i++ {
		bits := binary.LittleEndian.Uint32(mb[i*4:(i+1)*4])
		rgb3c[i] = math.Float32frombits(bits)
	}
	//fmt.Println(rgb3c[0: 100])

	filePath := "flowertest.jpg"
	img, err := imgio.Open(filePath)
	if err != nil {
		panic(err)
	}

	resized := transform.Resize(img, 299, 299, transform.Linear)
	//fmt.Println(resized)
	_, err = mxnet.CvtImageTo1DArray(resized, rgb3c)
	if err != nil {
		panic(err)
	}
	fmt.Println()
	//fmt.Println(res)

	symbol, err := ioutil.ReadFile("/data/102flowers-symbol.json")
	if err != nil {
		panic(err)
	}
	params, err := ioutil.ReadFile("/data/102flowers-0260.params")
	if err != nil {
		panic(err)
	}

	p, err := mxnet.CreatePredictor(symbol, params, mxnet.Device{mxnet.CPU_DEVICE, 0}, []mxnet.InputNode{{Key: "data", Shape: []uint32{1, 3, 299, 299}}})
	if err != nil {
		panic(err)
	}
	//if err := p.SetInput("data", res); err != nil {
	//	panic(err)
	//}
	fmt.Println(p)
}
<|endoftext|>


<commit_before>/*
Copyright 2021 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cel

import (
	"fmt"
	"strings"
	"sync"
	"time"

	"github.com/google/cel-go/cel"
	"github.com/google/cel-go/checker"
	apiextensions "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
	"k8s.io/apiextensions-apiserver/pkg/apiserver/schema"
	"k8s.io/apiextensions-apiserver/pkg/apiserver/schema/cel/library"
	"k8s.io/apiextensions-apiserver/pkg/apiserver/schema/cel/metrics"
	celmodel "k8s.io/apiextensions-apiserver/third_party/forked/celopenapi/model"
)

const (
	// ScopedVarName is the variable name assigned to the locally scoped data element of a CEL validation
	// expression.
	ScopedVarName = "self"

	// OldScopedVarName is the variable name assigned to the existing value of the locally scoped data element of a
	// CEL validation expression.
	OldScopedVarName = "oldSelf"

	// PerCallLimit specify the actual cost limit per CEL validation call
	// current PerCallLimit gives roughly 0.1 second for each expression validation call
	PerCallLimit = 1000000

	// RuntimeCELCostBudget is the overall cost budget for runtime CEL validation cost per CustomResource
	// current RuntimeCELCostBudget gives roughly 1 seconds for CR validation
	RuntimeCELCostBudget = 10000000

	// checkFrequency configures the number of iterations within a comprehension to evaluate
	// before checking whether the function evaluation has been interrupted
	checkFrequency = 100
)

// CompilationResult represents the cel compilation result for one rule
type CompilationResult struct {
	Program cel.Program
	Error   *Error
	// If true, the compiled expression contains a reference to the identifier "oldSelf", and its corresponding rule
	// is implicitly a transition rule.
	TransitionRule bool
	// Represents the worst-case cost of the compiled expression in terms of CEL's cost units, as used by cel.EstimateCost.
	MaxCost uint64
	// MaxCardinality represents the worse case number of times this validation rule could be invoked if contained under an
	// unbounded map or list in an OpenAPIv3 schema.
	MaxCardinality uint64
}

var (
	initEnvOnce sync.Once
	initEnv     *cel.Env
	initEnvErr  error
)

func getBaseEnv() (*cel.Env, error) {
	initEnvOnce.Do(func() {
		var opts []cel.EnvOption
		opts = append(opts, cel.HomogeneousAggregateLiterals())
		// Validate function declarations once during base env initialization,
		// so they don't need to be evaluated each time a CEL rule is compiled.
		// This is a relatively expensive operation.
		opts = append(opts, cel.EagerlyValidateDeclarations(true))
		opts = append(opts, library.ExtensionLibs...)

		initEnv, initEnvErr = cel.NewEnv(opts...)
	})
	return initEnv, initEnvErr
}

// Compile compiles all the XValidations rules (without recursing into the schema) and returns a slice containing a
// CompilationResult for each ValidationRule, or an error.
// Each CompilationResult may contain:
/// - non-nil Program, nil Error: The program was compiled successfully
//  - nil Program, non-nil Error: Compilation resulted in an error
//  - nil Program, nil Error: The provided rule was empty so compilation was not attempted
// perCallLimit was added for testing purpose only. Callers should always use const PerCallLimit as input.
func Compile(s *schema.Structural, isResourceRoot bool, perCallLimit uint64) ([]CompilationResult, error) {
	t := time.Now()
	defer metrics.Metrics.ObserveCompilation(time.Since(t))

	if len(s.Extensions.XValidations) == 0 {
		return nil, nil
	}
	celRules := s.Extensions.XValidations

	var propDecls []cel.EnvOption
	var root *celmodel.DeclType
	var ok bool
	baseEnv, err := getBaseEnv()
	if err != nil {
		return nil, err
	}
	reg := celmodel.NewRegistry(baseEnv)
	scopedTypeName := generateUniqueSelfTypeName()
	rt, err := celmodel.NewRuleTypes(scopedTypeName, s, isResourceRoot, reg)
	if err != nil {
		return nil, err
	}
	if rt == nil {
		return nil, nil
	}
	opts, err := rt.EnvOptions(baseEnv.TypeProvider())
	if err != nil {
		return nil, err
	}
	root, ok = rt.FindDeclType(scopedTypeName)
	if !ok {
		rootDecl := celmodel.SchemaDeclType(s, isResourceRoot)
		if rootDecl == nil {
			return nil, fmt.Errorf("rule declared on schema that does not support validation rules type: '%s' x-kubernetes-preserve-unknown-fields: '%t'", s.Type, s.XPreserveUnknownFields)
		}
		root = rootDecl.MaybeAssignTypeName(scopedTypeName)
	}
	propDecls = append(propDecls, cel.Variable(ScopedVarName, root.CelType()))
	propDecls = append(propDecls, cel.Variable(OldScopedVarName, root.CelType()))
	opts = append(opts, propDecls...)
	env, err := baseEnv.Extend(opts...)
	if err != nil {
		return nil, err
	}
	estimator := newCostEstimator(root)
	// compResults is the return value which saves a list of compilation results in the same order as x-kubernetes-validations rules.
	compResults := make([]CompilationResult, len(celRules))
	maxCardinality := celmodel.MaxCardinality(s)
	for i, rule := range celRules {
		compResults[i] = compileRule(rule, env, perCallLimit, estimator, maxCardinality)
	}

	return compResults, nil
}

func compileRule(rule apiextensions.ValidationRule, env *cel.Env, perCallLimit uint64, estimator *library.CostEstimator, maxCardinality uint64) (compilationResult CompilationResult) {
	if len(strings.TrimSpace(rule.Rule)) == 0 {
		// include a compilation result, but leave both program and error nil per documented return semantics of this
		// function
		return
	}
	ast, issues := env.Compile(rule.Rule)
	if issues != nil {
		compilationResult.Error = &Error{ErrorTypeInvalid, "compilation failed: " + issues.String()}
		return
	}
	if ast.OutputType() != cel.BoolType {
		compilationResult.Error = &Error{ErrorTypeInvalid, "cel expression must evaluate to a bool"}
		return
	}

	checkedExpr, err := cel.AstToCheckedExpr(ast)
	if err != nil {
		// should be impossible since env.Compile returned no issues
		compilationResult.Error = &Error{ErrorTypeInternal, "unexpected compilation error: " + err.Error()}
		return
	}
	for _, ref := range checkedExpr.ReferenceMap {
		if ref.Name == OldScopedVarName {
			compilationResult.TransitionRule = true
			break
		}
	}

	// TODO: Ideally we could configure the per expression limit at validation time and set it to the remaining overall budget, but we would either need a way to pass in a limit at evaluation time or move program creation to validation time
	prog, err := env.Program(ast,
		cel.EvalOptions(cel.OptOptimize, cel.OptTrackCost),
		cel.CostLimit(perCallLimit),
		cel.CostTracking(estimator),
		cel.OptimizeRegex(library.ExtensionLibRegexOptimizations...),
		cel.InterruptCheckFrequency(checkFrequency),
	)
	if err != nil {
		compilationResult.Error = &Error{ErrorTypeInvalid, "program instantiation failed: " + err.Error()}
		return
	}
	costEst, err := env.EstimateCost(ast, estimator)
	if err != nil {
		compilationResult.Error = &Error{ErrorTypeInternal, "cost estimation failed: " + err.Error()}
		return
	}
	compilationResult.MaxCost = costEst.Max
	compilationResult.MaxCardinality = maxCardinality
	compilationResult.Program = prog
	return
}

// generateUniqueSelfTypeName creates a placeholder type name to use in a CEL programs for cases
// where we do not wish to expose a stable type name to CEL validator rule authors. For this to effectively prevent
// developers from depending on the generated name (i.e. using it in CEL programs), it must be changed each time a
// CRD is created or updated.
func generateUniqueSelfTypeName() string {
	return fmt.Sprintf("selfType%d", time.Now().Nanosecond())
}

func newCostEstimator(root *celmodel.DeclType) *library.CostEstimator {
	return &library.CostEstimator{SizeEstimator: &sizeEstimator{root: root}}
}

type sizeEstimator struct {
	root *celmodel.DeclType
}

func (c *sizeEstimator) EstimateSize(element checker.AstNode) *checker.SizeEstimate {
	if len(element.Path()) == 0 {
		// Path() can return an empty list, early exit if it does since we can't
		// provide size estimates when that happens
		return nil
	}
	currentNode := c.root
	// cut off "self" from path, since we always start there
	for _, name := range element.Path()[1:] {
		switch name {
		case "@items", "@values":
			if currentNode.ElemType == nil {
				return nil
			}
			currentNode = currentNode.ElemType
		case "@keys":
			if currentNode.KeyType == nil {
				return nil
			}
			currentNode = currentNode.KeyType
		default:
			field, ok := currentNode.Fields[name]
			if !ok {
				return nil
			}
			if field.Type == nil {
				return nil
			}
			currentNode = field.Type
		}
	}
	return &checker.SizeEstimate{Min: 0, Max: uint64(currentNode.MaxElements)}
}

func (c *sizeEstimator) EstimateCallCost(function, overloadID string, target *checker.AstNode, args []checker.AstNode) *checker.CallEstimate {
	return nil
}
<commit_msg>Turn on DefaultUTCTimeZone for cel-go.<commit_after>/*
Copyright 2021 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cel

import (
	"fmt"
	"strings"
	"sync"
	"time"

	"github.com/google/cel-go/cel"
	"github.com/google/cel-go/checker"
	apiextensions "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
	"k8s.io/apiextensions-apiserver/pkg/apiserver/schema"
	"k8s.io/apiextensions-apiserver/pkg/apiserver/schema/cel/library"
	"k8s.io/apiextensions-apiserver/pkg/apiserver/schema/cel/metrics"
	celmodel "k8s.io/apiextensions-apiserver/third_party/forked/celopenapi/model"
)

const (
	// ScopedVarName is the variable name assigned to the locally scoped data element of a CEL validation
	// expression.
	ScopedVarName = "self"

	// OldScopedVarName is the variable name assigned to the existing value of the locally scoped data element of a
	// CEL validation expression.
	OldScopedVarName = "oldSelf"

	// PerCallLimit specify the actual cost limit per CEL validation call
	// current PerCallLimit gives roughly 0.1 second for each expression validation call
	PerCallLimit = 1000000

	// RuntimeCELCostBudget is the overall cost budget for runtime CEL validation cost per CustomResource
	// current RuntimeCELCostBudget gives roughly 1 seconds for CR validation
	RuntimeCELCostBudget = 10000000

	// checkFrequency configures the number of iterations within a comprehension to evaluate
	// before checking whether the function evaluation has been interrupted
	checkFrequency = 100
)

// CompilationResult represents the cel compilation result for one rule
type CompilationResult struct {
	Program cel.Program
	Error   *Error
	// If true, the compiled expression contains a reference to the identifier "oldSelf", and its corresponding rule
	// is implicitly a transition rule.
	TransitionRule bool
	// Represents the worst-case cost of the compiled expression in terms of CEL's cost units, as used by cel.EstimateCost.
	MaxCost uint64
	// MaxCardinality represents the worse case number of times this validation rule could be invoked if contained under an
	// unbounded map or list in an OpenAPIv3 schema.
	MaxCardinality uint64
}

var (
	initEnvOnce sync.Once
	initEnv     *cel.Env
	initEnvErr  error
)

func getBaseEnv() (*cel.Env, error) {
	initEnvOnce.Do(func() {
		var opts []cel.EnvOption
		opts = append(opts, cel.HomogeneousAggregateLiterals())
		// Validate function declarations once during base env initialization,
		// so they don't need to be evaluated each time a CEL rule is compiled.
		// This is a relatively expensive operation.
		opts = append(opts, cel.EagerlyValidateDeclarations(true), cel.DefaultUTCTimeZone(true))
		opts = append(opts, library.ExtensionLibs...)

		initEnv, initEnvErr = cel.NewEnv(opts...)
	})
	return initEnv, initEnvErr
}

// Compile compiles all the XValidations rules (without recursing into the schema) and returns a slice containing a
// CompilationResult for each ValidationRule, or an error.
// Each CompilationResult may contain:
/// - non-nil Program, nil Error: The program was compiled successfully
//  - nil Program, non-nil Error: Compilation resulted in an error
//  - nil Program, nil Error: The provided rule was empty so compilation was not attempted
// perCallLimit was added for testing purpose only. Callers should always use const PerCallLimit as input.
func Compile(s *schema.Structural, isResourceRoot bool, perCallLimit uint64) ([]CompilationResult, error) {
	t := time.Now()
	defer metrics.Metrics.ObserveCompilation(time.Since(t))

	if len(s.Extensions.XValidations) == 0 {
		return nil, nil
	}
	celRules := s.Extensions.XValidations

	var propDecls []cel.EnvOption
	var root *celmodel.DeclType
	var ok bool
	baseEnv, err := getBaseEnv()
	if err != nil {
		return nil, err
	}
	reg := celmodel.NewRegistry(baseEnv)
	scopedTypeName := generateUniqueSelfTypeName()
	rt, err := celmodel.NewRuleTypes(scopedTypeName, s, isResourceRoot, reg)
	if err != nil {
		return nil, err
	}
	if rt == nil {
		return nil, nil
	}
	opts, err := rt.EnvOptions(baseEnv.TypeProvider())
	if err != nil {
		return nil, err
	}
	root, ok = rt.FindDeclType(scopedTypeName)
	if !ok {
		rootDecl := celmodel.SchemaDeclType(s, isResourceRoot)
		if rootDecl == nil {
			return nil, fmt.Errorf("rule declared on schema that does not support validation rules type: '%s' x-kubernetes-preserve-unknown-fields: '%t'", s.Type, s.XPreserveUnknownFields)
		}
		root = rootDecl.MaybeAssignTypeName(scopedTypeName)
	}
	propDecls = append(propDecls, cel.Variable(ScopedVarName, root.CelType()))
	propDecls = append(propDecls, cel.Variable(OldScopedVarName, root.CelType()))
	opts = append(opts, propDecls...)
	env, err := baseEnv.Extend(opts...)
	if err != nil {
		return nil, err
	}
	estimator := newCostEstimator(root)
	// compResults is the return value which saves a list of compilation results in the same order as x-kubernetes-validations rules.
	compResults := make([]CompilationResult, len(celRules))
	maxCardinality := celmodel.MaxCardinality(s)
	for i, rule := range celRules {
		compResults[i] = compileRule(rule, env, perCallLimit, estimator, maxCardinality)
	}

	return compResults, nil
}

func compileRule(rule apiextensions.ValidationRule, env *cel.Env, perCallLimit uint64, estimator *library.CostEstimator, maxCardinality uint64) (compilationResult CompilationResult) {
	if len(strings.TrimSpace(rule.Rule)) == 0 {
		// include a compilation result, but leave both program and error nil per documented return semantics of this
		// function
		return
	}
	ast, issues := env.Compile(rule.Rule)
	if issues != nil {
		compilationResult.Error = &Error{ErrorTypeInvalid, "compilation failed: " + issues.String()}
		return
	}
	if ast.OutputType() != cel.BoolType {
		compilationResult.Error = &Error{ErrorTypeInvalid, "cel expression must evaluate to a bool"}
		return
	}

	checkedExpr, err := cel.AstToCheckedExpr(ast)
	if err != nil {
		// should be impossible since env.Compile returned no issues
		compilationResult.Error = &Error{ErrorTypeInternal, "unexpected compilation error: " + err.Error()}
		return
	}
	for _, ref := range checkedExpr.ReferenceMap {
		if ref.Name == OldScopedVarName {
			compilationResult.TransitionRule = true
			break
		}
	}

	// TODO: Ideally we could configure the per expression limit at validation time and set it to the remaining overall budget, but we would either need a way to pass in a limit at evaluation time or move program creation to validation time
	prog, err := env.Program(ast,
		cel.EvalOptions(cel.OptOptimize, cel.OptTrackCost),
		cel.CostLimit(perCallLimit),
		cel.CostTracking(estimator),
		cel.OptimizeRegex(library.ExtensionLibRegexOptimizations...),
		cel.InterruptCheckFrequency(checkFrequency),
	)
	if err != nil {
		compilationResult.Error = &Error{ErrorTypeInvalid, "program instantiation failed: " + err.Error()}
		return
	}
	costEst, err := env.EstimateCost(ast, estimator)
	if err != nil {
		compilationResult.Error = &Error{ErrorTypeInternal, "cost estimation failed: " + err.Error()}
		return
	}
	compilationResult.MaxCost = costEst.Max
	compilationResult.MaxCardinality = maxCardinality
	compilationResult.Program = prog
	return
}

// generateUniqueSelfTypeName creates a placeholder type name to use in a CEL programs for cases
// where we do not wish to expose a stable type name to CEL validator rule authors. For this to effectively prevent
// developers from depending on the generated name (i.e. using it in CEL programs), it must be changed each time a
// CRD is created or updated.
func generateUniqueSelfTypeName() string {
	return fmt.Sprintf("selfType%d", time.Now().Nanosecond())
}

func newCostEstimator(root *celmodel.DeclType) *library.CostEstimator {
	return &library.CostEstimator{SizeEstimator: &sizeEstimator{root: root}}
}

type sizeEstimator struct {
	root *celmodel.DeclType
}

func (c *sizeEstimator) EstimateSize(element checker.AstNode) *checker.SizeEstimate {
	if len(element.Path()) == 0 {
		// Path() can return an empty list, early exit if it does since we can't
		// provide size estimates when that happens
		return nil
	}
	currentNode := c.root
	// cut off "self" from path, since we always start there
	for _, name := range element.Path()[1:] {
		switch name {
		case "@items", "@values":
			if currentNode.ElemType == nil {
				return nil
			}
			currentNode = currentNode.ElemType
		case "@keys":
			if currentNode.KeyType == nil {
				return nil
			}
			currentNode = currentNode.KeyType
		default:
			field, ok := currentNode.Fields[name]
			if !ok {
				return nil
			}
			if field.Type == nil {
				return nil
			}
			currentNode = field.Type
		}
	}
	return &checker.SizeEstimate{Min: 0, Max: uint64(currentNode.MaxElements)}
}

func (c *sizeEstimator) EstimateCallCost(function, overloadID string, target *checker.AstNode, args []checker.AstNode) *checker.CallEstimate {
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package nodeidentifier

import (
	"testing"

	"k8s.io/apiserver/pkg/authentication/user"
)

func TestDefaultNodeIdentifier_NodeIdentity(t *testing.T) {
	tests := []struct {
		name           string
		user           user.Info
		expectNodeName string
		expectIsNode   bool
	}{
		{
			name:           "nil user",
			user:           nil,
			expectNodeName: "",
			expectIsNode:   false,
		},
		{
			name:           "node username without group",
			user:           &user.DefaultInfo{Name: "system:node:foo"},
			expectNodeName: "",
			expectIsNode:   false,
		},
		{
			name:           "node group without username",
			user:           &user.DefaultInfo{Name: "foo", Groups: []string{"system:nodes"}},
			expectNodeName: "",
			expectIsNode:   false,
		},
		{
			name:           "node group and username",
			user:           &user.DefaultInfo{Name: "system:node:foo", Groups: []string{"system:nodes"}},
			expectNodeName: "foo",
			expectIsNode:   true,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			nodeName, isNode := NewDefaultNodeIdentifier().NodeIdentity(tt.user)
			if nodeName != tt.expectNodeName {
				t.Errorf("DefaultNodeIdentifier.NodeIdentity() got = %v, want %v", nodeName, tt.expectNodeName)
			}
			if isNode != tt.expectIsNode {
				t.Errorf("DefaultNodeIdentifier.NodeIdentity() got1 = %v, want %v", isNode, tt.expectIsNode)
			}
		})
	}
}
<commit_msg>[pkg/auth/nodeidentifier/default_test.go]: fix testing error message typo<commit_after>/*
Copyright 2017 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package nodeidentifier

import (
	"testing"

	"k8s.io/apiserver/pkg/authentication/user"
)

func TestDefaultNodeIdentifier_NodeIdentity(t *testing.T) {
	tests := []struct {
		name           string
		user           user.Info
		expectNodeName string
		expectIsNode   bool
	}{
		{
			name:           "nil user",
			user:           nil,
			expectNodeName: "",
			expectIsNode:   false,
		},
		{
			name:           "node username without group",
			user:           &user.DefaultInfo{Name: "system:node:foo"},
			expectNodeName: "",
			expectIsNode:   false,
		},
		{
			name:           "node group without username",
			user:           &user.DefaultInfo{Name: "foo", Groups: []string{"system:nodes"}},
			expectNodeName: "",
			expectIsNode:   false,
		},
		{
			name:           "node group and username",
			user:           &user.DefaultInfo{Name: "system:node:foo", Groups: []string{"system:nodes"}},
			expectNodeName: "foo",
			expectIsNode:   true,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			nodeName, isNode := NewDefaultNodeIdentifier().NodeIdentity(tt.user)
			if nodeName != tt.expectNodeName {
				t.Errorf("DefaultNodeIdentifier.NodeIdentity() got = %v, want %v", nodeName, tt.expectNodeName)
			}
			if isNode != tt.expectIsNode {
				t.Errorf("DefaultNodeIdentifier.NodeIdentity() got = %v, want %v", isNode, tt.expectIsNode)
			}
		})
	}
}
<|endoftext|>


<commit_before>package fundingoffer

import (
	"encoding/json"
	"fmt"

	"github.com/bitfinexcom/bitfinex-api-go/pkg/convert"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/common"
)

type Offer struct {
	ID         int64
	Symbol     string
	MTSCreated int64
	MTSUpdated int64
	Amount     float64
	AmountOrig float64
	Type       string
	Flags      interface{}
	Status     string
	Rate       float64
	Period     int64
	Notify     bool
	Hidden     bool
	Insure     bool
	Renew      bool
	RateReal   float64
}

type New Offer
type Update Offer
type Cancel Offer
type Snapshot struct {
	Snapshot []*Offer
}

type CancelRequest struct {
	ID int64
}

func (cr *CancelRequest) ToJSON() ([]byte, error) {
	resp := struct {
		ID int64 `json:"id"`
	}{
		ID: cr.ID,
	}
	return json.Marshal(resp)
}

// MarshalJSON converts the offer cancel object into the format required by the
// bitfinex websocket service.
func (cr *CancelRequest) MarshalJSON() ([]byte, error) {
	b, err := cr.ToJSON()
	if err != nil {
		return nil, err
	}
	return []byte(fmt.Sprintf("[0, \"foc\", null, %s]", string(b))), nil
}

type SubmitRequest struct {
	Type   string
	Symbol string
	Amount float64
	Rate   float64
	Period int64
	Hidden bool
}

func (sr *SubmitRequest) ToJSON() ([]byte, error) {
	aux := struct {
		Type   string  `json:"type"`
		Symbol string  `json:"symbol"`
		Amount float64 `json:"amount,string"`
		Rate   float64 `json:"rate,string"`
		Period int64   `json:"period"`
		Flags  int     `json:"flags,omitempty"`
	}{
		Type:   sr.Type,
		Symbol: sr.Symbol,
		Amount: sr.Amount,
		Rate:   sr.Rate,
		Period: sr.Period,
	}
	if sr.Hidden {
		aux.Flags = aux.Flags + common.OrderFlagHidden
	}
	return json.Marshal(aux)
}

// MarshalJSON converts the offer submit object into the format required by the
// bitfinex websocket service.
func (sr *SubmitRequest) MarshalJSON() ([]byte, error) {
	aux, err := sr.ToJSON()
	if err != nil {
		return nil, err
	}
	return []byte(fmt.Sprintf("[0, \"fon\", null, %s]", string(aux))), nil
}

func FromRaw(raw []interface{}) (o *Offer, err error) {
	if len(raw) < 21 {
		return o, fmt.Errorf("data slice too short for offer: %#v", raw)
	}

	o = &Offer{
		ID:         convert.I64ValOrZero(raw[0]),
		Symbol:     convert.SValOrEmpty(raw[1]),
		MTSCreated: convert.I64ValOrZero(raw[2]),
		MTSUpdated: convert.I64ValOrZero(raw[3]),
		Amount:     convert.F64ValOrZero(raw[4]),
		AmountOrig: convert.F64ValOrZero(raw[5]),
		Type:       convert.SValOrEmpty(raw[6]),
		Flags:      raw[9],
		Status:     convert.SValOrEmpty(raw[10]),
		Rate:       convert.F64ValOrZero(raw[14]),
		Period:     convert.I64ValOrZero(raw[15]),
		Notify:     convert.BValOrFalse(raw[16]),
		Hidden:     convert.BValOrFalse(raw[17]),
		Insure:     convert.BValOrFalse(raw[18]),
		Renew:      convert.BValOrFalse(raw[19]),
		RateReal:   convert.F64ValOrZero(raw[20]),
	}

	return
}

func CancelFromRaw(raw []interface{}) (Cancel, error) {
	o, err := FromRaw(raw)
	if err != nil {
		return Cancel{}, err
	}
	return Cancel(*o), nil
}

func NewFromRaw(raw []interface{}) (New, error) {
	o, err := FromRaw(raw)
	if err != nil {
		return New{}, err
	}
	return New(*o), nil
}

func SnapshotFromRaw(raw []interface{}) (snap *Snapshot, err error) {
	if len(raw) == 0 {
		return snap, fmt.Errorf("data slice too short for offer: %#v", raw)
	}

	fos := make([]*Offer, 0)
	switch raw[0].(type) {
	case []interface{}:
		for _, v := range raw {
			if l, ok := v.([]interface{}); ok {
				o, err := FromRaw(l)
				if err != nil {
					return snap, err
				}
				fos = append(fos, o)
			}
		}
	default:
		return snap, fmt.Errorf("not a funding offer snapshot")
	}

	snap = &Snapshot{Snapshot: fos}
	return
}
<commit_msg>ability to map raw data to Update funding offer type<commit_after>package fundingoffer

import (
	"encoding/json"
	"fmt"

	"github.com/bitfinexcom/bitfinex-api-go/pkg/convert"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/common"
)

type Offer struct {
	ID         int64
	Symbol     string
	MTSCreated int64
	MTSUpdated int64
	Amount     float64
	AmountOrig float64
	Type       string
	Flags      interface{}
	Status     string
	Rate       float64
	Period     int64
	Notify     bool
	Hidden     bool
	Insure     bool
	Renew      bool
	RateReal   float64
}

type New Offer
type Update Offer
type Cancel Offer
type Snapshot struct {
	Snapshot []*Offer
}

type CancelRequest struct {
	ID int64
}

func (cr *CancelRequest) ToJSON() ([]byte, error) {
	resp := struct {
		ID int64 `json:"id"`
	}{
		ID: cr.ID,
	}
	return json.Marshal(resp)
}

// MarshalJSON converts the offer cancel object into the format required by the
// bitfinex websocket service.
func (cr *CancelRequest) MarshalJSON() ([]byte, error) {
	b, err := cr.ToJSON()
	if err != nil {
		return nil, err
	}
	return []byte(fmt.Sprintf("[0, \"foc\", null, %s]", string(b))), nil
}

type SubmitRequest struct {
	Type   string
	Symbol string
	Amount float64
	Rate   float64
	Period int64
	Hidden bool
}

func (sr *SubmitRequest) ToJSON() ([]byte, error) {
	aux := struct {
		Type   string  `json:"type"`
		Symbol string  `json:"symbol"`
		Amount float64 `json:"amount,string"`
		Rate   float64 `json:"rate,string"`
		Period int64   `json:"period"`
		Flags  int     `json:"flags,omitempty"`
	}{
		Type:   sr.Type,
		Symbol: sr.Symbol,
		Amount: sr.Amount,
		Rate:   sr.Rate,
		Period: sr.Period,
	}
	if sr.Hidden {
		aux.Flags = aux.Flags + common.OrderFlagHidden
	}
	return json.Marshal(aux)
}

// MarshalJSON converts the offer submit object into the format required by the
// bitfinex websocket service.
func (sr *SubmitRequest) MarshalJSON() ([]byte, error) {
	aux, err := sr.ToJSON()
	if err != nil {
		return nil, err
	}
	return []byte(fmt.Sprintf("[0, \"fon\", null, %s]", string(aux))), nil
}

func FromRaw(raw []interface{}) (o *Offer, err error) {
	if len(raw) < 21 {
		return o, fmt.Errorf("data slice too short for offer: %#v", raw)
	}

	o = &Offer{
		ID:         convert.I64ValOrZero(raw[0]),
		Symbol:     convert.SValOrEmpty(raw[1]),
		MTSCreated: convert.I64ValOrZero(raw[2]),
		MTSUpdated: convert.I64ValOrZero(raw[3]),
		Amount:     convert.F64ValOrZero(raw[4]),
		AmountOrig: convert.F64ValOrZero(raw[5]),
		Type:       convert.SValOrEmpty(raw[6]),
		Flags:      raw[9],
		Status:     convert.SValOrEmpty(raw[10]),
		Rate:       convert.F64ValOrZero(raw[14]),
		Period:     convert.I64ValOrZero(raw[15]),
		Notify:     convert.BValOrFalse(raw[16]),
		Hidden:     convert.BValOrFalse(raw[17]),
		Insure:     convert.BValOrFalse(raw[18]),
		Renew:      convert.BValOrFalse(raw[19]),
		RateReal:   convert.F64ValOrZero(raw[20]),
	}

	return
}

func CancelFromRaw(raw []interface{}) (Cancel, error) {
	o, err := FromRaw(raw)
	if err != nil {
		return Cancel{}, err
	}
	return Cancel(*o), nil
}

func NewFromRaw(raw []interface{}) (New, error) {
	o, err := FromRaw(raw)
	if err != nil {
		return New{}, err
	}
	return New(*o), nil
}

func UpdateFromRaw(raw []interface{}) (Update, error) {
	o, err := FromRaw(raw)
	if err != nil {
		return Update{}, err
	}
	return Update(*o), nil
}

func SnapshotFromRaw(raw []interface{}) (snap *Snapshot, err error) {
	if len(raw) == 0 {
		return snap, fmt.Errorf("data slice too short for offer: %#v", raw)
	}

	fos := make([]*Offer, 0)
	switch raw[0].(type) {
	case []interface{}:
		for _, v := range raw {
			if l, ok := v.([]interface{}); ok {
				o, err := FromRaw(l)
				if err != nil {
					return snap, err
				}
				fos = append(fos, o)
			}
		}
	default:
		return snap, fmt.Errorf("not a funding offer snapshot")
	}

	snap = &Snapshot{Snapshot: fos}
	return
}
<|endoftext|>


<commit_before>package main

import (
    "encoding/json"
    "log"
    "net"
    "net/http"
)

type ResponseImplements struct {
    Implements string
}

func main () {
    listener, err := net.Listen("unix", "/run/docker/plugins/dvol.sock")
    if err != nil {
        log.Fatal("Could not listen on /run/docker/plugins/dvol.sock")
    }

    http.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) {
        // stuff
        log.Print("<= /Plugin.Activate")
        responseJSON, _ := json.Marshal(&ResponseImplements{
            Implements: "VolumeDriver",
        })
        w.Write(responseJSON)
    })

    http.Serve(listener, nil)
}
<commit_msg>WIP on dvol volume plugin<commit_after>package main

import (
    "encoding/json"
    "log"
    "net"
    "net/http"
    "os"
)

const DVOL_SOCKET = "/run/docker/plugins/dvol.sock"

type ResponseImplements struct {
    Implements string
}

func main () {
    if _, err := os.Stat(DVOL_SOCKET); err == nil {
        if err = os.Remove(DVOL_SOCKET); err == nil {
            log.Fatalf("Could not clean up existing socket at %s", DVOL_SOCKET)
        }
    }
    listener, err := net.Listen("unix", DVOL_SOCKET)
    if err != nil {
        log.Fatalf("Could not listen on %s", DVOL_SOCKET)
    }

    http.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) {
        log.Print("<= /Plugin.Activate")
        responseJSON, _ := json.Marshal(&ResponseImplements{
            Implements: "VolumeDriver",
        })
        w.Write(responseJSON)
    })

    http.Serve(listener, nil)
}
<|endoftext|>


<commit_before>package collectors

import (
	"fmt"
	"io/ioutil"

	"strconv"
	"strings"

	"github.com/bosun-monitor/scollector/metadata"
	"github.com/bosun-monitor/scollector/opentsdb"
)

func WatchProcesses(procs []*WatchedProc) error {
	collectors = append(collectors, &IntervalCollector{
		F: func() (opentsdb.MultiDataPoint, error) {
			return c_linux_processes(procs)
		},
	})
	return nil
}

func linuxProcMonitor(w *WatchedProc, md *opentsdb.MultiDataPoint) error {
	var err error
	for pid, id := range w.Processes {
		stats_file, e := ioutil.ReadFile("/proc/" + pid + "/stat")
		if e != nil {
			w.Remove(pid)
			continue
		}
		io_file, e := ioutil.ReadFile("/proc/" + pid + "/io")
		if e != nil {
			w.Remove(pid)
			continue
		}
		stats := strings.Fields(string(stats_file))
		if len(stats) < 24 {
			err = fmt.Errorf("stats too short")
			continue
		}
		var io []string
		for _, line := range strings.Split(string(io_file), "\n") {
			f := strings.Fields(line)
			if len(f) == 2 {
				io = append(io, f[1])
			}
		}
		if len(io) < 6 {
			err = fmt.Errorf("io too short")
			continue
		}
		tags := opentsdb.TagSet{"name": w.Name, "id": strconv.Itoa(id)}
		Add(md, "linux.proc.cpu", stats[13], opentsdb.TagSet{"type": "user"}.Merge(tags), metadata.Counter, metadata.Pct, descLinuxProcCpuUser)
		Add(md, "linux.proc.cpu", stats[14], opentsdb.TagSet{"type": "system"}.Merge(tags), metadata.Counter, metadata.Pct, descLinuxProcCpuSystem)
		Add(md, "linux.proc.mem.fault", stats[9], opentsdb.TagSet{"type": "minflt"}.Merge(tags), metadata.Counter, metadata.Fault, descLinuxProcMemFaultMin)
		Add(md, "linux.proc.mem.fault", stats[11], opentsdb.TagSet{"type": "majflt"}.Merge(tags), metadata.Counter, metadata.Fault, descLinuxProcMemFaultMax)
		Add(md, "linux.proc.mem.virtual", stats[22], tags, metadata.Gauge, metadata.Bytes, descLinuxProcMemVirtual)
		Add(md, "linux.proc.mem.rss", stats[23], tags, metadata.Gauge, metadata.Page, descLinuxProcMemRss)
		Add(md, "linux.proc.char_io", io[0], opentsdb.TagSet{"type": "read"}.Merge(tags), metadata.Counter, metadata.Bytes, descLinuxProcCharIoRead)
		Add(md, "linux.proc.char_io", io[1], opentsdb.TagSet{"type": "write"}.Merge(tags), metadata.Counter, metadata.Bytes, descLinuxProcCharIoWrite)
		Add(md, "linux.proc.syscall", io[2], opentsdb.TagSet{"type": "read"}.Merge(tags), metadata.Counter, metadata.Syscall, descLinuxProcSyscallRead)
		Add(md, "linux.proc.syscall", io[3], opentsdb.TagSet{"type": "write"}.Merge(tags), metadata.Counter, metadata.Syscall, descLinuxProcSyscallWrite)
		Add(md, "linux.proc.io_bytes", io[4], opentsdb.TagSet{"type": "read"}.Merge(tags), metadata.Counter, metadata.Bytes, descLinuxProcIoBytesRead)
		Add(md, "linux.proc.io_bytes", io[5], opentsdb.TagSet{"type": "write"}.Merge(tags), metadata.Counter, metadata.Bytes, descLinuxProcIoBytesWrite)
	}
	return err
}

const (
	descLinuxProcCpuUser      = "The amount of time that this process has been scheduled in user mode."
	descLinuxProcCpuSystem    = "The amount of time that this process has been scheduled in kernel mode"
	descLinuxProcMemFaultMin  = "The number of minor faults the process has made which have not required loading a memory page from disk."
	descLinuxProcMemFaultMax  = "The number of major faults the process has made which have required loading a memory page from disk."
	descLinuxProcMemVirtual   = "The virtual memory size."
	descLinuxProcMemRss       = "The resident set size (number of pages the process has in real memory."
	descLinuxProcCharIoRead   = "The number of bytes which this task has caused to be read from storage. This is simply the sum of bytes which this process passed to read(2) and similar system calls. It includes things such as terminal I/O and is unaffected by whether or not actual physical disk I/O was required (the read might have been satisfied from pagecache)"
	descLinuxProcCharIoWrite  = "The number of bytes which this task has caused, or shall cause to be written to disk. Similar caveats apply here as with read."
	descLinuxProcSyscallRead  = "An attempt to count the number of read I/O operations—that is, system calls such as read(2) and pread(2)."
	descLinuxProcSyscallWrite = "Attempt to count the number of write I/O operations—that is, system calls such as write(2) and pwrite(2)."
	descLinuxProcIoBytesRead  = "An attempt to count the number of bytes which this process really did cause to be fetched from the storage layer. This is accurate for block-backed filesystems."
	descLinuxProcIoBytesWrite = "An Attempt to count the number of bytes which this process caused to be sent to the storage layer."
)

func getLinuxProccesses() ([]*Process, error) {
	files, err := ioutil.ReadDir("/proc")
	if err != nil {
		return nil, err
	}
	var pids []string
	for _, f := range files {
		if _, err := strconv.Atoi(f.Name()); err == nil && f.IsDir() {
			pids = append(pids, f.Name())
		}
	}
	var lps []*Process
	for _, pid := range pids {
		cmdline, err := ioutil.ReadFile("/proc/" + pid + "/cmdline")
		if err != nil {
			//Continue because the pid might not exist any more
			continue
		}
		cl := strings.Split(string(cmdline), "\x00")
		if len(cl) < 1 || len(cl[0]) == 0 {
			continue
		}
		lp := &Process{
			Pid:     pid,
			Command: cl[0],
		}
		if len(cl) > 1 {
			lp.Arguments = strings.Join(cl[1:], "")
		}
		lps = append(lps, lp)
	}
	return lps, nil
}

func c_linux_processes(procs []*WatchedProc) (opentsdb.MultiDataPoint, error) {
	var md opentsdb.MultiDataPoint
	lps, err := getLinuxProccesses()
	if err != nil {
		return nil, nil
	}
	for _, w := range procs {
		w.Check(lps)
		if e := linuxProcMonitor(w, &md); e != nil {
			err = e
		}
	}
	return md, err
}
<commit_msg>cmd/scollector: Needs a real name<commit_after>package collectors

import (
	"fmt"
	"io/ioutil"

	"strconv"
	"strings"

	"github.com/bosun-monitor/scollector/metadata"
	"github.com/bosun-monitor/scollector/opentsdb"
)

func WatchProcesses(procs []*WatchedProc) error {
	collectors = append(collectors, &IntervalCollector{
		F: func() (opentsdb.MultiDataPoint, error) {
			return c_linux_processes(procs)
		},
		name: "c_linux_processes",
	})
	return nil
}

func linuxProcMonitor(w *WatchedProc, md *opentsdb.MultiDataPoint) error {
	var err error
	for pid, id := range w.Processes {
		stats_file, e := ioutil.ReadFile("/proc/" + pid + "/stat")
		if e != nil {
			w.Remove(pid)
			continue
		}
		io_file, e := ioutil.ReadFile("/proc/" + pid + "/io")
		if e != nil {
			w.Remove(pid)
			continue
		}
		stats := strings.Fields(string(stats_file))
		if len(stats) < 24 {
			err = fmt.Errorf("stats too short")
			continue
		}
		var io []string
		for _, line := range strings.Split(string(io_file), "\n") {
			f := strings.Fields(line)
			if len(f) == 2 {
				io = append(io, f[1])
			}
		}
		if len(io) < 6 {
			err = fmt.Errorf("io too short")
			continue
		}
		tags := opentsdb.TagSet{"name": w.Name, "id": strconv.Itoa(id)}
		Add(md, "linux.proc.cpu", stats[13], opentsdb.TagSet{"type": "user"}.Merge(tags), metadata.Counter, metadata.Pct, descLinuxProcCpuUser)
		Add(md, "linux.proc.cpu", stats[14], opentsdb.TagSet{"type": "system"}.Merge(tags), metadata.Counter, metadata.Pct, descLinuxProcCpuSystem)
		Add(md, "linux.proc.mem.fault", stats[9], opentsdb.TagSet{"type": "minflt"}.Merge(tags), metadata.Counter, metadata.Fault, descLinuxProcMemFaultMin)
		Add(md, "linux.proc.mem.fault", stats[11], opentsdb.TagSet{"type": "majflt"}.Merge(tags), metadata.Counter, metadata.Fault, descLinuxProcMemFaultMax)
		Add(md, "linux.proc.mem.virtual", stats[22], tags, metadata.Gauge, metadata.Bytes, descLinuxProcMemVirtual)
		Add(md, "linux.proc.mem.rss", stats[23], tags, metadata.Gauge, metadata.Page, descLinuxProcMemRss)
		Add(md, "linux.proc.char_io", io[0], opentsdb.TagSet{"type": "read"}.Merge(tags), metadata.Counter, metadata.Bytes, descLinuxProcCharIoRead)
		Add(md, "linux.proc.char_io", io[1], opentsdb.TagSet{"type": "write"}.Merge(tags), metadata.Counter, metadata.Bytes, descLinuxProcCharIoWrite)
		Add(md, "linux.proc.syscall", io[2], opentsdb.TagSet{"type": "read"}.Merge(tags), metadata.Counter, metadata.Syscall, descLinuxProcSyscallRead)
		Add(md, "linux.proc.syscall", io[3], opentsdb.TagSet{"type": "write"}.Merge(tags), metadata.Counter, metadata.Syscall, descLinuxProcSyscallWrite)
		Add(md, "linux.proc.io_bytes", io[4], opentsdb.TagSet{"type": "read"}.Merge(tags), metadata.Counter, metadata.Bytes, descLinuxProcIoBytesRead)
		Add(md, "linux.proc.io_bytes", io[5], opentsdb.TagSet{"type": "write"}.Merge(tags), metadata.Counter, metadata.Bytes, descLinuxProcIoBytesWrite)
	}
	return err
}

const (
	descLinuxProcCpuUser      = "The amount of time that this process has been scheduled in user mode."
	descLinuxProcCpuSystem    = "The amount of time that this process has been scheduled in kernel mode"
	descLinuxProcMemFaultMin  = "The number of minor faults the process has made which have not required loading a memory page from disk."
	descLinuxProcMemFaultMax  = "The number of major faults the process has made which have required loading a memory page from disk."
	descLinuxProcMemVirtual   = "The virtual memory size."
	descLinuxProcMemRss       = "The resident set size (number of pages the process has in real memory."
	descLinuxProcCharIoRead   = "The number of bytes which this task has caused to be read from storage. This is simply the sum of bytes which this process passed to read(2) and similar system calls. It includes things such as terminal I/O and is unaffected by whether or not actual physical disk I/O was required (the read might have been satisfied from pagecache)"
	descLinuxProcCharIoWrite  = "The number of bytes which this task has caused, or shall cause to be written to disk. Similar caveats apply here as with read."
	descLinuxProcSyscallRead  = "An attempt to count the number of read I/O operations—that is, system calls such as read(2) and pread(2)."
	descLinuxProcSyscallWrite = "Attempt to count the number of write I/O operations—that is, system calls such as write(2) and pwrite(2)."
	descLinuxProcIoBytesRead  = "An attempt to count the number of bytes which this process really did cause to be fetched from the storage layer. This is accurate for block-backed filesystems."
	descLinuxProcIoBytesWrite = "An Attempt to count the number of bytes which this process caused to be sent to the storage layer."
)

func getLinuxProccesses() ([]*Process, error) {
	files, err := ioutil.ReadDir("/proc")
	if err != nil {
		return nil, err
	}
	var pids []string
	for _, f := range files {
		if _, err := strconv.Atoi(f.Name()); err == nil && f.IsDir() {
			pids = append(pids, f.Name())
		}
	}
	var lps []*Process
	for _, pid := range pids {
		cmdline, err := ioutil.ReadFile("/proc/" + pid + "/cmdline")
		if err != nil {
			//Continue because the pid might not exist any more
			continue
		}
		cl := strings.Split(string(cmdline), "\x00")
		if len(cl) < 1 || len(cl[0]) == 0 {
			continue
		}
		lp := &Process{
			Pid:     pid,
			Command: cl[0],
		}
		if len(cl) > 1 {
			lp.Arguments = strings.Join(cl[1:], "")
		}
		lps = append(lps, lp)
	}
	return lps, nil
}

func c_linux_processes(procs []*WatchedProc) (opentsdb.MultiDataPoint, error) {
	var md opentsdb.MultiDataPoint
	lps, err := getLinuxProccesses()
	if err != nil {
		return nil, nil
	}
	for _, w := range procs {
		w.Check(lps)
		if e := linuxProcMonitor(w, &md); e != nil {
			err = e
		}
	}
	return md, err
}
<|endoftext|>


<commit_before>package main

import "net/http"
import "os/exec"
import "strings"
import "os"
import "io/ioutil"
import "runtime"
import "github.com/fatih/color"

func main() {

	Repo := [6]string{"https://raw.githubusercontent.com/EgeBalci/ARCANUS/master/ARCANUS.go", "https://github.com/EgeBalci/ARCANUS/raw/master/ARCANUS_x64", "https://github.com/EgeBalci/ARCANUS/raw/master/ARCANUS_x64.exe", "https://github.com/EgeBalci/ARCANUS/raw/master/ARCANUS_x86", "https://github.com/EgeBalci/ARCANUS/raw/master/ARCANUS_x86.exe", "https://github.com/EgeBalci/ARCANUS/raw/master/README.md"}

	if runtime.GOOS == "windows" {
		exec.Command("cmd", "/C", "msg ARCANUS Update Started...").Run()
		exec.Command("cmd", "/C", "del ARCANUS.go").Run()
		exec.Command("cmd", "/C", "del ARCANUS_x64.exe").Run()
		exec.Command("cmd", "/C", "del ARCANUS_x86.exe").Run()
		exec.Command("cmd", "/C", "del ARCANUS_x64").Run()
		exec.Command("cmd", "/C", "del ARCANUS_x86").Run()
		color.Blue("[*] Updating ARCANUS...\n\n")
		for i := 0; i < len(Repo); i++ {
			response, _ := http.Get(Repo[i])
			defer response.Body.Close();
    		body, _ := ioutil.ReadAll(response.Body);

    		Name := strings.Split(Repo[i], "/")
    		color.Green("#	"+string(Name[(len(Name)-1)])+"		[OK]")
    		file, _ := os.Create(string(Name[(len(Name)-1)]))

    		file.WriteString(string(body))
		}
		/*ARC, _ := exec.Command("cmd", "/C", "echo %PROCESSOR_ARCHITECTURE%").Output()
		if strings.Contains(string(ARC), "x86") || strings.Contains(string(ARC), "X86") {
			exec.Command("cmd", "/C", "ARCANUS_x86.exe").Start()
		}else if strings.Contains(string(ARC), "AMD64") {
			exec.Command("cmd", "/C", "ARCANUS_x64.exe").Start()
		}*/
		exec.Command("cmd", "/C", "msg * ARCANUS Updated Succesfuly !").Run()
	}else if runtime.GOOS == "linux" {
		exec.Command("sh", "-c", "zenity --info --text=\"ARCANUS Update Started... \"").Run()
		exec.Command("sh", "-c", "rm ARCANUS.go").Run()
		exec.Command("sh", "-c", "rm ARCANUS_x64.exe").Run()
		exec.Command("sh", "-c", "rm ARCANUS_x86.exe").Run()
		exec.Command("sh", "-c", "rm ARCANUS_x64").Run()
		exec.Command("sh", "-c", "rm ARCANUS_x86").Run()
		color.Blue("[*] Updating ARCANUS...\n\n")
		for i := 0; i < len(Repo); i++ {
			response, _ := http.Get(Repo[i])
			defer response.Body.Close();
    		body, _ := ioutil.ReadAll(response.Body);

    		Name := strings.Split(Repo[i], "/")
    		color.Green("#	"+string(Name[(len(Name)-1)])+"		[OK]")
    		file, _ := os.Create(string(Name[(len(Name)-1)]))

    		file.WriteString(string(body))
		}
		exec.Command("sh", "-c", "zenity --info --text=\"ARCANUS Updated Succesfuly !\"").Run()
		/*ARC, _ := exec.Command("sh", "-c", "uname -a").Output()
		if strings.Contains(string(ARC), "x86") || strings.Contains(string(ARC), "X86") {
			exec.Command("sh", "-c", "./ARCANUS_x86").Start()
		}else if strings.Contains(string(ARC), "amd64") {
			exec.Command("sh", "-c", "./ARCANUS_x64").Start()
		}*/

	}

}
<commit_msg>Update Update.go<commit_after>package main

import "net/http"
import "os/exec"
import "strings"
import "os"
import "io/ioutil"
import "runtime"
import "github.com/fatih/color"

func main() {

	Repo := [6]string{"https://github.com/EgeBalci/ARCANUS/blob/master/SOURCE/ARCANUS.go", "https://github.com/EgeBalci/ARCANUS/raw/master/ARCANUS_x64", "https://github.com/EgeBalci/ARCANUS/raw/master/ARCANUS_x64.exe", "https://github.com/EgeBalci/ARCANUS/raw/master/ARCANUS_x86", "https://github.com/EgeBalci/ARCANUS/raw/master/ARCANUS_x86.exe", "https://github.com/EgeBalci/ARCANUS/raw/master/README.md"}

	if runtime.GOOS == "windows" {
		exec.Command("cmd", "/C", "msg ARCANUS Update Started...").Run()
		exec.Command("cmd", "/C", "del ARCANUS.go").Run()
		exec.Command("cmd", "/C", "del ARCANUS_x64.exe").Run()
		exec.Command("cmd", "/C", "del ARCANUS_x86.exe").Run()
		exec.Command("cmd", "/C", "del ARCANUS_x64").Run()
		exec.Command("cmd", "/C", "del ARCANUS_x86").Run()
		color.Blue("[*] Updating ARCANUS...\n\n")
		for i := 0; i < len(Repo); i++ {
			response, _ := http.Get(Repo[i])
			defer response.Body.Close();
    		body, _ := ioutil.ReadAll(response.Body);

    		Name := strings.Split(Repo[i], "/")
    		color.Green("#	"+string(Name[(len(Name)-1)])+"		[OK]")
    		file, _ := os.Create(string(Name[(len(Name)-1)]))

    		file.WriteString(string(body))
		}
		/*ARC, _ := exec.Command("cmd", "/C", "echo %PROCESSOR_ARCHITECTURE%").Output()
		if strings.Contains(string(ARC), "x86") || strings.Contains(string(ARC), "X86") {
			exec.Command("cmd", "/C", "ARCANUS_x86.exe").Start()
		}else if strings.Contains(string(ARC), "AMD64") {
			exec.Command("cmd", "/C", "ARCANUS_x64.exe").Start()
		}*/
		exec.Command("cmd", "/C", "msg * ARCANUS Updated Succesfuly !").Run()
	}else if runtime.GOOS == "linux" {
		exec.Command("sh", "-c", "zenity --info --text=\"ARCANUS Update Started... \"").Run()
		exec.Command("sh", "-c", "rm ARCANUS.go").Run()
		exec.Command("sh", "-c", "rm ARCANUS_x64.exe").Run()
		exec.Command("sh", "-c", "rm ARCANUS_x86.exe").Run()
		exec.Command("sh", "-c", "rm ARCANUS_x64").Run()
		exec.Command("sh", "-c", "rm ARCANUS_x86").Run()
		color.Blue("[*] Updating ARCANUS...\n\n")
		for i := 0; i < len(Repo); i++ {
			response, _ := http.Get(Repo[i])
			defer response.Body.Close();
    		body, _ := ioutil.ReadAll(response.Body);

    		Name := strings.Split(Repo[i], "/")
    		color.Green("#	"+string(Name[(len(Name)-1)])+"		[OK]")
    		file, _ := os.Create(string(Name[(len(Name)-1)]))

    		file.WriteString(string(body))
		}
		exec.Command("sh", "-c", "zenity --info --text=\"ARCANUS Updated Succesfuly !\"").Run()
		/*ARC, _ := exec.Command("sh", "-c", "uname -a").Output()
		if strings.Contains(string(ARC), "x86") || strings.Contains(string(ARC), "X86") {
			exec.Command("sh", "-c", "./ARCANUS_x86").Start()
		}else if strings.Contains(string(ARC), "amd64") {
			exec.Command("sh", "-c", "./ARCANUS_x64").Start()
		}*/

	}

}
<|endoftext|>


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

package service

import (
	"fmt"
	"os"
	"path/filepath"

	"github.com/juju/cmd"
	"github.com/juju/errors"
	"github.com/juju/names"
	"gopkg.in/juju/charm.v6-unstable"
	"gopkg.in/juju/charmrepo.v2-unstable"
	"launchpad.net/gnuflag"

	"github.com/juju/juju/api"
	apiservice "github.com/juju/juju/api/service"
	"github.com/juju/juju/cmd/juju/block"
	"github.com/juju/juju/cmd/modelcmd"
	"github.com/juju/juju/resource"
	"github.com/juju/juju/resource/resourceadapters"
)

// NewUpgradeCharmCommand returns a command which upgrades service's charm.
func NewUpgradeCharmCommand() cmd.Command {
	return modelcmd.Wrap(&upgradeCharmCommand{})
}

// UpgradeCharm is responsible for upgrading a service's charm.
type upgradeCharmCommand struct {
	modelcmd.ModelCommandBase
	ServiceName string
	ForceUnits  bool
	ForceSeries bool
	RepoPath    string // defaults to JUJU_REPOSITORY
	SwitchURL   string
	CharmPath   string
	Revision    int // defaults to -1 (latest)
	// Resources is a map of resource name to filename to be uploaded on upgrade.
	Resources map[string]string
}

const upgradeCharmDoc = `
When no flags are set, the service's charm will be upgraded to the latest
revision available in the repository from which it was originally deployed. An
explicit revision can be chosen with the --revision flag.

If the charm was not originally deployed from a repository, but from a path,
then a path will need to be supplied to allow an updated copy of the charm
to be located.

If the charm came from a local repository, its path will be assumed to be
$JUJU_REPOSITORY unless overridden by --repository. Note that deploying from
a local repository is deprecated in favour of deploying from a path.

Deploying from a path or local repository is intended to suit the workflow of a charm
author working on a single client machine; use of this deployment method from
multiple clients is not supported and may lead to confusing behaviour. Each
local charm gets uploaded with the revision specified in the charm, if possible,
otherwise it gets a unique revision (highest in state + 1).

When deploying from a path, the --path flag is used to specify the location from
which to load the updated charm. Note that the directory containing the charm must
match what was originally used to deploy the charm as a superficial check that the
updated charm is compatible.

Resources may be uploaded at upgrade time by specifying the --resource flag.
Following the resource flag should be name=filepath pair.  This flag may be
repeated more than once to upload more than one resource.

  juju upgrade-charm foo --resource bar=/some/file.tgz --resource baz=./docs/cfg.xml

Where bar and baz are resources named in the metadata for the foo charm.

If the new version of a charm does not explicitly support the service's series, the
upgrade is disallowed unless the --force-series flag is used. This option should be
used with caution since using a charm on a machine running an unsupported series may
cause unexpected behavior.

When using a local repository, the --switch flag allows you to replace the charm
with an entirely different one. The new charm's URL and revision are inferred as
they would be when running a deploy command.

Please note that --switch is dangerous, because juju only has limited
information with which to determine compatibility; the operation will succeed,
regardless of potential havoc, so long as the following conditions hold:

- The new charm must declare all relations that the service is currently
participating in.
- All config settings shared by the old and new charms must
have the same types.

The new charm may add new relations and configuration settings.

--switch and --path are mutually exclusive.

--path and --revision are mutually exclusive. The revision of the updated charm
is determined by the contents of the charm at the specified path.

--switch and --revision are mutually exclusive. To specify a given revision
number with --switch, give it in the charm URL, for instance "cs:wordpress-5"
would specify revision number 5 of the wordpress charm.

Use of the --force-units flag is not generally recommended; units upgraded while in an
error state will not have upgrade-charm hooks executed, and may cause unexpected
behavior.
`

func (c *upgradeCharmCommand) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "upgrade-charm",
		Args:    "<service>",
		Purpose: "upgrade a service's charm",
		Doc:     upgradeCharmDoc,
	}
}

func (c *upgradeCharmCommand) SetFlags(f *gnuflag.FlagSet) {
	f.BoolVar(&c.ForceUnits, "force-units", false, "upgrade all units immediately, even if in error state")
	f.BoolVar(&c.ForceSeries, "force-series", false, "upgrade even if series of deployed services are not supported by the new charm")
	f.StringVar(&c.RepoPath, "repository", os.Getenv("JUJU_REPOSITORY"), "local charm repository path")
	f.StringVar(&c.SwitchURL, "switch", "", "crossgrade to a different charm")
	f.StringVar(&c.CharmPath, "path", "", "upgrade to a charm located at path")
	f.IntVar(&c.Revision, "revision", -1, "explicit revision of current charm")
	f.Var(stringMap{&c.Resources}, "resource", "resource to be uploaded to the controller")
}

func (c *upgradeCharmCommand) Init(args []string) error {
	switch len(args) {
	case 1:
		if !names.IsValidService(args[0]) {
			return fmt.Errorf("invalid service name %q", args[0])
		}
		c.ServiceName = args[0]
	case 0:
		return fmt.Errorf("no service specified")
	default:
		return cmd.CheckEmpty(args[1:])
	}
	if c.SwitchURL != "" && c.Revision != -1 {
		return fmt.Errorf("--switch and --revision are mutually exclusive")
	}
	if c.CharmPath != "" && c.Revision != -1 {
		return fmt.Errorf("--path and --revision are mutually exclusive")
	}
	if c.SwitchURL != "" && c.CharmPath != "" {
		return fmt.Errorf("--switch and --path are mutually exclusive")
	}
	return nil
}

func (c *upgradeCharmCommand) newServiceAPIClient() (*apiservice.Client, error) {
	root, err := c.NewAPIRoot()
	if err != nil {
		return nil, errors.Trace(err)
	}
	return apiservice.NewClient(root), nil
}

// Run connects to the specified environment and starts the charm
// upgrade process.
func (c *upgradeCharmCommand) Run(ctx *cmd.Context) error {
	client, err := c.NewAPIClient()
	if err != nil {
		return err
	}
	defer client.Close()

	serviceClient, err := c.newServiceAPIClient()
	if err != nil {
		return err
	}

	oldURL, err := serviceClient.GetCharmURL(c.ServiceName)
	if err != nil {
		return err
	}

	newRef := c.SwitchURL
	if newRef == "" {
		newRef = c.CharmPath
	}
	if c.SwitchURL == "" && c.CharmPath == "" {
		// No new URL specified, but revision might have been.
		newRef = oldURL.WithRevision(c.Revision).String()
	}

	httpClient, err := c.HTTPClient()
	if err != nil {
		return errors.Trace(err)
	}
	csClient := newCharmStoreClient(httpClient)

	addedURL, err := c.addCharm(oldURL, newRef, ctx, client, csClient)
	if err != nil {
		return block.ProcessBlockedError(err, block.BlockChange)
	}

	charmInfo, err := client.CharmInfo(addedURL.String())
	if err != nil {
		return err
	}

	var ids map[string]string

	if len(c.Resources) > 0 {
		resclient, err := resourceadapters.NewAPIClient(c.NewAPIRoot)
		if err != nil {
			return errors.Trace(err)
		}
		svcs, err := resclient.ListResources([]string{c.ServiceName})
		if err != nil {
			return errors.Trace(err)
		}
		currentResources := svcs[0].Resources
		current := make(map[string]resource.Resource, len(currentResources))
		for _, res := range currentResources {
			current[res.Name] = res
		}

		var metaRes map[string]charmresource.Meta
		// We don't include metadata for any resources that were uploaded
		// previously that aren't getting overridden right now. Doing so would
		// cause those resources to get overridden, and they should be
		// maintained unless specifically overridden by the user.
		for name, res := range charmInfo.Meta.Resources {
			if _, ok := c.Resources[name]; !ok || current[name].Origin != charmresource.OriginUpload {
				metaRes[name] = res
			}
		}

		ids, err = handleResources(c, c.Resources, c.ServiceName, metaRes)
		if err != nil {
			return errors.Trace(err)
		}
	}

	cfg := apiservice.SetCharmConfig{
		ServiceName: c.ServiceName,
		CharmUrl:    addedURL.String(),
		ForceSeries: c.ForceSeries,
		ForceUnits:  c.ForceUnits,
		ResourceIDs: ids,
	}

	return block.ProcessBlockedError(serviceClient.SetCharm(cfg), block.BlockChange)
}

// addCharm interprets the new charmRef and adds the specified charm if the new charm is different
// to what's already deployed as specified by oldURL.
func (c *upgradeCharmCommand) addCharm(oldURL *charm.URL, charmRef string, ctx *cmd.Context,
	client *api.Client, csClient *csClient,
) (*charm.URL, error) {
	// Charm may have been supplied via a path reference.
	ch, newURL, err := charmrepo.NewCharmAtPathForceSeries(charmRef, oldURL.Series, c.ForceSeries)
	if err == nil {
		_, newName := filepath.Split(charmRef)
		if newName != oldURL.Name {
			return nil, fmt.Errorf("cannot upgrade %q to %q", oldURL.Name, newName)
		}
		return client.AddLocalCharm(newURL, ch)
	}
	if _, ok := err.(*charmrepo.NotFoundError); ok {
		return nil, errors.Errorf("no charm found at %q", charmRef)
	}
	// If we get a "not exists" or invalid path error then we attempt to interpret
	// the supplied charm reference as a URL below, otherwise we return the error.
	if err != os.ErrNotExist && !charmrepo.IsInvalidPathError(err) {
		return nil, err
	}

	// Charm has been supplied as a URL so we resolve and deploy using the store.
	conf, err := getClientConfig(client)
	if err != nil {
		return nil, err
	}

	newURL, supportedSeries, repo, err := resolveCharmStoreEntityURL(resolveCharmStoreEntityParams{
		urlStr:          charmRef,
		requestedSeries: oldURL.Series,
		forceSeries:     c.ForceSeries,
		csParams:        csClient.params,
		repoPath:        ctx.AbsPath(c.RepoPath),
		conf:            conf,
	})
	if err != nil {
		return nil, errors.Trace(err)
	}
	if !c.ForceSeries && oldURL.Series != "" && newURL.Series == "" && !isSeriesSupported(oldURL.Series, supportedSeries) {
		series := []string{"no series"}
		if len(supportedSeries) > 0 {
			series = supportedSeries
		}
		return nil, errors.Errorf(
			"cannot upgrade from single series %q charm to a charm supporting %q. Use --force-series to override.",
			oldURL.Series, series,
		)
	}
	// If no explicit revision was set with either SwitchURL
	// or Revision flags, discover the latest.
	if *newURL == *oldURL {
		newRef, _ := charm.ParseURL(charmRef)
		if newRef.Revision != -1 {
			return nil, fmt.Errorf("already running specified charm %q", newURL)
		}
		if newURL.Schema == "cs" {
			// No point in trying to upgrade a charm store charm when
			// we just determined that's the latest revision
			// available.
			return nil, fmt.Errorf("already running latest charm %q", newURL)
		}
	}

	addedURL, err := addCharmFromURL(client, newURL, repo, csClient)
	if err != nil {
		return nil, err
	}
	ctx.Infof("Added charm %q to the model.", addedURL)
	return addedURL, nil
}
<commit_msg>a little refactor<commit_after>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package service

import (
	"fmt"
	"os"
	"path/filepath"

	"github.com/juju/cmd"
	"github.com/juju/errors"
	"github.com/juju/names"
	"gopkg.in/juju/charm.v6-unstable"
	charmresource "gopkg.in/juju/charm.v6-unstable/resource"
	"gopkg.in/juju/charmrepo.v2-unstable"
	"launchpad.net/gnuflag"

	"github.com/juju/juju/api"
	apiservice "github.com/juju/juju/api/service"
	"github.com/juju/juju/cmd/juju/block"
	"github.com/juju/juju/cmd/modelcmd"
	"github.com/juju/juju/resource"
	"github.com/juju/juju/resource/resourceadapters"
)

// NewUpgradeCharmCommand returns a command which upgrades service's charm.
func NewUpgradeCharmCommand() cmd.Command {
	return modelcmd.Wrap(&upgradeCharmCommand{})
}

// UpgradeCharm is responsible for upgrading a service's charm.
type upgradeCharmCommand struct {
	modelcmd.ModelCommandBase
	ServiceName string
	ForceUnits  bool
	ForceSeries bool
	RepoPath    string // defaults to JUJU_REPOSITORY
	SwitchURL   string
	CharmPath   string
	Revision    int // defaults to -1 (latest)
	// Resources is a map of resource name to filename to be uploaded on upgrade.
	Resources map[string]string
}

const upgradeCharmDoc = `
When no flags are set, the service's charm will be upgraded to the latest
revision available in the repository from which it was originally deployed. An
explicit revision can be chosen with the --revision flag.

If the charm was not originally deployed from a repository, but from a path,
then a path will need to be supplied to allow an updated copy of the charm
to be located.

If the charm came from a local repository, its path will be assumed to be
$JUJU_REPOSITORY unless overridden by --repository. Note that deploying from
a local repository is deprecated in favour of deploying from a path.

Deploying from a path or local repository is intended to suit the workflow of a charm
author working on a single client machine; use of this deployment method from
multiple clients is not supported and may lead to confusing behaviour. Each
local charm gets uploaded with the revision specified in the charm, if possible,
otherwise it gets a unique revision (highest in state + 1).

When deploying from a path, the --path flag is used to specify the location from
which to load the updated charm. Note that the directory containing the charm must
match what was originally used to deploy the charm as a superficial check that the
updated charm is compatible.

Resources may be uploaded at upgrade time by specifying the --resource flag.
Following the resource flag should be name=filepath pair.  This flag may be
repeated more than once to upload more than one resource.

  juju upgrade-charm foo --resource bar=/some/file.tgz --resource baz=./docs/cfg.xml

Where bar and baz are resources named in the metadata for the foo charm.

If the new version of a charm does not explicitly support the service's series, the
upgrade is disallowed unless the --force-series flag is used. This option should be
used with caution since using a charm on a machine running an unsupported series may
cause unexpected behavior.

When using a local repository, the --switch flag allows you to replace the charm
with an entirely different one. The new charm's URL and revision are inferred as
they would be when running a deploy command.

Please note that --switch is dangerous, because juju only has limited
information with which to determine compatibility; the operation will succeed,
regardless of potential havoc, so long as the following conditions hold:

- The new charm must declare all relations that the service is currently
participating in.
- All config settings shared by the old and new charms must
have the same types.

The new charm may add new relations and configuration settings.

--switch and --path are mutually exclusive.

--path and --revision are mutually exclusive. The revision of the updated charm
is determined by the contents of the charm at the specified path.

--switch and --revision are mutually exclusive. To specify a given revision
number with --switch, give it in the charm URL, for instance "cs:wordpress-5"
would specify revision number 5 of the wordpress charm.

Use of the --force-units flag is not generally recommended; units upgraded while in an
error state will not have upgrade-charm hooks executed, and may cause unexpected
behavior.
`

func (c *upgradeCharmCommand) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "upgrade-charm",
		Args:    "<service>",
		Purpose: "upgrade a service's charm",
		Doc:     upgradeCharmDoc,
	}
}

func (c *upgradeCharmCommand) SetFlags(f *gnuflag.FlagSet) {
	f.BoolVar(&c.ForceUnits, "force-units", false, "upgrade all units immediately, even if in error state")
	f.BoolVar(&c.ForceSeries, "force-series", false, "upgrade even if series of deployed services are not supported by the new charm")
	f.StringVar(&c.RepoPath, "repository", os.Getenv("JUJU_REPOSITORY"), "local charm repository path")
	f.StringVar(&c.SwitchURL, "switch", "", "crossgrade to a different charm")
	f.StringVar(&c.CharmPath, "path", "", "upgrade to a charm located at path")
	f.IntVar(&c.Revision, "revision", -1, "explicit revision of current charm")
	f.Var(stringMap{&c.Resources}, "resource", "resource to be uploaded to the controller")
}

func (c *upgradeCharmCommand) Init(args []string) error {
	switch len(args) {
	case 1:
		if !names.IsValidService(args[0]) {
			return fmt.Errorf("invalid service name %q", args[0])
		}
		c.ServiceName = args[0]
	case 0:
		return fmt.Errorf("no service specified")
	default:
		return cmd.CheckEmpty(args[1:])
	}
	if c.SwitchURL != "" && c.Revision != -1 {
		return fmt.Errorf("--switch and --revision are mutually exclusive")
	}
	if c.CharmPath != "" && c.Revision != -1 {
		return fmt.Errorf("--path and --revision are mutually exclusive")
	}
	if c.SwitchURL != "" && c.CharmPath != "" {
		return fmt.Errorf("--switch and --path are mutually exclusive")
	}
	return nil
}

func (c *upgradeCharmCommand) newServiceAPIClient() (*apiservice.Client, error) {
	root, err := c.NewAPIRoot()
	if err != nil {
		return nil, errors.Trace(err)
	}
	return apiservice.NewClient(root), nil
}

// Run connects to the specified environment and starts the charm
// upgrade process.
func (c *upgradeCharmCommand) Run(ctx *cmd.Context) error {
	client, err := c.NewAPIClient()
	if err != nil {
		return err
	}
	defer client.Close()

	serviceClient, err := c.newServiceAPIClient()
	if err != nil {
		return err
	}

	oldURL, err := serviceClient.GetCharmURL(c.ServiceName)
	if err != nil {
		return err
	}

	newRef := c.SwitchURL
	if newRef == "" {
		newRef = c.CharmPath
	}
	if c.SwitchURL == "" && c.CharmPath == "" {
		// No new URL specified, but revision might have been.
		newRef = oldURL.WithRevision(c.Revision).String()
	}

	httpClient, err := c.HTTPClient()
	if err != nil {
		return errors.Trace(err)
	}
	csClient := newCharmStoreClient(httpClient)

	addedURL, err := c.addCharm(oldURL, newRef, ctx, client, csClient)
	if err != nil {
		return block.ProcessBlockedError(err, block.BlockChange)
	}

	charmInfo, err := client.CharmInfo(addedURL.String())
	if err != nil {
		return err
	}

	var ids map[string]string

	if len(c.Resources) > 0 {
		ids, err = c.upgradeResources(charmInfo.Meta.Resources)
		if err != nil {
			return errors.Trace(err)
		}
	}

	cfg := apiservice.SetCharmConfig{
		ServiceName: c.ServiceName,
		CharmUrl:    addedURL.String(),
		ForceSeries: c.ForceSeries,
		ForceUnits:  c.ForceUnits,
		ResourceIDs: ids,
	}

	return block.ProcessBlockedError(serviceClient.SetCharm(cfg), block.BlockChange)
}

func (c *upgradeCharmCommand) upgradeResources(storeResources map[string]charmresource.Meta) (map[string]string, error) {
	resclient, err := resourceadapters.NewAPIClient(c.NewAPIRoot)
	if err != nil {
		return nil, errors.Trace(err)
	}
	svcs, err := resclient.ListResources([]string{c.ServiceName})
	if err != nil {
		return nil, errors.Trace(err)
	}
	currentResources := svcs[0].Resources
	current := make(map[string]resource.Resource, len(currentResources))
	for _, res := range currentResources {
		current[res.Name] = res
	}

	var metaRes map[string]charmresource.Meta
	for name, res := range storeResources {
		if shouldUploadMeta(res, c.Resources, current) {
			metaRes[name] = res
		}
	}

	return handleResources(c, c.Resources, c.ServiceName, metaRes)
}

// shouldUploadMeta reports whether we should upload the metadata for the given
// resource.  This is always true for resources we're adding with the --resource
// flag. For resources we're not adding with --resource, we only upload metadata
// for charmstore resources.  previously uploaded resources stay pinned to the
// data the user uploaded.
func shouldUploadMeta(res charmresource.Meta, uploads map[string]string, current map[string]resource.Resource) bool {
	// Always upload metadata for resources the user is uploading during
	// upgrade-charm.
	if _, ok := uploads[res.Name]; ok {
		return true
	}
	cur, ok := current[res.Name]
	if !ok {
		// This should be impossible, but regardless, if there's no information
		// on the server, there should be.
		return true
	}
	// Never override existing resources a user has already uploaded.
	if cur.Origin == charmresource.OriginUpload {
		return false
	}
	return true
}

// addCharm interprets the new charmRef and adds the specified charm if the new charm is different
// to what's already deployed as specified by oldURL.
func (c *upgradeCharmCommand) addCharm(oldURL *charm.URL, charmRef string, ctx *cmd.Context,
	client *api.Client, csClient *csClient,
) (*charm.URL, error) {
	// Charm may have been supplied via a path reference.
	ch, newURL, err := charmrepo.NewCharmAtPathForceSeries(charmRef, oldURL.Series, c.ForceSeries)
	if err == nil {
		_, newName := filepath.Split(charmRef)
		if newName != oldURL.Name {
			return nil, fmt.Errorf("cannot upgrade %q to %q", oldURL.Name, newName)
		}
		return client.AddLocalCharm(newURL, ch)
	}
	if _, ok := err.(*charmrepo.NotFoundError); ok {
		return nil, errors.Errorf("no charm found at %q", charmRef)
	}
	// If we get a "not exists" or invalid path error then we attempt to interpret
	// the supplied charm reference as a URL below, otherwise we return the error.
	if err != os.ErrNotExist && !charmrepo.IsInvalidPathError(err) {
		return nil, err
	}

	// Charm has been supplied as a URL so we resolve and deploy using the store.
	conf, err := getClientConfig(client)
	if err != nil {
		return nil, err
	}

	newURL, supportedSeries, repo, err := resolveCharmStoreEntityURL(resolveCharmStoreEntityParams{
		urlStr:          charmRef,
		requestedSeries: oldURL.Series,
		forceSeries:     c.ForceSeries,
		csParams:        csClient.params,
		repoPath:        ctx.AbsPath(c.RepoPath),
		conf:            conf,
	})
	if err != nil {
		return nil, errors.Trace(err)
	}
	if !c.ForceSeries && oldURL.Series != "" && newURL.Series == "" && !isSeriesSupported(oldURL.Series, supportedSeries) {
		series := []string{"no series"}
		if len(supportedSeries) > 0 {
			series = supportedSeries
		}
		return nil, errors.Errorf(
			"cannot upgrade from single series %q charm to a charm supporting %q. Use --force-series to override.",
			oldURL.Series, series,
		)
	}
	// If no explicit revision was set with either SwitchURL
	// or Revision flags, discover the latest.
	if *newURL == *oldURL {
		newRef, _ := charm.ParseURL(charmRef)
		if newRef.Revision != -1 {
			return nil, fmt.Errorf("already running specified charm %q", newURL)
		}
		if newURL.Schema == "cs" {
			// No point in trying to upgrade a charm store charm when
			// we just determined that's the latest revision
			// available.
			return nil, fmt.Errorf("already running latest charm %q", newURL)
		}
	}

	addedURL, err := addCharmFromURL(client, newURL, repo, csClient)
	if err != nil {
		return nil, err
	}
	ctx.Infof("Added charm %q to the model.", addedURL)
	return addedURL, nil
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Package rbac implements the authorizer.Authorizer interface using roles base access control.
package rbac

import (
	"fmt"

	"github.com/golang/glog"

	"k8s.io/apiserver/pkg/authentication/user"
	"k8s.io/apiserver/pkg/authorization/authorizer"
	"k8s.io/kubernetes/pkg/apis/rbac"
	rbacregistryvalidation "k8s.io/kubernetes/pkg/registry/rbac/validation"
)

type RequestToRuleMapper interface {
	// RulesFor returns all known PolicyRules and any errors that happened while locating those rules.
	// Any rule returned is still valid, since rules are deny by default.  If you can pass with the rules
	// supplied, you do not have to fail the request.  If you cannot, you should indicate the error along
	// with your denial.
	RulesFor(subject user.Info, namespace string) ([]rbac.PolicyRule, error)
}

type RBACAuthorizer struct {
	authorizationRuleResolver RequestToRuleMapper
}

func (r *RBACAuthorizer) Authorize(requestAttributes authorizer.Attributes) (bool, string, error) {
	rules, ruleResolutionError := r.authorizationRuleResolver.RulesFor(requestAttributes.GetUser(), requestAttributes.GetNamespace())
	if RulesAllow(requestAttributes, rules...) {
		return true, "", nil
	}

	// Build a detailed log of the denial.
	// Make the whole block conditional so we don't do a lot of string-building we won't use.
	if glog.V(2) {
		var operation string
		if requestAttributes.IsResourceRequest() {
			operation = fmt.Sprintf(
				"%q on \"%v.%v/%v\"",
				requestAttributes.GetVerb(),
				requestAttributes.GetResource(), requestAttributes.GetAPIGroup(), requestAttributes.GetSubresource(),
			)
		} else {
			operation = fmt.Sprintf("%q nonResourceURL %q", requestAttributes.GetVerb(), requestAttributes.GetPath())
		}

		var scope string
		if ns := requestAttributes.GetNamespace(); len(ns) > 0 {
			scope = fmt.Sprintf("in namespace %q", ns)
		} else {
			scope = "cluster-wide"
		}

		glog.Infof("RBAC DENY: user %q groups %v cannot %s %s", requestAttributes.GetUser().GetName(), requestAttributes.GetUser().GetGroups(), operation, scope)
	}

	reason := ""
	if ruleResolutionError != nil {
		reason = fmt.Sprintf("%v", ruleResolutionError)
	}
	return false, reason, nil
}

func New(roles rbacregistryvalidation.RoleGetter, roleBindings rbacregistryvalidation.RoleBindingLister, clusterRoles rbacregistryvalidation.ClusterRoleGetter, clusterRoleBindings rbacregistryvalidation.ClusterRoleBindingLister) *RBACAuthorizer {
	authorizer := &RBACAuthorizer{
		authorizationRuleResolver: rbacregistryvalidation.NewDefaultRuleResolver(
			roles, roleBindings, clusterRoles, clusterRoleBindings,
		),
	}
	return authorizer
}

func RulesAllow(requestAttributes authorizer.Attributes, rules ...rbac.PolicyRule) bool {
	for _, rule := range rules {
		if RuleAllows(requestAttributes, rule) {
			return true
		}
	}

	return false
}

func RuleAllows(requestAttributes authorizer.Attributes, rule rbac.PolicyRule) bool {
	if requestAttributes.IsResourceRequest() {
		resource := requestAttributes.GetResource()
		if len(requestAttributes.GetSubresource()) > 0 {
			resource = requestAttributes.GetResource() + "/" + requestAttributes.GetSubresource()
		}

		return rbac.VerbMatches(rule, requestAttributes.GetVerb()) &&
			rbac.APIGroupMatches(rule, requestAttributes.GetAPIGroup()) &&
			rbac.ResourceMatches(rule, resource) &&
			rbac.ResourceNameMatches(rule, requestAttributes.GetName())
	}

	return rbac.VerbMatches(rule, requestAttributes.GetVerb()) &&
		rbac.NonResourceURLMatches(rule, requestAttributes.GetPath())
}
<commit_msg>Add detailed RBAC deny logging<commit_after>/*
Copyright 2016 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Package rbac implements the authorizer.Authorizer interface using roles base access control.
package rbac

import (
	"fmt"

	"github.com/golang/glog"

	"bytes"

	"k8s.io/apiserver/pkg/authentication/user"
	"k8s.io/apiserver/pkg/authorization/authorizer"
	"k8s.io/kubernetes/pkg/apis/rbac"
	rbacregistryvalidation "k8s.io/kubernetes/pkg/registry/rbac/validation"
)

type RequestToRuleMapper interface {
	// RulesFor returns all known PolicyRules and any errors that happened while locating those rules.
	// Any rule returned is still valid, since rules are deny by default.  If you can pass with the rules
	// supplied, you do not have to fail the request.  If you cannot, you should indicate the error along
	// with your denial.
	RulesFor(subject user.Info, namespace string) ([]rbac.PolicyRule, error)
}

type RBACAuthorizer struct {
	authorizationRuleResolver RequestToRuleMapper
}

func (r *RBACAuthorizer) Authorize(requestAttributes authorizer.Attributes) (bool, string, error) {
	rules, ruleResolutionError := r.authorizationRuleResolver.RulesFor(requestAttributes.GetUser(), requestAttributes.GetNamespace())
	if RulesAllow(requestAttributes, rules...) {
		return true, "", nil
	}

	// Build a detailed log of the denial.
	// Make the whole block conditional so we don't do a lot of string-building we won't use.
	if glog.V(2) {
		var operation string
		if requestAttributes.IsResourceRequest() {
			b := &bytes.Buffer{}
			b.WriteString(`"`)
			b.WriteString(requestAttributes.GetVerb())
			b.WriteString(`" resource "`)
			b.WriteString(requestAttributes.GetResource())
			if len(requestAttributes.GetAPIGroup()) > 0 {
				b.WriteString(`.`)
				b.WriteString(requestAttributes.GetAPIGroup())
			}
			if len(requestAttributes.GetSubresource()) > 0 {
				b.WriteString(`/`)
				b.WriteString(requestAttributes.GetSubresource())
			}
			b.WriteString(`"`)
			if len(requestAttributes.GetName()) > 0 {
				b.WriteString(` named "`)
				b.WriteString(requestAttributes.GetName())
				b.WriteString(`"`)
			}
			operation = b.String()
		} else {
			operation = fmt.Sprintf("%q nonResourceURL %q", requestAttributes.GetVerb(), requestAttributes.GetPath())
		}

		var scope string
		if ns := requestAttributes.GetNamespace(); len(ns) > 0 {
			scope = fmt.Sprintf("in namespace %q", ns)
		} else {
			scope = "cluster-wide"
		}

		glog.Infof("RBAC DENY: user %q groups %v cannot %s %s", requestAttributes.GetUser().GetName(), requestAttributes.GetUser().GetGroups(), operation, scope)
	}

	reason := ""
	if ruleResolutionError != nil {
		reason = fmt.Sprintf("%v", ruleResolutionError)
	}
	return false, reason, nil
}

func New(roles rbacregistryvalidation.RoleGetter, roleBindings rbacregistryvalidation.RoleBindingLister, clusterRoles rbacregistryvalidation.ClusterRoleGetter, clusterRoleBindings rbacregistryvalidation.ClusterRoleBindingLister) *RBACAuthorizer {
	authorizer := &RBACAuthorizer{
		authorizationRuleResolver: rbacregistryvalidation.NewDefaultRuleResolver(
			roles, roleBindings, clusterRoles, clusterRoleBindings,
		),
	}
	return authorizer
}

func RulesAllow(requestAttributes authorizer.Attributes, rules ...rbac.PolicyRule) bool {
	for _, rule := range rules {
		if RuleAllows(requestAttributes, rule) {
			return true
		}
	}

	return false
}

func RuleAllows(requestAttributes authorizer.Attributes, rule rbac.PolicyRule) bool {
	if requestAttributes.IsResourceRequest() {
		resource := requestAttributes.GetResource()
		if len(requestAttributes.GetSubresource()) > 0 {
			resource = requestAttributes.GetResource() + "/" + requestAttributes.GetSubresource()
		}

		return rbac.VerbMatches(rule, requestAttributes.GetVerb()) &&
			rbac.APIGroupMatches(rule, requestAttributes.GetAPIGroup()) &&
			rbac.ResourceMatches(rule, resource) &&
			rbac.ResourceNameMatches(rule, requestAttributes.GetName())
	}

	return rbac.VerbMatches(rule, requestAttributes.GetVerb()) &&
		rbac.NonResourceURLMatches(rule, requestAttributes.GetPath())
}
<|endoftext|>