<commit_before>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 backup_test

import (
	"errors"
	"github.com/jacobsa/aws/sdb"
	"github.com/jacobsa/aws/sdb/mock"
	"github.com/jacobsa/comeback/backup"
	"github.com/jacobsa/comeback/crypto"
	"github.com/jacobsa/comeback/crypto/mock"
	. "github.com/jacobsa/oglematchers"
	"github.com/jacobsa/oglemock"
	. "github.com/jacobsa/ogletest"
	"testing"
)

func TestRegistry(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

type registryTest struct {
	crypter mock_crypto.MockCrypter
	domain  mock_sdb.MockDomain
}

func (t *registryTest) SetUp(i *TestInfo) {
	t.crypter = mock_crypto.NewMockCrypter(i.MockController, "crypter")
	t.domain = mock_sdb.NewMockDomain(i.MockController, "domain")
}

////////////////////////////////////////////////////////////////////////
// NewRegistry
////////////////////////////////////////////////////////////////////////

type NewRegistryTest struct {
	registryTest

	registry backup.Registry
	err error
}

func init() { RegisterTestSuite(&NewRegistryTest{}) }

func (t *NewRegistryTest) callConstructor() {
	t.registry, t.err = backup.NewRegistry(t.crypter, t.domain)
}

func (t *NewRegistryTest) CallsGetAttributes() {
	// Domain
	ExpectCall(t.domain, "GetAttributes")(
		"comeback_marker",
		false,
		ElementsAre("encrypted_data")).
		WillOnce(oglemock.Return(nil, errors.New("")))

	// Call
	t.callConstructor()
}

func (t *NewRegistryTest) GetAttributesReturnsError() {
	// Domain
	ExpectCall(t.domain, "GetAttributes")(Any(), Any(), Any()).
		WillOnce(oglemock.Return(nil, errors.New("taco")))

	// Call
	t.callConstructor()

	ExpectThat(t.err, Error(HasSubstr("GetAttributes")))
	ExpectThat(t.err, Error(HasSubstr("taco")))
}

func (t *NewRegistryTest) CallsDecrypt() {
	// Domain
	attr := sdb.Attribute{Name: "encrypted_data", Value: "taco"}
	ExpectCall(t.domain, "GetAttributes")(Any(), Any(), Any()).
		WillOnce(oglemock.Return([]sdb.Attribute{attr}, nil))

	// Crypter
	ExpectCall(t.crypter, "Decrypt")(DeepEquals([]byte("taco"))).
		WillOnce(oglemock.Return(nil, errors.New("")))

	// Call
	t.callConstructor()
}

func (t *NewRegistryTest) DecryptReturnsGenericError() {
	// Domain
	attr := sdb.Attribute{Name: "encrypted_data"}
	ExpectCall(t.domain, "GetAttributes")(Any(), Any(), Any()).
		WillOnce(oglemock.Return([]sdb.Attribute{attr}, nil))

	// Crypter
	ExpectCall(t.crypter, "Decrypt")(Any()).
		WillOnce(oglemock.Return(nil, errors.New("taco")))

	// Call
	t.callConstructor()

	ExpectThat(t.err, Error(HasSubstr("Decrypt")))
	ExpectThat(t.err, Error(HasSubstr("taco")))
}

func (t *NewRegistryTest) DecryptReturnsNotAuthenticError() {
	// Domain
	attr := sdb.Attribute{Name: "encrypted_data"}
	ExpectCall(t.domain, "GetAttributes")(Any(), Any(), Any()).
		WillOnce(oglemock.Return([]sdb.Attribute{attr}, nil))

	// Crypter
	ExpectCall(t.crypter, "Decrypt")(Any()).
		WillOnce(oglemock.Return(nil, &crypto.NotAuthenticError{}))

	// Call
	t.callConstructor()

	_, ok := t.err.(*backup.IncompatibleCrypterError)
	AssertTrue(ok, "Error: %v", t.err)

	ExpectThat(t.err, Error(HasSubstr("crypter")))
	ExpectThat(t.err, Error(HasSubstr("incompatible")))
}

func (t *NewRegistryTest) DecryptSucceeds() {
	// Domain
	attr := sdb.Attribute{Name: "encrypted_data"}
	ExpectCall(t.domain, "GetAttributes")(Any(), Any(), Any()).
		WillOnce(oglemock.Return([]sdb.Attribute{attr}, nil))

	// Crypter
	ExpectCall(t.crypter, "Decrypt")(Any()).
		WillOnce(oglemock.Return([]byte{}, nil))

	// Call
	t.callConstructor()

	AssertEq(nil, t.err)
	ExpectNe(nil, t.registry)
}

func (t *NewRegistryTest) CallsEncrypt() {
	ExpectEq("TODO", "")
}

func (t *NewRegistryTest) EncryptReturnsError() {
	ExpectEq("TODO", "")
}

func (t *NewRegistryTest) CallsPutAttributes() {
	ExpectEq("TODO", "")
}

func (t *NewRegistryTest) PutAttributesReturnsError() {
	ExpectEq("TODO", "")
}

func (t *NewRegistryTest) PutAttributesSucceeds() {
	ExpectEq("TODO", "")
}
<commit_msg>NewRegistryTest.CallsEncrypt<commit_after>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 backup_test

import (
	"errors"
	"github.com/jacobsa/aws/sdb"
	"github.com/jacobsa/aws/sdb/mock"
	"github.com/jacobsa/comeback/backup"
	"github.com/jacobsa/comeback/crypto"
	"github.com/jacobsa/comeback/crypto/mock"
	. "github.com/jacobsa/oglematchers"
	"github.com/jacobsa/oglemock"
	. "github.com/jacobsa/ogletest"
	"testing"
)

func TestRegistry(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

type registryTest struct {
	crypter mock_crypto.MockCrypter
	domain  mock_sdb.MockDomain
}

func (t *registryTest) SetUp(i *TestInfo) {
	t.crypter = mock_crypto.NewMockCrypter(i.MockController, "crypter")
	t.domain = mock_sdb.NewMockDomain(i.MockController, "domain")
}

////////////////////////////////////////////////////////////////////////
// NewRegistry
////////////////////////////////////////////////////////////////////////

type NewRegistryTest struct {
	registryTest

	registry backup.Registry
	err error
}

func init() { RegisterTestSuite(&NewRegistryTest{}) }

func (t *NewRegistryTest) callConstructor() {
	t.registry, t.err = backup.NewRegistry(t.crypter, t.domain)
}

func (t *NewRegistryTest) CallsGetAttributes() {
	// Domain
	ExpectCall(t.domain, "GetAttributes")(
		"comeback_marker",
		false,
		ElementsAre("encrypted_data")).
		WillOnce(oglemock.Return(nil, errors.New("")))

	// Call
	t.callConstructor()
}

func (t *NewRegistryTest) GetAttributesReturnsError() {
	// Domain
	ExpectCall(t.domain, "GetAttributes")(Any(), Any(), Any()).
		WillOnce(oglemock.Return(nil, errors.New("taco")))

	// Call
	t.callConstructor()

	ExpectThat(t.err, Error(HasSubstr("GetAttributes")))
	ExpectThat(t.err, Error(HasSubstr("taco")))
}

func (t *NewRegistryTest) CallsDecrypt() {
	// Domain
	attr := sdb.Attribute{Name: "encrypted_data", Value: "taco"}
	ExpectCall(t.domain, "GetAttributes")(Any(), Any(), Any()).
		WillOnce(oglemock.Return([]sdb.Attribute{attr}, nil))

	// Crypter
	ExpectCall(t.crypter, "Decrypt")(DeepEquals([]byte("taco"))).
		WillOnce(oglemock.Return(nil, errors.New("")))

	// Call
	t.callConstructor()
}

func (t *NewRegistryTest) DecryptReturnsGenericError() {
	// Domain
	attr := sdb.Attribute{Name: "encrypted_data"}
	ExpectCall(t.domain, "GetAttributes")(Any(), Any(), Any()).
		WillOnce(oglemock.Return([]sdb.Attribute{attr}, nil))

	// Crypter
	ExpectCall(t.crypter, "Decrypt")(Any()).
		WillOnce(oglemock.Return(nil, errors.New("taco")))

	// Call
	t.callConstructor()

	ExpectThat(t.err, Error(HasSubstr("Decrypt")))
	ExpectThat(t.err, Error(HasSubstr("taco")))
}

func (t *NewRegistryTest) DecryptReturnsNotAuthenticError() {
	// Domain
	attr := sdb.Attribute{Name: "encrypted_data"}
	ExpectCall(t.domain, "GetAttributes")(Any(), Any(), Any()).
		WillOnce(oglemock.Return([]sdb.Attribute{attr}, nil))

	// Crypter
	ExpectCall(t.crypter, "Decrypt")(Any()).
		WillOnce(oglemock.Return(nil, &crypto.NotAuthenticError{}))

	// Call
	t.callConstructor()

	_, ok := t.err.(*backup.IncompatibleCrypterError)
	AssertTrue(ok, "Error: %v", t.err)

	ExpectThat(t.err, Error(HasSubstr("crypter")))
	ExpectThat(t.err, Error(HasSubstr("incompatible")))
}

func (t *NewRegistryTest) DecryptSucceeds() {
	// Domain
	attr := sdb.Attribute{Name: "encrypted_data"}
	ExpectCall(t.domain, "GetAttributes")(Any(), Any(), Any()).
		WillOnce(oglemock.Return([]sdb.Attribute{attr}, nil))

	// Crypter
	ExpectCall(t.crypter, "Decrypt")(Any()).
		WillOnce(oglemock.Return([]byte{}, nil))

	// Call
	t.callConstructor()

	AssertEq(nil, t.err)
	ExpectNe(nil, t.registry)
}

func (t *NewRegistryTest) CallsEncrypt() {
	// Domain
	ExpectCall(t.domain, "GetAttributes")(Any(), Any(), Any()).
		WillOnce(oglemock.Return([]sdb.Attribute{}, nil))

	// Crypter
	ExpectCall(t.crypter, "Encrypt")(Any()).
		WillOnce(oglemock.Return(nil, errors.New("")))

	// Call
	t.callConstructor()
}

func (t *NewRegistryTest) EncryptReturnsError() {
	ExpectEq("TODO", "")
}

func (t *NewRegistryTest) CallsPutAttributes() {
	ExpectEq("TODO", "")
}

func (t *NewRegistryTest) PutAttributesReturnsError() {
	ExpectEq("TODO", "")
}

func (t *NewRegistryTest) PutAttributesSucceeds() {
	ExpectEq("TODO", "")
}
<|endoftext|>


<commit_before>package field

import (
	"errors"
	"log"
)

const (
	TYPE_TEXT         = "text"
	TYPE_NUMBER       = "number"
	TYPE_CHECKBOXES   = "checkboxes"
	TYPE_RADIOBUTTONS = "radiobuttons"
	TYPE_IMAGES       = "images"
)

var ErrMissingType error = errors.New("Missing type.")
var ErrInvalidType error = errors.New("Invalid type.")
var ErrMissingLabel error = errors.New("Missing label.")
var ErrInvalidLabel error = errors.New("Invalid label.")
var ErrMissingValue error = errors.New("Missing value.")
var ErrInvalidValue error = errors.New("Invalid value.")

type Field struct {
	Type         string        `json:"type"`
	Label        string        `json:"label"`
	Required     bool          `json:"required"`
	Text         *Text         `json:"text,omitempty"`
	Number       *Number       `json:"number,omitempty"`
	Checkboxes   *Checkboxes   `json:"checkboxes,omitempty"`
	Radiobuttons *Radiobuttons `json:"radiobuttons,omitempty"`
	Images       *Images       `json:"images,omitempty"`
}

type Value interface {
	Validate() error
	IsEmpty() bool
}

func (field *Field) Validate() error {
	// ensure that only one field is filled out
	if field.Type != TYPE_TEXT && field.Text != nil ||
		field.Type != TYPE_NUMBER && field.Number != nil ||
		field.Type != TYPE_CHECKBOXES && field.Checkboxes != nil ||
		field.Type != TYPE_RADIOBUTTONS && field.Radiobuttons != nil ||
		field.Type != TYPE_IMAGES && field.Images != nil {
		return ErrInvalidValue
	}

	var value Value
	switch field.Type {
	case TYPE_TEXT:
		value = field.Text
	case TYPE_NUMBER:
		value = field.Number
	case TYPE_CHECKBOXES:
		value = field.Checkboxes
	case TYPE_RADIOBUTTONS:
		value = field.Radiobuttons
	case TYPE_IMAGES:
		value = field.Images
		log.Println("Image field")
	default:
		return ErrInvalidType
	}

	err := value.Validate()
	if err != nil {
		return err
	}
	if field.Required && value.IsEmpty() {
		return ErrInvalidValue
	}
	return nil
}

// func (field *Field) Validate() error {
// 	switch field.Type {
// 	// case TYPE_CHECKBOXES:
// 	// 	checkboxes, err := NewCheckboxes(field)
// 	// 	return err
// 	// case TYPE_RADIOBUTTONS:
// 	// 	radiobuttons, err := NewRadiobuttons(field)
// 	// 	return err
// 	case TYPE_TEXT:
// 		_, err := NewText(field)
// 		return err
// 	// case TYPE_IMAGES:
// 	// 	images, err := NewImages(field)
// 	// 	return err
// 	// case TYPE_NUMBER:
// 	// 	number, err := NewNumber(field)
// 	// 	return err
// 	default:
// 		return ErrInvalidType
// 	}
// 	return nil
// }

// func ParseFieldMap(fieldMap map[string]interface{}) {
// 	var field Field
// 	switch field.Type {
// 	case TYPE_CHECKBOX:
// 		fmt.Println("Checkbox")
// 	case TYPE_CHECKBOXES:
// 		fmt.Println("Checkboxes")
// 	case TYPE_RADIOBUTTON:
// 		fmt.Println("Radiobutton")
// 	case TYPE_RADIOBUTTONS:
// 		fmt.Println("Radiobuttons")
// 	default:
// 		fmt.Println("Error")
// 	}
// }
<commit_msg>Remove commented out code<commit_after>package field

import (
	"errors"
	"log"
)

const (
	TYPE_TEXT         = "text"
	TYPE_NUMBER       = "number"
	TYPE_CHECKBOXES   = "checkboxes"
	TYPE_RADIOBUTTONS = "radiobuttons"
	TYPE_IMAGES       = "images"
)

var ErrMissingType error = errors.New("Missing type.")
var ErrInvalidType error = errors.New("Invalid type.")
var ErrMissingLabel error = errors.New("Missing label.")
var ErrInvalidLabel error = errors.New("Invalid label.")
var ErrMissingValue error = errors.New("Missing value.")
var ErrInvalidValue error = errors.New("Invalid value.")

type Field struct {
	Type         string        `json:"type"`
	Label        string        `json:"label"`
	Required     bool          `json:"required"`
	Text         *Text         `json:"text,omitempty"`
	Number       *Number       `json:"number,omitempty"`
	Checkboxes   *Checkboxes   `json:"checkboxes,omitempty"`
	Radiobuttons *Radiobuttons `json:"radiobuttons,omitempty"`
	Images       *Images       `json:"images,omitempty"`
}

type Value interface {
	Validate() error
	IsEmpty() bool
}

func (field *Field) Validate() error {
	// ensure that only one field is filled out
	if field.Type != TYPE_TEXT && field.Text != nil ||
		field.Type != TYPE_NUMBER && field.Number != nil ||
		field.Type != TYPE_CHECKBOXES && field.Checkboxes != nil ||
		field.Type != TYPE_RADIOBUTTONS && field.Radiobuttons != nil ||
		field.Type != TYPE_IMAGES && field.Images != nil {
		return ErrInvalidValue
	}

	var value Value
	switch field.Type {
	case TYPE_TEXT:
		value = field.Text
	case TYPE_NUMBER:
		value = field.Number
	case TYPE_CHECKBOXES:
		value = field.Checkboxes
	case TYPE_RADIOBUTTONS:
		value = field.Radiobuttons
	case TYPE_IMAGES:
		value = field.Images
		log.Println("Image field")
	default:
		return ErrInvalidType
	}

	err := value.Validate()
	if err != nil {
		return err
	}
	if field.Required && value.IsEmpty() {
		return ErrInvalidValue
	}
	return nil
}
<|endoftext|>


<commit_before>package federation

import (
	"errors"
	"fmt"
	"sort"

	"github.com/samsarahq/thunder/graphql"
)

// serviceSchemas holds all schemas for all of versions of
// all executors services. It is a map from service name
// and version to schema.
type serviceSchemas map[string]map[string]*introspectionQueryResult

// FieldInfo holds federation-specific information for
// graphql.Fields used to plan and execute queries.
type FieldInfo struct {
	// Services is the set of all services that can resolve this
	// field. If a service has multiple versions, all versions
	// must be able to resolve the field.
	Services map[string]bool
}

// SchemaWithFederationInfo holds a graphql.Schema along with
// federtion-specific annotations per field.
type SchemaWithFederationInfo struct {
	Schema *graphql.Schema
	// Fields is a map of fields to services which they belong to
	Fields map[*graphql.Field]*FieldInfo
}

// convertVersionedSchemas takes schemas for all of versions of
// all executors services and generates a single merged schema
// annotated with mapping from field to all services that know
// how to resolve the field
func convertVersionedSchemas(schemas serviceSchemas) (*SchemaWithFederationInfo, error) {
	serviceNames := make([]string, 0, len(schemas))
	for service := range schemas {
		serviceNames = append(serviceNames, service)
	}
	sort.Strings(serviceNames)

	serviceSchemasByName := make(map[string]*introspectionQueryResult)

	// Finds the intersection of different version of the schemas
	var serviceSchemas []*introspectionQueryResult
	for _, service := range serviceNames {
		versions := schemas[service]

		versionNames := make([]string, 0, len(versions))
		for version := range versions {
			versionNames = append(versionNames, version)
		}
		sort.Strings(versionNames)

		var versionSchemas []*introspectionQueryResult
		for _, version := range versionNames {
			versionSchemas = append(versionSchemas, versions[version])
		}

		serviceSchema, err := mergeSchemaSlice(versionSchemas, Intersection)
		if err != nil {
			return nil, err
		}

		serviceSchemasByName[service] = serviceSchema

		serviceSchemas = append(serviceSchemas, serviceSchema)
	}

	// Finds the union of all the schemas from different executor services
	merged, err := mergeSchemaSlice(serviceSchemas, Union)
	if err != nil {
		return nil, err
	}

	types, err := parseSchema(merged)
	if err != nil {
		return nil, err
	}

	fieldInfos := make(map[*graphql.Field]*FieldInfo)
	for _, service := range serviceNames {
		for _, typ := range serviceSchemasByName[service].Schema.Types {
			if typ.Kind == "OBJECT" {
				obj := types[typ.Name].(*graphql.Object)

				for _, field := range typ.Fields {
					f := obj.Fields[field.Name]

					info, ok := fieldInfos[f]
					if !ok {
						info = &FieldInfo{
							Services: map[string]bool{},
						}
						fieldInfos[f] = info
					}
					info.Services[service] = true
				}
			}
		}
	}

	return &SchemaWithFederationInfo{
		Schema: &graphql.Schema{
			Query:    types["Query"],
			Mutation: types["Mutation"],
		},
		Fields: fieldInfos,
	}, nil
}

// convertSchema annotates the schema with federation information vt
// mapping fields to the corresponding services.
func convertSchema(schemas map[string]*introspectionQueryResult) (*SchemaWithFederationInfo, error) {
	versionedSchemas := make(serviceSchemas)
	for service, schema := range schemas {
		versionedSchemas[service] = map[string]*introspectionQueryResult{
			"": schema,
		}
	}
	return convertVersionedSchemas(versionedSchemas)
}

// lookupTypeRef maps the a introspected type to a graphql type
func lookupType(t *introspectionTypeRef, all map[string]graphql.Type) (*introspectionTypeRef, error) {
	if t == nil {
		return nil, errors.New("malformed typeref")
	}
	switch t.Kind {
	case "SCALAR", "OBJECT", "UNION", "INPUT_OBJECT", "ENUM":
		return t, nil
	case "LIST":
		return lookupType(t.OfType, all)
	case "NON_NULL":
		return lookupType(t.OfType, all)
	default:
		return nil, fmt.Errorf("unknown type kind %s", t.Kind)
	}
}

// lookupTypeRef maps the a introspected type to a graphql type
func lookupTypeRef(t *introspectionTypeRef, all map[string]graphql.Type) (graphql.Type, error) {
	if t == nil {
		return nil, errors.New("malformed typeref")
	}

	switch t.Kind {
	case "SCALAR", "OBJECT", "UNION", "INPUT_OBJECT", "ENUM":
		// TODO: enforce type?
		typ, ok := all[t.Name]
		if !ok {
			return nil, fmt.Errorf("type %s not found among top-level types", t.Name)
		}
		return typ, nil

	case "LIST":
		inner, err := lookupTypeRef(t.OfType, all)
		if err != nil {
			return nil, err
		}
		return &graphql.List{
			Type: inner,
		}, nil

	case "NON_NULL":
		inner, err := lookupTypeRef(t.OfType, all)
		if err != nil {
			return nil, err
		}
		return &graphql.NonNull{
			Type: inner,
		}, nil

	default:
		return nil, fmt.Errorf("unknown type kind %s", t.Kind)
	}
}

// parseInputFields maps a list of input types to a list of graphql types
func parseInputFields(source []introspectionInputField, all map[string]graphql.Type) (map[string]graphql.Type, error) {
	fields := make(map[string]graphql.Type)

	for _, field := range source {
		// Validate the inputType is valid
		rawType, err := lookupType(field.Type, all)
		if err != nil {
			return nil, fmt.Errorf("type %s not found", rawType.Name)
		}
		switch rawType.Kind {
		case "INPUT_OBJECT", "SCALAR":
		default:
			return nil, fmt.Errorf("input field %s has bad typ: %s", field.Name, rawType.Kind)
		}

		inputType, err := lookupTypeRef(field.Type, all)
		if err != nil {
			return nil, fmt.Errorf("field %s has bad typ: %v", field.Name, err)
		}
		fields[field.Name] = inputType
	}

	return fields, nil
}

// parseSchema takes the introspected schema, validates the types,
// and maps every field to the graphql types
func parseSchema(schema *introspectionQueryResult) (map[string]graphql.Type, error) {
	all := make(map[string]graphql.Type)

	for _, typ := range schema.Schema.Types {
		if _, ok := all[typ.Name]; ok {
			return nil, fmt.Errorf("duplicate type %s", typ.Name)
		}

		switch typ.Kind {
		case "OBJECT":
			all[typ.Name] = &graphql.Object{
				Name: typ.Name,
			}

		case "INPUT_OBJECT":
			all[typ.Name] = &graphql.InputObject{
				Name: typ.Name,
			}

		case "SCALAR":
			all[typ.Name] = &graphql.Scalar{
				Type: typ.Name,
			}

		case "UNION":
			all[typ.Name] = &graphql.Union{
				Name: typ.Name,
			}

		case "ENUM":
			all[typ.Name] = &graphql.Enum{
				Type: typ.Name,
			}

		default:
			return nil, fmt.Errorf("unknown type kind %s", typ.Kind)
		}
	}

	// Initialize barebone types
	for _, typ := range schema.Schema.Types {
		switch typ.Kind {
		case "OBJECT":
			fields := make(map[string]*graphql.Field)
			for _, field := range typ.Fields {
				fieldTyp, err := lookupTypeRef(field.Type, all)
				if err != nil {
					return nil, fmt.Errorf("typ %s field %s has bad typ: %v",
						typ.Name, field.Name, err)
				}

				parsed, err := parseInputFields(field.Args, all)
				if err != nil {
					return nil, fmt.Errorf("field %s input: %v", field.Name, err)
				}

				fields[field.Name] = &graphql.Field{
					Args: parsed,
					Type: fieldTyp,
				}
			}

			all[typ.Name].(*graphql.Object).Fields = fields

		case "INPUT_OBJECT":
			parsed, err := parseInputFields(typ.InputFields, all)
			if err != nil {
				return nil, fmt.Errorf("typ %s: %v", typ.Name, err)
			}

			all[typ.Name].(*graphql.InputObject).InputFields = parsed

		case "UNION":
			types := make(map[string]*graphql.Object)
			for _, other := range typ.PossibleTypes {
				if other.Kind != "OBJECT" {
					return nil, fmt.Errorf("typ %s has possible typ not OBJECT: %v", typ.Name, other)
				}
				typ, ok := all[other.Name].(*graphql.Object)
				if !ok {
					return nil, fmt.Errorf("typ %s possible typ %s does not refer to obj", typ.Name, other.Name)
				}
				types[typ.Name] = typ
			}

			all[typ.Name].(*graphql.Union).Types = types

		case "ENUM":
			// XXX: introspection relies on the EnumValues map.
			reverseMap := make(map[interface{}]string)
			values := make([]string, 0, len(typ.EnumValues))
			for _, value := range typ.EnumValues {
				values = append(values, value.Name)
				reverseMap[value.Name] = value.Name
			}

			enum := all[typ.Name].(*graphql.Enum)
			enum.Values = values
			enum.ReverseMap = reverseMap

		case "SCALAR":
			// pass

		default:
			return nil, fmt.Errorf("unknown type kind %s", typ.Kind)
		}
	}

	return all, nil
}

// XXX: for types missing __federation, take intersection?

// XXX: for (merged) unions, make sure we only send possible types
// to each service

// TODO: support descriptions in merging
<commit_msg>federation: schema supports an enum as an input arg<commit_after>package federation

import (
	"errors"
	"fmt"
	"sort"

	"github.com/samsarahq/thunder/graphql"
)

// serviceSchemas holds all schemas for all of versions of
// all executors services. It is a map from service name
// and version to schema.
type serviceSchemas map[string]map[string]*introspectionQueryResult

// FieldInfo holds federation-specific information for
// graphql.Fields used to plan and execute queries.
type FieldInfo struct {
	// Services is the set of all services that can resolve this
	// field. If a service has multiple versions, all versions
	// must be able to resolve the field.
	Services map[string]bool
}

// SchemaWithFederationInfo holds a graphql.Schema along with
// federtion-specific annotations per field.
type SchemaWithFederationInfo struct {
	Schema *graphql.Schema
	// Fields is a map of fields to services which they belong to
	Fields map[*graphql.Field]*FieldInfo
}

// convertVersionedSchemas takes schemas for all of versions of
// all executors services and generates a single merged schema
// annotated with mapping from field to all services that know
// how to resolve the field
func convertVersionedSchemas(schemas serviceSchemas) (*SchemaWithFederationInfo, error) {
	serviceNames := make([]string, 0, len(schemas))
	for service := range schemas {
		serviceNames = append(serviceNames, service)
	}
	sort.Strings(serviceNames)

	serviceSchemasByName := make(map[string]*introspectionQueryResult)

	// Finds the intersection of different version of the schemas
	var serviceSchemas []*introspectionQueryResult
	for _, service := range serviceNames {
		versions := schemas[service]

		versionNames := make([]string, 0, len(versions))
		for version := range versions {
			versionNames = append(versionNames, version)
		}
		sort.Strings(versionNames)

		var versionSchemas []*introspectionQueryResult
		for _, version := range versionNames {
			versionSchemas = append(versionSchemas, versions[version])
		}

		serviceSchema, err := mergeSchemaSlice(versionSchemas, Intersection)
		if err != nil {
			return nil, err
		}

		serviceSchemasByName[service] = serviceSchema

		serviceSchemas = append(serviceSchemas, serviceSchema)
	}

	// Finds the union of all the schemas from different executor services
	merged, err := mergeSchemaSlice(serviceSchemas, Union)
	if err != nil {
		return nil, err
	}

	types, err := parseSchema(merged)
	if err != nil {
		return nil, err
	}

	fieldInfos := make(map[*graphql.Field]*FieldInfo)
	for _, service := range serviceNames {
		for _, typ := range serviceSchemasByName[service].Schema.Types {
			if typ.Kind == "OBJECT" {
				obj := types[typ.Name].(*graphql.Object)

				for _, field := range typ.Fields {
					f := obj.Fields[field.Name]

					info, ok := fieldInfos[f]
					if !ok {
						info = &FieldInfo{
							Services: map[string]bool{},
						}
						fieldInfos[f] = info
					}
					info.Services[service] = true
				}
			}
		}
	}

	return &SchemaWithFederationInfo{
		Schema: &graphql.Schema{
			Query:    types["Query"],
			Mutation: types["Mutation"],
		},
		Fields: fieldInfos,
	}, nil
}

// convertSchema annotates the schema with federation information vt
// mapping fields to the corresponding services.
func convertSchema(schemas map[string]*introspectionQueryResult) (*SchemaWithFederationInfo, error) {
	versionedSchemas := make(serviceSchemas)
	for service, schema := range schemas {
		versionedSchemas[service] = map[string]*introspectionQueryResult{
			"": schema,
		}
	}
	return convertVersionedSchemas(versionedSchemas)
}

// lookupTypeRef maps the a introspected type to a graphql type
func lookupType(t *introspectionTypeRef, all map[string]graphql.Type) (*introspectionTypeRef, error) {
	if t == nil {
		return nil, errors.New("malformed typeref")
	}
	switch t.Kind {
	case "SCALAR", "OBJECT", "UNION", "INPUT_OBJECT", "ENUM":
		return t, nil
	case "LIST":
		return lookupType(t.OfType, all)
	case "NON_NULL":
		return lookupType(t.OfType, all)
	default:
		return nil, fmt.Errorf("unknown type kind %s", t.Kind)
	}
}

// lookupTypeRef maps the a introspected type to a graphql type
func lookupTypeRef(t *introspectionTypeRef, all map[string]graphql.Type) (graphql.Type, error) {
	if t == nil {
		return nil, errors.New("malformed typeref")
	}

	switch t.Kind {
	case "SCALAR", "OBJECT", "UNION", "INPUT_OBJECT", "ENUM":
		// TODO: enforce type?
		typ, ok := all[t.Name]
		if !ok {
			return nil, fmt.Errorf("type %s not found among top-level types", t.Name)
		}
		return typ, nil

	case "LIST":
		inner, err := lookupTypeRef(t.OfType, all)
		if err != nil {
			return nil, err
		}
		return &graphql.List{
			Type: inner,
		}, nil

	case "NON_NULL":
		inner, err := lookupTypeRef(t.OfType, all)
		if err != nil {
			return nil, err
		}
		return &graphql.NonNull{
			Type: inner,
		}, nil

	default:
		return nil, fmt.Errorf("unknown type kind %s", t.Kind)
	}
}

// parseInputFields maps a list of input types to a list of graphql types
func parseInputFields(source []introspectionInputField, all map[string]graphql.Type) (map[string]graphql.Type, error) {
	fields := make(map[string]graphql.Type)

	for _, field := range source {
		// Validate the inputType is valid
		rawType, err := lookupType(field.Type, all)
		if err != nil {
			return nil, fmt.Errorf("type %s not found", rawType.Name)
		}
		switch rawType.Kind {
		case "INPUT_OBJECT", "SCALAR", "ENUM":
		default:
			return nil, fmt.Errorf("input field %s has bad typ: %s", field.Name, rawType.Kind)
		}

		inputType, err := lookupTypeRef(field.Type, all)
		if err != nil {
			return nil, fmt.Errorf("field %s has bad typ: %v", field.Name, err)
		}
		fields[field.Name] = inputType
	}

	return fields, nil
}

// parseSchema takes the introspected schema, validates the types,
// and maps every field to the graphql types
func parseSchema(schema *introspectionQueryResult) (map[string]graphql.Type, error) {
	all := make(map[string]graphql.Type)

	for _, typ := range schema.Schema.Types {
		if _, ok := all[typ.Name]; ok {
			return nil, fmt.Errorf("duplicate type %s", typ.Name)
		}

		switch typ.Kind {
		case "OBJECT":
			all[typ.Name] = &graphql.Object{
				Name: typ.Name,
			}

		case "INPUT_OBJECT":
			all[typ.Name] = &graphql.InputObject{
				Name: typ.Name,
			}

		case "SCALAR":
			all[typ.Name] = &graphql.Scalar{
				Type: typ.Name,
			}

		case "UNION":
			all[typ.Name] = &graphql.Union{
				Name: typ.Name,
			}

		case "ENUM":
			all[typ.Name] = &graphql.Enum{
				Type: typ.Name,
			}

		default:
			return nil, fmt.Errorf("unknown type kind %s", typ.Kind)
		}
	}

	// Initialize barebone types
	for _, typ := range schema.Schema.Types {
		switch typ.Kind {
		case "OBJECT":
			fields := make(map[string]*graphql.Field)
			for _, field := range typ.Fields {
				fieldTyp, err := lookupTypeRef(field.Type, all)
				if err != nil {
					return nil, fmt.Errorf("typ %s field %s has bad typ: %v",
						typ.Name, field.Name, err)
				}

				parsed, err := parseInputFields(field.Args, all)
				if err != nil {
					return nil, fmt.Errorf("field %s input: %v", field.Name, err)
				}

				fields[field.Name] = &graphql.Field{
					Args: parsed,
					Type: fieldTyp,
				}
			}

			all[typ.Name].(*graphql.Object).Fields = fields

		case "INPUT_OBJECT":
			parsed, err := parseInputFields(typ.InputFields, all)
			if err != nil {
				return nil, fmt.Errorf("typ %s: %v", typ.Name, err)
			}

			all[typ.Name].(*graphql.InputObject).InputFields = parsed

		case "UNION":
			types := make(map[string]*graphql.Object)
			for _, other := range typ.PossibleTypes {
				if other.Kind != "OBJECT" {
					return nil, fmt.Errorf("typ %s has possible typ not OBJECT: %v", typ.Name, other)
				}
				typ, ok := all[other.Name].(*graphql.Object)
				if !ok {
					return nil, fmt.Errorf("typ %s possible typ %s does not refer to obj", typ.Name, other.Name)
				}
				types[typ.Name] = typ
			}

			all[typ.Name].(*graphql.Union).Types = types

		case "ENUM":
			// XXX: introspection relies on the EnumValues map.
			reverseMap := make(map[interface{}]string)
			values := make([]string, 0, len(typ.EnumValues))
			for _, value := range typ.EnumValues {
				values = append(values, value.Name)
				reverseMap[value.Name] = value.Name
			}

			enum := all[typ.Name].(*graphql.Enum)
			enum.Values = values
			enum.ReverseMap = reverseMap

		case "SCALAR":
			// pass

		default:
			return nil, fmt.Errorf("unknown type kind %s", typ.Kind)
		}
	}

	return all, nil
}

// XXX: for types missing __federation, take intersection?

// XXX: for (merged) unions, make sure we only send possible types
// to each service

// TODO: support descriptions in merging
<|endoftext|>


<commit_before>package main

import (
    "log"
    "fmt"
    "os"
    "path"

    "github.com/docker/libcompose/config"
    "github.com/docker/libcompose/project"
)

func main() {

    // # Get stack name from --name
	// # Get stack name from directory if not passed
    pwd, err := os.Getwd()
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
    _, dir := path.Split(pwd)

    project := project.NewProject(&project.Context{
            ComposeFiles: []string{"docker-compose.yml"},
            ProjectName:  dir,
    }, nil, &config.ParseOptions{})

    if err := project.Parse(); err != nil {
        log.Fatal(err)
    }

    // Networks

    if project.NetworkConfigs == nil || len(project.NetworkConfigs) == 0 {
        // if no network create default
        fmt.Println("No networks!")
    } else {
        for name, config := range project.NetworkConfigs {
            // # if network external check if exists
            if config.External.External {
                fmt.Println(fmt.Sprintf("Network: %s (external)", name))
                // handle external name
                if config.External.Name != "" {
                    fmt.Println(fmt.Sprintf("Network: %s (external: %s)", name, config.External.Name))
                }
            } else {
                // # else create network
                // # if no driver set default
                if config.Driver != "" {
                    fmt.Println(fmt.Sprintf("Network: %s (driver: %s)", name, config.Driver))
                } else {
                    fmt.Println(fmt.Sprintf("Network: %s (driver: default)", name))
                }
            }
        }
    }

    // # Volumes

    if project.VolumeConfigs == nil || len(project.VolumeConfigs) == 0 {
        // no volumes
        fmt.Println("No volumes")
    } else {
        for name, config := range project.VolumeConfigs {
            // # if volume external check if exists
            if config.External.External {
                fmt.Println(fmt.Sprintf("Volume: %s (external)", name))
                // handle external name
                if config.External.Name != "" {
                    fmt.Println(fmt.Sprintf("Volume: %s (external: %s)", name, config.External.Name))
                }
            } else {
                // # else create volume
                fmt.Println(fmt.Sprintf("Volume: %s", name))
            }
        }
    }

	// # Services
    // # Dependencies?

    // # Timeouts / Errors

}
<commit_msg>Add services logic<commit_after>package main

import (
    "log"
    "fmt"
    "os"
    "path"

    "github.com/docker/libcompose/config"
    "github.com/docker/libcompose/project"
)

func main() {

    // # Get stack name from --name
	// # Get stack name from directory if not passed
    pwd, err := os.Getwd()
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
    _, dir := path.Split(pwd)

    project := project.NewProject(&project.Context{
            ComposeFiles: []string{"docker-compose.yml"},
            ProjectName:  dir,
    }, nil, &config.ParseOptions{})

    if err := project.Parse(); err != nil {
        log.Fatal(err)
    }

    // Networks

    if project.NetworkConfigs == nil || len(project.NetworkConfigs) == 0 {
        // if no network create default
        fmt.Println("No networks!")
    } else {
        for name, config := range project.NetworkConfigs {
            // # if network external check if exists
            if config.External.External {
                fmt.Println(fmt.Sprintf("Network: %s (external)", name))
                // handle external name
                if config.External.Name != "" {
                    fmt.Println(fmt.Sprintf("Network: %s (external: %s)", name, config.External.Name))
                }
            } else {
                // # else create network
                // # if no driver set default
                if config.Driver != "" {
                    fmt.Println(fmt.Sprintf("Network: %s (driver: %s)", name, config.Driver))
                } else {
                    fmt.Println(fmt.Sprintf("Network: %s (driver: default)", name))
                }
            }
        }
    }

    // # Volumes

    if project.VolumeConfigs == nil || len(project.VolumeConfigs) == 0 {
        // no volumes
        fmt.Println("No volumes")
    } else {
        for name, config := range project.VolumeConfigs {
            // # if volume external check if exists
            if config.External.External {
                fmt.Println(fmt.Sprintf("Volume: %s (external)", name))
                // handle external name
                if config.External.Name != "" {
                    fmt.Println(fmt.Sprintf("Volume: %s (external: %s)", name, config.External.Name))
                }
            } else {
                // # else create volume
                fmt.Println(fmt.Sprintf("Volume: %s", name))
            }
        }
    }

	// # Services

    if project.ServiceConfigs == nil {
        // no service, abort?
        fmt.Println("No services")
    } else {
        for name, config := range project.ServiceConfigs.All() {
            // image, ports, networks, volumes
            fmt.Println(fmt.Sprintf("Service: %s", project.Name + "_" + name))
            if config.Image != "" {
                fmt.Println(fmt.Sprintf("  Image: %s", config.Image))
            } else {
                // # if no image abort
                fmt.Println("  No image!")
            }
            for _, port := range config.Ports {
                fmt.Println(fmt.Sprintf("  Port: %s", port))
            }
            if config.Networks != nil && len(config.Networks.Networks) != 0 {
                for _, network := range config.Networks.Networks {
                    fmt.Println(fmt.Sprintf("  Network: %s", network.RealName))
                }
            }
            if config.Volumes != nil && len(config.Volumes.Volumes) != 0 {
                for _, volume := range config.Volumes.Volumes {
                    fmt.Println(fmt.Sprintf("  Volume: %s", volume))
                }
            }
        }
    }

    // # Exposed Ports
    // # Dependencies?
    // # More services config params
    // # Timeouts / Errors

}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package cinder

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

	"github.com/container-storage-interface/spec/lib/go/csi"
	"golang.org/x/net/context"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"k8s.io/klog"

	"k8s.io/cloud-provider-openstack/pkg/csi/cinder/mount"
	"k8s.io/cloud-provider-openstack/pkg/csi/cinder/openstack"
	"k8s.io/cloud-provider-openstack/pkg/util/metadata"
)

type nodeServer struct {
	Driver   *CinderDriver
	Mount    mount.IMount
	Metadata openstack.IMetadata
}

func (ns *nodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublishVolumeRequest) (*csi.NodePublishVolumeResponse, error) {
	klog.V(4).Infof("NodePublishVolume: called with args %+v", *req)

	source := req.GetStagingTargetPath()
	targetPath := req.GetTargetPath()
	volumeCapability := req.GetVolumeCapability()

	if len(source) == 0 || len(targetPath) == 0 || volumeCapability == nil {
		return nil, status.Error(codes.InvalidArgument, "NodePublishVolume missing required arguments")
	}

	mountOptions := []string{"bind"}
	if req.GetReadonly() {
		mountOptions = append(mountOptions, "ro")
	} else {
		mountOptions = append(mountOptions, "rw")
	}

	if blk := volumeCapability.GetBlock(); blk != nil {
		return nodePublishVolumeForBlock(req, ns, mountOptions)
	}

	m := ns.Mount
	// Verify whether mounted
	notMnt, err := m.IsLikelyNotMountPointAttach(targetPath)
	if err != nil {
		return nil, status.Error(codes.Internal, err.Error())
	}

	// Volume Mount
	if notMnt {
		fsType := "ext4"
		if mnt := volumeCapability.GetMount(); mnt != nil {
			if mnt.FsType != "" {
				fsType = mnt.FsType
			}
		}
		// Mount
		err = m.Mount(source, targetPath, fsType, mountOptions)
		if err != nil {
			return nil, status.Error(codes.Internal, err.Error())
		}
	}

	return &csi.NodePublishVolumeResponse{}, nil
}

func nodePublishVolumeForBlock(req *csi.NodePublishVolumeRequest, ns *nodeServer, mountOptions []string) (*csi.NodePublishVolumeResponse, error) {
	klog.V(4).Infof("NodePublishVolumeBlock: called with args %+v", *req)

	volumeID := req.GetVolumeId()
	targetPath := req.GetTargetPath()
	podVolumePath := filepath.Dir(targetPath)

	m := ns.Mount

	// Do not trust the path provided by cinder, get the real path on node
	source, err := getDevicePath(volumeID, m)
	if source == "" {
		return nil, status.Error(codes.Internal, "Unable to find Device path for volume")
	}

	exists, err := m.GetBaseMounter().ExistsPath(podVolumePath)
	if err != nil {
		return nil, status.Error(codes.Internal, err.Error())
	}
	if !exists {
		if err := m.GetBaseMounter().MakeDir(podVolumePath); err != nil {
			return nil, status.Errorf(codes.Internal, "Could not create dir %q: %v", podVolumePath, err)
		}
	}
	err = m.GetBaseMounter().MakeFile(targetPath)
	if err != nil {
		return nil, status.Errorf(codes.Internal, "Error in making file %v", err)
	}

	if err := m.GetBaseMounter().Mount(source, targetPath, "", mountOptions); err != nil {
		if removeErr := os.Remove(targetPath); removeErr != nil {
			return nil, status.Errorf(codes.Internal, "Could not remove mount target %q: %v", targetPath, err)
		}
		return nil, status.Errorf(codes.Internal, "Could not mount %q at %q: %v", source, targetPath, err)
	}

	return &csi.NodePublishVolumeResponse{}, nil
}

func (ns *nodeServer) NodeUnpublishVolume(ctx context.Context, req *csi.NodeUnpublishVolumeRequest) (*csi.NodeUnpublishVolumeResponse, error) {
	klog.V(4).Infof("NodeUnPublishVolume: called with args %+v", *req)

	targetPath := req.GetTargetPath()
	if len(targetPath) == 0 {
		return nil, status.Error(codes.InvalidArgument, "NodeUnpublishVolume Target Path must be provided")
	}

	m := ns.Mount

	notMnt, err := m.IsLikelyNotMountPointDetach(targetPath)
	if err != nil && !mount.IsCorruptedMnt(err) {
		return nil, status.Error(codes.Internal, err.Error())
	}
	if notMnt && !mount.IsCorruptedMnt(err) {
		return nil, status.Error(codes.NotFound, "Volume not mounted")
	}

	err = m.UnmountPath(targetPath)
	if err != nil {
		return nil, status.Error(codes.Internal, err.Error())
	}

	return &csi.NodeUnpublishVolumeResponse{}, nil
}

func (ns *nodeServer) NodeStageVolume(ctx context.Context, req *csi.NodeStageVolumeRequest) (*csi.NodeStageVolumeResponse, error) {
	klog.V(4).Infof("NodeStageVolume: called with args %+v", *req)

	stagingTarget := req.GetStagingTargetPath()
	volumeCapability := req.GetVolumeCapability()
	volumeID := req.GetVolumeId()

	if len(volumeID) == 0 {
		return nil, status.Error(codes.InvalidArgument, "Volume Id not provided")
	}

	if len(stagingTarget) == 0 {
		return nil, status.Error(codes.InvalidArgument, "Staging target not provided")
	}
	if volumeCapability == nil {
		return nil, status.Error(codes.InvalidArgument, "NodeStageVolume Volume Capability must be provided")
	}

	m := ns.Mount
	// Do not trust the path provided by cinder, get the real path on node
	devicePath, err := getDevicePath(volumeID, m)
	if devicePath == "" {
		return nil, status.Error(codes.Internal, "Unable to find Device path for volume")
	}

	if blk := volumeCapability.GetBlock(); blk != nil {
		// If block volume, do nothing
		return &csi.NodeStageVolumeResponse{}, nil
	}

	// Verify whether mounted
	notMnt, err := m.IsLikelyNotMountPointAttach(stagingTarget)
	if err != nil {
		return nil, status.Error(codes.Internal, err.Error())
	}

	// Volume Mount
	if notMnt {
		// set default fstype is ext4
		fsType := "ext4"
		var options []string
		if mnt := volumeCapability.GetMount(); mnt != nil {
			if mnt.FsType != "" {
				fsType = mnt.FsType
			}
			mountFlags := mnt.GetMountFlags()
			options = append(options, mountFlags...)
		}
		// Mount
		err = m.FormatAndMount(devicePath, stagingTarget, fsType, options)
		if err != nil {
			return nil, status.Error(codes.Internal, err.Error())
		}
	}

	return &csi.NodeStageVolumeResponse{}, nil
}

func (ns *nodeServer) NodeUnstageVolume(ctx context.Context, req *csi.NodeUnstageVolumeRequest) (*csi.NodeUnstageVolumeResponse, error) {
	klog.V(4).Infof("NodeUnstageVolume: called with args %+v", *req)

	if len(req.GetVolumeId()) == 0 {
		return nil, status.Error(codes.InvalidArgument, "Volume Id not provided")
	}

	stagingTargetPath := req.GetStagingTargetPath()
	if len(stagingTargetPath) == 0 {
		return nil, status.Error(codes.InvalidArgument, "NodeUnstageVolume Staging Target Path must be provided")
	}

	m := ns.Mount

	notMnt, err := m.IsLikelyNotMountPointDetach(stagingTargetPath)
	if err != nil && !mount.IsCorruptedMnt(err) {
		return nil, status.Error(codes.Internal, err.Error())
	}
	if notMnt && !mount.IsCorruptedMnt(err) {
		return nil, status.Error(codes.NotFound, "Volume not mounted")
	}

	err = m.UnmountPath(stagingTargetPath)
	if err != nil {
		return nil, status.Error(codes.Internal, err.Error())
	}

	return &csi.NodeUnstageVolumeResponse{}, nil
}

func (ns *nodeServer) NodeGetInfo(ctx context.Context, req *csi.NodeGetInfoRequest) (*csi.NodeGetInfoResponse, error) {

	nodeID, err := getNodeID(ns.Mount, ns.Metadata)
	if err != nil {
		return nil, err
	}
	zone, err := getAvailabilityZoneMetadataService(ns.Metadata)
	topology := &csi.Topology{Segments: map[string]string{topologyKey: zone}}

	maxVolume := getMaxVolumeLimit()

	return &csi.NodeGetInfoResponse{
		NodeId:             nodeID,
		AccessibleTopology: topology,
		MaxVolumesPerNode:  maxVolume,
	}, nil
}

func (ns *nodeServer) NodeGetCapabilities(ctx context.Context, req *csi.NodeGetCapabilitiesRequest) (*csi.NodeGetCapabilitiesResponse, error) {
	klog.V(5).Infof("NodeGetCapabilities called with req: %#v", req)

	return &csi.NodeGetCapabilitiesResponse{
		Capabilities: ns.Driver.nscap,
	}, nil
}

func (ns *nodeServer) NodeGetVolumeStats(ctx context.Context, req *csi.NodeGetVolumeStatsRequest) (*csi.NodeGetVolumeStatsResponse, error) {
	return nil, status.Error(codes.Unimplemented, fmt.Sprintf("NodeGetVolumeStats is not yet implemented"))
}

func (ns *nodeServer) NodeExpandVolume(ctx context.Context, req *csi.NodeExpandVolumeRequest) (*csi.NodeExpandVolumeResponse, error) {
	return nil, status.Error(codes.Unimplemented, fmt.Sprintf("NodeExpandVolume is not yet implemented"))
}

func getDevicePath(volumeID string, m mount.IMount) (string, error) {
	var devicePath string
	devicePath, _ = m.GetDevicePath(volumeID)
	if devicePath == "" {
		// try to get from metadata service
		devicePath = metadata.GetDevicePath(volumeID)
	}

	return devicePath, nil

}
func getNodeIDMountProvider(m mount.IMount) (string, error) {
	nodeID, err := m.GetInstanceID()
	if err != nil {
		klog.V(3).Infof("Failed to GetInstanceID: %v", err)
		return "", err
	}

	return nodeID, nil
}

func getNodeIDMetdataService(m openstack.IMetadata) (string, error) {

	nodeID, err := m.GetInstanceID()
	if err != nil {
		return "", err
	}
	return nodeID, nil
}

func getAvailabilityZoneMetadataService(m openstack.IMetadata) (string, error) {

	zone, err := m.GetAvailabilityZone()
	if err != nil {
		return "", err
	}
	return zone, nil
}

func getNodeID(mount mount.IMount, metadata openstack.IMetadata) (string, error) {
	// First try to get instance id from mount provider
	nodeID, err := getNodeIDMountProvider(mount)
	if err == nil || nodeID != "" {
		return nodeID, nil
	}

	klog.V(3).Infof("Failed to GetInstanceID from mount data: %v", err)
	klog.V(3).Info("Trying to GetInstanceID from metadata service")
	nodeID, err = getNodeIDMetdataService(metadata)
	if err != nil {
		klog.V(3).Infof("Failed to GetInstanceID from metadata service: %v", err)
		return "", err
	}
	return nodeID, nil
}

func getMaxVolumeLimit() int64 {
	return openstack.GetMaxVolLimit()

}
<commit_msg>Remove unnucessary log and adjust some logic (#353)<commit_after>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package cinder

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

	"github.com/container-storage-interface/spec/lib/go/csi"
	"golang.org/x/net/context"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"k8s.io/klog"

	"k8s.io/cloud-provider-openstack/pkg/csi/cinder/mount"
	"k8s.io/cloud-provider-openstack/pkg/csi/cinder/openstack"
	"k8s.io/cloud-provider-openstack/pkg/util/metadata"
)

type nodeServer struct {
	Driver   *CinderDriver
	Mount    mount.IMount
	Metadata openstack.IMetadata
}

func (ns *nodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublishVolumeRequest) (*csi.NodePublishVolumeResponse, error) {
	klog.V(4).Infof("NodePublishVolume: called with args %+v", *req)

	source := req.GetStagingTargetPath()
	targetPath := req.GetTargetPath()
	volumeCapability := req.GetVolumeCapability()

	if len(source) == 0 || len(targetPath) == 0 || volumeCapability == nil {
		return nil, status.Error(codes.InvalidArgument, "NodePublishVolume missing required arguments")
	}

	mountOptions := []string{"bind"}
	if req.GetReadonly() {
		mountOptions = append(mountOptions, "ro")
	} else {
		mountOptions = append(mountOptions, "rw")
	}

	if blk := volumeCapability.GetBlock(); blk != nil {
		return nodePublishVolumeForBlock(req, ns, mountOptions)
	}

	m := ns.Mount
	// Verify whether mounted
	notMnt, err := m.IsLikelyNotMountPointAttach(targetPath)
	if err != nil {
		return nil, status.Error(codes.Internal, err.Error())
	}

	// Volume Mount
	if notMnt {
		fsType := "ext4"
		if mnt := volumeCapability.GetMount(); mnt != nil {
			if mnt.FsType != "" {
				fsType = mnt.FsType
			}
		}
		// Mount
		err = m.Mount(source, targetPath, fsType, mountOptions)
		if err != nil {
			return nil, status.Error(codes.Internal, err.Error())
		}
	}

	return &csi.NodePublishVolumeResponse{}, nil
}

func nodePublishVolumeForBlock(req *csi.NodePublishVolumeRequest, ns *nodeServer, mountOptions []string) (*csi.NodePublishVolumeResponse, error) {
	klog.V(4).Infof("NodePublishVolumeBlock: called with args %+v", *req)

	volumeID := req.GetVolumeId()
	targetPath := req.GetTargetPath()
	podVolumePath := filepath.Dir(targetPath)

	m := ns.Mount

	// Do not trust the path provided by cinder, get the real path on node
	source, err := getDevicePath(volumeID, m)
	if source == "" {
		return nil, status.Error(codes.Internal, "Unable to find Device path for volume")
	}

	exists, err := m.GetBaseMounter().ExistsPath(podVolumePath)
	if err != nil {
		return nil, status.Error(codes.Internal, err.Error())
	}
	if !exists {
		if err := m.GetBaseMounter().MakeDir(podVolumePath); err != nil {
			return nil, status.Errorf(codes.Internal, "Could not create dir %q: %v", podVolumePath, err)
		}
	}
	err = m.GetBaseMounter().MakeFile(targetPath)
	if err != nil {
		return nil, status.Errorf(codes.Internal, "Error in making file %v", err)
	}

	if err := m.GetBaseMounter().Mount(source, targetPath, "", mountOptions); err != nil {
		if removeErr := os.Remove(targetPath); removeErr != nil {
			return nil, status.Errorf(codes.Internal, "Could not remove mount target %q: %v", targetPath, err)
		}
		return nil, status.Errorf(codes.Internal, "Could not mount %q at %q: %v", source, targetPath, err)
	}

	return &csi.NodePublishVolumeResponse{}, nil
}

func (ns *nodeServer) NodeUnpublishVolume(ctx context.Context, req *csi.NodeUnpublishVolumeRequest) (*csi.NodeUnpublishVolumeResponse, error) {
	klog.V(4).Infof("NodeUnPublishVolume: called with args %+v", *req)

	targetPath := req.GetTargetPath()
	if len(targetPath) == 0 {
		return nil, status.Error(codes.InvalidArgument, "NodeUnpublishVolume Target Path must be provided")
	}

	m := ns.Mount

	notMnt, err := m.IsLikelyNotMountPointDetach(targetPath)
	if err != nil && !mount.IsCorruptedMnt(err) {
		return nil, status.Error(codes.Internal, err.Error())
	}
	if notMnt && !mount.IsCorruptedMnt(err) {
		return nil, status.Error(codes.NotFound, "Volume not mounted")
	}

	err = m.UnmountPath(targetPath)
	if err != nil {
		return nil, status.Error(codes.Internal, err.Error())
	}

	return &csi.NodeUnpublishVolumeResponse{}, nil
}

func (ns *nodeServer) NodeStageVolume(ctx context.Context, req *csi.NodeStageVolumeRequest) (*csi.NodeStageVolumeResponse, error) {
	klog.V(4).Infof("NodeStageVolume: called with args %+v", *req)

	stagingTarget := req.GetStagingTargetPath()
	volumeCapability := req.GetVolumeCapability()
	volumeID := req.GetVolumeId()

	if len(volumeID) == 0 {
		return nil, status.Error(codes.InvalidArgument, "Volume Id not provided")
	}

	if len(stagingTarget) == 0 {
		return nil, status.Error(codes.InvalidArgument, "Staging target not provided")
	}
	if volumeCapability == nil {
		return nil, status.Error(codes.InvalidArgument, "NodeStageVolume Volume Capability must be provided")
	}

	m := ns.Mount
	// Do not trust the path provided by cinder, get the real path on node
	devicePath, err := getDevicePath(volumeID, m)
	if devicePath == "" {
		return nil, status.Error(codes.Internal, "Unable to find Device path for volume")
	}

	if blk := volumeCapability.GetBlock(); blk != nil {
		// If block volume, do nothing
		return &csi.NodeStageVolumeResponse{}, nil
	}

	// Verify whether mounted
	notMnt, err := m.IsLikelyNotMountPointAttach(stagingTarget)
	if err != nil {
		return nil, status.Error(codes.Internal, err.Error())
	}

	// Volume Mount
	if notMnt {
		// set default fstype is ext4
		fsType := "ext4"
		var options []string
		if mnt := volumeCapability.GetMount(); mnt != nil {
			if mnt.FsType != "" {
				fsType = mnt.FsType
			}
			mountFlags := mnt.GetMountFlags()
			options = append(options, mountFlags...)
		}
		// Mount
		err = m.FormatAndMount(devicePath, stagingTarget, fsType, options)
		if err != nil {
			return nil, status.Error(codes.Internal, err.Error())
		}
	}

	return &csi.NodeStageVolumeResponse{}, nil
}

func (ns *nodeServer) NodeUnstageVolume(ctx context.Context, req *csi.NodeUnstageVolumeRequest) (*csi.NodeUnstageVolumeResponse, error) {
	klog.V(4).Infof("NodeUnstageVolume: called with args %+v", *req)

	if len(req.GetVolumeId()) == 0 {
		return nil, status.Error(codes.InvalidArgument, "Volume Id not provided")
	}

	stagingTargetPath := req.GetStagingTargetPath()
	if len(stagingTargetPath) == 0 {
		return nil, status.Error(codes.InvalidArgument, "NodeUnstageVolume Staging Target Path must be provided")
	}

	m := ns.Mount

	notMnt, err := m.IsLikelyNotMountPointDetach(stagingTargetPath)
	if err != nil && !mount.IsCorruptedMnt(err) {
		return nil, status.Error(codes.Internal, err.Error())
	}
	if notMnt && !mount.IsCorruptedMnt(err) {
		return nil, status.Error(codes.NotFound, "Volume not mounted")
	}

	err = m.UnmountPath(stagingTargetPath)
	if err != nil {
		return nil, status.Error(codes.Internal, err.Error())
	}

	return &csi.NodeUnstageVolumeResponse{}, nil
}

func (ns *nodeServer) NodeGetInfo(ctx context.Context, req *csi.NodeGetInfoRequest) (*csi.NodeGetInfoResponse, error) {

	nodeID, err := getNodeID(ns.Mount, ns.Metadata)
	if err != nil {
		return nil, err
	}
	zone, err := getAvailabilityZoneMetadataService(ns.Metadata)
	topology := &csi.Topology{Segments: map[string]string{topologyKey: zone}}

	maxVolume := getMaxVolumeLimit()

	return &csi.NodeGetInfoResponse{
		NodeId:             nodeID,
		AccessibleTopology: topology,
		MaxVolumesPerNode:  maxVolume,
	}, nil
}

func (ns *nodeServer) NodeGetCapabilities(ctx context.Context, req *csi.NodeGetCapabilitiesRequest) (*csi.NodeGetCapabilitiesResponse, error) {
	klog.V(5).Infof("NodeGetCapabilities called with req: %#v", req)

	return &csi.NodeGetCapabilitiesResponse{
		Capabilities: ns.Driver.nscap,
	}, nil
}

func (ns *nodeServer) NodeGetVolumeStats(ctx context.Context, req *csi.NodeGetVolumeStatsRequest) (*csi.NodeGetVolumeStatsResponse, error) {
	return nil, status.Error(codes.Unimplemented, fmt.Sprintf("NodeGetVolumeStats is not yet implemented"))
}

func (ns *nodeServer) NodeExpandVolume(ctx context.Context, req *csi.NodeExpandVolumeRequest) (*csi.NodeExpandVolumeResponse, error) {
	return nil, status.Error(codes.Unimplemented, fmt.Sprintf("NodeExpandVolume is not yet implemented"))
}

func getDevicePath(volumeID string, m mount.IMount) (string, error) {
	var devicePath string
	devicePath, _ = m.GetDevicePath(volumeID)
	if devicePath == "" {
		// try to get from metadata service
		devicePath = metadata.GetDevicePath(volumeID)
	}

	return devicePath, nil

}
func getNodeIDMountProvider(m mount.IMount) (string, error) {
	nodeID, err := m.GetInstanceID()
	if err != nil {
		klog.V(3).Infof("Failed to GetInstanceID: %v", err)
		return "", err
	}

	return nodeID, nil
}

func getNodeIDMetdataService(m openstack.IMetadata) (string, error) {

	nodeID, err := m.GetInstanceID()
	if err != nil {
		return "", err
	}
	return nodeID, nil
}

func getAvailabilityZoneMetadataService(m openstack.IMetadata) (string, error) {

	zone, err := m.GetAvailabilityZone()
	if err != nil {
		return "", err
	}
	return zone, nil
}

func getNodeID(mount mount.IMount, metadata openstack.IMetadata) (string, error) {
	// First try to get instance id from mount provider
	nodeID, err := getNodeIDMountProvider(mount)
	if err == nil {
		return nodeID, nil
	}

	klog.V(3).Infof("Trying to GetInstanceID from metadata service")
	nodeID, err = getNodeIDMetdataService(metadata)
	if err != nil {
		klog.V(3).Infof("Failed to GetInstanceID from metadata service: %v", err)
		return "", err
	}
	return nodeID, nil
}

func getMaxVolumeLimit() int64 {
	return openstack.GetMaxVolLimit()

}
<|endoftext|>


<commit_before>package helm

import (
	"fmt"
	"github.com/Aptomi/aptomi/pkg/event"
	"github.com/Aptomi/aptomi/pkg/util"
	"github.com/Aptomi/aptomi/pkg/util/retry"
	"io/ioutil"
	"k8s.io/helm/cmd/helm/installer"
	"k8s.io/helm/pkg/helm"
	"k8s.io/helm/pkg/helm/portforwarder"
	"k8s.io/helm/pkg/kube"
	"k8s.io/helm/pkg/repo"
	"strings"
)

func getHelmReleaseInfo(params util.NestedParameterMap) (repository, name, version string, err error) {
	repository, ok := params["chartRepo"].(string)
	if !ok {
		err = fmt.Errorf("chartRepo is a mandatory paraneter")
		return
	}

	name, ok = params["chartName"].(string)
	if !ok {
		err = fmt.Errorf("chartName is a mandatory paraneter")
		return
	}

	version = params["chartVersion"].(string)

	return
}

func getHelmReleaseName(deployName string) string {
	return strings.ToLower(util.EscapeName(deployName))
}

func findHelmRelease(helmClient *helm.Client, name string) (bool, error) {
	// todo(slukjanov): use release list filter
	resp, err := helmClient.ListReleases()
	if err != nil {
		return false, err
	}

	for _, release := range resp.Releases {
		if release.Name == name {
			return true, nil
		}
	}

	return false, nil
}

func (cache *clusterCache) newHelmClient(eventLog *event.Log) (*helm.Client, error) {
	if err := cache.ensureTillerTunnel(eventLog); err != nil {
		return nil, err
	}

	return helm.NewClient(helm.Host(cache.tillerHost)), nil
}

func (cache *clusterCache) ensureTillerTunnel(eventLog *event.Log) error {
	cache.lock.Lock()
	defer cache.lock.Unlock()

	if len(cache.tillerHost) > 0 {
		// todo(slukjanov): verify that tunnel is still alive??
		// connection already set up, skip
		return nil
	}

	var tunnelErr error
	ok := retry.Do(120, 5, func() bool {
		cache.tillerTunnel, tunnelErr = cache.newTillerTunnel()

		if tunnelErr != nil {
			if strings.Contains(tunnelErr.Error(), "could not find tiller") {
				err := cache.setupTiller(eventLog)
				if err != nil {
					tunnelErr = err
					return false
				}
			}

			return false
		}

		port := cache.tillerTunnel.Local
		cache.tillerHost = fmt.Sprintf("localhost:%d", port)
		eventLog.WithFields(event.Fields{}).Debugf("Created k8s tunnel using local port: %d", port)

		return true
	})

	if !ok {
		if tunnelErr != nil {
			return tunnelErr
		}

		return fmt.Errorf("tiller tunnel creation timeout for cluster: %s", cache.cluster.Name)
	}

	return nil
}

func (cache *clusterCache) newTillerTunnel() (*kube.Tunnel, error) {
	config, client, err := cache.newKubeClient()
	if err != nil {
		return nil, err
	}

	tillerNamespace := cache.cluster.Config.TillerNamespace
	if tillerNamespace == "" {
		tillerNamespace = "kube-system"
	}

	return portforwarder.New(tillerNamespace, client, config)
}

func (cache *clusterCache) setupTiller(eventLog *event.Log) error {
	_, client, err := cache.newKubeClient()
	if err != nil {
		return err
	}

	tillerNamespace := cache.cluster.Config.TillerNamespace
	if tillerNamespace == "" {
		tillerNamespace = "kube-system"
	}

	err = cache.ensureKubeNamespace(client, tillerNamespace)
	if err != nil {
		return err
	}

	err = cache.createKubeServiceAccount(client, tillerNamespace)
	if err != nil {
		return err
	}

	err = cache.createKubeClusterRoleBinding(client, tillerNamespace)
	if err != nil {
		return err
	}

	return installer.Install(client, &installer.Options{
		Namespace:      tillerNamespace,
		ImageSpec:      "gcr.io/kubernetes-helm/tiller:v2.6.2",
		ServiceAccount: "tiller-" + tillerNamespace,
	})
}

func (plugin *Plugin) fetchChart(repository, name, version string) (string, error) {
	chartURL, err := repo.FindChartInRepoURL(
		repository, name, version,
		"", "", "",
		newGetterProviders(),
	)
	if err != nil {
		return "", fmt.Errorf("error while getting chart url in repo: %s", err)
	}

	chartFile, err := ioutil.TempFile("charts", name)
	if err != nil {
		return "", fmt.Errorf("error while creating temp file for downloading chart: %s", err)
	}

	chartGetter, err := newHTTPGetter(chartURL, "", "", "")
	if err != nil {
		return "", fmt.Errorf("error while creating chart downloader: %s", err)
	}

	resp, err := chartGetter.Get(chartURL)
	if err != nil {
		return "", fmt.Errorf("error while downloading chart: %s", err)
	}

	_, err = chartFile.Write(resp.Bytes())
	if err != nil {
		return "", fmt.Errorf("error while writing downloaded chart to the temp file")
	}

	return chartFile.Name(), nil
}
<commit_msg>Add event log entry about creating tiller<commit_after>package helm

import (
	"fmt"
	"github.com/Aptomi/aptomi/pkg/event"
	"github.com/Aptomi/aptomi/pkg/util"
	"github.com/Aptomi/aptomi/pkg/util/retry"
	"io/ioutil"
	"k8s.io/helm/cmd/helm/installer"
	"k8s.io/helm/pkg/helm"
	"k8s.io/helm/pkg/helm/portforwarder"
	"k8s.io/helm/pkg/kube"
	"k8s.io/helm/pkg/repo"
	"strings"
)

func getHelmReleaseInfo(params util.NestedParameterMap) (repository, name, version string, err error) {
	repository, ok := params["chartRepo"].(string)
	if !ok {
		err = fmt.Errorf("chartRepo is a mandatory paraneter")
		return
	}

	name, ok = params["chartName"].(string)
	if !ok {
		err = fmt.Errorf("chartName is a mandatory paraneter")
		return
	}

	version = params["chartVersion"].(string)

	return
}

func getHelmReleaseName(deployName string) string {
	return strings.ToLower(util.EscapeName(deployName))
}

func findHelmRelease(helmClient *helm.Client, name string) (bool, error) {
	// todo(slukjanov): use release list filter
	resp, err := helmClient.ListReleases()
	if err != nil {
		return false, err
	}

	for _, release := range resp.Releases {
		if release.Name == name {
			return true, nil
		}
	}

	return false, nil
}

func (cache *clusterCache) newHelmClient(eventLog *event.Log) (*helm.Client, error) {
	if err := cache.ensureTillerTunnel(eventLog); err != nil {
		return nil, err
	}

	return helm.NewClient(helm.Host(cache.tillerHost)), nil
}

func (cache *clusterCache) ensureTillerTunnel(eventLog *event.Log) error {
	cache.lock.Lock()
	defer cache.lock.Unlock()

	if len(cache.tillerHost) > 0 {
		// todo(slukjanov): verify that tunnel is still alive??
		// connection already set up, skip
		return nil
	}

	var tunnelErr error
	ok := retry.Do(120, 5, func() bool {
		cache.tillerTunnel, tunnelErr = cache.newTillerTunnel()

		if tunnelErr != nil {
			if strings.Contains(tunnelErr.Error(), "could not find tiller") {
				err := cache.setupTiller(eventLog)
				if err != nil {
					tunnelErr = err
					return false
				}
			}

			return false
		}

		port := cache.tillerTunnel.Local
		cache.tillerHost = fmt.Sprintf("localhost:%d", port)
		eventLog.WithFields(event.Fields{}).Debugf("Created k8s tunnel using local port: %d", port)

		return true
	})

	if !ok {
		if tunnelErr != nil {
			return tunnelErr
		}

		return fmt.Errorf("tiller tunnel creation timeout for cluster: %s", cache.cluster.Name)
	}

	return nil
}

func (cache *clusterCache) newTillerTunnel() (*kube.Tunnel, error) {
	config, client, err := cache.newKubeClient()
	if err != nil {
		return nil, err
	}

	tillerNamespace := cache.cluster.Config.TillerNamespace
	if tillerNamespace == "" {
		tillerNamespace = "kube-system"
	}

	return portforwarder.New(tillerNamespace, client, config)
}

func (cache *clusterCache) setupTiller(eventLog *event.Log) error {
	_, client, err := cache.newKubeClient()
	if err != nil {
		return err
	}

	tillerNamespace := cache.cluster.Config.TillerNamespace
	if tillerNamespace == "" {
		tillerNamespace = "kube-system"
	}

	eventLog.WithFields(event.Fields{}).Debugf("Setting up tiller in cluster %s namespace %s", cache.cluster.Name, tillerNamespace)

	err = cache.ensureKubeNamespace(client, tillerNamespace)
	if err != nil {
		return err
	}

	err = cache.createKubeServiceAccount(client, tillerNamespace)
	if err != nil {
		return err
	}

	err = cache.createKubeClusterRoleBinding(client, tillerNamespace)
	if err != nil {
		return err
	}

	return installer.Install(client, &installer.Options{
		Namespace:      tillerNamespace,
		ImageSpec:      "gcr.io/kubernetes-helm/tiller:v2.6.2",
		ServiceAccount: "tiller-" + tillerNamespace,
	})
}

func (plugin *Plugin) fetchChart(repository, name, version string) (string, error) {
	chartURL, err := repo.FindChartInRepoURL(
		repository, name, version,
		"", "", "",
		newGetterProviders(),
	)
	if err != nil {
		return "", fmt.Errorf("error while getting chart url in repo: %s", err)
	}

	chartFile, err := ioutil.TempFile("charts", name)
	if err != nil {
		return "", fmt.Errorf("error while creating temp file for downloading chart: %s", err)
	}

	chartGetter, err := newHTTPGetter(chartURL, "", "", "")
	if err != nil {
		return "", fmt.Errorf("error while creating chart downloader: %s", err)
	}

	resp, err := chartGetter.Get(chartURL)
	if err != nil {
		return "", fmt.Errorf("error while downloading chart: %s", err)
	}

	_, err = chartFile.Write(resp.Bytes())
	if err != nil {
		return "", fmt.Errorf("error while writing downloaded chart to the temp file")
	}

	return chartFile.Name(), nil
}
<|endoftext|>


<commit_before>package service

import (
	"log"
	"strconv"
	"strings"
	"sync"

	"github.com/artemnikitin/devicefarm-ci-tool/model"
	"github.com/artemnikitin/devicefarm-ci-tool/tools"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/devicefarm"
)

func createScheduleRunInput(p *DeviceFarmRun) *devicefarm.ScheduleRunInput {
	var wg sync.WaitGroup
	result := &devicefarm.ScheduleRunInput{
		ProjectArn: aws.String(p.ProjectArn),
		Test:       &devicefarm.ScheduleRunTest{},
		Configuration: &devicefarm.ScheduleRunConfiguration{
			Radios: &devicefarm.Radios{
				Bluetooth: aws.Bool(true),
				Gps:       aws.Bool(true),
				Nfc:       aws.Bool(true),
				Wifi:      aws.Bool(true),
			},
			Location: &devicefarm.Location{
				Latitude:  aws.Float64(47.6204),
				Longitude: aws.Float64(-122.3491),
			},
		},
	}

	result.Name = aws.String(p.Config.RunName)
	result.Configuration.AuxiliaryApps = aws.StringSlice(p.Config.AdditionalData.AuxiliaryApps)
	if p.Config.AdditionalData.BillingMethod != "" {
		result.Configuration.BillingMethod = aws.String(p.Config.AdditionalData.BillingMethod)
	}
	result.Configuration.Locale = aws.String(p.Config.AdditionalData.Locale)
	if p.Config.AdditionalData.Location.Latitude != 0 {
		result.Configuration.Location.Latitude = aws.Float64(p.Config.AdditionalData.Location.Latitude)
	}
	if p.Config.AdditionalData.Location.Longitude != 0 {
		result.Configuration.Location.Longitude = aws.Float64(p.Config.AdditionalData.Location.Longitude)
	}
	if p.Config.AdditionalData.NetworkProfileArn != "" {
		result.Configuration.NetworkProfileArn = aws.String(p.Config.AdditionalData.NetworkProfileArn)
	}
	result.Configuration.Radios.Bluetooth = aws.Bool(stringToBool(p.Config.AdditionalData.Radios.Bluetooth))
	result.Configuration.Radios.Gps = aws.Bool(stringToBool(p.Config.AdditionalData.Radios.Gps))
	result.Configuration.Radios.Nfc = aws.Bool(stringToBool(p.Config.AdditionalData.Radios.Nfc))
	result.Configuration.Radios.Wifi = aws.Bool(stringToBool(p.Config.AdditionalData.Radios.Wifi))
	result.Test.Filter = aws.String(p.Config.Test.Filter)
	result.Test.Parameters = aws.StringMap(p.Config.Test.Parameters)
	if p.Config.Test.Type != "" {
		result.Test.Type = aws.String(p.Config.Test.Type)
	} else {
		result.Test.Type = aws.String(devicefarm.TestTypeBuiltinFuzz)
	}
	if p.Config.Test.TestPackageArn != "" {
		result.Test.TestPackageArn = aws.String(p.Config.Test.TestPackageArn)
	} else {
		uploadTestPackage(p, result, &wg)
	}
	if p.Config.AdditionalData.ExtraDataPackageArn != "" {
		result.Configuration.ExtraDataPackageArn = aws.String(p.Config.AdditionalData.ExtraDataPackageArn)
	} else {
		uploadExtraData(p, result, &wg)
	}
	wg.Wait()
	return result
}

func stringToBool(str string) bool {
	b, err := strconv.ParseBool(strings.ToLower(str))
	if err != nil {
		return true
	}
	return b
}

func uploadExtraData(p *DeviceFarmRun, result *devicefarm.ScheduleRunInput, wg *sync.WaitGroup) {
	if p.Config.AdditionalData.ExtraDataPackageArn == "" && p.Config.AdditionalData.ExtraDataPackagePath != "" {
		wg.Add(1)
		go func() {
			log.Println("Prepare extra data for uploading...")
			arn, url := p.CreateUploadWithType(p.ProjectArn, p.Config.AdditionalData.ExtraDataPackagePath, "EXTERNAL_DATA")
			httpResponse := tools.UploadFile(p.Config.AdditionalData.ExtraDataPackagePath, url)
			if httpResponse != 200 {
				log.Fatal("Can't upload test app")
			}
			p.WaitForAppProcessed(arn, 5)
			result.Configuration.ExtraDataPackageArn = aws.String(arn)
			wg.Done()
		}()
	}
}

func uploadTestPackage(p *DeviceFarmRun, result *devicefarm.ScheduleRunInput, wg *sync.WaitGroup) {
	if p.Config.Test.TestPackageArn == "" && p.Config.Test.TestPackagePath != "" {
		wg.Add(1)
		go func() {
			log.Println("Prepare tests for uploading...")
			t := model.GetUploadTypeForTest(p.Config.Test.Type)
			arn, url := p.CreateUploadWithType(p.ProjectArn, p.Config.Test.TestPackagePath, t)
			httpResponse := tools.UploadFile(p.Config.Test.TestPackagePath, url)
			if httpResponse != 200 {
				log.Fatal("Can't upload test app")
			}
			p.WaitForAppProcessed(arn, 5)
			result.Test.TestPackageArn = aws.String(arn)
			wg.Done()
		}()
	}
}
<commit_msg>Support specifying job timeout via config<commit_after>package service

import (
	"log"
	"strconv"
	"strings"
	"sync"

	"github.com/artemnikitin/devicefarm-ci-tool/model"
	"github.com/artemnikitin/devicefarm-ci-tool/tools"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/devicefarm"
)

func createScheduleRunInput(p *DeviceFarmRun) *devicefarm.ScheduleRunInput {
	var wg sync.WaitGroup
	result := &devicefarm.ScheduleRunInput{
		ProjectArn: aws.String(p.ProjectArn),
		Test:       &devicefarm.ScheduleRunTest{},
		Configuration: &devicefarm.ScheduleRunConfiguration{
			Radios: &devicefarm.Radios{
				Bluetooth: aws.Bool(true),
				Gps:       aws.Bool(true),
				Nfc:       aws.Bool(true),
				Wifi:      aws.Bool(true),
			},
			Location: &devicefarm.Location{
				Latitude:  aws.Float64(47.6204),
				Longitude: aws.Float64(-122.3491),
			},
		},
	}

	result.Name = aws.String(p.Config.RunName)
	result.Configuration.AuxiliaryApps = aws.StringSlice(p.Config.AdditionalData.AuxiliaryApps)
	if p.Config.AdditionalData.BillingMethod != "" {
		result.Configuration.BillingMethod = aws.String(p.Config.AdditionalData.BillingMethod)
	}
	result.Configuration.Locale = aws.String(p.Config.AdditionalData.Locale)
	if p.Config.AdditionalData.Location.Latitude != 0 {
		result.Configuration.Location.Latitude = aws.Float64(p.Config.AdditionalData.Location.Latitude)
	}
	if p.Config.AdditionalData.Location.Longitude != 0 {
		result.Configuration.Location.Longitude = aws.Float64(p.Config.AdditionalData.Location.Longitude)
	}
	if p.Config.AdditionalData.NetworkProfileArn != "" {
		result.Configuration.NetworkProfileArn = aws.String(p.Config.AdditionalData.NetworkProfileArn)
	}
	result.Configuration.Radios.Bluetooth = aws.Bool(stringToBool(p.Config.AdditionalData.Radios.Bluetooth))
	result.Configuration.Radios.Gps = aws.Bool(stringToBool(p.Config.AdditionalData.Radios.Gps))
	result.Configuration.Radios.Nfc = aws.Bool(stringToBool(p.Config.AdditionalData.Radios.Nfc))
	result.Configuration.Radios.Wifi = aws.Bool(stringToBool(p.Config.AdditionalData.Radios.Wifi))
	result.Test.Filter = aws.String(p.Config.Test.Filter)
	result.Test.Parameters = aws.StringMap(p.Config.Test.Parameters)
	if p.Config.Test.Type != "" {
		result.Test.Type = aws.String(p.Config.Test.Type)
	} else {
		result.Test.Type = aws.String(devicefarm.TestTypeBuiltinFuzz)
	}
	if p.Config.Test.TestPackageArn != "" {
		result.Test.TestPackageArn = aws.String(p.Config.Test.TestPackageArn)
	} else {
		uploadTestPackage(p, result, &wg)
	}
	if p.Config.AdditionalData.ExtraDataPackageArn != "" {
		result.Configuration.ExtraDataPackageArn = aws.String(p.Config.AdditionalData.ExtraDataPackageArn)
	} else {
		uploadExtraData(p, result, &wg)
	}
	if p.Config.ExecutionConfiguration.JobTimeoutMinutes != 0 {
		result.ExecutionConfiguration.JobTimeoutMinutes = aws.Int64(int64(p.Config.ExecutionConfiguration.JobTimeoutMinutes))
	}
	wg.Wait()
	return result
}

func stringToBool(str string) bool {
	b, err := strconv.ParseBool(strings.ToLower(str))
	if err != nil {
		return true
	}
	return b
}

func uploadExtraData(p *DeviceFarmRun, result *devicefarm.ScheduleRunInput, wg *sync.WaitGroup) {
	if p.Config.AdditionalData.ExtraDataPackageArn == "" && p.Config.AdditionalData.ExtraDataPackagePath != "" {
		wg.Add(1)
		go func() {
			log.Println("Prepare extra data for uploading...")
			arn, url := p.CreateUploadWithType(p.ProjectArn, p.Config.AdditionalData.ExtraDataPackagePath, "EXTERNAL_DATA")
			httpResponse := tools.UploadFile(p.Config.AdditionalData.ExtraDataPackagePath, url)
			if httpResponse != 200 {
				log.Fatal("Can't upload test app")
			}
			p.WaitForAppProcessed(arn, 5)
			result.Configuration.ExtraDataPackageArn = aws.String(arn)
			wg.Done()
		}()
	}
}

func uploadTestPackage(p *DeviceFarmRun, result *devicefarm.ScheduleRunInput, wg *sync.WaitGroup) {
	if p.Config.Test.TestPackageArn == "" && p.Config.Test.TestPackagePath != "" {
		wg.Add(1)
		go func() {
			log.Println("Prepare tests for uploading...")
			t := model.GetUploadTypeForTest(p.Config.Test.Type)
			arn, url := p.CreateUploadWithType(p.ProjectArn, p.Config.Test.TestPackagePath, t)
			httpResponse := tools.UploadFile(p.Config.Test.TestPackagePath, url)
			if httpResponse != 200 {
				log.Fatal("Can't upload test app")
			}
			p.WaitForAppProcessed(arn, 5)
			result.Test.TestPackageArn = aws.String(arn)
			wg.Done()
		}()
	}
}
<|endoftext|>


<commit_before>package file

import (
	"os"
	"syscall"
	"time"
)

func Time(fn string) (time.Time, time.Time, time.Time, error) {
	file, err := os.Stat(fn)
	if err != nil {
		return time.Time{}, time.Time{}, time.Time{}, err
	}
	mtime := file.ModTime()
	stat := file.Sys().(*syscall.Stat_t)
	atime := time.Unix(0, file.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds())
	ctime := time.Unix(0, file.Sys().(*syscall.Win32FileAttributeData).LastWriteTime.Nanoseconds())
	return atime, mtime, ctime, nil
}
<commit_msg>fix file.Time on windows (hopefully)<commit_after>package file

import (
	"os"
	"syscall"
	"time"
)

func Time(fn string) (time.Time, time.Time, time.Time, error) {
	file, err := os.Stat(fn)
	if err != nil {
		return time.Time{}, time.Time{}, time.Time{}, err
	}
	mtime := file.ModTime()
	atime := time.Unix(0, file.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds())
	ctime := time.Unix(0, file.Sys().(*syscall.Win32FileAttributeData).LastWriteTime.Nanoseconds())
	return atime, mtime, ctime, nil
}
<|endoftext|>


<commit_before>// Copyright 2018 Jigsaw Operations 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
//
//     https://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 shadowsocks

import (
	"bytes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/binary"
	"fmt"
	"io"

	"github.com/shadowsocks/go-shadowsocks2/shadowaead"
)

// payloadSizeMask is the maximum size of payload in bytes.
const payloadSizeMask = 0x3FFF // 16*1024 - 1

// Writer is an io.Writer that also implements io.ReaderFrom to
// allow for piping the data without extra allocations and copies.
type Writer interface {
	io.Writer
	io.ReaderFrom
}

type shadowsocksWriter struct {
	writer   io.Writer
	ssCipher shadowaead.Cipher
	// Wrapper for input that arrives as a slice.
	byteWrapper bytes.Reader
	// These are lazily initialized:
	buf  []byte
	aead cipher.AEAD
	// Index of the next encrypted chunk to write.
	counter []byte
}

// NewShadowsocksWriter creates a Writer that encrypts the given Writer using
// the shadowsocks protocol with the given shadowsocks cipher.
func NewShadowsocksWriter(writer io.Writer, ssCipher shadowaead.Cipher) Writer {
	return &shadowsocksWriter{writer: writer, ssCipher: ssCipher}
}

// init generates a random salt, sets up the AEAD object and writes
// the salt to the inner Writer.
func (sw *shadowsocksWriter) init() (err error) {
	if sw.aead == nil {
		salt := make([]byte, sw.ssCipher.SaltSize())
		if _, err := io.ReadFull(rand.Reader, salt); err != nil {
			return fmt.Errorf("failed to generate salt: %v", err)
		}
		_, err := sw.writer.Write(salt)
		if err != nil {
			return fmt.Errorf("failed to write salt: %v", err)
		}
		sw.aead, err = sw.ssCipher.Encrypter(salt)
		if err != nil {
			return fmt.Errorf("failed to create AEAD: %v", err)
		}
		sw.counter = make([]byte, sw.aead.NonceSize())
		sw.buf = make([]byte, 2+sw.aead.Overhead()+payloadSizeMask+sw.aead.Overhead())
	}
	return nil
}

// WriteBlock encrypts and writes the input buffer as one signed block.
func (sw *shadowsocksWriter) encryptBlock(ciphertext []byte, plaintext []byte) ([]byte, error) {
	out := sw.aead.Seal(ciphertext, sw.counter, plaintext, nil)
	increment(sw.counter)
	return out, nil
}

func (sw *shadowsocksWriter) Write(p []byte) (int, error) {
	sw.byteWrapper.Reset(p)
	n, err := sw.ReadFrom(&sw.byteWrapper)
	return int(n), err
}

func (sw *shadowsocksWriter) ReadFrom(r io.Reader) (int64, error) {
	if err := sw.init(); err != nil {
		return 0, err
	}
	var written int64
	sizeBuf := sw.buf[:2+sw.aead.Overhead()]
	payloadBuf := sw.buf[len(sizeBuf):]
	for {
		plaintextSize, err := r.Read(payloadBuf[:payloadSizeMask])
		if plaintextSize > 0 {
			binary.BigEndian.PutUint16(sizeBuf, uint16(plaintextSize))
			_, err = sw.encryptBlock(sizeBuf[:0], sizeBuf[:2])
			if err != nil {
				return written, fmt.Errorf("failed to encypt payload size: %v", err)
			}
			_, err := sw.encryptBlock(payloadBuf[:0], payloadBuf[:plaintextSize])
			if err != nil {
				return written, fmt.Errorf("failed to encrypt payload: %v", err)
			}
			payloadSize := plaintextSize + sw.aead.Overhead()
			_, err = sw.writer.Write(sw.buf[:len(sizeBuf)+payloadSize])
			written += int64(plaintextSize)
		}
		if err != nil {
			if err == io.EOF { // ignore EOF as per io.ReaderFrom contract
				return written, nil
			}
			return written, fmt.Errorf("Failed to read payload: %v", err)
		}
	}
}

// ChunkReader is similar to io.Reader, except that it controls its own
// buffer granularity.
type ChunkReader interface {
	// ReadChunk reads the next chunk and returns its payload.  The caller must
	// complete its use of the returned buffer before the next call.
	// The buffer is nil iff there is an error.  io.EOF indicates a close.
	ReadChunk() ([]byte, error)
}

type chunkReader struct {
	reader   io.Reader
	ssCipher shadowaead.Cipher
	// These are lazily initialized:
	aead cipher.AEAD
	// Index of the next encrypted chunk to read.
	counter []byte
	buf     []byte
}

// Reader is an io.Reader that also implements io.WriterTo to
// allow for piping the data without extra allocations and copies.
type Reader interface {
	io.Reader
	io.WriterTo
}

// NewShadowsocksReader creates a Reader that decrypts the given Reader using
// the shadowsocks protocol with the given shadowsocks cipher.
func NewShadowsocksReader(reader io.Reader, ssCipher shadowaead.Cipher) Reader {
	return &readConverter{
		cr: &chunkReader{reader: reader, ssCipher: ssCipher},
	}
}

// init reads the salt from the inner Reader and sets up the AEAD object
func (cr *chunkReader) init() (err error) {
	if cr.aead == nil {
		// For chacha20-poly1305, SaltSize is 32, NonceSize is 12 and Overhead is 16.
		salt := make([]byte, cr.ssCipher.SaltSize())
		if _, err := io.ReadFull(cr.reader, salt); err != nil {
			if err != io.EOF && err != io.ErrUnexpectedEOF {
				err = fmt.Errorf("failed to read salt: %v", err)
			}
			return err
		}
		cr.aead, err = cr.ssCipher.Decrypter(salt)
		if err != nil {
			return fmt.Errorf("failed to create AEAD: %v", err)
		}
		cr.counter = make([]byte, cr.aead.NonceSize())
		cr.buf = make([]byte, payloadSizeMask+cr.aead.Overhead())
	}
	return nil
}

// readMessage reads, decrypts, and verifies a single AEAD ciphertext.
// The ciphertext and tag (i.e. "overhead") must exactly fill `buf`,
// and the decrypted message will be placed in buf[:len(buf)-overhead].
// Returns an error only if the block could not be read.
func (cr *chunkReader) readMessage(buf []byte) error {
	_, err := io.ReadFull(cr.reader, buf)
	if err != nil {
		return err
	}
	_, err = cr.aead.Open(buf[:0], cr.counter, buf, nil)
	increment(cr.counter)
	if err != nil {
		return fmt.Errorf("failed to decrypt: %v", err)
	}
	return nil
}

func (cr *chunkReader) ReadChunk() ([]byte, error) {
	if err := cr.init(); err != nil {
		return nil, err
	}
	// In Shadowsocks-AEAD, each chunk consists of two
	// encrypted messages.  The first message contains the payload length,
	// and the second message is the payload.
	sizeBuf := cr.buf[:2+cr.aead.Overhead()]
	if err := cr.readMessage(sizeBuf); err != nil {
		if err != io.EOF && err != io.ErrUnexpectedEOF {
			err = fmt.Errorf("failed to read payload size: %v", err)
		}
		return nil, err
	}
	size := int(binary.BigEndian.Uint16(sizeBuf) & payloadSizeMask)
	sizeWithTag := size + cr.aead.Overhead()
	if cap(cr.buf) < sizeWithTag {
		// This code is unreachable.
		return nil, io.ErrShortBuffer
	}
	payloadBuf := cr.buf[:sizeWithTag]
	if err := cr.readMessage(payloadBuf); err != nil {
		if err == io.EOF { // EOF is not expected mid-chunk.
			err = io.ErrUnexpectedEOF
		}
		return nil, err
	}
	return payloadBuf[:size], nil
}

// readConverter adapts from ChunkReader, with source-controlled
// chunk sizes, to Go-style IO.
type readConverter struct {
	cr       ChunkReader
	leftover []byte
}

func (c *readConverter) Read(b []byte) (int, error) {
	if err := c.ensureLeftover(); err != nil {
		return 0, err
	}
	n := copy(b, c.leftover)
	c.leftover = c.leftover[n:]
	return n, nil
}

func (c *readConverter) WriteTo(w io.Writer) (written int64, err error) {
	for {
		if err = c.ensureLeftover(); err != nil {
			if err == io.EOF {
				err = nil
			}
			return written, err
		}
		n, err := w.Write(c.leftover)
		written += int64(n)
		c.leftover = c.leftover[n:]
		if err != nil {
			return written, err
		}
	}
}

// Ensures that c.leftover is nonempty.  If leftover is empty, this method
// waits for incoming data and decrypts it.
// Returns an error only if c.leftover could not be populated.
func (c *readConverter) ensureLeftover() error {
	if len(c.leftover) > 0 {
		return nil
	}
	payload, err := c.cr.ReadChunk()
	if err != nil {
		return err
	}
	c.leftover = payload
	return nil
}

// increment little-endian encoded unsigned integer b. Wrap around on overflow.
func increment(b []byte) {
	for i := range b {
		b[i]++
		if b[i] != 0 {
			return
		}
	}
}
<commit_msg>Coalesce the salt and the first message<commit_after>// Copyright 2018 Jigsaw Operations 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
//
//     https://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 shadowsocks

import (
	"bytes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/binary"
	"fmt"
	"io"

	"github.com/shadowsocks/go-shadowsocks2/shadowaead"
)

// payloadSizeMask is the maximum size of payload in bytes.
const payloadSizeMask = 0x3FFF // 16*1024 - 1

// Writer is an io.Writer that also implements io.ReaderFrom to
// allow for piping the data without extra allocations and copies.
type Writer interface {
	io.Writer
	io.ReaderFrom
}

type shadowsocksWriter struct {
	writer   io.Writer
	ssCipher shadowaead.Cipher
	// Wrapper for input that arrives as a slice.
	byteWrapper bytes.Reader
	// These are lazily initialized:
	buf  []byte
	aead cipher.AEAD
	// Index of the next encrypted chunk to write.
	counter []byte
}

// NewShadowsocksWriter creates a Writer that encrypts the given Writer using
// the shadowsocks protocol with the given shadowsocks cipher.
func NewShadowsocksWriter(writer io.Writer, ssCipher shadowaead.Cipher) Writer {
	return &shadowsocksWriter{writer: writer, ssCipher: ssCipher}
}

// init generates a random salt, sets up the AEAD object and writes
// the salt to the inner Writer.
func (sw *shadowsocksWriter) init() (err error) {
	if sw.aead == nil {
		salt := make([]byte, sw.ssCipher.SaltSize())
		if _, err := io.ReadFull(rand.Reader, salt); err != nil {
			return fmt.Errorf("failed to generate salt: %v", err)
		}
		sw.aead, err = sw.ssCipher.Encrypter(salt)
		if err != nil {
			return fmt.Errorf("failed to create AEAD: %v", err)
		}
		sw.counter = make([]byte, sw.aead.NonceSize())
		// The maximum length message is the salt (first message only), length, length tag,
		// payload, and payload tag.
		sizeBufSize := 2 + sw.aead.Overhead()
		maxPayloadBufSize := payloadSizeMask + sw.aead.Overhead()
		sw.buf = make([]byte, len(salt)+sizeBufSize+maxPayloadBufSize)
		// Store the salt at the start of sw.buf.
		copy(sw.buf, salt)
	}
	return nil
}

// encryptBlock encrypts `plaintext` in-place.  The slice must have enough capacity
// for the tag. Returns the total ciphertext length.
func (sw *shadowsocksWriter) encryptBlock(plaintext []byte) int {
	out := sw.aead.Seal(plaintext[:0], sw.counter, plaintext, nil)
	increment(sw.counter)
	return len(out)
}

func (sw *shadowsocksWriter) Write(p []byte) (int, error) {
	sw.byteWrapper.Reset(p)
	n, err := sw.ReadFrom(&sw.byteWrapper)
	return int(n), err
}

func isZero(b []byte) bool {
	for _, v := range b {
		if v != 0 {
			return false
		}
	}
	return true
}

func (sw *shadowsocksWriter) ReadFrom(r io.Reader) (int64, error) {
	if err := sw.init(); err != nil {
		return 0, err
	}
	var written int64

	// sw.buf starts with the salt.
	saltSize := sw.ssCipher.SaltSize()
	// Normally we ignore the salt at the beginning of sw.buf.
	start := saltSize
	if isZero(sw.counter) {
		// For the first message, include the salt.
		start = 0
	}

	// Each Shadowsocks-TCP message consists of a fixed-length size block, followed by
	// a variable-length payload block.
	sizeBuf := sw.buf[saltSize : saltSize+2+sw.aead.Overhead()]
	payloadBuf := sw.buf[saltSize+len(sizeBuf):]
	for {
		plaintextSize, err := r.Read(payloadBuf[:payloadSizeMask])
		if plaintextSize > 0 {
			binary.BigEndian.PutUint16(sizeBuf, uint16(plaintextSize))
			sw.encryptBlock(sizeBuf[:2])
			payloadSize := sw.encryptBlock(payloadBuf[:plaintextSize])
			_, err = sw.writer.Write(sw.buf[start : saltSize+len(sizeBuf)+payloadSize])
			written += int64(plaintextSize)
			start = saltSize // Skip the salt for all writes except the first.
		}
		if err != nil {
			if err == io.EOF { // ignore EOF as per io.ReaderFrom contract
				return written, nil
			}
			return written, fmt.Errorf("Failed to read payload: %v", err)
		}
	}
}

// ChunkReader is similar to io.Reader, except that it controls its own
// buffer granularity.
type ChunkReader interface {
	// ReadChunk reads the next chunk and returns its payload.  The caller must
	// complete its use of the returned buffer before the next call.
	// The buffer is nil iff there is an error.  io.EOF indicates a close.
	ReadChunk() ([]byte, error)
}

type chunkReader struct {
	reader   io.Reader
	ssCipher shadowaead.Cipher
	// These are lazily initialized:
	aead cipher.AEAD
	// Index of the next encrypted chunk to read.
	counter []byte
	buf     []byte
}

// Reader is an io.Reader that also implements io.WriterTo to
// allow for piping the data without extra allocations and copies.
type Reader interface {
	io.Reader
	io.WriterTo
}

// NewShadowsocksReader creates a Reader that decrypts the given Reader using
// the shadowsocks protocol with the given shadowsocks cipher.
func NewShadowsocksReader(reader io.Reader, ssCipher shadowaead.Cipher) Reader {
	return &readConverter{
		cr: &chunkReader{reader: reader, ssCipher: ssCipher},
	}
}

// init reads the salt from the inner Reader and sets up the AEAD object
func (cr *chunkReader) init() (err error) {
	if cr.aead == nil {
		// For chacha20-poly1305, SaltSize is 32, NonceSize is 12 and Overhead is 16.
		salt := make([]byte, cr.ssCipher.SaltSize())
		if _, err := io.ReadFull(cr.reader, salt); err != nil {
			if err != io.EOF && err != io.ErrUnexpectedEOF {
				err = fmt.Errorf("failed to read salt: %v", err)
			}
			return err
		}
		cr.aead, err = cr.ssCipher.Decrypter(salt)
		if err != nil {
			return fmt.Errorf("failed to create AEAD: %v", err)
		}
		cr.counter = make([]byte, cr.aead.NonceSize())
		cr.buf = make([]byte, payloadSizeMask+cr.aead.Overhead())
	}
	return nil
}

// readMessage reads, decrypts, and verifies a single AEAD ciphertext.
// The ciphertext and tag (i.e. "overhead") must exactly fill `buf`,
// and the decrypted message will be placed in buf[:len(buf)-overhead].
// Returns an error only if the block could not be read.
func (cr *chunkReader) readMessage(buf []byte) error {
	_, err := io.ReadFull(cr.reader, buf)
	if err != nil {
		return err
	}
	_, err = cr.aead.Open(buf[:0], cr.counter, buf, nil)
	increment(cr.counter)
	if err != nil {
		return fmt.Errorf("failed to decrypt: %v", err)
	}
	return nil
}

func (cr *chunkReader) ReadChunk() ([]byte, error) {
	if err := cr.init(); err != nil {
		return nil, err
	}
	// In Shadowsocks-AEAD, each chunk consists of two
	// encrypted messages.  The first message contains the payload length,
	// and the second message is the payload.
	sizeBuf := cr.buf[:2+cr.aead.Overhead()]
	if err := cr.readMessage(sizeBuf); err != nil {
		if err != io.EOF && err != io.ErrUnexpectedEOF {
			err = fmt.Errorf("failed to read payload size: %v", err)
		}
		return nil, err
	}
	size := int(binary.BigEndian.Uint16(sizeBuf) & payloadSizeMask)
	sizeWithTag := size + cr.aead.Overhead()
	if cap(cr.buf) < sizeWithTag {
		// This code is unreachable.
		return nil, io.ErrShortBuffer
	}
	payloadBuf := cr.buf[:sizeWithTag]
	if err := cr.readMessage(payloadBuf); err != nil {
		if err == io.EOF { // EOF is not expected mid-chunk.
			err = io.ErrUnexpectedEOF
		}
		return nil, err
	}
	return payloadBuf[:size], nil
}

// readConverter adapts from ChunkReader, with source-controlled
// chunk sizes, to Go-style IO.
type readConverter struct {
	cr       ChunkReader
	leftover []byte
}

func (c *readConverter) Read(b []byte) (int, error) {
	if err := c.ensureLeftover(); err != nil {
		return 0, err
	}
	n := copy(b, c.leftover)
	c.leftover = c.leftover[n:]
	return n, nil
}

func (c *readConverter) WriteTo(w io.Writer) (written int64, err error) {
	for {
		if err = c.ensureLeftover(); err != nil {
			if err == io.EOF {
				err = nil
			}
			return written, err
		}
		n, err := w.Write(c.leftover)
		written += int64(n)
		c.leftover = c.leftover[n:]
		if err != nil {
			return written, err
		}
	}
}

// Ensures that c.leftover is nonempty.  If leftover is empty, this method
// waits for incoming data and decrypts it.
// Returns an error only if c.leftover could not be populated.
func (c *readConverter) ensureLeftover() error {
	if len(c.leftover) > 0 {
		return nil
	}
	payload, err := c.cr.ReadChunk()
	if err != nil {
		return err
	}
	c.leftover = payload
	return nil
}

// increment little-endian encoded unsigned integer b. Wrap around on overflow.
func increment(b []byte) {
	for i := range b {
		b[i]++
		if b[i] != 0 {
			return
		}
	}
}
<|endoftext|>


<commit_before>package redis

import (
    "sync"
    "time"
    "strconv"
    "github.com/BluePecker/JwtAuth/storage"
    "github.com/go-redis/redis"
    "fmt"
)

type Redis struct {
    mu     sync.RWMutex
    create time.Time
    values storage.MemStore
    client *redis.Client
}

func (driver *Redis) Initializer(opt storage.Options) error {
    driver.client = redis.NewClient(&redis.Options{
        Network: "tcp",
        Addr: opt.Host + ":" + strconv.Itoa(opt.Port),
        PoolSize: opt.PoolSize,
        OnConnect: func(conn *redis.Conn) error {
            fmt.Println("conn: ", conn)
            return nil
        },
    })
    err := driver.client.Ping().Err()
    if err != nil {
        defer driver.client.Close()
    }
    fmt.Println(err)
    return err
}

func (driver *Redis) TTL(key string) int {
    driver.mu.RLock()
    defer driver.mu.RUnlock()
    return driver.values.TTL(key)
}

func (driver *Redis) Read(key string) (interface{}, error) {
    return nil, nil
}

func (driver *Redis) ReadInt(key string) (int, error) {
    return 0, nil
}

func (driver *Redis) ReadString(key string) string {
    return ""
}

func (driver *Redis) Upgrade(key string, expire int) {

}

func (driver *Redis) Write(key string, value interface{}, expire int) {

}

func (driver *Redis) WriteImmutable(key string, value interface{}, expire int) {

}

func init() {
    storage.Register("redis", &Redis{})
}<commit_msg>debug<commit_after>package redis

import (
    "sync"
    "time"
    "strconv"
    "github.com/BluePecker/JwtAuth/storage"
    "github.com/go-redis/redis"
)

type Redis struct {
    mu     sync.RWMutex
    create time.Time
    values storage.MemStore
    client *redis.Client
}

func (driver *Redis) Initializer(opt storage.Options) error {
    driver.client = redis.NewClient(&redis.Options{
        Network: "tcp",
        Addr: opt.Host + ":" + strconv.Itoa(opt.Port),
        PoolSize: opt.PoolSize,
    })
    err := driver.client.Ping().Err()
    if err != nil {
        defer driver.client.Close()
    }
    return err
}

func (driver *Redis) TTL(key string) int {
    driver.mu.RLock()
    defer driver.mu.RUnlock()
    return driver.values.TTL(key)
}

func (driver *Redis) Read(key string) (interface{}, error) {
    return nil, nil
}

func (driver *Redis) ReadInt(key string) (int, error) {
    return 0, nil
}

func (driver *Redis) ReadString(key string) string {
    return ""
}

func (driver *Redis) Upgrade(key string, expire int) {

}

func (driver *Redis) Write(key string, value interface{}, expire int) {

}

func (driver *Redis) WriteImmutable(key string, value interface{}, expire int) {

}

func init() {
    storage.Register("redis", &Redis{})
}<|endoftext|>