<commit_before>package uritemplates

import (
	"encoding/json"
	"os"
	"testing"
)

type spec struct {
	title  string
	values map[string]interface{}
	tests  []specTest
}
type specTest struct {
	template string
	expected []string
}

func loadSpec(t *testing.T, path string) []spec {

	file, err := os.Open(path)
	if err != nil {
		t.Errorf("Failed to load test specification: %s", err)
	}

	stat, _ := file.Stat()
	buffer := make([]byte, stat.Size())
	_, err = file.Read(buffer)
	if err != nil {
		t.Errorf("Failed to load test specification: %s", err)
	}

	var root_ interface{}
	err = json.Unmarshal(buffer, &root_)
	if err != nil {
		t.Errorf("Failed to load test specification: %s", err)
	}

	root := root_.(map[string]interface{})
	results := make([]spec, 1024)
	i := -1
	for title, spec_ := range root {
		i = i + 1
		results[i].title = title
		specMap := spec_.(map[string]interface{})
		results[i].values = specMap["variables"].(map[string]interface{})
		tests := specMap["testcases"].([]interface{})
		results[i].tests = make([]specTest, len(tests))
		for k, test_ := range tests {
			test := test_.([]interface{})
			results[i].tests[k].template = test[0].(string)
			switch typ := test[1].(type) {
			case string:
				results[i].tests[k].expected = make([]string, 1)
				results[i].tests[k].expected[0] = test[1].(string)
			case []interface{}:
				arr := test[1].([]interface{})
				results[i].tests[k].expected = make([]string, len(arr))
				for m, s := range arr {
					results[i].tests[k].expected[m] = s.(string)
				}
			default:
				t.Errorf("Unrecognized value type %v", typ)
			}
		}
	}
	return results
}

func TestStandards(t *testing.T) {
	var spec = loadSpec(t, "tests/spec-examples-by-section.json")
	for _, group := range spec {
		for _, test := range group.tests {
			template, err := Parse(test.template)
			if err != nil {
				t.Errorf("%s: %s %v", group.title, err, test.template)
			}
			result := template.ExpandString(group.values)
			pass := false
			for _, expected := range test.expected {
				if result == expected {
					pass = true
				}
			}
			if !pass {
				t.Errorf("%s: expected %v, but got %v", group.title, test.expected[0], result)
			}
		}
	}
}
<commit_msg>Include extended tests.<commit_after>package uritemplates

import (
	"encoding/json"
	"os"
	"testing"
)

type spec struct {
	title  string
	values map[string]interface{}
	tests  []specTest
}
type specTest struct {
	template string
	expected []string
}

func loadSpec(t *testing.T, path string) []spec {

	file, err := os.Open(path)
	if err != nil {
		t.Errorf("Failed to load test specification: %s", err)
	}

	stat, _ := file.Stat()
	buffer := make([]byte, stat.Size())
	_, err = file.Read(buffer)
	if err != nil {
		t.Errorf("Failed to load test specification: %s", err)
	}

	var root_ interface{}
	err = json.Unmarshal(buffer, &root_)
	if err != nil {
		t.Errorf("Failed to load test specification: %s", err)
	}

	root := root_.(map[string]interface{})
	results := make([]spec, 1024)
	i := -1
	for title, spec_ := range root {
		i = i + 1
		results[i].title = title
		specMap := spec_.(map[string]interface{})
		results[i].values = specMap["variables"].(map[string]interface{})
		tests := specMap["testcases"].([]interface{})
		results[i].tests = make([]specTest, len(tests))
		for k, test_ := range tests {
			test := test_.([]interface{})
			results[i].tests[k].template = test[0].(string)
			switch typ := test[1].(type) {
			case string:
				results[i].tests[k].expected = make([]string, 1)
				results[i].tests[k].expected[0] = test[1].(string)
			case []interface{}:
				arr := test[1].([]interface{})
				results[i].tests[k].expected = make([]string, len(arr))
				for m, s := range arr {
					results[i].tests[k].expected[m] = s.(string)
				}
			default:
				t.Errorf("Unrecognized value type %v", typ)
			}
		}
	}
	return results
}

func runSpec(t *testing.T, path string) {
	var spec = loadSpec(t, path)
	for _, group := range spec {
		for _, test := range group.tests {
			template, err := Parse(test.template)
			if err != nil {
				t.Errorf("%s: %s %v", group.title, err, test.template)
			}
			result := template.ExpandString(group.values)
			pass := false
			for _, expected := range test.expected {
				if result == expected {
					pass = true
				}
			}
			if !pass {
				t.Errorf("%s: expected %v, but got %v", group.title, test.expected[0], result)
			}
		}
	}
}

func TestExtended(t *testing.T) {
	runSpec(t, "tests/extended-tests.json")
}

func TestSpecExamples(t *testing.T) {
	runSpec(t, "tests/spec-examples.json")
}
<|endoftext|>


<commit_before>package client

import (
	"net/http"

	"github.com/pkg/errors"
)

type (
	ClientConfig struct {
		GitUrlPattern string `json:"gitUrlPattern"`
		ApiVersion    string `json:"apiVersion"`
	}
)

func (api *ApiClient) GetClientConfig() (*ClientConfig, error) {
	endpoint := "/clientconfig/"

	response, err := api.Do(http.MethodGet, endpoint, nil)
	if err != nil {
		return nil, err
	}

	var gc ClientConfig
	err = response.ParseFirstItem(&gc)
	if err != nil {
		return nil, errors.Wrap(err, "git config")
	}

	return &gc, nil
}
<commit_msg>Fixed endpoint in GetClientConfig (#121)<commit_after>package client

import (
	"net/http"

	"github.com/pkg/errors"
)

type (
	ClientConfig struct {
		GitUrlPattern string `json:"gitUrlPattern"`
		ApiVersion    string `json:"apiVersion"`
	}
)

func (api *ApiClient) GetClientConfig() (*ClientConfig, error) {
	endpoint := "/clientconfig"

	response, err := api.Do(http.MethodGet, endpoint, nil)
	if err != nil {
		return nil, err
	}

	var gc ClientConfig
	err = response.ParseFirstItem(&gc)
	if err != nil {
		return nil, errors.Wrap(err, "git config")
	}

	return &gc, nil
}
<|endoftext|>


<commit_before>package cmd

import (
	"context"
	"github.com/containers/image/v5/transports/alltransports"
	"github.com/containers/image/v5/types"
	"github.com/spf13/cobra"

	"github.com/openshift/source-to-image/pkg/api"
	"github.com/openshift/source-to-image/pkg/api/constants"
	"github.com/openshift/source-to-image/pkg/build/strategies/dockerfile"
	"github.com/openshift/source-to-image/pkg/util/fs"
)

// getImageLabels attempts to inspect an image existing in a remote registry.
func getImageLabels(ctx context.Context, ref types.ImageReference) (map[string]string, error) {
	img, err := ref.NewImage(ctx, &types.SystemContext{})
	if err != nil {
		return nil, err
	}

	imageMetadata, err := img.Inspect(ctx)
	if err != nil {
		return nil, err
	}

	return imageMetadata.Labels, nil
}

// generateDockerfile generates a Dockerfile with the given configuration.
func generateDockerfile(cfg *api.Config) error {
	fileSystem := fs.NewFileSystem()
	builder, err := dockerfile.New(cfg, fileSystem)
	if err != nil {
		return err
	}

	_, err = builder.Build(cfg)
	if err != nil {
		return err
	}

	return nil
}

// adjustConfigWithImageLabels adjusts the configuration with given labels.
func adjustConfigWithImageLabels(cfg *api.Config, labels map[string]string) {
	if v, ok := labels[constants.ScriptsURLLabel]; ok {
		cfg.ScriptsURL = v
	}

	if v, ok := labels[constants.DestinationLabel]; ok {
		cfg.Destination = v
	}

}

// NewCmdGenerate implements the S2I cli generate command.
func NewCmdGenerate(cfg *api.Config) *cobra.Command {
	generateCmd := &cobra.Command{
		Use:   "generate <image> <dockerfile>",
		Short: "Generate a Dockerfile based on the provided builder image",
		Example: `
# Generate a Dockerfile from a builder image:
$ s2i generate docker://docker.io/centos/nodejs-10-centos7 Dockerfile.gen
`,
		RunE: func(cmd *cobra.Command, _ []string) error {
			if cmd.Flags().NArg() != 2 {
				return cmd.Help()
			}

			ref, err := alltransports.ParseImageName(cmd.Flags().Arg(0))
			if err != nil {
				return err
			}

			cfg.BuilderImage = ref.DockerReference().Name()
			cfg.AsDockerfile = cmd.Flags().Arg(1)

			ctx := context.Background()
			var imageLabels map[string]string
			if imageLabels, err = getImageLabels(ctx, ref); err != nil {
				return err
			}

			adjustConfigWithImageLabels(cfg, imageLabels)
			return generateDockerfile(cfg)
		},
	}

	generateCmd.Flags().BoolVarP(&(cfg.Quiet), "quiet", "q", false, "Operate quietly. Suppress all non-error output.")
	generateCmd.Flags().VarP(&(cfg.Environment), "env", "e", "Specify an single environment variable in NAME=VALUE format")
	generateCmd.Flags().StringVarP(&(cfg.AssembleUser), "assemble-user", "", "", "Specify the user to run assemble with")
	generateCmd.Flags().StringVarP(&(cfg.AssembleRuntimeUser), "assemble-runtime-user", "", "", "Specify the user to run assemble-runtime with")

	return generateCmd
}
<commit_msg>Sync docs and command usage<commit_after>package cmd

import (
	"context"
	"github.com/containers/image/v5/transports/alltransports"
	"github.com/containers/image/v5/types"
	"github.com/spf13/cobra"

	"github.com/openshift/source-to-image/pkg/api"
	"github.com/openshift/source-to-image/pkg/api/constants"
	"github.com/openshift/source-to-image/pkg/build/strategies/dockerfile"
	"github.com/openshift/source-to-image/pkg/util/fs"
)

// getImageLabels attempts to inspect an image existing in a remote registry.
func getImageLabels(ctx context.Context, ref types.ImageReference) (map[string]string, error) {
	img, err := ref.NewImage(ctx, &types.SystemContext{})
	if err != nil {
		return nil, err
	}

	imageMetadata, err := img.Inspect(ctx)
	if err != nil {
		return nil, err
	}

	return imageMetadata.Labels, nil
}

// generateDockerfile generates a Dockerfile with the given configuration.
func generateDockerfile(cfg *api.Config) error {
	fileSystem := fs.NewFileSystem()
	builder, err := dockerfile.New(cfg, fileSystem)
	if err != nil {
		return err
	}

	_, err = builder.Build(cfg)
	if err != nil {
		return err
	}

	return nil
}

// adjustConfigWithImageLabels adjusts the configuration with given labels.
func adjustConfigWithImageLabels(cfg *api.Config, labels map[string]string) {
	if v, ok := labels[constants.ScriptsURLLabel]; ok {
		cfg.ScriptsURL = v
	}

	if v, ok := labels[constants.DestinationLabel]; ok {
		cfg.Destination = v
	}

}

// NewCmdGenerate implements the S2I cli generate command.
func NewCmdGenerate(cfg *api.Config) *cobra.Command {
	generateCmd := &cobra.Command{
		Use: "generate <image> <dockerfile>",
		Short: "Generate a Dockerfile using an existing S2I builder	image " +
			"that can be used to produce an image by any application " +
			"supporting the format.",
		Example: `
# Generate a Dockerfile for the centos/nodejs-10-centos7 builder image:
$ s2i generate docker://docker.io/centos/nodejs-10-centos7 Dockerfile.gen
`,
		RunE: func(cmd *cobra.Command, _ []string) error {
			if cmd.Flags().NArg() != 2 {
				return cmd.Help()
			}

			ref, err := alltransports.ParseImageName(cmd.Flags().Arg(0))
			if err != nil {
				return err
			}

			cfg.BuilderImage = ref.DockerReference().Name()
			cfg.AsDockerfile = cmd.Flags().Arg(1)

			ctx := context.Background()
			var imageLabels map[string]string
			if imageLabels, err = getImageLabels(ctx, ref); err != nil {
				return err
			}

			adjustConfigWithImageLabels(cfg, imageLabels)
			return generateDockerfile(cfg)
		},
	}

	generateCmd.Flags().BoolVarP(&(cfg.Quiet), "quiet", "q", false, "Operate quietly. Suppress all non-error output.")
	generateCmd.Flags().VarP(&(cfg.Environment), "env", "e", "Specify an single environment variable in NAME=VALUE format")
	generateCmd.Flags().StringVarP(&(cfg.AssembleUser), "assemble-user", "", "", "Specify the user to run assemble with")
	generateCmd.Flags().StringVarP(&(cfg.AssembleRuntimeUser), "assemble-runtime-user", "", "", "Specify the user to run assemble-runtime with")

	return generateCmd
}
<|endoftext|>


<commit_before>package cxxtypes

// Id is a C/C++ identifier
type Id interface {
	// IdName returns the name of this identifier
	// e.g. my_fct
	//      MyClass
	//      vector<int>
	//      fabs
	//      g_some_global_variable
	IdName() string

	// IdScopedName returns the scoped name of this identifier
	// e.g. some_namespace::my_fct
	//      SomeOtherNamespace::MyClass
	//      std::vector<int>
	//      std::fabs
	//      g_some_global_variable
	IdScopedName() string

	// IdKind returns the kind of this identifier
	//  IK_Var | IK_Typ | IK_Fct | IK_Nsp
	IdKind() IdKind
}

// IdKind represents the specific kind of identifier an Id represents.
// The zero IdKind is not a valid kind.
type IdKind uint

const (
	IK_Invalid IdKind = iota

	IK_Var // a variable
	IK_Typ // a type (class, fct type, struct, enum, ...)
	IK_Fct // a function, operator function, method, method operator, ...
	IK_Nsp // a namespace
)

// the db of all identifiers
var g_ids map[string]Id

// IdByName retrieves an identifier by its fully qualified name.
// Returns nil if no such identifier exists.
func IdByName(n string) Id {
	id, ok := g_ids[n]
	if ok {
		return id
	}
	return nil
}

// IdNames returns the list of identifier names currently defined.
func IdNames() []string {
	names := make([]string, 0, len(g_ids))
	for k, _ := range g_ids {
		names = append(names, k)
	}
	return names
}

// NumId returns the number of currently defined identifiers
func NumId() int {
	return len(g_ids)
}

// idBase implements the Id interface
type idBase struct {
	name        string
	scoped_name string
	kind        IdKind
}

func (id *idBase) IdName() string {
	return id.name
}

func (id *idBase) IdScopedName() string {
	return id.scoped_name
}

func (id *idBase) IdKind() IdKind {
	return id.kind
}

// Function represents a function identifier
//  e.g. std::fabs
type Function struct {
	idBase `cxxtypes:"function"`
	tspec      TypeSpecifier // or'ed value of virtual/inline/...
	variadic   bool          // whether this function is variadic
	params     []Parameter   // the parameters to this function
	ret        Type          // return type of this function
}

// NewFunction returns a new function identifier
func NewFunction(name, scoped_name string, qual TypeQualifier, specifiers TypeSpecifier, variadic bool, params []Parameter, ret Type) *Function {
	id := &Function{
		idBase: idBase{
			name: name,
			scoped_name: scoped_name,
			kind: IK_Fct,
		},
		tspec:    specifiers,
		variadic: variadic,
		params:   make([]Parameter, 0, len(params)),
		ret:      ret,
	}
	return id
}

// Specifier returns the type specifier for this function
func (t *Function) Specifier() TypeSpecifier {
	return t.tspec
}

func (t *Function) IsVirtual() bool {
	return (t.tspec & TS_Virtual) != 0
}

func (t *Function) IsStatic() bool {
	return (t.tspec & TS_Static) != 0
}

func (t *Function) IsConstructor() bool {
	return (t.tspec & TS_Constructor) != 0
}

func (t *Function) IsDestructor() bool {
	return (t.tspec & TS_Destructor) != 0
}

func (t *Function) IsCopyConstructor() bool {
	return (t.tspec & TS_CopyCtor) != 0
}

func (t *Function) IsOperator() bool {
	return (t.tspec & TS_Operator) != 0
}

func (t *Function) IsMethod() bool {
	return (t.tspec & TS_Method) != 0
}

func (t *Function) IsInline() bool {
	return (t.tspec & TS_Inline) != 0
}

func (t *Function) IsConverter() bool {
	return (t.tspec & TS_Converter) != 0
}

// IsVariadic returns whether this function is variadic
func (t *Function) IsVariadic() bool {
	return t.variadic
}

// NumParam returns a function's input parameter count.
func (t *Function) NumParam() int {
	return len(t.params)
}

// Param returns the i'th parameter of this function.
// It panics if i is not in the range [0, NumParam())
func (t *Function) Param(i int) *Parameter {
	if i < 0 || i >= t.NumParam() {
		panic("cxxtypes: Param index out of range")
	}
	return &t.params[i]
}

// NumDefaultParam returns the number of parameters of a function's input which have a default value.
func (t *Function) NumDefaultParam() int {
	n := 0
	for i, _ := range t.params {
		if t.params[i].defval {
			n += 1
		}
	}
	return n
}

// ReturnType returns the return type of this function.
// FIXME: return nil for 'void' fct ?
// FIXME: return nil for ctor/dtor ?
func (t *Function) ReturnType() Type {
	return t.ret
}

// OverloadFunctionSet is a set of functions which are part of the same overload
type OverloadFunctionSet struct {
	idBase `cxxtypes:"overloadfctset"`
	fcts []*Function
}

// NumFunction returns the number of overloads in that set
func (id *OverloadFunctionSet) NumFunction() int {
	return len(id.fcts)
}

// Function returns the i-th overloaded function in the set
// It panics if i is not in the range [0, NumFunction())
func (id *OverloadFunctionSet) Function(i int) *Function {
	if i < 0 || i >= id.NumFunction() {
		panic("cxxtypes: Function index out of range")
	}
	return id.fcts[i]
}

// ----------------------------------------------------------------------------
// make sure the interfaces are implemented
var _ Id = (*Function)(nil)
var _ Id = (*OverloadFunctionSet)(nil)

// EOF
<commit_msg>added embryo of an overload function set<commit_after>package cxxtypes

// Id is a C/C++ identifier
type Id interface {
	// IdName returns the name of this identifier
	// e.g. my_fct
	//      MyClass
	//      vector<int>
	//      fabs
	//      g_some_global_variable
	IdName() string

	// IdScopedName returns the scoped name of this identifier
	// e.g. some_namespace::my_fct
	//      SomeOtherNamespace::MyClass
	//      std::vector<int>
	//      std::fabs
	//      g_some_global_variable
	IdScopedName() string

	// IdKind returns the kind of this identifier
	//  IK_Var | IK_Typ | IK_Fct | IK_Nsp
	IdKind() IdKind
}

// IdKind represents the specific kind of identifier an Id represents.
// The zero IdKind is not a valid kind.
type IdKind uint

const (
	IK_Invalid IdKind = iota

	IK_Var // a variable
	IK_Typ // a type (class, fct type, struct, enum, ...)
	IK_Fct // a function, operator function, method, method operator, ...
	IK_Nsp // a namespace
)

// the db of all identifiers
var g_ids map[string]Id

// IdByName retrieves an identifier by its fully qualified name.
// Returns nil if no such identifier exists.
func IdByName(n string) Id {
	id, ok := g_ids[n]
	if ok {
		return id
	}
	return nil
}

// IdNames returns the list of identifier names currently defined.
func IdNames() []string {
	names := make([]string, 0, len(g_ids))
	for k, _ := range g_ids {
		names = append(names, k)
	}
	return names
}

// NumId returns the number of currently defined identifiers
func NumId() int {
	return len(g_ids)
}

// idBase implements the Id interface
type idBase struct {
	name        string
	scoped_name string
	kind        IdKind
}

func (id *idBase) IdName() string {
	return id.name
}

func (id *idBase) IdScopedName() string {
	return id.scoped_name
}

func (id *idBase) IdKind() IdKind {
	return id.kind
}

// Function represents a function identifier
//  e.g. std::fabs
type Function struct {
	idBase `cxxtypes:"function"`
	tspec      TypeSpecifier // or'ed value of virtual/inline/...
	variadic   bool          // whether this function is variadic
	params     []Parameter   // the parameters to this function
	ret        Type          // return type of this function
}

// NewFunction returns a new function identifier
func NewFunction(name, scoped_name string, qual TypeQualifier, specifiers TypeSpecifier, variadic bool, params []Parameter, ret Type) *Function {
	id := &Function{
		idBase: idBase{
			name: name,
			scoped_name: scoped_name,
			kind: IK_Fct,
		},
		tspec:    specifiers,
		variadic: variadic,
		params:   make([]Parameter, 0, len(params)),
		ret:      ret,
	}
	return id
}

// Specifier returns the type specifier for this function
func (t *Function) Specifier() TypeSpecifier {
	return t.tspec
}

func (t *Function) IsVirtual() bool {
	return (t.tspec & TS_Virtual) != 0
}

func (t *Function) IsStatic() bool {
	return (t.tspec & TS_Static) != 0
}

func (t *Function) IsConstructor() bool {
	return (t.tspec & TS_Constructor) != 0
}

func (t *Function) IsDestructor() bool {
	return (t.tspec & TS_Destructor) != 0
}

func (t *Function) IsCopyConstructor() bool {
	return (t.tspec & TS_CopyCtor) != 0
}

func (t *Function) IsOperator() bool {
	return (t.tspec & TS_Operator) != 0
}

func (t *Function) IsMethod() bool {
	return (t.tspec & TS_Method) != 0
}

func (t *Function) IsInline() bool {
	return (t.tspec & TS_Inline) != 0
}

func (t *Function) IsConverter() bool {
	return (t.tspec & TS_Converter) != 0
}

// IsVariadic returns whether this function is variadic
func (t *Function) IsVariadic() bool {
	return t.variadic
}

// NumParam returns a function's input parameter count.
func (t *Function) NumParam() int {
	return len(t.params)
}

// Param returns the i'th parameter of this function.
// It panics if i is not in the range [0, NumParam())
func (t *Function) Param(i int) *Parameter {
	if i < 0 || i >= t.NumParam() {
		panic("cxxtypes: Param index out of range")
	}
	return &t.params[i]
}

// NumDefaultParam returns the number of parameters of a function's input which have a default value.
func (t *Function) NumDefaultParam() int {
	n := 0
	for i, _ := range t.params {
		if t.params[i].defval {
			n += 1
		}
	}
	return n
}

// ReturnType returns the return type of this function.
// FIXME: return nil for 'void' fct ?
// FIXME: return nil for ctor/dtor ?
func (t *Function) ReturnType() Type {
	return t.ret
}

// OverloadFunctionSet is a set of functions which are part of the same overload
type OverloadFunctionSet struct {
	idBase `cxxtypes:"overloadfctset"`
	fcts []*Function
}

// NumFunction returns the number of overloads in that set
func (id *OverloadFunctionSet) NumFunction() int {
	return len(id.fcts)
}

// Function returns the i-th overloaded function in the set
// It panics if i is not in the range [0, NumFunction())
func (id *OverloadFunctionSet) Function(i int) *Function {
	if i < 0 || i >= id.NumFunction() {
		panic("cxxtypes: Function index out of range")
	}
	return id.fcts[i]
}

// ----------------------------------------------------------------------------
// make sure the interfaces are implemented

var _ Id = (*Function)(nil)
var _ Id = (*OverloadFunctionSet)(nil)

// EOF
<|endoftext|>


<commit_before>/*
Copyright 2020 Google LLC

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 signer

import (
	"github.com/golang/glog"
	"github.com/grafeas/kritis/pkg/kritis/apis/kritis/v1beta1"
	"github.com/grafeas/kritis/pkg/kritis/attestation"
	"github.com/grafeas/kritis/pkg/kritis/crd/authority"
	"github.com/grafeas/kritis/pkg/kritis/cryptolib"
	"github.com/grafeas/kritis/pkg/kritis/metadata"
	"github.com/grafeas/kritis/pkg/kritis/util"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// A signer is used for creating attestations for an image.
type Signer struct {
	config *config
	client metadata.ReadWriteClient
}

// A signer config that includes necessary data and handler for signing.
type config struct {
	cSigner cryptolib.Signer
	// an AttestaionAuthority that is used in metadata client APIs.
	// We should consider refactor it out because:
	// 1. the only useful field here is noteName
	// 2. other fields, e.g., public key, are unset
	// TODO: refactor out the authority code
	authority v1beta1.AttestationAuthority
	project   string
}

// Creating a new signer object.
func New(client metadata.ReadWriteClient, cSigner cryptolib.Signer, noteName string, project string) Signer {
	return Signer{
		client: client,
		config: &config{
			cSigner,
			v1beta1.AttestationAuthority{
				ObjectMeta: metav1.ObjectMeta{Name: "signing-aa"},
				Spec: v1beta1.AttestationAuthoritySpec{
					NoteReference: noteName,
					PublicKeys:    []v1beta1.PublicKey{},
				},
			},
			project,
		},
	}
}

// ImageVulnerabilities is an input for running vulnerability policy validation.
type ImageVulnerabilities struct {
	ImageRef        string
	Vulnerabilities []metadata.Vulnerability
}

// For testing
var (
	authFetcher = authority.Authority
)

// SignImage signs an image without doing any policy check.
// Returns an error if creating an attestation fails.
func (s Signer) SignImage(image string) error {
	existed, _ := s.isAttestationAlreadyExist(image)
	if existed {
		glog.Warningf("Attestation for image %q has already been created.", image)
		return nil
	}

	glog.Infof("Creating attestation for image %q.", image)
	// Create attestation
	att, err := s.createAttestation(image)
	if err != nil {
		return err
	}
	glog.Infof("Attestation for image %q is successfully created locally.", image)

	glog.Infof("Uploading attestation for image %q.", image)
	if err := s.uploadAttestation(image, att); err != nil {
		return err
	}
	glog.Infof("Attestation for image %q is successfully uploaded.", image)

	return nil
}

// Creating an atestation.
func (s Signer) createAttestation(image string) (*cryptolib.Attestation, error) {
	payload, err := attestation.AtomicContainerPayload(image)
	if err != nil {
		return nil, err
	}

	att, err := s.config.cSigner.CreateAttestation(payload)
	if err != nil {
		return nil, err
	}
	return att, nil
}

// Uploading an attestation if not already exist under the same note.
// The method will create a note if it does not already exist.
// Returns error if upload failed, e.g., if an attestation already exists.
func (s Signer) uploadAttestation(image string, att *cryptolib.Attestation) error {
	note, err := util.GetOrCreateAttestationNote(s.client, &s.config.authority)
	if err != nil {
		return err
	}

	// Upload attestation
	_, err = s.client.UploadAttestationOccurrence(note.GetName(), image, att, s.config.project, metadata.PgpSignatureType)
	return err
}

func (s Signer) isAttestationAlreadyExist(image string) (bool, error) {
	atts, err := s.client.Attestations(image, &s.config.authority)
	if err == nil && len(atts) > 0 {
		return true, nil
	}

	return false, err
}
<commit_msg>Upload generic attestation instead of pgp attestation.<commit_after>/*
Copyright 2020 Google LLC

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 signer

import (
	"github.com/golang/glog"
	"github.com/grafeas/kritis/pkg/kritis/apis/kritis/v1beta1"
	"github.com/grafeas/kritis/pkg/kritis/attestation"
	"github.com/grafeas/kritis/pkg/kritis/crd/authority"
	"github.com/grafeas/kritis/pkg/kritis/cryptolib"
	"github.com/grafeas/kritis/pkg/kritis/metadata"
	"github.com/grafeas/kritis/pkg/kritis/util"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// A signer is used for creating attestations for an image.
type Signer struct {
	config *config
	client metadata.ReadWriteClient
}

// A signer config that includes necessary data and handler for signing.
type config struct {
	cSigner cryptolib.Signer
	// an AttestaionAuthority that is used in metadata client APIs.
	// We should consider refactor it out because:
	// 1. the only useful field here is noteName
	// 2. other fields, e.g., public key, are unset
	// TODO: refactor out the authority code
	authority v1beta1.AttestationAuthority
	project   string
}

// Creating a new signer object.
func New(client metadata.ReadWriteClient, cSigner cryptolib.Signer, noteName string, project string) Signer {
	return Signer{
		client: client,
		config: &config{
			cSigner,
			v1beta1.AttestationAuthority{
				ObjectMeta: metav1.ObjectMeta{Name: "signing-aa"},
				Spec: v1beta1.AttestationAuthoritySpec{
					NoteReference: noteName,
					PublicKeys:    []v1beta1.PublicKey{},
				},
			},
			project,
		},
	}
}

// ImageVulnerabilities is an input for running vulnerability policy validation.
type ImageVulnerabilities struct {
	ImageRef        string
	Vulnerabilities []metadata.Vulnerability
}

// For testing
var (
	authFetcher = authority.Authority
)

// SignImage signs an image without doing any policy check.
// Returns an error if creating an attestation fails.
func (s Signer) SignImage(image string) error {
	existed, _ := s.isAttestationAlreadyExist(image)
	if existed {
		glog.Warningf("Attestation for image %q has already been created.", image)
		return nil
	}

	glog.Infof("Creating attestation for image %q.", image)
	// Create attestation
	att, err := s.createAttestation(image)
	if err != nil {
		return err
	}
	glog.Infof("Attestation for image %q is successfully created locally.", image)

	glog.Infof("Uploading attestation for image %q.", image)
	if err := s.uploadAttestation(image, att); err != nil {
		return err
	}
	glog.Infof("Attestation for image %q is successfully uploaded.", image)

	return nil
}

// Creating an atestation.
func (s Signer) createAttestation(image string) (*cryptolib.Attestation, error) {
	payload, err := attestation.AtomicContainerPayload(image)
	if err != nil {
		return nil, err
	}

	att, err := s.config.cSigner.CreateAttestation(payload)
	if err != nil {
		return nil, err
	}
	return att, nil
}

// Uploading an attestation if not already exist under the same note.
// The method will create a note if it does not already exist.
// Returns error if upload failed, e.g., if an attestation already exists.
func (s Signer) uploadAttestation(image string, att *cryptolib.Attestation) error {
	note, err := util.GetOrCreateAttestationNote(s.client, &s.config.authority)
	if err != nil {
		return err
	}

	// Upload attestation
	_, err = s.client.UploadAttestationOccurrence(note.GetName(), image, att, s.config.project, metadata.GenericSignatureType)
	return err
}

func (s Signer) isAttestationAlreadyExist(image string) (bool, error) {
	atts, err := s.client.Attestations(image, &s.config.authority)
	if err == nil && len(atts) > 0 {
		return true, nil
	}

	return false, err
}
<|endoftext|>


<commit_before>// Copyright 2017 the gousb Authors.  All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package usb

import (
	"reflect"
	"testing"
	"time"
)

func TestEndpoint(t *testing.T) {
	defer func(i libusbIntf) { libusb = i }(libusb)
	for _, epCfg := range []struct {
		method string
		InterfaceSetup
		EndpointInfo
	}{
		{"Read", testBulkInSetup, testBulkInEP},
		{"Write", testIsoOutSetup, testIsoOutEP},
	} {
		t.Run(epCfg.method, func(t *testing.T) {
			for _, tc := range []struct {
				desc    string
				buf     []byte
				ret     int
				status  TransferStatus
				want    int
				wantErr bool
			}{
				{
					desc: "empty buffer",
					buf:  nil,
					ret:  10,
					want: 0,
				},
				{
					desc: "128B buffer, 60 transferred",
					buf:  make([]byte, 128),
					ret:  60,
					want: 60,
				},
				{
					desc:    "128B buffer, 10 transferred and then error",
					buf:     make([]byte, 128),
					ret:     10,
					status:  LIBUSB_TRANSFER_ERROR,
					want:    10,
					wantErr: true,
				},
			} {
				lib := newFakeLibusb()
				libusb = lib
				ep := newEndpoint(nil, epCfg.InterfaceSetup, epCfg.EndpointInfo, time.Second, time.Second)
				op, ok := reflect.TypeOf(ep).MethodByName(epCfg.method)
				if !ok {
					t.Fatalf("method %s not found in endpoint struct", epCfg.method)
				}
				go func() {
					fakeT := lib.waitForSubmitted()
					fakeT.length = tc.ret
					fakeT.status = tc.status
					close(fakeT.done)
				}()
				opv := op.Func.Interface().(func(*endpoint, []byte) (int, error))
				got, err := opv(ep, tc.buf)
				if (err != nil) != tc.wantErr {
					t.Errorf("%s: bulkInEP.Read(): got err: %v, err != nil is %v, want %v", tc.desc, err, err != nil, tc.wantErr)
					continue
				}
				if got != tc.want {
					t.Errorf("%s: bulkInEP.Read(): got %d bytes, want %d", tc.desc, got, tc.want)
				}
			}
		})
	}
}

func TestEndpointWrongDirection(t *testing.T) {
	ep := &endpoint{
		InterfaceSetup: testBulkInSetup,
		EndpointInfo:   testBulkInEP,
	}
	_, err := ep.Write([]byte{1, 2, 3})
	if err == nil {
		t.Error("bulkInEP.Write(): got nil error, want non-nil")
	}
	ep = &endpoint{
		InterfaceSetup: testIsoOutSetup,
		EndpointInfo:   testIsoOutEP,
	}
	_, err = ep.Read(make([]byte, 64))
	if err == nil {
		t.Error("isoOutEP.Read(): got nil error, want non-nil")
	}
}

func TestOpenEndpoint(t *testing.T) {
	origLib := libusb
	defer func() { libusb = origLib }()
	libusb = newFakeLibusb()

	c := NewContext()
	dev, err := c.OpenDeviceWithVidPid(0x8888, 0x0002)
	if dev == nil {
		t.Fatal("OpenDeviceWithVidPid(0x8888, 0x0002): got nil device, need non-nil")
	}
	defer dev.Close()
	if err != nil {
		t.Fatalf("OpenDeviceWithVidPid(0x8888, 0x0002): got error %v, want nil", err)
	}
	ep, err := dev.OpenEndpoint(1, 1, 1, 0x86)
	if err != nil {
		t.Errorf("OpenEndpoint(cfg=1, if=1, alt=1, ep=0x86): got error %v, want nil", err)
	}
	i := ep.Info()
	if got, want := i.Address, uint8(0x86); got != want {
		t.Errorf("OpenEndpoint(cfg=1, if=1, alt=2, ep=0x86): ep.Info.Address = %x, want %x", got, want)
	}
	if got, want := i.MaxIsoPacket, uint32(2*1024); got != want {
		t.Errorf("OpenEndpoint(cfg=1, if=1, alt=2, ep=0x86): ep.Info.MaxIsoPacket = %d, want %d", got, want)
	}
}
<commit_msg>fix test descriptions<commit_after>// Copyright 2017 the gousb Authors.  All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package usb

import (
	"reflect"
	"testing"
	"time"
)

func TestEndpoint(t *testing.T) {
	defer func(i libusbIntf) { libusb = i }(libusb)
	for _, epCfg := range []struct {
		method string
		InterfaceSetup
		EndpointInfo
	}{
		{"Read", testBulkInSetup, testBulkInEP},
		{"Write", testIsoOutSetup, testIsoOutEP},
	} {
		t.Run(epCfg.method, func(t *testing.T) {
			for _, tc := range []struct {
				desc    string
				buf     []byte
				ret     int
				status  TransferStatus
				want    int
				wantErr bool
			}{
				{
					desc: "empty buffer",
					buf:  nil,
					ret:  10,
					want: 0,
				},
				{
					desc: "128B buffer, 60 transferred",
					buf:  make([]byte, 128),
					ret:  60,
					want: 60,
				},
				{
					desc:    "128B buffer, 10 transferred and then error",
					buf:     make([]byte, 128),
					ret:     10,
					status:  LIBUSB_TRANSFER_ERROR,
					want:    10,
					wantErr: true,
				},
			} {
				lib := newFakeLibusb()
				libusb = lib
				ep := newEndpoint(nil, epCfg.InterfaceSetup, epCfg.EndpointInfo, time.Second, time.Second)
				op, ok := reflect.TypeOf(ep).MethodByName(epCfg.method)
				if !ok {
					t.Fatalf("method %s not found in endpoint struct", epCfg.method)
				}
				go func() {
					fakeT := lib.waitForSubmitted()
					fakeT.length = tc.ret
					fakeT.status = tc.status
					close(fakeT.done)
				}()
				opv := op.Func.Interface().(func(*endpoint, []byte) (int, error))
				got, err := opv(ep, tc.buf)
				if (err != nil) != tc.wantErr {
					t.Errorf("%s: bulkInEP.Read(): got err: %v, err != nil is %v, want %v", tc.desc, err, err != nil, tc.wantErr)
					continue
				}
				if got != tc.want {
					t.Errorf("%s: bulkInEP.Read(): got %d bytes, want %d", tc.desc, got, tc.want)
				}
			}
		})
	}
}

func TestEndpointWrongDirection(t *testing.T) {
	ep := &endpoint{
		InterfaceSetup: testBulkInSetup,
		EndpointInfo:   testBulkInEP,
	}
	_, err := ep.Write([]byte{1, 2, 3})
	if err == nil {
		t.Error("bulkInEP.Write(): got nil error, want non-nil")
	}
	ep = &endpoint{
		InterfaceSetup: testIsoOutSetup,
		EndpointInfo:   testIsoOutEP,
	}
	_, err = ep.Read(make([]byte, 64))
	if err == nil {
		t.Error("isoOutEP.Read(): got nil error, want non-nil")
	}
}

func TestOpenEndpoint(t *testing.T) {
	origLib := libusb
	defer func() { libusb = origLib }()
	libusb = newFakeLibusb()

	c := NewContext()
	dev, err := c.OpenDeviceWithVidPid(0x8888, 0x0002)
	if dev == nil {
		t.Fatal("OpenDeviceWithVidPid(0x8888, 0x0002): got nil device, need non-nil")
	}
	defer dev.Close()
	if err != nil {
		t.Fatalf("OpenDeviceWithVidPid(0x8888, 0x0002): got error %v, want nil", err)
	}
	ep, err := dev.OpenEndpoint(1, 1, 1, 0x86)
	if err != nil {
		t.Errorf("OpenEndpoint(cfg=1, if=1, alt=1, ep=0x86): got error %v, want nil", err)
	}
	i := ep.Info()
	if got, want := i.Address, uint8(0x86); got != want {
		t.Errorf("OpenEndpoint(cfg=1, if=1, alt=1, ep=0x86): ep.Info.Address = %x, want %x", got, want)
	}
	if got, want := i.MaxIsoPacket, uint32(2*1024); got != want {
		t.Errorf("OpenEndpoint(cfg=1, if=1, alt=1, ep=0x86): ep.Info.MaxIsoPacket = %d, want %d", got, want)
	}
}
<|endoftext|>


<commit_before>// Copyright 2016-2017 Authors of Cilium
//
// 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 kvstore

import (
	"time"

	log "github.com/Sirupsen/logrus"
	. "gopkg.in/check.v1"
)

type KvstoreSuite struct{}

var _ = Suite(&KvstoreSuite{})

func (s *KvstoreSuite) SetUpTest(c *C) {
	log.SetLevel(log.DebugLevel)

	err := SetupDummy()
	c.Assert(err, IsNil)
}

func drainEvents(w *Watcher) {
	for len(w.Events) > 0 {
		<-w.Events
	}
}

func expectEvent(c *C, w *Watcher, typ EventType, key string, val []byte) {
	log.WithFields(log.Fields{
		"type":  typ,
		"key":   key,
		"value": string(val),
	}).Debugf("Expecting event")

	select {
	case event := <-w.Events:
		c.Assert(event.Typ, Equals, typ)
		c.Assert(event.Key, DeepEquals, key)

		// etcd does not provide the value of deleted keys
		if backend == "consul" {
			c.Assert(event.Value, DeepEquals, val)
		}
	case <-time.After(30 * time.Second):
		c.Fatal("timeout while waiting for kvstore watcher event")
	}
}

func (s *KvstoreSuite) TestWatch(c *C) {
	DeleteTree("foo/")
	defer DeleteTree("foo/")

	w := Watch("testWatcher1", "foo/", 100)
	c.Assert(c, Not(IsNil))

	key1, key2 := "foo/key1", "foo/key2"
	val1, val2 := []byte("val1"), []byte("val2")

	err := CreateOnly(key1, val1, false)
	c.Assert(err, IsNil)
	expectEvent(c, w, EventTypeCreate, key1, val1)

	err = Set(key1, val2)
	c.Assert(err, IsNil)
	expectEvent(c, w, EventTypeModify, key1, val2)

	err = CreateOnly(key2, val2, false)
	c.Assert(err, IsNil)
	expectEvent(c, w, EventTypeCreate, key2, val2)

	err = Delete(key1)
	c.Assert(err, IsNil)
	expectEvent(c, w, EventTypeDelete, key1, val2)

	err = Delete(key2)
	c.Assert(err, IsNil)
	expectEvent(c, w, EventTypeDelete, key2, val2)

	w.Stop()
}

func (s *KvstoreSuite) TestListAndWatch(c *C) {
	key1, key2 := "foo2/key1", "foo2/key2"
	val1, val2 := []byte("val1"), []byte("val2")

	DeleteTree("foo2/")
	defer DeleteTree("foo2/")

	err := CreateOnly(key1, val1, false)
	c.Assert(err, IsNil)

	w := ListAndWatch("testWatcher2", "foo2/", 100)
	c.Assert(c, Not(IsNil))

	expectEvent(c, w, EventTypeCreate, key1, val1)

	err = CreateOnly(key2, val2, false)
	c.Assert(err, IsNil)
	expectEvent(c, w, EventTypeCreate, key2, val2)

	err = Delete(key1)
	c.Assert(err, IsNil)
	expectEvent(c, w, EventTypeDelete, key1, val1)

	err = CreateOnly(key1, val1, false)
	c.Assert(err, IsNil)
	expectEvent(c, w, EventTypeCreate, key1, val1)

	err = Delete(key1)
	c.Assert(err, IsNil)
	expectEvent(c, w, EventTypeDelete, key1, val1)

	err = Delete(key2)
	c.Assert(err, IsNil)
	expectEvent(c, w, EventTypeDelete, key2, val2)

	w.Stop()
}
<commit_msg>kvstore: Disable watcher tests until GH-1388 is fixed<commit_after>// Copyright 2016-2017 Authors of Cilium
//
// 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 kvstore

import (
	"time"

	log "github.com/Sirupsen/logrus"
	. "gopkg.in/check.v1"
)

type KvstoreSuite struct{}

var _ = Suite(&KvstoreSuite{})

func (s *KvstoreSuite) SetUpTest(c *C) {
	log.SetLevel(log.DebugLevel)

	err := SetupDummy()
	c.Assert(err, IsNil)
}

func drainEvents(w *Watcher) {
	for len(w.Events) > 0 {
		<-w.Events
	}
}

func expectEvent(c *C, w *Watcher, typ EventType, key string, val []byte) {
	log.WithFields(log.Fields{
		"type":  typ,
		"key":   key,
		"value": string(val),
	}).Debugf("Expecting event")

	select {
	case event := <-w.Events:
		c.Assert(event.Typ, Equals, typ)
		c.Assert(event.Key, DeepEquals, key)

		// etcd does not provide the value of deleted keys
		if backend == "consul" {
			c.Assert(event.Value, DeepEquals, val)
		}
	case <-time.After(30 * time.Second):
		c.Fatal("timeout while waiting for kvstore watcher event")
	}
}

func (s *KvstoreSuite) TestWatch(c *C) {
	// FIXME GH-1388 Re-enable when fixed
	if backend == Consul {
		c.Skip("consul currently broken (GH-1388)")
	}

	DeleteTree("foo/")
	defer DeleteTree("foo/")

	w := Watch("testWatcher1", "foo/", 100)
	c.Assert(c, Not(IsNil))

	key1, key2 := "foo/key1", "foo/key2"
	val1, val2 := []byte("val1"), []byte("val2")

	err := CreateOnly(key1, val1, false)
	c.Assert(err, IsNil)
	expectEvent(c, w, EventTypeCreate, key1, val1)

	err = Set(key1, val2)
	c.Assert(err, IsNil)
	expectEvent(c, w, EventTypeModify, key1, val2)

	err = CreateOnly(key2, val2, false)
	c.Assert(err, IsNil)
	expectEvent(c, w, EventTypeCreate, key2, val2)

	err = Delete(key1)
	c.Assert(err, IsNil)
	expectEvent(c, w, EventTypeDelete, key1, val2)

	err = Delete(key2)
	c.Assert(err, IsNil)
	expectEvent(c, w, EventTypeDelete, key2, val2)

	w.Stop()
}

func (s *KvstoreSuite) TestListAndWatch(c *C) {
	// FIXME GH-1388 Re-enable when fixed
	if backend == Consul {
		c.Skip("consul currently broken (GH-1388)")
	}

	key1, key2 := "foo2/key1", "foo2/key2"
	val1, val2 := []byte("val1"), []byte("val2")

	DeleteTree("foo2/")
	defer DeleteTree("foo2/")

	err := CreateOnly(key1, val1, false)
	c.Assert(err, IsNil)

	w := ListAndWatch("testWatcher2", "foo2/", 100)
	c.Assert(c, Not(IsNil))

	expectEvent(c, w, EventTypeCreate, key1, val1)

	err = CreateOnly(key2, val2, false)
	c.Assert(err, IsNil)
	expectEvent(c, w, EventTypeCreate, key2, val2)

	err = Delete(key1)
	c.Assert(err, IsNil)
	expectEvent(c, w, EventTypeDelete, key1, val1)

	err = CreateOnly(key1, val1, false)
	c.Assert(err, IsNil)
	expectEvent(c, w, EventTypeCreate, key1, val1)

	err = Delete(key1)
	c.Assert(err, IsNil)
	expectEvent(c, w, EventTypeDelete, key1, val1)

	err = Delete(key2)
	c.Assert(err, IsNil)
	expectEvent(c, w, EventTypeDelete, key2, val2)

	w.Stop()
}
<|endoftext|>


<commit_before>package network

import (
	"reflect"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"nimona.io/internal/fixtures"
	"nimona.io/pkg/context"
	"nimona.io/pkg/crypto"
	"nimona.io/pkg/errors"
	"nimona.io/pkg/object"
	"nimona.io/pkg/peer"
	"nimona.io/pkg/tilde"
)

func TestNetwork_SimpleConnection(t *testing.T) {
	n1 := New(context.Background())
	n2 := New(context.Background())

	l1, err := n1.Listen(context.Background(), "127.0.0.1:0", ListenOnLocalIPs)
	require.NoError(t, err)
	defer l1.Close()

	l2, err := n2.Listen(context.Background(), "127.0.0.1:0", ListenOnLocalIPs)
	require.NoError(t, err)
	defer l2.Close()

	testObj := &object.Object{
		Type: "foo",
		Data: tilde.Map{
			"foo": tilde.String("bar"),
		},
	}

	// subscribe to objects of type "foo" coming to n2
	sub := n2.Subscribe(
		FilterByObjectType("foo"),
	)
	require.NotNil(t, sub)

	// send from p1 to p2
	err = n1.Send(
		context.Background(),
		testObj,
		n2.GetPeerKey().PublicKey(),
		SendWithConnectionInfo(
			&peer.ConnectionInfo{
				PublicKey: n2.GetPeerKey().PublicKey(),
				Addresses: n2.GetAddresses(),
			},
		),
	)
	require.NoError(t, err)

	// wait for event from n1 to arrive
	env, err := sub.Next()
	require.NoError(t, err)
	assert.Equal(t, testObj, env.Payload)

	// subscribe to all objects coming to n1
	sub = n1.Subscribe()

	// send from p2 to p1
	err = n2.Send(
		context.Background(),
		testObj,
		n1.GetPeerKey().PublicKey(),
		SendWithConnectionInfo(
			&peer.ConnectionInfo{
				PublicKey: n1.GetPeerKey().PublicKey(),
				Addresses: n1.GetAddresses(),
			},
		),
	)
	require.NoError(t, err)

	// next object should be our foo
	env, err = sub.Next()
	require.NoError(t, err)
	require.NotNil(t, sub)
	assert.Equal(t, testObj, env.Payload)

	t.Run("re-establish broken connections", func(t *testing.T) {
		// close p2's connection to p1
		c, err := n2.(*network).connmgr.GetConnection(context.
			New(),
			&peer.ConnectionInfo{
				PublicKey: n1.GetPeerKey().PublicKey(),
			},
		)
		require.NoError(t, err)
		err = c.Close()
		require.NoError(t, err)
		// try to send something from p1 to p2
		err = n1.Send(
			context.Background(),
			testObj,
			n2.GetPeerKey().PublicKey(),
			SendWithConnectionInfo(
				&peer.ConnectionInfo{
					PublicKey: n2.GetPeerKey().PublicKey(),
					Addresses: n2.GetAddresses(),
				},
			),
		)
		require.NoError(t, err)
	})

	t.Run("wait for response", func(t *testing.T) {
		req := &fixtures.TestRequest{
			RequestID: "1",
			Foo:       "bar",
		}
		res := &fixtures.TestResponse{
			RequestID: "1",
			Foo:       "bar",
		}
		// sub for p2 based on rID
		gotRes := &fixtures.TestResponse{}
		reqSub := n2.Subscribe(
			FilterByRequestID("1"),
		)
		// send request from p1 to p2 in a go routine
		sendErr := make(chan error)
		go func() {
			reqo, err := object.Marshal(req)
			require.NoError(t, err)
			sendErr <- n1.Send(
				context.Background(),
				reqo,
				n2.GetPeerKey().PublicKey(),
				SendWithResponse(gotRes, 0),
			)
		}()
		// wait for p2 to get the req
		gotReq := <-reqSub.Channel()
		assert.Equal(t, "1", string(gotReq.Payload.Data["requestID"].(tilde.String)))
		// send response from p2 to p1
		reso, err := object.Marshal(res)
		require.NoError(t, err)
		require.NoError(t, err)
		// nolint: errcheck
		n2.Send(
			context.Background(),
			reso,
			n1.GetPeerKey().PublicKey(),
			SendWithConnectionInfo(
				&peer.ConnectionInfo{
					PublicKey: n1.GetPeerKey().PublicKey(),
					Addresses: n1.GetAddresses(),
				},
			),
		)
		// check response
		err = <-sendErr
		require.NoError(t, err)
		assert.Equal(t, res, gotRes)
	})
}

func TestNetwork_Relay(t *testing.T) {
	n0 := New(context.Background())
	n1 := New(context.Background())
	n2 := New(context.Background())

	l0, err := n0.Listen(context.Background(), "127.0.0.1:0", ListenOnLocalIPs)
	require.NoError(t, err)
	defer l0.Close()

	p0 := &peer.ConnectionInfo{
		PublicKey: n0.GetPeerKey().PublicKey(),
		Addresses: n0.GetAddresses(),
	}

	p1 := &peer.ConnectionInfo{
		PublicKey: n1.GetPeerKey().PublicKey(),
		Addresses: n1.GetAddresses(),
		Relays: []*peer.ConnectionInfo{
			p0,
		},
	}

	p2 := &peer.ConnectionInfo{
		PublicKey: n2.GetPeerKey().PublicKey(),
		Addresses: n2.GetAddresses(),
		Relays: []*peer.ConnectionInfo{
			p0,
		},
	}

	testObj := &object.Object{
		Type: "foo",
		Data: tilde.Map{
			"foo": tilde.String("bar"),
		},
	}

	testObjFromP1 := &object.Object{
		Type: "foo",
		Metadata: object.Metadata{
			Owner: n1.GetPeerKey().PublicKey().DID(),
		},
		Data: tilde.Map{
			"foo": tilde.String("bar"),
		},
	}

	testObjFromP2 := &object.Object{
		Type: "foo",
		Metadata: object.Metadata{
			Owner: n2.GetPeerKey().PublicKey().DID(),
		},
		Data: tilde.Map{
			"foo": tilde.String("bar"),
		},
	}

	// send from p1 to p0
	err = n1.Send(
		context.Background(),
		testObj,
		p0.PublicKey,
		SendWithConnectionInfo(p0),
	)
	require.NoError(t, err)

	// send from p2 to p0
	err = n2.Send(
		context.Background(),
		testObj,
		p0.PublicKey,
		SendWithConnectionInfo(p0),
	)
	require.NoError(t, err)

	// now we should be able to send from p1 to p2
	sub := n2.Subscribe(FilterByObjectType("foo"))
	err = n1.Send(
		context.Background(),
		testObjFromP1,
		p2.PublicKey,
		SendWithConnectionInfo(p2),
	)
	require.NoError(t, err)

	env, err := sub.Next()
	require.NoError(t, err)

	require.NotNil(t, sub)
	assert.Equal(t,
		testObjFromP1.Metadata.Signature,
		env.Payload.Metadata.Signature,
	)

	// send from p2 to p1
	sub = n1.Subscribe(FilterByObjectType("foo"))

	err = n2.Send(
		context.Background(),
		testObjFromP2,
		p1.PublicKey,
		SendWithConnectionInfo(p1),
	)
	require.NoError(t, err)

	env, err = sub.Next()
	require.NoError(t, err)

	require.NotNil(t, sub)
	assert.Equal(t,
		testObjFromP2.Metadata.Signature,
		env.Payload.Metadata.Signature,
	)
}

func Test_network_lookup(t *testing.T) {
	p0, err := crypto.NewEd25519PrivateKey()
	require.NoError(t, err)

	fooConnInfo := &peer.ConnectionInfo{
		Version:   1,
		PublicKey: p0.PublicKey(),
		Addresses: []string{"a", "b"},
	}
	type fields struct {
		resolvers []Resolver
	}
	type args struct {
		publicKey crypto.PublicKey
	}
	tests := []struct {
		name    string
		fields  fields
		args    args
		want    *peer.ConnectionInfo
		wantErr bool
	}{{
		name: "one resolver, returns, should pass",
		fields: fields{
			resolvers: []Resolver{
				&testResolver{
					peers: map[string]*peer.ConnectionInfo{
						fooConnInfo.PublicKey.String(): fooConnInfo,
					},
				},
			},
		},
		args: args{
			publicKey: fooConnInfo.PublicKey,
		},
		want: fooConnInfo,
	}, {
		name: "two resolver, second returns, should pass",
		fields: fields{
			resolvers: []Resolver{
				&testResolver{
					peers: map[string]*peer.ConnectionInfo{},
				},
				&testResolver{
					peers: map[string]*peer.ConnectionInfo{
						fooConnInfo.PublicKey.String(): fooConnInfo,
					},
				},
			},
		},
		args: args{
			publicKey: fooConnInfo.PublicKey,
		},
		want: fooConnInfo,
	}, {
		name: "two resolver, none returns, should fail",
		fields: fields{
			resolvers: []Resolver{
				&testResolver{
					peers: map[string]*peer.ConnectionInfo{},
				},
				&testResolver{
					peers: map[string]*peer.ConnectionInfo{},
				},
			},
		},
		args: args{
			publicKey: fooConnInfo.PublicKey,
		},
		want:    nil,
		wantErr: true,
	}}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			w := New(
				context.Background(),
			).(*network)
			for _, r := range tt.fields.resolvers {
				w.RegisterResolver(r)
			}
			got, err := w.lookup(context.Background(), tt.args.publicKey)
			if (err != nil) != tt.wantErr {
				t.Errorf("error = %v, wantErr %v", err, tt.wantErr)
				return
			}
			if !reflect.DeepEqual(got, tt.want) {
				t.Errorf("got %v, want %v", got, tt.want)
			}
		})
	}
}

type testResolver struct {
	peers map[string]*peer.ConnectionInfo
}

func (r *testResolver) LookupPeer(
	ctx context.Context,
	publicKey crypto.PublicKey,
) (*peer.ConnectionInfo, error) {
	c, ok := r.peers[publicKey.String()]
	if !ok || c == nil {
		return nil, errors.Error("not found")
	}
	return c, nil
}
<commit_msg>test(network): add benchmark for network send<commit_after>package network

import (
	"reflect"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"nimona.io/internal/fixtures"
	"nimona.io/pkg/context"
	"nimona.io/pkg/crypto"
	"nimona.io/pkg/errors"
	"nimona.io/pkg/object"
	"nimona.io/pkg/peer"
	"nimona.io/pkg/tilde"
)

func TestNetwork_SimpleConnection(t *testing.T) {
	n1 := New(context.Background())
	n2 := New(context.Background())

	l1, err := n1.Listen(context.Background(), "127.0.0.1:0", ListenOnLocalIPs)
	require.NoError(t, err)
	defer l1.Close()

	l2, err := n2.Listen(context.Background(), "127.0.0.1:0", ListenOnLocalIPs)
	require.NoError(t, err)
	defer l2.Close()

	testObj := &object.Object{
		Type: "foo",
		Data: tilde.Map{
			"foo": tilde.String("bar"),
		},
	}

	// subscribe to objects of type "foo" coming to n2
	sub := n2.Subscribe(
		FilterByObjectType("foo"),
	)
	require.NotNil(t, sub)

	// send from p1 to p2
	err = n1.Send(
		context.Background(),
		testObj,
		n2.GetPeerKey().PublicKey(),
		SendWithConnectionInfo(
			&peer.ConnectionInfo{
				PublicKey: n2.GetPeerKey().PublicKey(),
				Addresses: n2.GetAddresses(),
			},
		),
	)
	require.NoError(t, err)

	// wait for event from n1 to arrive
	env, err := sub.Next()
	require.NoError(t, err)
	assert.Equal(t, testObj, env.Payload)

	// subscribe to all objects coming to n1
	sub = n1.Subscribe()

	// send from p2 to p1
	err = n2.Send(
		context.Background(),
		testObj,
		n1.GetPeerKey().PublicKey(),
		SendWithConnectionInfo(
			&peer.ConnectionInfo{
				PublicKey: n1.GetPeerKey().PublicKey(),
				Addresses: n1.GetAddresses(),
			},
		),
	)
	require.NoError(t, err)

	// next object should be our foo
	env, err = sub.Next()
	require.NoError(t, err)
	require.NotNil(t, sub)
	assert.Equal(t, testObj, env.Payload)

	t.Run("re-establish broken connections", func(t *testing.T) {
		// close p2's connection to p1
		c, err := n2.(*network).connmgr.GetConnection(context.
			New(),
			&peer.ConnectionInfo{
				PublicKey: n1.GetPeerKey().PublicKey(),
			},
		)
		require.NoError(t, err)
		err = c.Close()
		require.NoError(t, err)
		// try to send something from p1 to p2
		err = n1.Send(
			context.Background(),
			testObj,
			n2.GetPeerKey().PublicKey(),
			SendWithConnectionInfo(
				&peer.ConnectionInfo{
					PublicKey: n2.GetPeerKey().PublicKey(),
					Addresses: n2.GetAddresses(),
				},
			),
		)
		require.NoError(t, err)
	})

	t.Run("wait for response", func(t *testing.T) {
		req := &fixtures.TestRequest{
			RequestID: "1",
			Foo:       "bar",
		}
		res := &fixtures.TestResponse{
			RequestID: "1",
			Foo:       "bar",
		}
		// sub for p2 based on rID
		gotRes := &fixtures.TestResponse{}
		reqSub := n2.Subscribe(
			FilterByRequestID("1"),
		)
		// send request from p1 to p2 in a go routine
		sendErr := make(chan error)
		go func() {
			reqo, err := object.Marshal(req)
			require.NoError(t, err)
			sendErr <- n1.Send(
				context.Background(),
				reqo,
				n2.GetPeerKey().PublicKey(),
				SendWithResponse(gotRes, 0),
			)
		}()
		// wait for p2 to get the req
		gotReq := <-reqSub.Channel()
		assert.Equal(t, "1", string(gotReq.Payload.Data["requestID"].(tilde.String)))
		// send response from p2 to p1
		reso, err := object.Marshal(res)
		require.NoError(t, err)
		require.NoError(t, err)
		// nolint: errcheck
		n2.Send(
			context.Background(),
			reso,
			n1.GetPeerKey().PublicKey(),
			SendWithConnectionInfo(
				&peer.ConnectionInfo{
					PublicKey: n1.GetPeerKey().PublicKey(),
					Addresses: n1.GetAddresses(),
				},
			),
		)
		// check response
		err = <-sendErr
		require.NoError(t, err)
		assert.Equal(t, res, gotRes)
	})
}

func TestNetwork_Relay(t *testing.T) {
	n0 := New(context.Background())
	n1 := New(context.Background())
	n2 := New(context.Background())

	l0, err := n0.Listen(context.Background(), "127.0.0.1:0", ListenOnLocalIPs)
	require.NoError(t, err)
	defer l0.Close()

	p0 := &peer.ConnectionInfo{
		PublicKey: n0.GetPeerKey().PublicKey(),
		Addresses: n0.GetAddresses(),
	}

	p1 := &peer.ConnectionInfo{
		PublicKey: n1.GetPeerKey().PublicKey(),
		Addresses: n1.GetAddresses(),
		Relays: []*peer.ConnectionInfo{
			p0,
		},
	}

	p2 := &peer.ConnectionInfo{
		PublicKey: n2.GetPeerKey().PublicKey(),
		Addresses: n2.GetAddresses(),
		Relays: []*peer.ConnectionInfo{
			p0,
		},
	}

	testObj := &object.Object{
		Type: "foo",
		Data: tilde.Map{
			"foo": tilde.String("bar"),
		},
	}

	testObjFromP1 := &object.Object{
		Type: "foo",
		Metadata: object.Metadata{
			Owner: n1.GetPeerKey().PublicKey().DID(),
		},
		Data: tilde.Map{
			"foo": tilde.String("bar"),
		},
	}

	testObjFromP2 := &object.Object{
		Type: "foo",
		Metadata: object.Metadata{
			Owner: n2.GetPeerKey().PublicKey().DID(),
		},
		Data: tilde.Map{
			"foo": tilde.String("bar"),
		},
	}

	// send from p1 to p0
	err = n1.Send(
		context.Background(),
		testObj,
		p0.PublicKey,
		SendWithConnectionInfo(p0),
	)
	require.NoError(t, err)

	// send from p2 to p0
	err = n2.Send(
		context.Background(),
		testObj,
		p0.PublicKey,
		SendWithConnectionInfo(p0),
	)
	require.NoError(t, err)

	// now we should be able to send from p1 to p2
	sub := n2.Subscribe(FilterByObjectType("foo"))
	err = n1.Send(
		context.Background(),
		testObjFromP1,
		p2.PublicKey,
		SendWithConnectionInfo(p2),
	)
	require.NoError(t, err)

	env, err := sub.Next()
	require.NoError(t, err)

	require.NotNil(t, sub)
	assert.Equal(t,
		testObjFromP1.Metadata.Signature,
		env.Payload.Metadata.Signature,
	)

	// send from p2 to p1
	sub = n1.Subscribe(FilterByObjectType("foo"))

	err = n2.Send(
		context.Background(),
		testObjFromP2,
		p1.PublicKey,
		SendWithConnectionInfo(p1),
	)
	require.NoError(t, err)

	env, err = sub.Next()
	require.NoError(t, err)

	require.NotNil(t, sub)
	assert.Equal(t,
		testObjFromP2.Metadata.Signature,
		env.Payload.Metadata.Signature,
	)
}

func Test_network_lookup(t *testing.T) {
	p0, err := crypto.NewEd25519PrivateKey()
	require.NoError(t, err)

	fooConnInfo := &peer.ConnectionInfo{
		Version:   1,
		PublicKey: p0.PublicKey(),
		Addresses: []string{"a", "b"},
	}
	type fields struct {
		resolvers []Resolver
	}
	type args struct {
		publicKey crypto.PublicKey
	}
	tests := []struct {
		name    string
		fields  fields
		args    args
		want    *peer.ConnectionInfo
		wantErr bool
	}{{
		name: "one resolver, returns, should pass",
		fields: fields{
			resolvers: []Resolver{
				&testResolver{
					peers: map[string]*peer.ConnectionInfo{
						fooConnInfo.PublicKey.String(): fooConnInfo,
					},
				},
			},
		},
		args: args{
			publicKey: fooConnInfo.PublicKey,
		},
		want: fooConnInfo,
	}, {
		name: "two resolver, second returns, should pass",
		fields: fields{
			resolvers: []Resolver{
				&testResolver{
					peers: map[string]*peer.ConnectionInfo{},
				},
				&testResolver{
					peers: map[string]*peer.ConnectionInfo{
						fooConnInfo.PublicKey.String(): fooConnInfo,
					},
				},
			},
		},
		args: args{
			publicKey: fooConnInfo.PublicKey,
		},
		want: fooConnInfo,
	}, {
		name: "two resolver, none returns, should fail",
		fields: fields{
			resolvers: []Resolver{
				&testResolver{
					peers: map[string]*peer.ConnectionInfo{},
				},
				&testResolver{
					peers: map[string]*peer.ConnectionInfo{},
				},
			},
		},
		args: args{
			publicKey: fooConnInfo.PublicKey,
		},
		want:    nil,
		wantErr: true,
	}}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			w := New(
				context.Background(),
			).(*network)
			for _, r := range tt.fields.resolvers {
				w.RegisterResolver(r)
			}
			got, err := w.lookup(context.Background(), tt.args.publicKey)
			if (err != nil) != tt.wantErr {
				t.Errorf("error = %v, wantErr %v", err, tt.wantErr)
				return
			}
			if !reflect.DeepEqual(got, tt.want) {
				t.Errorf("got %v, want %v", got, tt.want)
			}
		})
	}
}

func BenchmarkNetworkSendToSinglePeer(b *testing.B) {
	n1 := New(context.Background())

	l1, err := n1.Listen(context.Background(), "127.0.0.1:0", ListenOnLocalIPs)
	require.NoError(b, err)
	defer l1.Close()

	n1s := n1.Subscribe(FilterByObjectType("foo")).Channel()

	for n := 0; n < b.N; n++ {
		n2 := New(context.Background())
		err = n2.Send(
			context.Background(),
			&object.Object{
				Type: "foo",
				Data: tilde.Map{
					"foo": tilde.String("bar"),
				},
			},
			n1.GetPeerKey().PublicKey(),
			SendWithConnectionInfo(
				&peer.ConnectionInfo{
					PublicKey: n1.GetPeerKey().PublicKey(),
					Addresses: n1.GetAddresses(),
				},
			),
		)
		require.NoError(b, err)
		select {
		case env := <-n1s:
			require.NotNil(b, env)
		case <-time.After(time.Second):
			b.Fatal("timeout")
		}
		err = n2.Close()
		require.NoError(b, err)
	}
}

type testResolver struct {
	peers map[string]*peer.ConnectionInfo
}

func (r *testResolver) LookupPeer(
	ctx context.Context,
	publicKey crypto.PublicKey,
) (*peer.ConnectionInfo, error) {
	c, ok := r.peers[publicKey.String()]
	if !ok || c == nil {
		return nil, errors.Error("not found")
	}
	return c, nil
}
<|endoftext|>


<commit_before>// +build linux

/*
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 ipvs

import (
	"errors"
	"fmt"
	"net"
	"strings"
	"syscall"

	"github.com/docker/libnetwork/ipvs"
	"github.com/golang/glog"
	utilexec "k8s.io/utils/exec"
)

const cmdIP = "ip"

// runner implements Interface.
type runner struct {
	exec       utilexec.Interface
	ipvsHandle *ipvs.Handle
}

// New returns a new Interface which will call ipvs APIs.
func New(exec utilexec.Interface) Interface {
	ihandle, err := ipvs.New("")
	if err != nil {
		glog.Errorf("IPVS interface can't be initialized, error: %v", err)
		return nil
	}
	return &runner{
		exec:       exec,
		ipvsHandle: ihandle,
	}
}

// EnsureVirtualServerAddressBind is part of Interface.
func (runner *runner) EnsureVirtualServerAddressBind(vs *VirtualServer, dummyDev string) (exist bool, err error) {
	addr := vs.Address.String() + "/32"
	args := []string{"addr", "add", addr, "dev", dummyDev}
	out, err := runner.exec.Command(cmdIP, args...).CombinedOutput()
	if err != nil {
		// "exit status 2" will be returned if the address is already bound to dummy device
		if ee, ok := err.(utilexec.ExitError); ok {
			if ee.Exited() && ee.ExitStatus() == 2 {
				return true, nil
			}
		}
		return false, fmt.Errorf("error bind address: %s to dummy interface: %s, err: %v: %s", vs.Address.String(), dummyDev, err, out)
	}
	return false, nil
}

// UnbindVirtualServerAddress is part of Interface.
func (runner *runner) UnbindVirtualServerAddress(vs *VirtualServer, dummyDev string) error {
	addr := vs.Address.String() + "/32"
	args := []string{"addr", "del", addr, "dev", dummyDev}
	out, err := runner.exec.Command(cmdIP, args...).CombinedOutput()
	if err != nil {
		return fmt.Errorf("error unbind address: %s from dummy interface: %s, err: %v: %s", vs.Address.String(), dummyDev, err, out)
	}
	return nil
}

// AddVirtualServer is part of Interface.
func (runner *runner) AddVirtualServer(vs *VirtualServer) error {
	eSvc, err := toBackendService(vs)
	if err != nil {
		return err
	}
	return runner.ipvsHandle.NewService(eSvc)
}

// UpdateVirtualServer is part of Interface.
func (runner *runner) UpdateVirtualServer(vs *VirtualServer) error {
	bSvc, err := toBackendService(vs)
	if err != nil {
		return err
	}
	return runner.ipvsHandle.UpdateService(bSvc)
}

// DeleteVirtualServer is part of Interface.
func (runner *runner) DeleteVirtualServer(vs *VirtualServer) error {
	bSvc, err := toBackendService(vs)
	if err != nil {
		return err
	}
	return runner.ipvsHandle.DelService(bSvc)
}

// GetVirtualServer is part of Interface.
func (runner *runner) GetVirtualServer(vs *VirtualServer) (*VirtualServer, error) {
	bSvc, err := toBackendService(vs)
	if err != nil {
		return nil, err
	}
	ipvsService, err := runner.ipvsHandle.GetService(bSvc)
	if err != nil {
		return nil, err
	}
	virtualServer, err := toVirtualServer(ipvsService)
	if err != nil {
		return nil, err
	}
	return virtualServer, nil
}

// GetVirtualServers is part of Interface.
func (runner *runner) GetVirtualServers() ([]*VirtualServer, error) {
	ipvsServices, err := runner.ipvsHandle.GetServices()
	if err != nil {
		return nil, err
	}
	vss := make([]*VirtualServer, 0)
	for _, ipvsService := range ipvsServices {
		vs, err := toVirtualServer(ipvsService)
		if err != nil {
			return nil, err
		}
		vss = append(vss, vs)
	}
	return vss, nil
}

// Flush is part of Interface.  Currently we delete IPVS services one by one
func (runner *runner) Flush() error {
	vss, err := runner.GetVirtualServers()
	if err != nil {
		return err
	}
	for _, vs := range vss {
		err := runner.DeleteVirtualServer(vs)
		// TODO: aggregate errors?
		if err != nil {
			return err
		}
	}
	return nil
}

// AddRealServer is part of Interface.
func (runner *runner) AddRealServer(vs *VirtualServer, rs *RealServer) error {
	bSvc, err := toBackendService(vs)
	if err != nil {
		return err
	}
	bDst, err := toBackendDestination(rs)
	if err != nil {
		return err
	}
	return runner.ipvsHandle.NewDestination(bSvc, bDst)
}

// DeleteRealServer is part of Interface.
func (runner *runner) DeleteRealServer(vs *VirtualServer, rs *RealServer) error {
	bSvc, err := toBackendService(vs)
	if err != nil {
		return err
	}
	bDst, err := toBackendDestination(rs)
	if err != nil {
		return err
	}
	return runner.ipvsHandle.DelDestination(bSvc, bDst)
}

// GetRealServers is part of Interface.
func (runner *runner) GetRealServers(vs *VirtualServer) ([]*RealServer, error) {
	bSvc, err := toBackendService(vs)
	if err != nil {
		return nil, err
	}
	bDestinations, err := runner.ipvsHandle.GetDestinations(bSvc)
	if err != nil {
		return nil, err
	}
	realServers := make([]*RealServer, 0)
	for _, dest := range bDestinations {
		dst, err := toRealServer(dest)
		// TODO: aggregate errors?
		if err != nil {
			return nil, err
		}
		realServers = append(realServers, dst)
	}
	return realServers, nil
}

// toVirtualServer converts an IPVS service representation to the equivalent virtual server structure.
func toVirtualServer(svc *ipvs.Service) (*VirtualServer, error) {
	if svc == nil {
		return nil, errors.New("ipvs svc should not be empty")
	}
	vs := &VirtualServer{
		Address:   svc.Address,
		Port:      svc.Port,
		Scheduler: svc.SchedName,
		Protocol:  protocolNumbeToString(ProtoType(svc.Protocol)),
		Flags:     ServiceFlags(svc.Flags),
		Timeout:   svc.Timeout,
	}

	if vs.Address == nil {
		if svc.AddressFamily == syscall.AF_INET {
			vs.Address = net.IPv4zero
		} else {
			vs.Address = net.IPv6zero
		}
	}
	return vs, nil
}

// toRealServer converts an IPVS destination representation to the equivalent real server structure.
func toRealServer(dst *ipvs.Destination) (*RealServer, error) {
	if dst == nil {
		return nil, errors.New("ipvs destination should not be empty")
	}
	return &RealServer{
		Address: dst.Address,
		Port:    dst.Port,
		Weight:  dst.Weight,
	}, nil
}

// toBackendService converts an IPVS real server representation to the equivalent "backend" service structure.
func toBackendService(vs *VirtualServer) (*ipvs.Service, error) {
	if vs == nil {
		return nil, errors.New("virtual server should not be empty")
	}
	bakSvc := &ipvs.Service{
		Address:   vs.Address,
		Protocol:  stringToProtocolNumber(vs.Protocol),
		Port:      vs.Port,
		SchedName: vs.Scheduler,
		Flags:     uint32(vs.Flags),
		Timeout:   vs.Timeout,
	}

	if ip4 := vs.Address.To4(); ip4 != nil {
		bakSvc.AddressFamily = syscall.AF_INET
		bakSvc.Netmask = 0xffffffff
	} else {
		bakSvc.AddressFamily = syscall.AF_INET6
		bakSvc.Netmask = 128
	}
	return bakSvc, nil
}

// toBackendDestination converts an IPVS real server representation to the equivalent "backend" destination structure.
func toBackendDestination(rs *RealServer) (*ipvs.Destination, error) {
	if rs == nil {
		return nil, errors.New("real server should not be empty")
	}
	return &ipvs.Destination{
		Address: rs.Address,
		Port:    rs.Port,
		Weight:  rs.Weight,
	}, nil
}

// stringToProtocolNumber returns the protocol value for the given name
func stringToProtocolNumber(protocol string) uint16 {
	switch strings.ToLower(protocol) {
	case "tcp":
		return uint16(syscall.IPPROTO_TCP)
	case "udp":
		return uint16(syscall.IPPROTO_UDP)
	}
	return uint16(0)
}

// protocolNumbeToString returns the name for the given protocol value.
func protocolNumbeToString(proto ProtoType) string {
	switch proto {
	case syscall.IPPROTO_TCP:
		return "TCP"
	case syscall.IPPROTO_UDP:
		return "UDP"
	}
	return ""
}

// ProtoType is IPVS service protocol type
type ProtoType uint16
<commit_msg>support ipvs flush API<commit_after>// +build linux

/*
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 ipvs

import (
	"errors"
	"fmt"
	"net"
	"strings"
	"syscall"

	"github.com/docker/libnetwork/ipvs"
	"github.com/golang/glog"
	utilexec "k8s.io/utils/exec"
)

const cmdIP = "ip"

// runner implements Interface.
type runner struct {
	exec       utilexec.Interface
	ipvsHandle *ipvs.Handle
}

// New returns a new Interface which will call ipvs APIs.
func New(exec utilexec.Interface) Interface {
	ihandle, err := ipvs.New("")
	if err != nil {
		glog.Errorf("IPVS interface can't be initialized, error: %v", err)
		return nil
	}
	return &runner{
		exec:       exec,
		ipvsHandle: ihandle,
	}
}

// EnsureVirtualServerAddressBind is part of Interface.
func (runner *runner) EnsureVirtualServerAddressBind(vs *VirtualServer, dummyDev string) (exist bool, err error) {
	addr := vs.Address.String() + "/32"
	args := []string{"addr", "add", addr, "dev", dummyDev}
	out, err := runner.exec.Command(cmdIP, args...).CombinedOutput()
	if err != nil {
		// "exit status 2" will be returned if the address is already bound to dummy device
		if ee, ok := err.(utilexec.ExitError); ok {
			if ee.Exited() && ee.ExitStatus() == 2 {
				return true, nil
			}
		}
		return false, fmt.Errorf("error bind address: %s to dummy interface: %s, err: %v: %s", vs.Address.String(), dummyDev, err, out)
	}
	return false, nil
}

// UnbindVirtualServerAddress is part of Interface.
func (runner *runner) UnbindVirtualServerAddress(vs *VirtualServer, dummyDev string) error {
	addr := vs.Address.String() + "/32"
	args := []string{"addr", "del", addr, "dev", dummyDev}
	out, err := runner.exec.Command(cmdIP, args...).CombinedOutput()
	if err != nil {
		return fmt.Errorf("error unbind address: %s from dummy interface: %s, err: %v: %s", vs.Address.String(), dummyDev, err, out)
	}
	return nil
}

// AddVirtualServer is part of Interface.
func (runner *runner) AddVirtualServer(vs *VirtualServer) error {
	eSvc, err := toBackendService(vs)
	if err != nil {
		return err
	}
	return runner.ipvsHandle.NewService(eSvc)
}

// UpdateVirtualServer is part of Interface.
func (runner *runner) UpdateVirtualServer(vs *VirtualServer) error {
	bSvc, err := toBackendService(vs)
	if err != nil {
		return err
	}
	return runner.ipvsHandle.UpdateService(bSvc)
}

// DeleteVirtualServer is part of Interface.
func (runner *runner) DeleteVirtualServer(vs *VirtualServer) error {
	bSvc, err := toBackendService(vs)
	if err != nil {
		return err
	}
	return runner.ipvsHandle.DelService(bSvc)
}

// GetVirtualServer is part of Interface.
func (runner *runner) GetVirtualServer(vs *VirtualServer) (*VirtualServer, error) {
	bSvc, err := toBackendService(vs)
	if err != nil {
		return nil, err
	}
	ipvsService, err := runner.ipvsHandle.GetService(bSvc)
	if err != nil {
		return nil, err
	}
	virtualServer, err := toVirtualServer(ipvsService)
	if err != nil {
		return nil, err
	}
	return virtualServer, nil
}

// GetVirtualServers is part of Interface.
func (runner *runner) GetVirtualServers() ([]*VirtualServer, error) {
	ipvsServices, err := runner.ipvsHandle.GetServices()
	if err != nil {
		return nil, err
	}
	vss := make([]*VirtualServer, 0)
	for _, ipvsService := range ipvsServices {
		vs, err := toVirtualServer(ipvsService)
		if err != nil {
			return nil, err
		}
		vss = append(vss, vs)
	}
	return vss, nil
}

// Flush is part of Interface.  Currently we delete IPVS services one by one
func (runner *runner) Flush() error {
	return runner.ipvsHandle.Flush()
}

// AddRealServer is part of Interface.
func (runner *runner) AddRealServer(vs *VirtualServer, rs *RealServer) error {
	bSvc, err := toBackendService(vs)
	if err != nil {
		return err
	}
	bDst, err := toBackendDestination(rs)
	if err != nil {
		return err
	}
	return runner.ipvsHandle.NewDestination(bSvc, bDst)
}

// DeleteRealServer is part of Interface.
func (runner *runner) DeleteRealServer(vs *VirtualServer, rs *RealServer) error {
	bSvc, err := toBackendService(vs)
	if err != nil {
		return err
	}
	bDst, err := toBackendDestination(rs)
	if err != nil {
		return err
	}
	return runner.ipvsHandle.DelDestination(bSvc, bDst)
}

// GetRealServers is part of Interface.
func (runner *runner) GetRealServers(vs *VirtualServer) ([]*RealServer, error) {
	bSvc, err := toBackendService(vs)
	if err != nil {
		return nil, err
	}
	bDestinations, err := runner.ipvsHandle.GetDestinations(bSvc)
	if err != nil {
		return nil, err
	}
	realServers := make([]*RealServer, 0)
	for _, dest := range bDestinations {
		dst, err := toRealServer(dest)
		// TODO: aggregate errors?
		if err != nil {
			return nil, err
		}
		realServers = append(realServers, dst)
	}
	return realServers, nil
}

// toVirtualServer converts an IPVS service representation to the equivalent virtual server structure.
func toVirtualServer(svc *ipvs.Service) (*VirtualServer, error) {
	if svc == nil {
		return nil, errors.New("ipvs svc should not be empty")
	}
	vs := &VirtualServer{
		Address:   svc.Address,
		Port:      svc.Port,
		Scheduler: svc.SchedName,
		Protocol:  protocolNumbeToString(ProtoType(svc.Protocol)),
		Flags:     ServiceFlags(svc.Flags),
		Timeout:   svc.Timeout,
	}

	if vs.Address == nil {
		if svc.AddressFamily == syscall.AF_INET {
			vs.Address = net.IPv4zero
		} else {
			vs.Address = net.IPv6zero
		}
	}
	return vs, nil
}

// toRealServer converts an IPVS destination representation to the equivalent real server structure.
func toRealServer(dst *ipvs.Destination) (*RealServer, error) {
	if dst == nil {
		return nil, errors.New("ipvs destination should not be empty")
	}
	return &RealServer{
		Address: dst.Address,
		Port:    dst.Port,
		Weight:  dst.Weight,
	}, nil
}

// toBackendService converts an IPVS real server representation to the equivalent "backend" service structure.
func toBackendService(vs *VirtualServer) (*ipvs.Service, error) {
	if vs == nil {
		return nil, errors.New("virtual server should not be empty")
	}
	bakSvc := &ipvs.Service{
		Address:   vs.Address,
		Protocol:  stringToProtocolNumber(vs.Protocol),
		Port:      vs.Port,
		SchedName: vs.Scheduler,
		Flags:     uint32(vs.Flags),
		Timeout:   vs.Timeout,
	}

	if ip4 := vs.Address.To4(); ip4 != nil {
		bakSvc.AddressFamily = syscall.AF_INET
		bakSvc.Netmask = 0xffffffff
	} else {
		bakSvc.AddressFamily = syscall.AF_INET6
		bakSvc.Netmask = 128
	}
	return bakSvc, nil
}

// toBackendDestination converts an IPVS real server representation to the equivalent "backend" destination structure.
func toBackendDestination(rs *RealServer) (*ipvs.Destination, error) {
	if rs == nil {
		return nil, errors.New("real server should not be empty")
	}
	return &ipvs.Destination{
		Address: rs.Address,
		Port:    rs.Port,
		Weight:  rs.Weight,
	}, nil
}

// stringToProtocolNumber returns the protocol value for the given name
func stringToProtocolNumber(protocol string) uint16 {
	switch strings.ToLower(protocol) {
	case "tcp":
		return uint16(syscall.IPPROTO_TCP)
	case "udp":
		return uint16(syscall.IPPROTO_UDP)
	}
	return uint16(0)
}

// protocolNumbeToString returns the name for the given protocol value.
func protocolNumbeToString(proto ProtoType) string {
	switch proto {
	case syscall.IPPROTO_TCP:
		return "TCP"
	case syscall.IPPROTO_UDP:
		return "UDP"
	}
	return ""
}

// ProtoType is IPVS service protocol type
type ProtoType uint16
<|endoftext|>


<commit_before>// Copyright 2019 The Berglas 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 berglas

import (
	"context"
	"os"
	"runtime"

	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

// chmodSupported indicates whether the OS supports chmod
const chmodSupported = runtime.GOOS != "windows" && runtime.GOOS != "plan9"

// Resolve parses and extracts a berglas reference. See Client.Resolve for more
// details and examples.
func Resolve(ctx context.Context, s string) ([]byte, error) {
	client, err := New(ctx)
	if err != nil {
		return nil, err
	}
	return client.Resolve(ctx, s)
}

// Resolve parses and extracts a berglas reference. The result is the plaintext
// secrets contents, or a path to the decrypted contents on disk.
func (c *Client) Resolve(ctx context.Context, s string) ([]byte, error) {
	logger := c.Logger().WithFields(logrus.Fields{
		"reference": s,
	})

	logger.Debug("resolve.start")
	defer logger.Debug("resolve.finish")

	ref, err := ParseReference(s)
	if err != nil {
		return nil, errors.Wrapf(err, "failed to parse reference %s", s)
	}

	var req accessRequest
	switch ref.Type() {
	case ReferenceTypeSecretManager:
		req = &SecretManagerAccessRequest{
			Project: ref.Project(),
			Name:    ref.Name(),
			Version: ref.Version(),
		}
	case ReferenceTypeStorage:
		req = &StorageAccessRequest{
			Bucket:     ref.Bucket(),
			Object:     ref.Object(),
			Generation: ref.Generation(),
		}
	}

	plaintext, err := c.Access(ctx, req)
	if err != nil {
		return nil, errors.Wrapf(err, "failed to access secret %s", ref.String())
	}

	if pth := ref.Filepath(); pth != "" {
		logger.WithField("filepath", pth).Debug("writing to filepath")

		f, err := os.OpenFile(ref.Filepath(), os.O_RDWR|os.O_CREATE, 0600)
		if err != nil {
			return nil, errors.Wrapf(err, "failed to open filepath %s", pth)
		}

		if chmodSupported {
			if err := f.Chmod(0600); err != nil {
				return nil, errors.Wrapf(err, "failed to chmod filepath %s", pth)
			}
		}

		if _, err := f.Write(plaintext); err != nil {
			return nil, errors.Wrapf(err, "failed to write secret to filepath %s", pth)
		}

		if err := f.Sync(); err != nil {
			return nil, errors.Wrapf(err, "failed to sync filepath %s", pth)
		}

		if err := f.Close(); err != nil {
			return nil, errors.Wrapf(err, "failed to close filepath %s", pth)
		}

		// Set the plaintext to the resulting file path
		plaintext = []byte(f.Name())
	}

	return plaintext, nil
}
<commit_msg>Truncate file when opening<commit_after>// Copyright 2019 The Berglas 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 berglas

import (
	"context"
	"os"
	"runtime"

	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

// chmodSupported indicates whether the OS supports chmod
const chmodSupported = runtime.GOOS != "windows" && runtime.GOOS != "plan9"

// Resolve parses and extracts a berglas reference. See Client.Resolve for more
// details and examples.
func Resolve(ctx context.Context, s string) ([]byte, error) {
	client, err := New(ctx)
	if err != nil {
		return nil, err
	}
	return client.Resolve(ctx, s)
}

// Resolve parses and extracts a berglas reference. The result is the plaintext
// secrets contents, or a path to the decrypted contents on disk.
func (c *Client) Resolve(ctx context.Context, s string) ([]byte, error) {
	logger := c.Logger().WithFields(logrus.Fields{
		"reference": s,
	})

	logger.Debug("resolve.start")
	defer logger.Debug("resolve.finish")

	ref, err := ParseReference(s)
	if err != nil {
		return nil, errors.Wrapf(err, "failed to parse reference %s", s)
	}

	var req accessRequest
	switch ref.Type() {
	case ReferenceTypeSecretManager:
		req = &SecretManagerAccessRequest{
			Project: ref.Project(),
			Name:    ref.Name(),
			Version: ref.Version(),
		}
	case ReferenceTypeStorage:
		req = &StorageAccessRequest{
			Bucket:     ref.Bucket(),
			Object:     ref.Object(),
			Generation: ref.Generation(),
		}
	}

	plaintext, err := c.Access(ctx, req)
	if err != nil {
		return nil, errors.Wrapf(err, "failed to access secret %s", ref.String())
	}

	if pth := ref.Filepath(); pth != "" {
		logger.WithField("filepath", pth).Debug("writing to filepath")

		f, err := os.OpenFile(ref.Filepath(), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
		if err != nil {
			return nil, errors.Wrapf(err, "failed to open filepath %s", pth)
		}

		if chmodSupported {
			if err := f.Chmod(0600); err != nil {
				return nil, errors.Wrapf(err, "failed to chmod filepath %s", pth)
			}
		}

		if _, err := f.Write(plaintext); err != nil {
			return nil, errors.Wrapf(err, "failed to write secret to filepath %s", pth)
		}

		if err := f.Sync(); err != nil {
			return nil, errors.Wrapf(err, "failed to sync filepath %s", pth)
		}

		if err := f.Close(); err != nil {
			return nil, errors.Wrapf(err, "failed to close filepath %s", pth)
		}

		// Set the plaintext to the resulting file path
		plaintext = []byte(f.Name())
	}

	return plaintext, nil
}
<|endoftext|>


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

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

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

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

package chartutil

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

	"k8s.io/helm/pkg/proto/hapi/chart"
)

const (
	// ChartfileName is the default Chart file name.
	ChartfileName = "Chart.yaml"
	// ValuesfileName is the default values file name.
	ValuesfileName = "values.yaml"
	// TemplatesDir is the relative directory name for templates.
	TemplatesDir = "templates"
	// ChartsDir is the relative directory name for charts dependencies.
	ChartsDir = "charts"
	// IgnorefileName is the name of the Helm ignore file.
	IgnorefileName = ".helmignore"
	// DeploymentName is the name of the example deployment file.
	DeploymentName = "deployment.yaml"
	// ServiceName is the name of the example service file.
	ServiceName = "service.yaml"
	// NotesName is the name of the example NOTES.txt file.
	NotesName = "NOTES.txt"
	// HelpersName is the name of the example NOTES.txt file.
	HelpersName = "_helpers.tpl"
)

const defaultValues = `# Default values for %s.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
replicaCount: 1
image:
  repository: nginx
  tag: stable
  pullPolicy: IfNotPresent
service:
  name: nginx
  type: ClusterIP
  externalPort: 80
  internalPort: 80
resources:
  limits:
    cpu: 100m
    memory: 128Mi
  requests:
    cpu: 100m
    memory: 128Mi

`

const defaultIgnore = `# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*~
# Various IDEs
.project
.idea/
*.tmproj
`

const defaultDeployment = `apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: {{ template "fullname" . }}
  labels:
    chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
spec:
  replicas: {{ .Values.replicaCount }}
  template:
    metadata:
      labels:
        app: {{ template "fullname" . }}
    spec:
      containers:
      - name: nginx
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
        imagePullPolicy: {{ .Values.image.pullPolicy }}
        ports:
        - containerPort: {{ .Values.service.internalPort }}
        livenessProbe:
          httpGet:
            path: /
            port: 80
        readinessProbe:
          httpGet:
            path: /
            port: 80
        resources:
{{ toYaml .Values.resources | indent 12 }}
`

const defaultService = `apiVersion: v1
kind: Service
metadata:
  name: {{ template "fullname" . }}
  labels:
    chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
spec:
  type: {{ .Values.service.type }}
  ports:
  - port: {{ .Values.service.externalPort }}
    targetPort: {{ .Values.service.internalPort }}
    protocol: TCP
    name: {{ .Values.service.name }}
  selector:
    app: {{ template "fullname" . }}
`

const defaultNotes = `1. Get the application URL by running these commands:
{{- if contains "NodePort" .Values.service.type }}
  export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "fullname" . }})
  export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
  echo http://$NODE_IP:$NODE_PORT/login
{{- else if contains "LoadBalancer" .Values.service.type }}
**** NOTE: It may take a few minutes for the LoadBalancer IP to be available.                      ****
****       You can watch the status of by running 'kubectl get svc -w {{ template "fullname" . }}' ****
  export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
  echo http://$SERVICE_IP:{{ .Values.Master.ServicePort }}
{{- else if contains "ClusterIP"  .Values.service.type }}
  export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "component={{ template "fullname" . }}-master" -o jsonpath="{.items[0].metadata.name}")
  echo http://127.0.0.1:{{ .Values.service.externalPort }}
  kubectl port-forward $POD_NAME {{ .Values.service.externalPort }}:{{ .Values.service.externalPort }}
{{- end }}
`

const defaultHelpers = `{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 24 -}}
{{- end -}}

{{/*
Create a default fully qualified app name.
We truncate at 24 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
*/}}
{{- define "fullname" -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- printf "%s-%s" .Release.Name $name | trunc 24 -}}
{{- end -}}
`

// Create creates a new chart in a directory.
//
// Inside of dir, this will create a directory based on the name of
// chartfile.Name. It will then write the Chart.yaml into this directory and
// create the (empty) appropriate directories.
//
// The returned string will point to the newly created directory. It will be
// an absolute path, even if the provided base directory was relative.
//
// If dir does not exist, this will return an error.
// If Chart.yaml or any directories cannot be created, this will return an
// error. In such a case, this will attempt to clean up by removing the
// new chart directory.
func Create(chartfile *chart.Metadata, dir string) (string, error) {
	path, err := filepath.Abs(dir)
	if err != nil {
		return path, err
	}

	if fi, err := os.Stat(path); err != nil {
		return path, err
	} else if !fi.IsDir() {
		return path, fmt.Errorf("no such directory %s", path)
	}

	n := chartfile.Name
	cdir := filepath.Join(path, n)
	if fi, err := os.Stat(cdir); err == nil && !fi.IsDir() {
		return cdir, fmt.Errorf("file %s already exists and is not a directory", cdir)
	}
	if err := os.MkdirAll(cdir, 0755); err != nil {
		return cdir, err
	}

	if err := SaveChartfile(filepath.Join(cdir, ChartfileName), chartfile); err != nil {
		return cdir, err
	}

	val := []byte(fmt.Sprintf(defaultValues, chartfile.Name))
	if err := ioutil.WriteFile(filepath.Join(cdir, ValuesfileName), val, 0644); err != nil {
		return cdir, err
	}

	val = []byte(defaultIgnore)
	if err := ioutil.WriteFile(filepath.Join(cdir, IgnorefileName), val, 0644); err != nil {
		return cdir, err
	}

	for _, d := range []string{TemplatesDir, ChartsDir} {
		if err := os.MkdirAll(filepath.Join(cdir, d), 0755); err != nil {
			return cdir, err
		}
	}

	// Write out deployment.yaml
	val = []byte(defaultDeployment)
	if err := ioutil.WriteFile(filepath.Join(cdir, TemplatesDir, DeploymentName), val, 0644); err != nil {
			return cdir, err
	}

	// Write out service.yaml
	val = []byte(defaultService)
	if err := ioutil.WriteFile(filepath.Join(cdir, TemplatesDir, ServiceName), val, 0644); err != nil {
			return cdir, err
	}

	// Write out NOTES.txt
	val = []byte(defaultNotes)
	if err := ioutil.WriteFile(filepath.Join(cdir, TemplatesDir, NotesName), val, 0644); err != nil {
			return cdir, err
	}

	// Write out _helpers.tpl
	val = []byte(defaultHelpers)
	if err := ioutil.WriteFile(filepath.Join(cdir, TemplatesDir, HelpersName), val, 0644); err != nil {
			return cdir, err
	}
	return cdir, nil
}
<commit_msg>Fix formatting<commit_after>/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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

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

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

package chartutil

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

	"k8s.io/helm/pkg/proto/hapi/chart"
)

const (
	// ChartfileName is the default Chart file name.
	ChartfileName = "Chart.yaml"
	// ValuesfileName is the default values file name.
	ValuesfileName = "values.yaml"
	// TemplatesDir is the relative directory name for templates.
	TemplatesDir = "templates"
	// ChartsDir is the relative directory name for charts dependencies.
	ChartsDir = "charts"
	// IgnorefileName is the name of the Helm ignore file.
	IgnorefileName = ".helmignore"
	// DeploymentName is the name of the example deployment file.
	DeploymentName = "deployment.yaml"
	// ServiceName is the name of the example service file.
	ServiceName = "service.yaml"
	// NotesName is the name of the example NOTES.txt file.
	NotesName = "NOTES.txt"
	// HelpersName is the name of the example NOTES.txt file.
	HelpersName = "_helpers.tpl"
)

const defaultValues = `# Default values for %s.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
replicaCount: 1
image:
  repository: nginx
  tag: stable
  pullPolicy: IfNotPresent
service:
  name: nginx
  type: ClusterIP
  externalPort: 80
  internalPort: 80
resources:
  limits:
    cpu: 100m
    memory: 128Mi
  requests:
    cpu: 100m
    memory: 128Mi

`

const defaultIgnore = `# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*~
# Various IDEs
.project
.idea/
*.tmproj
`

const defaultDeployment = `apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: {{ template "fullname" . }}
  labels:
    chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
spec:
  replicas: {{ .Values.replicaCount }}
  template:
    metadata:
      labels:
        app: {{ template "fullname" . }}
    spec:
      containers:
      - name: nginx
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
        imagePullPolicy: {{ .Values.image.pullPolicy }}
        ports:
        - containerPort: {{ .Values.service.internalPort }}
        livenessProbe:
          httpGet:
            path: /
            port: 80
        readinessProbe:
          httpGet:
            path: /
            port: 80
        resources:
{{ toYaml .Values.resources | indent 12 }}
`

const defaultService = `apiVersion: v1
kind: Service
metadata:
  name: {{ template "fullname" . }}
  labels:
    chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
spec:
  type: {{ .Values.service.type }}
  ports:
  - port: {{ .Values.service.externalPort }}
    targetPort: {{ .Values.service.internalPort }}
    protocol: TCP
    name: {{ .Values.service.name }}
  selector:
    app: {{ template "fullname" . }}
`

const defaultNotes = `1. Get the application URL by running these commands:
{{- if contains "NodePort" .Values.service.type }}
  export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "fullname" . }})
  export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
  echo http://$NODE_IP:$NODE_PORT/login
{{- else if contains "LoadBalancer" .Values.service.type }}
**** NOTE: It may take a few minutes for the LoadBalancer IP to be available.                      ****
****       You can watch the status of by running 'kubectl get svc -w {{ template "fullname" . }}' ****
  export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
  echo http://$SERVICE_IP:{{ .Values.Master.ServicePort }}
{{- else if contains "ClusterIP"  .Values.service.type }}
  export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "component={{ template "fullname" . }}-master" -o jsonpath="{.items[0].metadata.name}")
  echo http://127.0.0.1:{{ .Values.service.externalPort }}
  kubectl port-forward $POD_NAME {{ .Values.service.externalPort }}:{{ .Values.service.externalPort }}
{{- end }}
`

const defaultHelpers = `{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 24 -}}
{{- end -}}

{{/*
Create a default fully qualified app name.
We truncate at 24 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
*/}}
{{- define "fullname" -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- printf "%s-%s" .Release.Name $name | trunc 24 -}}
{{- end -}}
`

// Create creates a new chart in a directory.
//
// Inside of dir, this will create a directory based on the name of
// chartfile.Name. It will then write the Chart.yaml into this directory and
// create the (empty) appropriate directories.
//
// The returned string will point to the newly created directory. It will be
// an absolute path, even if the provided base directory was relative.
//
// If dir does not exist, this will return an error.
// If Chart.yaml or any directories cannot be created, this will return an
// error. In such a case, this will attempt to clean up by removing the
// new chart directory.
func Create(chartfile *chart.Metadata, dir string) (string, error) {
	path, err := filepath.Abs(dir)
	if err != nil {
		return path, err
	}

	if fi, err := os.Stat(path); err != nil {
		return path, err
	} else if !fi.IsDir() {
		return path, fmt.Errorf("no such directory %s", path)
	}

	n := chartfile.Name
	cdir := filepath.Join(path, n)
	if fi, err := os.Stat(cdir); err == nil && !fi.IsDir() {
		return cdir, fmt.Errorf("file %s already exists and is not a directory", cdir)
	}
	if err := os.MkdirAll(cdir, 0755); err != nil {
		return cdir, err
	}

	if err := SaveChartfile(filepath.Join(cdir, ChartfileName), chartfile); err != nil {
		return cdir, err
	}

	val := []byte(fmt.Sprintf(defaultValues, chartfile.Name))
	if err := ioutil.WriteFile(filepath.Join(cdir, ValuesfileName), val, 0644); err != nil {
		return cdir, err
	}

	val = []byte(defaultIgnore)
	if err := ioutil.WriteFile(filepath.Join(cdir, IgnorefileName), val, 0644); err != nil {
		return cdir, err
	}

	for _, d := range []string{TemplatesDir, ChartsDir} {
		if err := os.MkdirAll(filepath.Join(cdir, d), 0755); err != nil {
			return cdir, err
		}
	}

	// Write out deployment.yaml
	val = []byte(defaultDeployment)
	if err := ioutil.WriteFile(filepath.Join(cdir, TemplatesDir, DeploymentName), val, 0644); err != nil {
		return cdir, err
	}

	// Write out service.yaml
	val = []byte(defaultService)
	if err := ioutil.WriteFile(filepath.Join(cdir, TemplatesDir, ServiceName), val, 0644); err != nil {
		return cdir, err
	}

	// Write out NOTES.txt
	val = []byte(defaultNotes)
	if err := ioutil.WriteFile(filepath.Join(cdir, TemplatesDir, NotesName), val, 0644); err != nil {
		return cdir, err
	}

	// Write out _helpers.tpl
	val = []byte(defaultHelpers)
	if err := ioutil.WriteFile(filepath.Join(cdir, TemplatesDir, HelpersName), val, 0644); err != nil {
		return cdir, err
	}
	return cdir, nil
}
<|endoftext|>