<commit_before>package errortypes_test

import (
	"errors"
	"testing"

	"github.com/robfig/soy/errortypes"
)

func TestIsErrFilePos(t *testing.T) {
	var tests = []struct {
		name string
		in   error
		out  bool
	}{
		{
			name: "nil",
			out:  false,
		},
		{
			name: "errors.New",
			in:   errors.New("an error"),
			out:  false,
		},
		{
			name: "new ErrFilePos",
			in:   errortypes.NewErrFilePosf("file.soy", 1, 2, "message"),
			out:  true,
		},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			got := errortypes.IsErrFilePos(test.in)
			if got != test.out {
				t.Errorf("Expected %v, got %v", test.out, got)
			}
		})
	}
}

func TestToErrFilePos(t *testing.T) {
	var tests = []struct {
		name             string
		in               error
		expectNil        bool
		expectedFilename string
		expectedLine     int
		expectedCol      int
	}{
		{
			name:      "nil",
			expectNil: true,
		},
		{
			name:      "errors.New",
			in:        errors.New("an error"),
			expectNil: true,
		},
		{
			name:             "new ErrFilePos",
			in:               errortypes.NewErrFilePosf("file.soy", 1, 2, "message"),
			expectNil:        false,
			expectedFilename: "file.soy",
			expectedLine:     1,
			expectedCol:      2,
		},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			got := errortypes.ToErrFilePos(test.in)
			if test.expectNil && got != nil {
				t.Errorf("expected ErrFilePos to be nil")
			}
			if !test.expectNil {
				if got == nil {
					t.Errorf("expected ErrFilePos to be non-nil")
					return
				}
				if got.File() != test.expectedFilename {
					t.Errorf("expected file '%s', got '%s'", test.expectedFilename, got.File())
				}
				if got.Line() != test.expectedLine {
					t.Errorf("expected line %d, got %d", test.expectedLine, got.Line())
				}
				if got.Col() != test.expectedCol {
					t.Errorf("expected col %d, got %d", test.expectedCol, got.Col())
				}
			}
		})
	}
}
<commit_msg>Remove usage of t.Run for Go 1.2 testing in Travis<commit_after>package errortypes_test

import (
	"errors"
	"testing"

	"github.com/robfig/soy/errortypes"
)

func TestIsErrFilePos(t *testing.T) {
	var tests = []struct {
		name string
		in   error
		out  bool
	}{
		{
			name: "nil",
			out:  false,
		},
		{
			name: "errors.New",
			in:   errors.New("an error"),
			out:  false,
		},
		{
			name: "new ErrFilePos",
			in:   errortypes.NewErrFilePosf("file.soy", 1, 2, "message"),
			out:  true,
		},
	}
	for _, test := range tests {
		got := errortypes.IsErrFilePos(test.in)
		if got != test.out {
			t.Errorf("%s: Expected %v, got %v", test.name, test.out, got)
		}
	}
}

func TestToErrFilePos(t *testing.T) {
	var tests = []struct {
		name             string
		in               error
		expectNil        bool
		expectedFilename string
		expectedLine     int
		expectedCol      int
	}{
		{
			name:      "nil",
			expectNil: true,
		},
		{
			name:      "errors.New",
			in:        errors.New("an error"),
			expectNil: true,
		},
		{
			name:             "new ErrFilePos",
			in:               errortypes.NewErrFilePosf("file.soy", 1, 2, "message"),
			expectNil:        false,
			expectedFilename: "file.soy",
			expectedLine:     1,
			expectedCol:      2,
		},
	}
	for _, test := range tests {
		got := errortypes.ToErrFilePos(test.in)
		if test.expectNil && got != nil {
			t.Errorf("%s: expected ErrFilePos to be nil", test.name)
		}
		if !test.expectNil {
			if got == nil {
				t.Errorf("%s: expected ErrFilePos to be non-nil", test.name)
				return
			}
			if got.File() != test.expectedFilename {
				t.Errorf("%s: expected file '%s', got '%s'", test.name, test.expectedFilename, got.File())
			}
			if got.Line() != test.expectedLine {
				t.Errorf("%s: expected line %d, got %d", test.name, test.expectedLine, got.Line())
			}
			if got.Col() != test.expectedCol {
				t.Errorf("%s: expected col %d, got %d", test.name, test.expectedCol, got.Col())
			}
		}
	}
}
<|endoftext|>


<commit_before>package common

import (
	"fmt"
	"strings"
	//
	"github.com/golangdaddy/tarantula/web"
	"github.com/golangdaddy/tarantula/web/validation"
	"github.com/golangdaddy/tarantula/router/common/openapi"
)

/*
type HandlerSpec struct {
	Method string `json:"method"`
	Endpoint string `json:"endpoint"`
	MockEndpoint string `json:"mockEndpoint"`
	MockPayload interface{} `json:"mockPayload,omitempty"`
	PayloadSchema interface{} `json:"payloadSchema,omitempty"`
	OptionalPayloadSchema interface{} `json:"optionalPayloadSchema,omitempty"`
	ResponseSchema interface{} `json:"responseSchema,omitempty"`
	RouteParams map[string]*validation.Config `json:"routeParams,omitempty"`
	IsFile bool `json:"isFile"`
	FilePath string `json:"filePath,omitempty"`
	Description string `json:"description,omitempty"`
}
*/

func pointerFloat64(f float64) *float64 {
	if f == 0 {
		return nil
	}
	return &f
}

// Builds the handler documentation object.
func (config *Config) BuildOpenAPISpec(req web.RequestInterface) *openapi.APISpec {

	handlers := map[*Handler]*HandlerSpec{}

	// do the legacy spec operation
	config.RLock()
	spec := config.Spec
	for _, handler := range config.Handlers {
		handlers[handler] = handler.Spec(req)
	}
	config.RUnlock()

	for handler, handlerSpec := range handlers {

		// create the object that holds the handler's definition
		pathMethod := &openapi.PathMethod{
			Produces: []string{
				"application/json",
			},
			Parameters: []*openapi.Parameter{},
			Description: handler.Description,
			Responses: openapi.Responses{
				Code200: &openapi.StatusCode{
					Description: "Done OK",
					Schema: openapi.StatusSchema{
						Type: "object",
					},
				},
			},
		}

		k := strings.Replace(
			fmt.Sprintf("%s-%s", handler.Node.FullPath(), handler.Method),
			"/",
			"",
			-1,
		)
		definition := &openapi.Definition{
			Type: "object",
			Properties: map[string]openapi.Parameter{},
		}

		// check the type of payload
		switch t := handlerSpec.PayloadSchema.(type) {
			case map[string]*validation.Config:

				// dont make a param object for GET routes etc
				if len(t) == 0 { continue }

				pathMethod.Parameters = append(
					pathMethod.Parameters,
					&openapi.Parameter{
						Required: true,
						Name: "body",
						In: "body",
						Description: handler.Description,
						Schema: &openapi.Schema{
							Ref: "#/definitions/" + k,
						},
					},
				)

				requiredBodyParams := []string{}

				// add body params to the definition properties
				for key, cfg := range t {

					requiredBodyParams = append(
						requiredBodyParams,
						key,
					)

					param := openapi.Parameter{}
					param.Description = cfg.DescriptionValue
					param.Minimum = pointerFloat64(cfg.Min)
					param.Maximum = pointerFloat64(cfg.Max)
					param.Default = cfg.DefaultValue
					param.Format = cfg.Type

					switch param.Format {
					case "bool":
						param.Type = "boolean"
					case "string":
						param.Type = "string"
					case "int64", "int":
						param.Type = "integer"
					case "float32", "float64":
						param.Type = "number"
					}

					definition.Properties[key] = param

				}

				definition.Required = requiredBodyParams

		}

		// only create the definition if it has contents
		if len(definition.Properties) > 0 {
			spec.Definitions[k] = definition
		}

		// route params
		for name, cfg := range handlerSpec.RouteParams {
			param := &openapi.Parameter{}
			param.In = "path"
			param.Name = name
			param.Description = cfg.DescriptionValue
			param.Type = cfg.Type
			minLength := int64(cfg.Min)
			maxLength := int64(cfg.Max)
			param.MinLength = &minLength
			param.MaxLength = &maxLength

			pathMethod.Parameters = append(pathMethod.Parameters, param)
		}

		fullPath := handler.Node.FullPath()
		_, ok := spec.Paths[fullPath]
		if !ok {
			spec.Paths[fullPath] = &openapi.Path{}
		}

		var f *openapi.Path

		switch handler.Method {
		case "GET":
			f = spec.Paths[fullPath]
			f.GET = pathMethod
		case "POST":
			f = spec.Paths[fullPath]
			f.POST = pathMethod
		case "PUT":
			f = spec.Paths[fullPath]
			f.PUT = pathMethod
		case "PATCH":
			f = spec.Paths[fullPath]
			f.PATCH = pathMethod
		case "DELETE":
			f = spec.Paths[fullPath]
			f.DELETE = pathMethod
		case "HEAD":
			f = spec.Paths[fullPath]
			f.HEAD = pathMethod
		case "OPTIONS":
			f = spec.Paths[fullPath]
			f.OPTIONS = pathMethod
		default:
			panic("wtf")
		}

		fmt.Println(fullPath, handler.Method, f)
	}

	return spec
}
<commit_msg>fix openapi spec builder<commit_after>package common

import (
	"fmt"
	"strings"
	//
	"github.com/golangdaddy/tarantula/web"
	"github.com/golangdaddy/tarantula/web/validation"
	"github.com/golangdaddy/tarantula/router/common/openapi"
)

/*
type HandlerSpec struct {
	Method string `json:"method"`
	Endpoint string `json:"endpoint"`
	MockEndpoint string `json:"mockEndpoint"`
	MockPayload interface{} `json:"mockPayload,omitempty"`
	PayloadSchema interface{} `json:"payloadSchema,omitempty"`
	OptionalPayloadSchema interface{} `json:"optionalPayloadSchema,omitempty"`
	ResponseSchema interface{} `json:"responseSchema,omitempty"`
	RouteParams map[string]*validation.Config `json:"routeParams,omitempty"`
	IsFile bool `json:"isFile"`
	FilePath string `json:"filePath,omitempty"`
	Description string `json:"description,omitempty"`
}
*/

func pointerFloat64(f float64) *float64 {
	if f == 0 {
		return nil
	}
	return &f
}

// Builds the handler documentation object.
func (config *Config) BuildOpenAPISpec(req web.RequestInterface) *openapi.APISpec {

	handlers := map[*Handler]*HandlerSpec{}

	// do the legacy spec operation
	config.RLock()
	spec := config.Spec
	for _, handler := range config.Handlers {
		handlers[handler] = handler.Spec(req)
	}
	config.RUnlock()

	for handler, handlerSpec := range handlers {

		// create the object that holds the handler's definition
		pathMethod := &openapi.PathMethod{
			Produces: []string{
				"application/json",
			},
			Parameters: []*openapi.Parameter{},
			Description: handler.Description,
			Responses: openapi.Responses{
				Code200: &openapi.StatusCode{
					Description: "Done OK",
					Schema: openapi.StatusSchema{
						Type: "object",
					},
				},
			},
		}

		k := strings.Replace(
			fmt.Sprintf("%s-%s", handler.Node.FullPath(), handler.Method),
			"/",
			"_",
			-1,
		)
		definition := &openapi.Definition{
			Type: "object",
			Properties: map[string]openapi.Parameter{},
		}

		// check the type of payload
		switch t := handlerSpec.PayloadSchema.(type) {
			case map[string]*validation.Config:

				// dont make a param object for GET routes etc
				if len(t) == 0 { continue }

				pathMethod.Parameters = append(
					pathMethod.Parameters,
					&openapi.Parameter{
						Required: true,
						Name: "body",
						In: "body",
						Description: handler.Description,
						Schema: &openapi.Schema{
							Ref: "#/definitions/" + k,
						},
					},
				)

				requiredBodyParams := []string{}

				// add body params to the definition properties
				for key, cfg := range t {

					requiredBodyParams = append(
						requiredBodyParams,
						key,
					)

					param := openapi.Parameter{}
					param.Description = cfg.DescriptionValue
					param.Minimum = pointerFloat64(cfg.Min)
					param.Maximum = pointerFloat64(cfg.Max)
					param.Default = cfg.DefaultValue
					param.Format = cfg.Type

					switch param.Format {
					case "bool":
						param.Type = "boolean"
					case "string":
						param.Type = "string"
					case "int64", "int":
						param.Type = "integer"
					case "float32", "float64":
						param.Type = "number"
					}

					definition.Properties[key] = param

				}

				definition.Required = requiredBodyParams

		}

		// only create the definition if it has contents
		if len(definition.Properties) > 0 {
			spec.Definitions[k] = definition
		}

		// route params
		for name, cfg := range handlerSpec.RouteParams {
			param := &openapi.Parameter{}
			param.In = "path"
			param.Name = name
			param.Description = cfg.DescriptionValue
			param.Type = cfg.Type
			minLength := int64(cfg.Min)
			maxLength := int64(cfg.Max)
			param.MinLength = &minLength
			param.MaxLength = &maxLength

			pathMethod.Parameters = append(pathMethod.Parameters, param)
		}

		fullPath := handler.Node.FullPath()
		_, ok := spec.Paths[fullPath]
		if !ok {
			spec.Paths[fullPath] = &openapi.Path{}
		}

		var f *openapi.Path

		switch handler.Method {
		case "GET":
			f = spec.Paths[fullPath]
			f.GET = pathMethod
		case "POST":
			f = spec.Paths[fullPath]
			f.POST = pathMethod
		case "PUT":
			f = spec.Paths[fullPath]
			f.PUT = pathMethod
		case "PATCH":
			f = spec.Paths[fullPath]
			f.PATCH = pathMethod
		case "DELETE":
			f = spec.Paths[fullPath]
			f.DELETE = pathMethod
		case "HEAD":
			f = spec.Paths[fullPath]
			f.HEAD = pathMethod
		case "OPTIONS":
			f = spec.Paths[fullPath]
			f.OPTIONS = pathMethod
		default:
			panic("wtf")
		}

		fmt.Println(fullPath, handler.Method, f)
	}

	return spec
}
<|endoftext|>


<commit_before>package models

import (
	"database/sql"
	"encoding/json"
	"time"

	"github.com/antihax/evedata/services/conservator"
	"github.com/guregu/null"
	"golang.org/x/oauth2"
)

// Obtain an authenticated client from a stored access/refresh token.
func GetCRESTToken(characterID int32, ownerHash string, tokenCharacterID int32) (*CRESTToken, error) {
	tok := &CRESTToken{}
	if err := database.QueryRowx(
		`SELECT expiry, tokenType, accessToken, refreshToken, tokenCharacterID, characterID, characterName
			FROM evedata.crestTokens
			WHERE characterID = ? AND (characterOwnerHash = ? OR characterOwnerHash = "") AND tokenCharacterID = ?
			LIMIT 1`,
		characterID, ownerHash, tokenCharacterID).StructScan(tok); err != nil {

		return nil, err
	}

	return tok, nil
}

type CRESTToken struct {
	Expiry           time.Time           `db:"expiry" json:"expiry,omitempty"`
	CharacterID      int32               `db:"characterID" json:"characterID,omitempty"`
	TokenType        string              `db:"tokenType" json:"tokenType,omitempty"`
	TokenCharacterID int32               `db:"tokenCharacterID" json:"tokenCharacterID,omitempty"`
	CharacterName    string              `db:"characterName" json:"characterName,omitempty"`
	LastCode         int64               `db:"lastCode" json:"lastCode,omitempty"`
	LastStatus       null.String         `db:"lastStatus" json:"lastStatus,omitempty"`
	AccessToken      string              `db:"accessToken" json:"accessToken,omitempty"`
	RefreshToken     string              `db:"refreshToken" json:"refreshToken,omitempty"`
	Scopes           string              `db:"scopes" json:"scopes"`
	AuthCharacter    int                 `db:"authCharacter" json:"authCharacter"`
	SharingInt       string              `db:"sharingint" json:"_,omitempty"`
	Sharing          []conservator.Share `json:"sharing"`
}

type IntegrationToken struct {
	Type                string      `db:"type" json:"type,omitempty"`
	Expiry              time.Time   `db:"expiry" json:"expiry,omitempty"`
	CharacterID         int32       `db:"characterID" json:"characterID,omitempty"`
	IntegrationUserID   string      `db:"integrationUserID" json:"integrationUserID,omitempty"`
	IntegrationUserName string      `db:"integrationUserName" json:"integrationUserName,omitempty"`
	TokenType           string      `db:"tokenType" json:"tokenType,omitempty"`
	LastCode            int64       `db:"lastCode" json:"lastCode,omitempty"`
	LastStatus          null.String `db:"lastStatus" json:"lastStatus,omitempty"`
	AccessToken         string      `db:"accessToken" json:"accessToken,omitempty"`
	RefreshToken        string      `db:"refreshToken" json:"refreshToken,omitempty"`
	Scopes              string      `db:"scopes" json:"scopes"`
}

// [BENCHMARK] TODO
func GetCharacterIDByName(character string) (int32, error) {
	var id int32
	if err := database.Get(&id, `
		SELECT characterID
		FROM evedata.characters C
		WHERE C.name = ? LIMIT 1;`, character); err != nil && err != sql.ErrNoRows {
		return id, err
	}
	return id, nil
}

type CursorCharacter struct {
	CursorCharacterID   int32  `db:"cursorCharacterID" json:"cursorCharacterID"`
	CursorCharacterName string `db:"cursorCharacterName" json:"cursorCharacterName"`
}

// [BENCHMARK] TODO
func GetCursorCharacter(characterID int32) (CursorCharacter, error) {
	cursor := CursorCharacter{}

	if err := database.Get(&cursor, `
		SELECT cursorCharacterID, T.characterName AS cursorCharacterName
		FROM evedata.cursorCharacter C
		INNER JOIN evedata.crestTokens T ON C.cursorCharacterID = T.tokenCharacterID AND C.characterID = T.characterID
		WHERE C.characterID = ?;`, characterID); err != nil {
		return cursor, err
	}
	return cursor, nil
}

// [BENCHMARK] TODO
func SetCursorCharacter(characterID int32, cursorCharacterID int32) error {
	if _, err := database.Exec(`
	INSERT INTO evedata.cursorCharacter (characterID, cursorCharacterID)
		SELECT characterID, tokenCharacterID AS cursorCharacterID
		FROM evedata.crestTokens WHERE characterID = ? AND tokenCharacterID = ? LIMIT 1
	ON DUPLICATE KEY UPDATE cursorCharacterID = VALUES(cursorCharacterID)
		;`, characterID, cursorCharacterID); err != nil {
		return err
	}
	return nil
}

// [BENCHMARK] 0.000 sec / 0.000 sec
func GetCRESTTokens(characterID int32, ownerHash string) ([]CRESTToken, error) {
	tokens := []CRESTToken{}
	if err := database.Select(&tokens, `
		SELECT T.characterID, T.tokenCharacterID, characterName, lastCode, lastStatus, scopes, authCharacter,
		IFNULL(
			CONCAT("[", GROUP_CONCAT(CONCAT(
				'{"id": ', entityID,
				', "types": "', types, '"',
				', "entityName": "', IFNULL(A.name, C.name), '"',
				', "type": "', IF(A.name IS NULL, "corporation", "alliance"), '"',
				'}')),
			"]")
		, "[]") AS sharingint
		FROM evedata.crestTokens T
		LEFT OUTER JOIN evedata.sharing S ON T.tokenCharacterID = S.tokenCharacterID AND T.characterID = S.characterID
		LEFT OUTER JOIN evedata.corporations C ON C.corporationID = S.entityID
		LEFT OUTER JOIN evedata.alliances A ON A.allianceID = S.entityID
		WHERE T.characterID = ? AND (T.characterOwnerHash = ? OR T.characterOwnerHash = "")
		GROUP BY characterID, tokenCharacterID;
		;`, characterID, ownerHash); err != nil {

		return nil, err
	}

	// Unmarshal our sharing data.
	for index := range tokens {
		share := []conservator.Share{}
		if err := json.Unmarshal([]byte(tokens[index].SharingInt), &share); err != nil {
			return nil, err
		}
		tokens[index].Sharing = share
		tokens[index].SharingInt = ""
	}
	return tokens, nil
}

// AddCRESTToken adds an SSO token to the database or updates it if one exists.
// resetting status and if errors were mailed to the user.
func AddCRESTToken(characterID int32, tokenCharacterID int32, characterName string, tok *oauth2.Token, scopes, ownerHash string, corporationID, allianceID, factionID int32) error {
	if _, err := database.Exec(`
		INSERT INTO evedata.crestTokens	(characterID, tokenCharacterID, accessToken, refreshToken, expiry,
				tokenType, characterName, scopes, lastStatus, characterOwnerHash, corporationID, allianceID, factionID)
			VALUES		(?,?,?,?,?,?,?,?,"Unused",?,?,?,?)
			ON DUPLICATE KEY UPDATE
				accessToken 		= VALUES(accessToken),
				refreshToken 		= VALUES(refreshToken),
				expiry 				= VALUES(expiry),
				tokenType 			= VALUES(tokenType),
				characterOwnerHash	= VALUES(characterOwnerHash),
				scopes 				= VALUES(scopes),
				corporationID 		= VALUES(corporationID),
				allianceID	 		= VALUES(allianceID),
				factionID	 		= VALUES(factionID),
				lastStatus			= "Unused",
				mailedError 		= 0`,
		characterID, tokenCharacterID, tok.AccessToken, tok.RefreshToken, tok.Expiry, tok.TokenType, characterName, scopes, ownerHash, corporationID, allianceID, factionID); err != nil {
		return err
	}
	return nil
}

func DeleteCRESTToken(characterID int32, tokenCharacterID int32) error {
	if _, err := database.Exec(`DELETE FROM evedata.crestTokens WHERE characterID = ? AND tokenCharacterID = ? LIMIT 1`,
		characterID, tokenCharacterID); err != nil {

		return err
	}
	return nil
}

// AddIntegrationToken adds a oauth2 token to the database for integrations or updates it if one exists.
// resetting status and if errors were mailed to the user.
func AddIntegrationToken(tokenType string, characterID int32, userID string, userName string, tok *oauth2.Token, scopes string) error {
	if _, err := database.Exec(`
		INSERT INTO evedata.integrationTokens	(type, characterID, integrationUserID, integrationUserName, accessToken, refreshToken, expiry,
				tokenType, scopes, lastStatus)
			VALUES		(?,?,?,?,?,?,?,?,?,"Unused")
			ON DUPLICATE KEY UPDATE
				accessToken 		= VALUES(accessToken),
				refreshToken 		= VALUES(refreshToken),
				expiry 				= VALUES(expiry),
				tokenType 			= VALUES(tokenType),
				scopes 				= VALUES(scopes),
				lastStatus			= "Unused",
				mailedError 		= 0`,
		tokenType, characterID, userID, userName, tok.AccessToken, tok.RefreshToken, tok.Expiry, tok.TokenType, scopes); err != nil {
		return err
	}
	return nil
}

// [BENCHMARK] 0.000 sec / 0.000 sec
func GetIntegrationTokens(characterID int32) ([]IntegrationToken, error) {
	tokens := []IntegrationToken{}
	if err := database.Select(&tokens, `
		SELECT characterID,
			integrationUserID,
			type,
			integrationUserName,
			expiry,
			tokenType,
			lastCode,
			lastStatus,
			scopes
			FROM evedata.integrationTokens
			WHERE characterID = ?;
		`, characterID); err != nil {

		return nil, err
	}

	return tokens, nil
}

func DeleteIntegrationToken(tokenType string, characterID int32, integrationUserID string) error {
	if _, err := database.Exec(`DELETE FROM evedata.integrationTokens WHERE characterID = ? AND integrationUserID = ? AND type = ? LIMIT 1`,
		characterID, integrationUserID, tokenType); err != nil {
		return err
	}
	return nil
}

func UpdateCharacter(characterID int32, name string, bloodlineID int32, ancestryID int32, corporationID int32, allianceID int32,
	race int32, gender string, securityStatus float32, cacheUntil time.Time) error {
	cacheUntil = time.Now().UTC().Add(time.Hour * 24 * 5)
	if _, err := database.Exec(`
		INSERT INTO evedata.characters (characterID,name,bloodlineID,ancestryID,corporationID,allianceID,race,gender,securityStatus,updated,cacheUntil)
			VALUES(?,?,?,?,?,?,evedata.raceByID(?),?,?,UTC_TIMESTAMP(),?)
			ON DUPLICATE KEY UPDATE
			corporationID=VALUES(corporationID), gender=VALUES(gender), allianceID=VALUES(allianceID), securityStatus=VALUES(securityStatus), updated = UTC_TIMESTAMP(), cacheUntil=VALUES(cacheUntil)
	`, characterID, name, bloodlineID, ancestryID, corporationID, allianceID, race, gender, securityStatus, cacheUntil); err != nil {
		return err
	}
	return nil
}

func UpdateCorporationHistory(characterID int32, corporationID int32, recordID int32, startDate time.Time) error {
	if _, err := database.Exec(`
		INSERT INTO evedata.corporationHistory (characterID,startDate,recordID,corporationID)
			VALUES(?,?,?,?)
			ON DUPLICATE KEY UPDATE
			startDate=VALUES(startDate)
	`, characterID, startDate, recordID, corporationID); err != nil {
		return err
	}
	return nil
}

type Character struct {
	CharacterID     int32       `db:"characterID" json:"characterID"`
	CharacterName   string      `db:"characterName" json:"characterName"`
	CorporationID   int32       `db:"corporationID" json:"corporationID"`
	CorporationName string      `db:"corporationName" json:"corporationName"`
	AllianceID      int32       `db:"allianceID" json:"allianceID"`
	AllianceName    null.String `db:"allianceName" json:"allianceName"`
	Race            string      `db:"race" json:"race"`
	SecurityStatus  float64     `db:"securityStatus" json:"securityStatus"`
}

// Obtain Character information by ID.
// [BENCHMARK] 0.000 sec / 0.000 sec
func GetCharacter(id int32) (*Character, error) {
	ref := Character{}
	if err := database.QueryRowx(`
		SELECT
			characterID,
			C.name AS characterName,
		    C.corporationID,
		    IFNULL(Co.name, "Unknown Name") AS corporationName,
		    C.allianceID,
		    Al.name AS allianceName,
		    race,
		    securityStatus

		FROM evedata.characters C
		LEFT OUTER JOIN evedata.corporations Co ON Co.corporationID = C.corporationID
		LEFT OUTER JOIN evedata.alliances Al ON Al.allianceID = C.allianceID
		WHERE characterID = ?
		LIMIT 1`, id).StructScan(&ref); err != nil {
		return nil, err
	}
	return &ref, nil
}

type CorporationHistory struct {
	CorporationID   int32     `db:"corporationID" json:"id"`
	CorporationName string    `db:"corporationName" json:"name"`
	StartDate       time.Time `db:"startDate" json:"startDate"`
	Type            string    `db:"type" json:"type"`
}

// Obtain Character information by ID.
// [BENCHMARK] 0.000 sec / 0.000 sec
func GetCorporationHistory(id int32) ([]CorporationHistory, error) {
	ref := []CorporationHistory{}
	if err := database.Select(&ref, `
		SELECT
			C.corporationID,
			C.name AS corporationName,
			startDate

		FROM evedata.corporationHistory H
		INNER JOIN evedata.corporations C ON C.corporationID = H.corporationID
		WHERE H.characterID = ?
		ORDER BY startDate DESC
		`, id); err != nil {
		return nil, err
	}
	for i := range ref {
		ref[i].Type = "corporation"
	}
	return ref, nil
}

type Entity struct {
	EntityID   int32  `db:"entityID" json:"entityID"`
	EntityName string `db:"entityName" json:"entityName"`
	EntityType string `db:"entityType" json:"entityType"`
}

// GetEntitiesWithRole determine which corporation/alliance roles are available
// [BENCHMARK] 0.000 sec / 0.000 sec
func GetEntitiesWithRole(characterID int32, role string) ([]Entity, error) {
	ref := []Entity{}
	if err := database.Select(&ref, `
		SELECT DISTINCT C.corporationID AS entityID, name AS entityName, "corporation" AS entityType
		FROM evedata.crestTokens T
		INNER JOIN evedata.corporations C ON C.corporationID = T.corporationID
		WHERE FIND_IN_SET(?, T.roles) AND T.characterID = ?
        UNION
   		SELECT DISTINCT A.allianceID AS entityID, name AS entityName, "alliance" AS entityType
		FROM evedata.crestTokens T
		INNER JOIN evedata.alliances A ON A.allianceID = T.allianceID AND T.corporationID = A.executorCorpID
		WHERE FIND_IN_SET(?, T.roles) AND T.characterID = ?
		`, role, characterID, role, characterID); err != nil {
		return nil, err
	}
	return ref, nil
}
<commit_msg>return if the mail password is set<commit_after>package models

import (
	"database/sql"
	"encoding/json"
	"time"

	"github.com/antihax/evedata/services/conservator"
	"github.com/guregu/null"
	"golang.org/x/oauth2"
)

// Obtain an authenticated client from a stored access/refresh token.
func GetCRESTToken(characterID int32, ownerHash string, tokenCharacterID int32) (*CRESTToken, error) {
	tok := &CRESTToken{}
	if err := database.QueryRowx(
		`SELECT expiry, tokenType, accessToken, refreshToken, tokenCharacterID, characterID, characterName
			FROM evedata.crestTokens
			WHERE characterID = ? AND (characterOwnerHash = ? OR characterOwnerHash = "") AND tokenCharacterID = ?
			LIMIT 1`,
		characterID, ownerHash, tokenCharacterID).StructScan(tok); err != nil {

		return nil, err
	}

	return tok, nil
}

type CRESTToken struct {
	Expiry           time.Time           `db:"expiry" json:"expiry,omitempty"`
	CharacterID      int32               `db:"characterID" json:"characterID,omitempty"`
	TokenType        string              `db:"tokenType" json:"tokenType,omitempty"`
	TokenCharacterID int32               `db:"tokenCharacterID" json:"tokenCharacterID,omitempty"`
	CharacterName    string              `db:"characterName" json:"characterName,omitempty"`
	LastCode         int64               `db:"lastCode" json:"lastCode,omitempty"`
	LastStatus       null.String         `db:"lastStatus" json:"lastStatus,omitempty"`
	AccessToken      string              `db:"accessToken" json:"accessToken,omitempty"`
	RefreshToken     string              `db:"refreshToken" json:"refreshToken,omitempty"`
	Scopes           string              `db:"scopes" json:"scopes"`
	AuthCharacter    int                 `db:"authCharacter" json:"authCharacter"`
	SharingInt       string              `db:"sharingint" json:"_,omitempty"`
	Sharing          []conservator.Share `json:"sharing"`
}

type IntegrationToken struct {
	Type                string      `db:"type" json:"type,omitempty"`
	Expiry              time.Time   `db:"expiry" json:"expiry,omitempty"`
	CharacterID         int32       `db:"characterID" json:"characterID,omitempty"`
	IntegrationUserID   string      `db:"integrationUserID" json:"integrationUserID,omitempty"`
	IntegrationUserName string      `db:"integrationUserName" json:"integrationUserName,omitempty"`
	TokenType           string      `db:"tokenType" json:"tokenType,omitempty"`
	LastCode            int64       `db:"lastCode" json:"lastCode,omitempty"`
	LastStatus          null.String `db:"lastStatus" json:"lastStatus,omitempty"`
	AccessToken         string      `db:"accessToken" json:"accessToken,omitempty"`
	RefreshToken        string      `db:"refreshToken" json:"refreshToken,omitempty"`
	Scopes              string      `db:"scopes" json:"scopes"`
}

// [BENCHMARK] TODO
func GetCharacterIDByName(character string) (int32, error) {
	var id int32
	if err := database.Get(&id, `
		SELECT characterID
		FROM evedata.characters C
		WHERE C.name = ? LIMIT 1;`, character); err != nil && err != sql.ErrNoRows {
		return id, err
	}
	return id, nil
}

type CursorCharacter struct {
	CursorCharacterID   int32  `db:"cursorCharacterID" json:"cursorCharacterID"`
	CursorCharacterName string `db:"cursorCharacterName" json:"cursorCharacterName"`
}

// [BENCHMARK] TODO
func GetCursorCharacter(characterID int32) (CursorCharacter, error) {
	cursor := CursorCharacter{}

	if err := database.Get(&cursor, `
		SELECT cursorCharacterID, T.characterName AS cursorCharacterName
		FROM evedata.cursorCharacter C
		INNER JOIN evedata.crestTokens T ON C.cursorCharacterID = T.tokenCharacterID AND C.characterID = T.characterID
		WHERE C.characterID = ?;`, characterID); err != nil {
		return cursor, err
	}
	return cursor, nil
}

// [BENCHMARK] TODO
func SetCursorCharacter(characterID int32, cursorCharacterID int32) error {
	if _, err := database.Exec(`
	INSERT INTO evedata.cursorCharacter (characterID, cursorCharacterID)
		SELECT characterID, tokenCharacterID AS cursorCharacterID
		FROM evedata.crestTokens WHERE characterID = ? AND tokenCharacterID = ? LIMIT 1
	ON DUPLICATE KEY UPDATE cursorCharacterID = VALUES(cursorCharacterID)
		;`, characterID, cursorCharacterID); err != nil {
		return err
	}
	return nil
}

// [BENCHMARK] 0.000 sec / 0.000 sec
func GetCRESTTokens(characterID int32, ownerHash string) ([]CRESTToken, error) {
	tokens := []CRESTToken{}
	if err := database.Select(&tokens, `
		SELECT T.characterID, T.tokenCharacterID, characterName, IF(mailPassword != "", "Set", "Not Set") AS mailPassword,
		lastCode, lastStatus, scopes, authCharacter,
		IFNULL(
			CONCAT("[", GROUP_CONCAT(CONCAT(
				'{"id": ', entityID,
				', "types": "', types, '"',
				', "entityName": "', IFNULL(A.name, C.name), '"',
				', "type": "', IF(A.name IS NULL, "corporation", "alliance"), '"',
				'}')),
			"]")
		, "[]") AS sharingint
		FROM evedata.crestTokens T
		LEFT OUTER JOIN evedata.sharing S ON T.tokenCharacterID = S.tokenCharacterID AND T.characterID = S.characterID
		LEFT OUTER JOIN evedata.corporations C ON C.corporationID = S.entityID
		LEFT OUTER JOIN evedata.alliances A ON A.allianceID = S.entityID
		WHERE T.characterID = ? AND (T.characterOwnerHash = ? OR T.characterOwnerHash = "")
		GROUP BY characterID, tokenCharacterID;
		;`, characterID, ownerHash); err != nil {

		return nil, err
	}

	// Unmarshal our sharing data.
	for index := range tokens {
		share := []conservator.Share{}
		if err := json.Unmarshal([]byte(tokens[index].SharingInt), &share); err != nil {
			return nil, err
		}
		tokens[index].Sharing = share
		tokens[index].SharingInt = ""
	}
	return tokens, nil
}

// AddCRESTToken adds an SSO token to the database or updates it if one exists.
// resetting status and if errors were mailed to the user.
func AddCRESTToken(characterID int32, tokenCharacterID int32, characterName string, tok *oauth2.Token, scopes, ownerHash string, corporationID, allianceID, factionID int32) error {
	if _, err := database.Exec(`
		INSERT INTO evedata.crestTokens	(characterID, tokenCharacterID, accessToken, refreshToken, expiry,
				tokenType, characterName, scopes, lastStatus, characterOwnerHash, corporationID, allianceID, factionID)
			VALUES		(?,?,?,?,?,?,?,?,"Unused",?,?,?,?)
			ON DUPLICATE KEY UPDATE
				accessToken 		= VALUES(accessToken),
				refreshToken 		= VALUES(refreshToken),
				expiry 				= VALUES(expiry),
				tokenType 			= VALUES(tokenType),
				characterOwnerHash	= VALUES(characterOwnerHash),
				scopes 				= VALUES(scopes),
				corporationID 		= VALUES(corporationID),
				allianceID	 		= VALUES(allianceID),
				factionID	 		= VALUES(factionID),
				lastStatus			= "Unused",
				mailedError 		= 0`,
		characterID, tokenCharacterID, tok.AccessToken, tok.RefreshToken, tok.Expiry, tok.TokenType, characterName, scopes, ownerHash, corporationID, allianceID, factionID); err != nil {
		return err
	}
	return nil
}

func DeleteCRESTToken(characterID int32, tokenCharacterID int32) error {
	if _, err := database.Exec(`DELETE FROM evedata.crestTokens WHERE characterID = ? AND tokenCharacterID = ? LIMIT 1`,
		characterID, tokenCharacterID); err != nil {

		return err
	}
	return nil
}

// AddIntegrationToken adds a oauth2 token to the database for integrations or updates it if one exists.
// resetting status and if errors were mailed to the user.
func AddIntegrationToken(tokenType string, characterID int32, userID string, userName string, tok *oauth2.Token, scopes string) error {
	if _, err := database.Exec(`
		INSERT INTO evedata.integrationTokens	(type, characterID, integrationUserID, integrationUserName, accessToken, refreshToken, expiry,
				tokenType, scopes, lastStatus)
			VALUES		(?,?,?,?,?,?,?,?,?,"Unused")
			ON DUPLICATE KEY UPDATE
				accessToken 		= VALUES(accessToken),
				refreshToken 		= VALUES(refreshToken),
				expiry 				= VALUES(expiry),
				tokenType 			= VALUES(tokenType),
				scopes 				= VALUES(scopes),
				lastStatus			= "Unused",
				mailedError 		= 0`,
		tokenType, characterID, userID, userName, tok.AccessToken, tok.RefreshToken, tok.Expiry, tok.TokenType, scopes); err != nil {
		return err
	}
	return nil
}

// [BENCHMARK] 0.000 sec / 0.000 sec
func GetIntegrationTokens(characterID int32) ([]IntegrationToken, error) {
	tokens := []IntegrationToken{}
	if err := database.Select(&tokens, `
		SELECT characterID,
			integrationUserID,
			type,
			integrationUserName,
			expiry,
			tokenType,
			lastCode,
			lastStatus,
			scopes
			FROM evedata.integrationTokens
			WHERE characterID = ?;
		`, characterID); err != nil {

		return nil, err
	}

	return tokens, nil
}

func DeleteIntegrationToken(tokenType string, characterID int32, integrationUserID string) error {
	if _, err := database.Exec(`DELETE FROM evedata.integrationTokens WHERE characterID = ? AND integrationUserID = ? AND type = ? LIMIT 1`,
		characterID, integrationUserID, tokenType); err != nil {
		return err
	}
	return nil
}

func UpdateCharacter(characterID int32, name string, bloodlineID int32, ancestryID int32, corporationID int32, allianceID int32,
	race int32, gender string, securityStatus float32, cacheUntil time.Time) error {
	cacheUntil = time.Now().UTC().Add(time.Hour * 24 * 5)
	if _, err := database.Exec(`
		INSERT INTO evedata.characters (characterID,name,bloodlineID,ancestryID,corporationID,allianceID,race,gender,securityStatus,updated,cacheUntil)
			VALUES(?,?,?,?,?,?,evedata.raceByID(?),?,?,UTC_TIMESTAMP(),?)
			ON DUPLICATE KEY UPDATE
			corporationID=VALUES(corporationID), gender=VALUES(gender), allianceID=VALUES(allianceID), securityStatus=VALUES(securityStatus), updated = UTC_TIMESTAMP(), cacheUntil=VALUES(cacheUntil)
	`, characterID, name, bloodlineID, ancestryID, corporationID, allianceID, race, gender, securityStatus, cacheUntil); err != nil {
		return err
	}
	return nil
}

func UpdateCorporationHistory(characterID int32, corporationID int32, recordID int32, startDate time.Time) error {
	if _, err := database.Exec(`
		INSERT INTO evedata.corporationHistory (characterID,startDate,recordID,corporationID)
			VALUES(?,?,?,?)
			ON DUPLICATE KEY UPDATE
			startDate=VALUES(startDate)
	`, characterID, startDate, recordID, corporationID); err != nil {
		return err
	}
	return nil
}

type Character struct {
	CharacterID     int32       `db:"characterID" json:"characterID"`
	CharacterName   string      `db:"characterName" json:"characterName"`
	CorporationID   int32       `db:"corporationID" json:"corporationID"`
	CorporationName string      `db:"corporationName" json:"corporationName"`
	AllianceID      int32       `db:"allianceID" json:"allianceID"`
	AllianceName    null.String `db:"allianceName" json:"allianceName"`
	Race            string      `db:"race" json:"race"`
	SecurityStatus  float64     `db:"securityStatus" json:"securityStatus"`
}

// Obtain Character information by ID.
// [BENCHMARK] 0.000 sec / 0.000 sec
func GetCharacter(id int32) (*Character, error) {
	ref := Character{}
	if err := database.QueryRowx(`
		SELECT
			characterID,
			C.name AS characterName,
		    C.corporationID,
		    IFNULL(Co.name, "Unknown Name") AS corporationName,
		    C.allianceID,
		    Al.name AS allianceName,
		    race,
		    securityStatus

		FROM evedata.characters C
		LEFT OUTER JOIN evedata.corporations Co ON Co.corporationID = C.corporationID
		LEFT OUTER JOIN evedata.alliances Al ON Al.allianceID = C.allianceID
		WHERE characterID = ?
		LIMIT 1`, id).StructScan(&ref); err != nil {
		return nil, err
	}
	return &ref, nil
}

type CorporationHistory struct {
	CorporationID   int32     `db:"corporationID" json:"id"`
	CorporationName string    `db:"corporationName" json:"name"`
	StartDate       time.Time `db:"startDate" json:"startDate"`
	Type            string    `db:"type" json:"type"`
}

// Obtain Character information by ID.
// [BENCHMARK] 0.000 sec / 0.000 sec
func GetCorporationHistory(id int32) ([]CorporationHistory, error) {
	ref := []CorporationHistory{}
	if err := database.Select(&ref, `
		SELECT
			C.corporationID,
			C.name AS corporationName,
			startDate

		FROM evedata.corporationHistory H
		INNER JOIN evedata.corporations C ON C.corporationID = H.corporationID
		WHERE H.characterID = ?
		ORDER BY startDate DESC
		`, id); err != nil {
		return nil, err
	}
	for i := range ref {
		ref[i].Type = "corporation"
	}
	return ref, nil
}

type Entity struct {
	EntityID   int32  `db:"entityID" json:"entityID"`
	EntityName string `db:"entityName" json:"entityName"`
	EntityType string `db:"entityType" json:"entityType"`
}

// GetEntitiesWithRole determine which corporation/alliance roles are available
// [BENCHMARK] 0.000 sec / 0.000 sec
func GetEntitiesWithRole(characterID int32, role string) ([]Entity, error) {
	ref := []Entity{}
	if err := database.Select(&ref, `
		SELECT DISTINCT C.corporationID AS entityID, name AS entityName, "corporation" AS entityType
		FROM evedata.crestTokens T
		INNER JOIN evedata.corporations C ON C.corporationID = T.corporationID
		WHERE FIND_IN_SET(?, T.roles) AND T.characterID = ?
        UNION
   		SELECT DISTINCT A.allianceID AS entityID, name AS entityName, "alliance" AS entityType
		FROM evedata.crestTokens T
		INNER JOIN evedata.alliances A ON A.allianceID = T.allianceID AND T.corporationID = A.executorCorpID
		WHERE FIND_IN_SET(?, T.roles) AND T.characterID = ?
		`, role, characterID, role, characterID); err != nil {
		return nil, err
	}
	return ref, nil
}
<|endoftext|>


<commit_before>// Copyright The OpenTelemetry 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 main // import "go.opentelemetry.io/otel/bridge/opencensus/examples/simple"

import (
	"context"
	"log"

	octrace "go.opencensus.io/trace"

	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/bridge/opencensus"
	"go.opentelemetry.io/otel/exporters/stdout"
	sdktrace "go.opentelemetry.io/otel/sdk/trace"
)

func main() {
	ctx := context.Background()

	log.Println("Configuring OpenCensus.  Not Registering any OpenCensus exporters.")
	octrace.ApplyConfig(octrace.Config{DefaultSampler: octrace.AlwaysSample()})

	log.Println("Registering OpenTelemetry stdout exporter.")
	otExporter, err := stdout.NewExporter(stdout.WithPrettyPrint())
	if err != nil {
		log.Fatal(err)
	}
	tp := sdktrace.NewTracerProvider(sdktrace.WithSyncer(otExporter))
	otel.SetTracerProvider(tp)

	log.Println("Installing the OpenCensus bridge to make OpenCensus libraries write spans using OpenTelemetry.")
	tracer := tp.Tracer("simple")
	octrace.DefaultTracer = opencensus.NewTracer(tracer)

	log.Println("Creating OpenCensus span, which should be printed out using the OpenTelemetry stdout exporter.\n-- It should have no parent, since it is the first span.")
	ctx, outerOCSpan := octrace.StartSpan(ctx, "OpenCensusOuterSpan")
	outerOCSpan.End()

	log.Println("Creating OpenTelemetry span\n-- It should have the OpenCensus span as a parent, since the OpenCensus span was written with using OpenTelemetry APIs.")
	ctx, otspan := tracer.Start(ctx, "OpenTelemetrySpan")
	otspan.End()

	log.Println("Creating OpenCensus span, which should be printed out using the OpenTelemetry stdout exporter.\n-- It should have the OpenTelemetry span as a parent, since it was written using OpenTelemetry APIs")
	_, innerOCSpan := octrace.StartSpan(ctx, "OpenCensusInnerSpan")
	innerOCSpan.End()
}
<commit_msg>Remove inaccurate and unnecessary import comment (#1481)<commit_after>// Copyright The OpenTelemetry 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 main

import (
	"context"
	"log"

	octrace "go.opencensus.io/trace"

	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/bridge/opencensus"
	"go.opentelemetry.io/otel/exporters/stdout"
	sdktrace "go.opentelemetry.io/otel/sdk/trace"
)

func main() {
	ctx := context.Background()

	log.Println("Configuring OpenCensus.  Not Registering any OpenCensus exporters.")
	octrace.ApplyConfig(octrace.Config{DefaultSampler: octrace.AlwaysSample()})

	log.Println("Registering OpenTelemetry stdout exporter.")
	otExporter, err := stdout.NewExporter(stdout.WithPrettyPrint())
	if err != nil {
		log.Fatal(err)
	}
	tp := sdktrace.NewTracerProvider(sdktrace.WithSyncer(otExporter))
	otel.SetTracerProvider(tp)

	log.Println("Installing the OpenCensus bridge to make OpenCensus libraries write spans using OpenTelemetry.")
	tracer := tp.Tracer("simple")
	octrace.DefaultTracer = opencensus.NewTracer(tracer)

	log.Println("Creating OpenCensus span, which should be printed out using the OpenTelemetry stdout exporter.\n-- It should have no parent, since it is the first span.")
	ctx, outerOCSpan := octrace.StartSpan(ctx, "OpenCensusOuterSpan")
	outerOCSpan.End()

	log.Println("Creating OpenTelemetry span\n-- It should have the OpenCensus span as a parent, since the OpenCensus span was written with using OpenTelemetry APIs.")
	ctx, otspan := tracer.Start(ctx, "OpenTelemetrySpan")
	otspan.End()

	log.Println("Creating OpenCensus span, which should be printed out using the OpenTelemetry stdout exporter.\n-- It should have the OpenTelemetry span as a parent, since it was written using OpenTelemetry APIs")
	_, innerOCSpan := octrace.StartSpan(ctx, "OpenCensusInnerSpan")
	innerOCSpan.End()
}
<|endoftext|>


<commit_before>package zmtp

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"strings"
)

type Connection struct {
	rw                         io.ReadWriter
	securityMechanism          SecurityMechanism
	socket                     Socket
	isPrepared                 bool
	asServer, otherEndAsServer bool
}

type SocketType string

const (
	ClientSocketType SocketType = "CLIENT"
	ServerSocketType SocketType = "SERVER"
)

func NewConnection(rw io.ReadWriter) *Connection {
	return &Connection{rw: rw}
}

func (c *Connection) Prepare(mechanism SecurityMechanism, socketType SocketType, asServer bool, applicationMetadata map[string]string) (map[string]string, error) {
	if c.isPrepared {
		return nil, errors.New("Connection was already prepared")
	}

	c.isPrepared = true
	c.securityMechanism = mechanism

	var err error
	if c.socket, err = NewSocket(socketType); err != nil {
		return nil, fmt.Errorf("gomq/zmtp: Got error while creating socket: %v", err)
	}

	// Send/recv greeting
	if err := c.sendGreeting(asServer); err != nil {
		return nil, fmt.Errorf("gomq/zmtp: Got error while sending greeting: %v", err)
	}
	if err := c.recvGreeting(asServer); err != nil {
		return nil, fmt.Errorf("gomq/zmtp: Got error while receiving greeting: %v", err)
	}

	// Do security handshake
	if err := mechanism.Handshake(); err != nil {
		return nil, fmt.Errorf("gomq/zmtp: Got error while running the security handshake: %v", err)
	}

	// Send/recv metadata
	if err := c.sendMetadata(socketType, applicationMetadata); err != nil {
		return nil, fmt.Errorf("gomq/zmtp: Got error while sending metadata: %v", err)
	}

	otherEndApplicationMetaData, err := c.recvMetadata()
	if err != nil {
		return nil, fmt.Errorf("gomq/zmtp: Got error while receiving metadata: %v", err)
	}

	return otherEndApplicationMetaData, nil
}

func (c *Connection) sendGreeting(asServer bool) error {
	greeting := greeting{
		SignaturePrefix: signaturePrefix,
		SignatureSuffix: signatureSuffix,
		Version:         version,
	}
	toNullPaddedString(string(c.securityMechanism.Type()), greeting.Mechanism[:])

	if err := binary.Write(c.rw, byteOrder, &greeting); err != nil {
		return err
	}

	return nil
}

func (c *Connection) recvGreeting(asServer bool) error {
	var greeting greeting

	if err := binary.Read(c.rw, byteOrder, &greeting); err != nil {
		return fmt.Errorf("Error while reading: %v", err)
	}

	if greeting.SignaturePrefix != signaturePrefix {
		return fmt.Errorf("Signature prefix received does not correspond with expected signature. Received: %#v. Expected: %#v.", greeting.SignaturePrefix, signaturePrefix)
	}

	if greeting.SignatureSuffix != signatureSuffix {
		return fmt.Errorf("Signature prefix received does not correspond with expected signature. Received: %#v. Expected: %#v.", greeting.SignatureSuffix, signatureSuffix)
	}

	if greeting.Version != version {
		return fmt.Errorf("Version %v.%v received does match expected version %v.%v", int(greeting.Version[0]), int(greeting.Version[1]), int(majorVersion), int(minorVersion))
	}

	var otherMechanism = fromNullPaddedString(greeting.Mechanism[:])
	var thisMechanism = string(c.securityMechanism.Type())
	if thisMechanism != otherMechanism {
		return fmt.Errorf("Encryption mechanism on other side %q does not match this side's %q", otherMechanism, thisMechanism)
	}

	otherEndAsServer, err := fromByteBool(greeting.ServerFlag)
	if err != nil {
		return err
	}
	c.otherEndAsServer = otherEndAsServer

	return nil
}

func (c *Connection) sendMetadata(socketType SocketType, applicationMetadata map[string]string) error {
	buffer := new(bytes.Buffer)
	var usedKeys map[string]struct{}

	for k, v := range applicationMetadata {
		if len(k) == 0 {
			return errors.New("Cannot send empty application metadata key")
		}

		lowerCaseKey := strings.ToLower(k)
		if _, alreadyPresent := usedKeys[lowerCaseKey]; alreadyPresent {
			return fmt.Errorf("Key %q is specified multiple times with different casing", lowerCaseKey)
		}

		usedKeys[lowerCaseKey] = struct{}{}
		c.writeMetadata(buffer, "x-"+lowerCaseKey, v)
	}

	c.writeMetadata(buffer, "socket-type", string(socketType))

	return c.SendCommand("READY", buffer.Bytes())
}

func (c *Connection) writeMetadata(buffer *bytes.Buffer, name string, value string) {
	buffer.WriteByte(byte(len(name)))
	buffer.WriteString(name)
	binary.Write(buffer, byteOrder, uint32(len(value)))
	buffer.WriteString(value)
}

func (c *Connection) recvMetadata() (map[string]string, error) {
	isCommand, body, err := c.read()
	if err != nil {
		return nil, err
	}

	if !isCommand {
		return nil, errors.New("Got a message frame for metadata, expected a command frame")
	}

	command, err := c.parseCommand(body)
	if err != nil {
		return nil, err
	}

	if command.Name != "READY" {
		return nil, fmt.Errorf("Got a %v command for metadata instead of the expected READY command frame", command.Name)
	}

	metadata := make(map[string]string)
	applicationMetadata := make(map[string]string)
	i := 0
	for i < len(command.Body) {
		// Key length
		keyLength := int(command.Body[i])
		if i+keyLength >= len(command.Body) {
			return nil, fmt.Errorf("metadata key of length %v overflows body of length %v at position %v", keyLength, len(command.Body), i)
		}
		i++

		// Key
		key := strings.ToLower(string(command.Body[i : i+keyLength]))
		i += keyLength

		// Value length
		var rawValueLength uint32
		if err := binary.Read(bytes.NewBuffer(command.Body[i:i+4]), byteOrder, &rawValueLength); err != nil {
			return nil, err
		}

		if uint64(rawValueLength) > uint64(maxInt) {
			return nil, fmt.Errorf("Length of value %v overflows integer max length %v on this platform", rawValueLength, maxInt)
		}

		valueLength := int(rawValueLength)
		if i+valueLength >= len(command.Body) {
			return nil, fmt.Errorf("metadata value of length %v overflows body of length %v at position %v", valueLength, len(command.Body), i)
		}
		i += 4

		// Value
		value := string(command.Body[i : i+valueLength])
		i += valueLength

		if strings.HasPrefix(key, "x-") {
			applicationMetadata[key[2:]] = value
		} else {
			metadata[key] = value
		}
	}

	socketType := metadata["socket-type"]
	if !c.socket.IsSocketTypeCompatible(SocketType(socketType)) {
		return nil, fmt.Errorf("Socket type %v is not compatible with %v", c.socket.Type(), socketType)
	}

	return applicationMetadata, nil
}

func (c *Connection) SendCommand(commandName string, body []byte) error {
	if len(commandName) > 255 {
		return errors.New("Command names may not be longer than 255 characters")
	}

	// Make the buffer of the correct lenght and reset it
	buffer := new(bytes.Buffer)
	buffer.WriteByte(byte(len(commandName)))
	buffer.Write([]byte(commandName))
	buffer.Write(body)

	return c.send(true, buffer.Bytes())
}

func (c *Connection) SendFrame(body []byte) error {
	return c.send(false, body)
}

func (c *Connection) send(isCommand bool, body []byte) error {
	// Compute total body length
	length := len(body)

	var bitFlags byte

	// More flag: Unused, we don't support multiframe messages

	// Long flag
	isLong := length > 255
	if isLong {
		bitFlags ^= isLongBitFlag
	}

	// Command flag
	if isCommand {
		bitFlags ^= isCommandBitFlag
	}

	// Write out the message itself
	if _, err := c.rw.Write([]byte{bitFlags}); err != nil {
		return err
	}

	if isLong {
		if err := binary.Write(c.rw, byteOrder, int64(len(body))); err != nil {
			return err
		}
	} else {
		if err := binary.Write(c.rw, byteOrder, uint8(len(body))); err != nil {
			return err
		}
	}

	if _, err := c.rw.Write(c.securityMechanism.Encrypt(body)); err != nil {
		return err
	}

	return nil
}

// Recv starts listening to the ReadWriter and passes *Message, *Command and
// *Error messages to channels
func (c *Connection) Recv(messageOut chan *Message, commandOut chan *Command, errorOut chan *Error) {
	go func() {
		for {
			// Actually read out the body and send it over the channel now
			isCommand, body, err := c.read()
			if err != nil {
				errorOut <- &Error{Error: err}
				return
			}

			if !isCommand {
				// Data frame
				messageOut <- &Message{Body: body}
			} else {
				command, err := c.parseCommand(body)
				if err != nil {
					errorOut <- &Error{Error: err}
					return
				}

				// Check what type of command we got
				// Certain commands we deal with directly, the rest we send over to the application
				switch command.Name {
				case "PING":
					// When we get a ping, we want to send back a pong, we don't really care about the contents right now
					if err := c.SendCommand("PONG", nil); err != nil {
						errorOut <- &Error{Error: err}
						return
					}
				default:
					commandOut <- &Command{Name: command.Name, Body: command.Body}
				}

			}
		}
	}()
}

// read returns the isCommand flag, the body of the message, and optionally an error
func (c *Connection) read() (bool, []byte, error) {
	var header [2]byte
	var longLength [4]byte

	// Read out the header
	readLength := uint64(0)
	for readLength != 2 {
		l, err := c.rw.Read(header[readLength:])
		if err != nil {
			return false, nil, err
		}

		readLength += uint64(l)
	}

	bitFlags := header[0]

	// Read all the flags
	hasMore := bitFlags&hasMoreBitFlag == hasMoreBitFlag
	isLong := bitFlags&isLongBitFlag == isLongBitFlag
	isCommand := bitFlags&isCommandBitFlag == isCommandBitFlag

	// Error out in case get a more flag set to true
	if hasMore {
		return false, nil, errors.New("Received a packet with the MORE flag set to true, we don't support more")
	}

	// Determine the actual length of the body
	bodyLength := uint64(0)
	if isLong {
		// We read 2 bytes of the header already
		// In case of a long message, the length is bytes 2-8 of the header
		// We already have the first byte, so assign it, and then read the rest
		longLength[0] = header[1]

		readLength := 1
		for readLength != 8 {
			l, err := c.rw.Read(longLength[readLength:])
			if err != nil {
				return false, nil, err
			}

			readLength += l
		}

		if err := binary.Read(bytes.NewBuffer(longLength[:]), byteOrder, &bodyLength); err != nil {
			return false, nil, err
		}
	} else {
		// Short message length is just 1 byte, read it
		bodyLength = uint64(header[1])
	}

	if bodyLength > uint64(maxInt64) {
		return false, nil, fmt.Errorf("Body length %v overflows max int64 value %v", bodyLength, maxInt64)
	}

	buffer := new(bytes.Buffer)
	readLength = 0
	for readLength < bodyLength {
		l, err := buffer.ReadFrom(io.LimitReader(c.rw, int64(bodyLength)-int64(readLength)))
		if err != nil {
			return false, nil, err
		}

		readLength += uint64(l)
	}

	return isCommand, buffer.Bytes(), nil
}

func (c *Connection) parseCommand(body []byte) (*Command, error) {
	// Sanity check
	if len(body) == 0 {
		return nil, errors.New("Got empty command frame body")
	}

	// Read out the command length
	commandNameLength := int(body[0])
	if commandNameLength > len(body)-1 {
		return nil, fmt.Errorf("Got command name length %v, which is too long for a body of length %v", commandNameLength, len(body))
	}

	command := &Command{
		Name: string(body[1 : commandNameLength+1]),
		Body: body[1+commandNameLength:],
	}

	return command, nil
}
<commit_msg>Problem: zmtp.Recv should have one way channels<commit_after>package zmtp

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"strings"
)

type Connection struct {
	rw                         io.ReadWriter
	securityMechanism          SecurityMechanism
	socket                     Socket
	isPrepared                 bool
	asServer, otherEndAsServer bool
}

type SocketType string

const (
	ClientSocketType SocketType = "CLIENT"
	ServerSocketType SocketType = "SERVER"
)

func NewConnection(rw io.ReadWriter) *Connection {
	return &Connection{rw: rw}
}

func (c *Connection) Prepare(mechanism SecurityMechanism, socketType SocketType, asServer bool, applicationMetadata map[string]string) (map[string]string, error) {
	if c.isPrepared {
		return nil, errors.New("Connection was already prepared")
	}

	c.isPrepared = true
	c.securityMechanism = mechanism

	var err error
	if c.socket, err = NewSocket(socketType); err != nil {
		return nil, fmt.Errorf("gomq/zmtp: Got error while creating socket: %v", err)
	}

	// Send/recv greeting
	if err := c.sendGreeting(asServer); err != nil {
		return nil, fmt.Errorf("gomq/zmtp: Got error while sending greeting: %v", err)
	}
	if err := c.recvGreeting(asServer); err != nil {
		return nil, fmt.Errorf("gomq/zmtp: Got error while receiving greeting: %v", err)
	}

	// Do security handshake
	if err := mechanism.Handshake(); err != nil {
		return nil, fmt.Errorf("gomq/zmtp: Got error while running the security handshake: %v", err)
	}

	// Send/recv metadata
	if err := c.sendMetadata(socketType, applicationMetadata); err != nil {
		return nil, fmt.Errorf("gomq/zmtp: Got error while sending metadata: %v", err)
	}

	otherEndApplicationMetaData, err := c.recvMetadata()
	if err != nil {
		return nil, fmt.Errorf("gomq/zmtp: Got error while receiving metadata: %v", err)
	}

	return otherEndApplicationMetaData, nil
}

func (c *Connection) sendGreeting(asServer bool) error {
	greeting := greeting{
		SignaturePrefix: signaturePrefix,
		SignatureSuffix: signatureSuffix,
		Version:         version,
	}
	toNullPaddedString(string(c.securityMechanism.Type()), greeting.Mechanism[:])

	if err := binary.Write(c.rw, byteOrder, &greeting); err != nil {
		return err
	}

	return nil
}

func (c *Connection) recvGreeting(asServer bool) error {
	var greeting greeting

	if err := binary.Read(c.rw, byteOrder, &greeting); err != nil {
		return fmt.Errorf("Error while reading: %v", err)
	}

	if greeting.SignaturePrefix != signaturePrefix {
		return fmt.Errorf("Signature prefix received does not correspond with expected signature. Received: %#v. Expected: %#v.", greeting.SignaturePrefix, signaturePrefix)
	}

	if greeting.SignatureSuffix != signatureSuffix {
		return fmt.Errorf("Signature prefix received does not correspond with expected signature. Received: %#v. Expected: %#v.", greeting.SignatureSuffix, signatureSuffix)
	}

	if greeting.Version != version {
		return fmt.Errorf("Version %v.%v received does match expected version %v.%v", int(greeting.Version[0]), int(greeting.Version[1]), int(majorVersion), int(minorVersion))
	}

	var otherMechanism = fromNullPaddedString(greeting.Mechanism[:])
	var thisMechanism = string(c.securityMechanism.Type())
	if thisMechanism != otherMechanism {
		return fmt.Errorf("Encryption mechanism on other side %q does not match this side's %q", otherMechanism, thisMechanism)
	}

	otherEndAsServer, err := fromByteBool(greeting.ServerFlag)
	if err != nil {
		return err
	}
	c.otherEndAsServer = otherEndAsServer

	return nil
}

func (c *Connection) sendMetadata(socketType SocketType, applicationMetadata map[string]string) error {
	buffer := new(bytes.Buffer)
	var usedKeys map[string]struct{}

	for k, v := range applicationMetadata {
		if len(k) == 0 {
			return errors.New("Cannot send empty application metadata key")
		}

		lowerCaseKey := strings.ToLower(k)
		if _, alreadyPresent := usedKeys[lowerCaseKey]; alreadyPresent {
			return fmt.Errorf("Key %q is specified multiple times with different casing", lowerCaseKey)
		}

		usedKeys[lowerCaseKey] = struct{}{}
		c.writeMetadata(buffer, "x-"+lowerCaseKey, v)
	}

	c.writeMetadata(buffer, "socket-type", string(socketType))

	return c.SendCommand("READY", buffer.Bytes())
}

func (c *Connection) writeMetadata(buffer *bytes.Buffer, name string, value string) {
	buffer.WriteByte(byte(len(name)))
	buffer.WriteString(name)
	binary.Write(buffer, byteOrder, uint32(len(value)))
	buffer.WriteString(value)
}

func (c *Connection) recvMetadata() (map[string]string, error) {
	isCommand, body, err := c.read()
	if err != nil {
		return nil, err
	}

	if !isCommand {
		return nil, errors.New("Got a message frame for metadata, expected a command frame")
	}

	command, err := c.parseCommand(body)
	if err != nil {
		return nil, err
	}

	if command.Name != "READY" {
		return nil, fmt.Errorf("Got a %v command for metadata instead of the expected READY command frame", command.Name)
	}

	metadata := make(map[string]string)
	applicationMetadata := make(map[string]string)
	i := 0
	for i < len(command.Body) {
		// Key length
		keyLength := int(command.Body[i])
		if i+keyLength >= len(command.Body) {
			return nil, fmt.Errorf("metadata key of length %v overflows body of length %v at position %v", keyLength, len(command.Body), i)
		}
		i++

		// Key
		key := strings.ToLower(string(command.Body[i : i+keyLength]))
		i += keyLength

		// Value length
		var rawValueLength uint32
		if err := binary.Read(bytes.NewBuffer(command.Body[i:i+4]), byteOrder, &rawValueLength); err != nil {
			return nil, err
		}

		if uint64(rawValueLength) > uint64(maxInt) {
			return nil, fmt.Errorf("Length of value %v overflows integer max length %v on this platform", rawValueLength, maxInt)
		}

		valueLength := int(rawValueLength)
		if i+valueLength >= len(command.Body) {
			return nil, fmt.Errorf("metadata value of length %v overflows body of length %v at position %v", valueLength, len(command.Body), i)
		}
		i += 4

		// Value
		value := string(command.Body[i : i+valueLength])
		i += valueLength

		if strings.HasPrefix(key, "x-") {
			applicationMetadata[key[2:]] = value
		} else {
			metadata[key] = value
		}
	}

	socketType := metadata["socket-type"]
	if !c.socket.IsSocketTypeCompatible(SocketType(socketType)) {
		return nil, fmt.Errorf("Socket type %v is not compatible with %v", c.socket.Type(), socketType)
	}

	return applicationMetadata, nil
}

func (c *Connection) SendCommand(commandName string, body []byte) error {
	if len(commandName) > 255 {
		return errors.New("Command names may not be longer than 255 characters")
	}

	// Make the buffer of the correct lenght and reset it
	buffer := new(bytes.Buffer)
	buffer.WriteByte(byte(len(commandName)))
	buffer.Write([]byte(commandName))
	buffer.Write(body)

	return c.send(true, buffer.Bytes())
}

func (c *Connection) SendFrame(body []byte) error {
	return c.send(false, body)
}

func (c *Connection) send(isCommand bool, body []byte) error {
	// Compute total body length
	length := len(body)

	var bitFlags byte

	// More flag: Unused, we don't support multiframe messages

	// Long flag
	isLong := length > 255
	if isLong {
		bitFlags ^= isLongBitFlag
	}

	// Command flag
	if isCommand {
		bitFlags ^= isCommandBitFlag
	}

	// Write out the message itself
	if _, err := c.rw.Write([]byte{bitFlags}); err != nil {
		return err
	}

	if isLong {
		if err := binary.Write(c.rw, byteOrder, int64(len(body))); err != nil {
			return err
		}
	} else {
		if err := binary.Write(c.rw, byteOrder, uint8(len(body))); err != nil {
			return err
		}
	}

	if _, err := c.rw.Write(c.securityMechanism.Encrypt(body)); err != nil {
		return err
	}

	return nil
}

// Recv starts listening to the ReadWriter and passes *Message, *Command and
// *Error messages to channels
func (c *Connection) Recv(messageOut chan<- *Message, commandOut chan<- *Command, errorOut chan<- *Error) {
	go func() {
		for {
			// Actually read out the body and send it over the channel now
			isCommand, body, err := c.read()
			if err != nil {
				errorOut <- &Error{Error: err}
				return
			}

			if !isCommand {
				// Data frame
				messageOut <- &Message{Body: body}
			} else {
				command, err := c.parseCommand(body)
				if err != nil {
					errorOut <- &Error{Error: err}
					return
				}

				// Check what type of command we got
				// Certain commands we deal with directly, the rest we send over to the application
				switch command.Name {
				case "PING":
					// When we get a ping, we want to send back a pong, we don't really care about the contents right now
					if err := c.SendCommand("PONG", nil); err != nil {
						errorOut <- &Error{Error: err}
						return
					}
				default:
					commandOut <- &Command{Name: command.Name, Body: command.Body}
				}

			}
		}
	}()
}

// read returns the isCommand flag, the body of the message, and optionally an error
func (c *Connection) read() (bool, []byte, error) {
	var header [2]byte
	var longLength [4]byte

	// Read out the header
	readLength := uint64(0)
	for readLength != 2 {
		l, err := c.rw.Read(header[readLength:])
		if err != nil {
			return false, nil, err
		}

		readLength += uint64(l)
	}

	bitFlags := header[0]

	// Read all the flags
	hasMore := bitFlags&hasMoreBitFlag == hasMoreBitFlag
	isLong := bitFlags&isLongBitFlag == isLongBitFlag
	isCommand := bitFlags&isCommandBitFlag == isCommandBitFlag

	// Error out in case get a more flag set to true
	if hasMore {
		return false, nil, errors.New("Received a packet with the MORE flag set to true, we don't support more")
	}

	// Determine the actual length of the body
	bodyLength := uint64(0)
	if isLong {
		// We read 2 bytes of the header already
		// In case of a long message, the length is bytes 2-8 of the header
		// We already have the first byte, so assign it, and then read the rest
		longLength[0] = header[1]

		readLength := 1
		for readLength != 8 {
			l, err := c.rw.Read(longLength[readLength:])
			if err != nil {
				return false, nil, err
			}

			readLength += l
		}

		if err := binary.Read(bytes.NewBuffer(longLength[:]), byteOrder, &bodyLength); err != nil {
			return false, nil, err
		}
	} else {
		// Short message length is just 1 byte, read it
		bodyLength = uint64(header[1])
	}

	if bodyLength > uint64(maxInt64) {
		return false, nil, fmt.Errorf("Body length %v overflows max int64 value %v", bodyLength, maxInt64)
	}

	buffer := new(bytes.Buffer)
	readLength = 0
	for readLength < bodyLength {
		l, err := buffer.ReadFrom(io.LimitReader(c.rw, int64(bodyLength)-int64(readLength)))
		if err != nil {
			return false, nil, err
		}

		readLength += uint64(l)
	}

	return isCommand, buffer.Bytes(), nil
}

func (c *Connection) parseCommand(body []byte) (*Command, error) {
	// Sanity check
	if len(body) == 0 {
		return nil, errors.New("Got empty command frame body")
	}

	// Read out the command length
	commandNameLength := int(body[0])
	if commandNameLength > len(body)-1 {
		return nil, fmt.Errorf("Got command name length %v, which is too long for a body of length %v", commandNameLength, len(body))
	}

	command := &Command{
		Name: string(body[1 : commandNameLength+1]),
		Body: body[1+commandNameLength:],
	}

	return command, nil
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

package openstack

import (
	"errors"
	"fmt"
	"io/ioutil"
	"path"
	"strings"

	"k8s.io/kubernetes/pkg/volume"

	"github.com/rackspace/gophercloud"
	"github.com/rackspace/gophercloud/openstack"
	"github.com/rackspace/gophercloud/openstack/blockstorage/v1/volumes"
	"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/volumeattach"
	"github.com/rackspace/gophercloud/pagination"

	"github.com/golang/glog"
)

// Attaches given cinder volume to the compute running kubelet
func (os *OpenStack) AttachDisk(instanceID string, diskName string) (string, error) {
	disk, err := os.getVolume(diskName)
	if err != nil {
		return "", err
	}
	cClient, err := openstack.NewComputeV2(os.provider, gophercloud.EndpointOpts{
		Region: os.region,
	})
	if err != nil || cClient == nil {
		glog.Errorf("Unable to initialize nova client for region: %s", os.region)
		return "", err
	}

	if len(disk.Attachments) > 0 && disk.Attachments[0]["server_id"] != nil {
		if instanceID == disk.Attachments[0]["server_id"] {
			glog.V(4).Infof("Disk: %q is already attached to compute: %q", diskName, instanceID)
			return disk.ID, nil
		} else {
			errMsg := fmt.Sprintf("Disk %q is attached to a different compute: %q, should be detached before proceeding", diskName, disk.Attachments[0]["server_id"])
			glog.Errorf(errMsg)
			return "", errors.New(errMsg)
		}
	}
	// add read only flag here if possible spothanis
	_, err = volumeattach.Create(cClient, instanceID, &volumeattach.CreateOpts{
		VolumeID: disk.ID,
	}).Extract()
	if err != nil {
		glog.Errorf("Failed to attach %s volume to %s compute", diskName, instanceID)
		return "", err
	}
	glog.V(2).Infof("Successfully attached %s volume to %s compute", diskName, instanceID)
	return disk.ID, nil
}

// Detaches given cinder volume from the compute running kubelet
func (os *OpenStack) DetachDisk(instanceID string, partialDiskId string) error {
	disk, err := os.getVolume(partialDiskId)
	if err != nil {
		return err
	}
	cClient, err := openstack.NewComputeV2(os.provider, gophercloud.EndpointOpts{
		Region: os.region,
	})
	if err != nil || cClient == nil {
		glog.Errorf("Unable to initialize nova client for region: %s", os.region)
		return err
	}
	if len(disk.Attachments) > 0 && disk.Attachments[0]["server_id"] != nil && instanceID == disk.Attachments[0]["server_id"] {
		// This is a blocking call and effects kubelet's performance directly.
		// We should consider kicking it out into a separate routine, if it is bad.
		err = volumeattach.Delete(cClient, instanceID, disk.ID).ExtractErr()
		if err != nil {
			glog.Errorf("Failed to delete volume %s from compute %s attached %v", disk.ID, instanceID, err)
			return err
		}
		glog.V(2).Infof("Successfully detached volume: %s from compute: %s", disk.ID, instanceID)
	} else {
		errMsg := fmt.Sprintf("Disk: %s has no attachments or is not attached to compute: %s", disk.Name, instanceID)
		glog.Errorf(errMsg)
		return errors.New(errMsg)
	}
	return nil
}

// Takes a partial/full disk id or diskname
func (os *OpenStack) getVolume(diskName string) (volumes.Volume, error) {
	sClient, err := openstack.NewBlockStorageV1(os.provider, gophercloud.EndpointOpts{
		Region: os.region,
	})

	var volume volumes.Volume
	if err != nil || sClient == nil {
		glog.Errorf("Unable to initialize cinder client for region: %s", os.region)
		return volume, err
	}

	err = volumes.List(sClient, nil).EachPage(func(page pagination.Page) (bool, error) {
		vols, err := volumes.ExtractVolumes(page)
		if err != nil {
			glog.Errorf("Failed to extract volumes: %v", err)
			return false, err
		} else {
			for _, v := range vols {
				glog.V(4).Infof("%s %s %v", v.ID, v.Name, v.Attachments)
				if v.Name == diskName || strings.Contains(v.ID, diskName) {
					volume = v
					return true, nil
				}
			}
		}
		// if it reached here then no disk with the given name was found.
		errmsg := fmt.Sprintf("Unable to find disk: %s in region %s", diskName, os.region)
		return false, errors.New(errmsg)
	})
	if err != nil {
		glog.Errorf("Error occurred getting volume: %s", diskName)
		return volume, err
	}
	return volume, err
}

// Create a volume of given size (in GiB)
func (os *OpenStack) CreateVolume(name string, size int, vtype, availability string, tags *map[string]string) (volumeName string, err error) {

	sClient, err := openstack.NewBlockStorageV1(os.provider, gophercloud.EndpointOpts{
		Region: os.region,
	})

	if err != nil || sClient == nil {
		glog.Errorf("Unable to initialize cinder client for region: %s", os.region)
		return "", err
	}

	opts := volumes.CreateOpts{
		Name:         name,
		Size:         size,
		VolumeType:   vtype,
		Availability: availability,
	}
	if tags != nil {
		opts.Metadata = *tags
	}
	vol, err := volumes.Create(sClient, opts).Extract()
	if err != nil {
		glog.Errorf("Failed to create a %d GB volume: %v", size, err)
		return "", err
	}
	glog.Infof("Created volume %v", vol.ID)
	return vol.ID, err
}

// GetDevicePath returns the path of an attached block storage volume, specified by its id.
func (os *OpenStack) GetDevicePath(diskId string) string {
	files, _ := ioutil.ReadDir("/dev/disk/by-id/")
	for _, f := range files {
		if strings.Contains(f.Name(), "virtio-") {
			devid_prefix := f.Name()[len("virtio-"):len(f.Name())]
			if strings.Contains(diskId, devid_prefix) {
				glog.V(4).Infof("Found disk attached as %q; full devicepath: %s\n", f.Name(), path.Join("/dev/disk/by-id/", f.Name()))
				return path.Join("/dev/disk/by-id/", f.Name())
			}
		}
	}
	glog.Warningf("Failed to find device for the diskid: %q\n", diskId)
	return ""
}

func (os *OpenStack) DeleteVolume(volumeName string) error {
	used, err := os.diskIsUsed(volumeName)
	if err != nil {
		return err
	}
	if used {
		msg := fmt.Sprintf("Cannot delete the volume %q, it's still attached to a node", volumeName)
		return volume.NewDeletedVolumeInUseError(msg)
	}

	sClient, err := openstack.NewBlockStorageV1(os.provider, gophercloud.EndpointOpts{
		Region: os.region,
	})

	if err != nil || sClient == nil {
		glog.Errorf("Unable to initialize cinder client for region: %s", os.region)
		return err
	}
	err = volumes.Delete(sClient, volumeName).ExtractErr()
	if err != nil {
		glog.Errorf("Cannot delete volume %s: %v", volumeName, err)
	}
	return err
}

// Get device path of attached volume to the compute running kubelet
func (os *OpenStack) GetAttachmentDiskPath(instanceID string, diskName string) (string, error) {
	disk, err := os.getVolume(diskName)
	if err != nil {
		return "", err
	}
	if len(disk.Attachments) > 0 && disk.Attachments[0]["server_id"] != nil {
		if instanceID == disk.Attachments[0]["server_id"] {
			// Attachment[0]["device"] points to the device path
			// see http://developer.openstack.org/api-ref-blockstorage-v1.html
			return disk.Attachments[0]["device"].(string), nil
		} else {
			errMsg := fmt.Sprintf("Disk %q is attached to a different compute: %q, should be detached before proceeding", diskName, disk.Attachments[0]["server_id"])
			glog.Errorf(errMsg)
			return "", errors.New(errMsg)
		}
	}
	return "", fmt.Errorf("volume %s is not attached to %s", diskName, instanceID)
}

// query if a volume is attached to a compute instance
func (os *OpenStack) DiskIsAttached(diskName, instanceID string) (bool, error) {
	disk, err := os.getVolume(diskName)
	if err != nil {
		return false, err
	}
	if len(disk.Attachments) > 0 && disk.Attachments[0]["server_id"] != nil && instanceID == disk.Attachments[0]["server_id"] {
		return true, nil
	}
	return false, nil
}

// query if a list of volumes are attached to a compute instance
func (os *OpenStack) DisksAreAttached(diskNames []string, instanceID string) (map[string]bool, error) {
	attached := make(map[string]bool)
	for _, diskName := range diskNames {
		attached[diskName] = false
	}
	for _, diskName := range diskNames {
		disk, err := os.getVolume(diskName)
		if err != nil {
			continue
		}
		if len(disk.Attachments) > 0 && disk.Attachments[0]["server_id"] != nil && instanceID == disk.Attachments[0]["server_id"] {
			attached[diskName] = true
		}
	}
	return attached, nil
}

// diskIsUsed returns true a disk is attached to any node.
func (os *OpenStack) diskIsUsed(diskName string) (bool, error) {
	disk, err := os.getVolume(diskName)
	if err != nil {
		return false, err
	}
	if len(disk.Attachments) > 0 {
		return true, nil
	}
	return false, nil
}
<commit_msg>Support OpenStack+ESXi Volumes in GetDevicePath<commit_after>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

package openstack

import (
	"errors"
	"fmt"
	"io/ioutil"
	"path"
	"strings"

	"k8s.io/kubernetes/pkg/volume"

	"github.com/rackspace/gophercloud"
	"github.com/rackspace/gophercloud/openstack"
	"github.com/rackspace/gophercloud/openstack/blockstorage/v1/volumes"
	"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/volumeattach"
	"github.com/rackspace/gophercloud/pagination"

	"github.com/golang/glog"
)

// Attaches given cinder volume to the compute running kubelet
func (os *OpenStack) AttachDisk(instanceID string, diskName string) (string, error) {
	disk, err := os.getVolume(diskName)
	if err != nil {
		return "", err
	}
	cClient, err := openstack.NewComputeV2(os.provider, gophercloud.EndpointOpts{
		Region: os.region,
	})
	if err != nil || cClient == nil {
		glog.Errorf("Unable to initialize nova client for region: %s", os.region)
		return "", err
	}

	if len(disk.Attachments) > 0 && disk.Attachments[0]["server_id"] != nil {
		if instanceID == disk.Attachments[0]["server_id"] {
			glog.V(4).Infof("Disk: %q is already attached to compute: %q", diskName, instanceID)
			return disk.ID, nil
		} else {
			errMsg := fmt.Sprintf("Disk %q is attached to a different compute: %q, should be detached before proceeding", diskName, disk.Attachments[0]["server_id"])
			glog.Errorf(errMsg)
			return "", errors.New(errMsg)
		}
	}
	// add read only flag here if possible spothanis
	_, err = volumeattach.Create(cClient, instanceID, &volumeattach.CreateOpts{
		VolumeID: disk.ID,
	}).Extract()
	if err != nil {
		glog.Errorf("Failed to attach %s volume to %s compute", diskName, instanceID)
		return "", err
	}
	glog.V(2).Infof("Successfully attached %s volume to %s compute", diskName, instanceID)
	return disk.ID, nil
}

// Detaches given cinder volume from the compute running kubelet
func (os *OpenStack) DetachDisk(instanceID string, partialDiskId string) error {
	disk, err := os.getVolume(partialDiskId)
	if err != nil {
		return err
	}
	cClient, err := openstack.NewComputeV2(os.provider, gophercloud.EndpointOpts{
		Region: os.region,
	})
	if err != nil || cClient == nil {
		glog.Errorf("Unable to initialize nova client for region: %s", os.region)
		return err
	}
	if len(disk.Attachments) > 0 && disk.Attachments[0]["server_id"] != nil && instanceID == disk.Attachments[0]["server_id"] {
		// This is a blocking call and effects kubelet's performance directly.
		// We should consider kicking it out into a separate routine, if it is bad.
		err = volumeattach.Delete(cClient, instanceID, disk.ID).ExtractErr()
		if err != nil {
			glog.Errorf("Failed to delete volume %s from compute %s attached %v", disk.ID, instanceID, err)
			return err
		}
		glog.V(2).Infof("Successfully detached volume: %s from compute: %s", disk.ID, instanceID)
	} else {
		errMsg := fmt.Sprintf("Disk: %s has no attachments or is not attached to compute: %s", disk.Name, instanceID)
		glog.Errorf(errMsg)
		return errors.New(errMsg)
	}
	return nil
}

// Takes a partial/full disk id or diskname
func (os *OpenStack) getVolume(diskName string) (volumes.Volume, error) {
	sClient, err := openstack.NewBlockStorageV1(os.provider, gophercloud.EndpointOpts{
		Region: os.region,
	})

	var volume volumes.Volume
	if err != nil || sClient == nil {
		glog.Errorf("Unable to initialize cinder client for region: %s", os.region)
		return volume, err
	}

	err = volumes.List(sClient, nil).EachPage(func(page pagination.Page) (bool, error) {
		vols, err := volumes.ExtractVolumes(page)
		if err != nil {
			glog.Errorf("Failed to extract volumes: %v", err)
			return false, err
		} else {
			for _, v := range vols {
				glog.V(4).Infof("%s %s %v", v.ID, v.Name, v.Attachments)
				if v.Name == diskName || strings.Contains(v.ID, diskName) {
					volume = v
					return true, nil
				}
			}
		}
		// if it reached here then no disk with the given name was found.
		errmsg := fmt.Sprintf("Unable to find disk: %s in region %s", diskName, os.region)
		return false, errors.New(errmsg)
	})
	if err != nil {
		glog.Errorf("Error occurred getting volume: %s", diskName)
		return volume, err
	}
	return volume, err
}

// Create a volume of given size (in GiB)
func (os *OpenStack) CreateVolume(name string, size int, vtype, availability string, tags *map[string]string) (volumeName string, err error) {

	sClient, err := openstack.NewBlockStorageV1(os.provider, gophercloud.EndpointOpts{
		Region: os.region,
	})

	if err != nil || sClient == nil {
		glog.Errorf("Unable to initialize cinder client for region: %s", os.region)
		return "", err
	}

	opts := volumes.CreateOpts{
		Name:         name,
		Size:         size,
		VolumeType:   vtype,
		Availability: availability,
	}
	if tags != nil {
		opts.Metadata = *tags
	}
	vol, err := volumes.Create(sClient, opts).Extract()
	if err != nil {
		glog.Errorf("Failed to create a %d GB volume: %v", size, err)
		return "", err
	}
	glog.Infof("Created volume %v", vol.ID)
	return vol.ID, err
}

// GetDevicePath returns the path of an attached block storage volume, specified by its id.
func (os *OpenStack) GetDevicePath(diskId string) string {
	// Build a list of candidate device paths
	candidateDeviceNodes := []string{
		// KVM
		fmt.Sprintf("virtio-%s", diskId[:20]),
		// ESXi
		fmt.Sprintf("wwn-0x%s", strings.Replace(diskId, "-", "", -1)),
	}

	files, _ := ioutil.ReadDir("/dev/disk/by-id/")

	for _, f := range files {
		for _, c := range candidateDeviceNodes {
			if c == f.Name() {
				glog.V(4).Infof("Found disk attached as %q; full devicepath: %s\n", f.Name(), path.Join("/dev/disk/by-id/", f.Name()))
				return path.Join("/dev/disk/by-id/", f.Name())
			}
		}
	}

	glog.Warningf("Failed to find device for the diskid: %q\n", diskId)
	return ""
}

func (os *OpenStack) DeleteVolume(volumeName string) error {
	used, err := os.diskIsUsed(volumeName)
	if err != nil {
		return err
	}
	if used {
		msg := fmt.Sprintf("Cannot delete the volume %q, it's still attached to a node", volumeName)
		return volume.NewDeletedVolumeInUseError(msg)
	}

	sClient, err := openstack.NewBlockStorageV1(os.provider, gophercloud.EndpointOpts{
		Region: os.region,
	})

	if err != nil || sClient == nil {
		glog.Errorf("Unable to initialize cinder client for region: %s", os.region)
		return err
	}
	err = volumes.Delete(sClient, volumeName).ExtractErr()
	if err != nil {
		glog.Errorf("Cannot delete volume %s: %v", volumeName, err)
	}
	return err
}

// Get device path of attached volume to the compute running kubelet
func (os *OpenStack) GetAttachmentDiskPath(instanceID string, diskName string) (string, error) {
	disk, err := os.getVolume(diskName)
	if err != nil {
		return "", err
	}
	if len(disk.Attachments) > 0 && disk.Attachments[0]["server_id"] != nil {
		if instanceID == disk.Attachments[0]["server_id"] {
			// Attachment[0]["device"] points to the device path
			// see http://developer.openstack.org/api-ref-blockstorage-v1.html
			return disk.Attachments[0]["device"].(string), nil
		} else {
			errMsg := fmt.Sprintf("Disk %q is attached to a different compute: %q, should be detached before proceeding", diskName, disk.Attachments[0]["server_id"])
			glog.Errorf(errMsg)
			return "", errors.New(errMsg)
		}
	}
	return "", fmt.Errorf("volume %s is not attached to %s", diskName, instanceID)
}

// query if a volume is attached to a compute instance
func (os *OpenStack) DiskIsAttached(diskName, instanceID string) (bool, error) {
	disk, err := os.getVolume(diskName)
	if err != nil {
		return false, err
	}
	if len(disk.Attachments) > 0 && disk.Attachments[0]["server_id"] != nil && instanceID == disk.Attachments[0]["server_id"] {
		return true, nil
	}
	return false, nil
}

// query if a list of volumes are attached to a compute instance
func (os *OpenStack) DisksAreAttached(diskNames []string, instanceID string) (map[string]bool, error) {
	attached := make(map[string]bool)
	for _, diskName := range diskNames {
		attached[diskName] = false
	}
	for _, diskName := range diskNames {
		disk, err := os.getVolume(diskName)
		if err != nil {
			continue
		}
		if len(disk.Attachments) > 0 && disk.Attachments[0]["server_id"] != nil && instanceID == disk.Attachments[0]["server_id"] {
			attached[diskName] = true
		}
	}
	return attached, nil
}

// diskIsUsed returns true a disk is attached to any node.
func (os *OpenStack) diskIsUsed(diskName string) (bool, error) {
	disk, err := os.getVolume(diskName)
	if err != nil {
		return false, err
	}
	if len(disk.Attachments) > 0 {
		return true, nil
	}
	return false, nil
}
<|endoftext|>


<commit_before>/*
Copyright 2021 The Vitess 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 main

import (
	"reflect"
	"testing"
)

func Test_groupPRs(t *testing.T) {
	tests := []struct {
		name    string
		prInfos []prInfo
		want    map[string]map[string][]prInfo
	}{
		{name: "Single PR info with no labels", prInfos: []prInfo{{Title: "pr 1", Number: 1}}, want: map[string]map[string][]prInfo{"Other": {"Other": []prInfo{{Title: "pr 1", Number: 1}}}}},
		{name: "Single PR info with type label", prInfos: []prInfo{{Title: "pr 1", Number: 1, Labels: []label{{Name: prefixType + "Bug"}}}}, want: map[string]map[string][]prInfo{"Bug": {"Other": []prInfo{{Title: "pr 1", Number: 1, Labels: []label{{Name: prefixType + "Bug"}}}}}}},
		{name: "Single PR info with type and component labels", prInfos: []prInfo{{Title: "pr 1", Number: 1, Labels: []label{{Name: prefixType + "Bug"}, {Name: prefixComponent + "VTGate"}}}}, want: map[string]map[string][]prInfo{"Bug": {"VTGate": []prInfo{{Title: "pr 1", Number: 1, Labels: []label{{Name: prefixType + "Bug"}, {Name: prefixComponent + "VTGate"}}}}}}},
		{name: "Multiple PR infos with type and component labels", prInfos: []prInfo{
			{Title: "pr 1", Number: 1, Labels: []label{{Name: prefixType + "Bug"}, {Name: prefixComponent + "VTGate"}}},
			{Title: "pr 2", Number: 2, Labels: []label{{Name: prefixType + "Feature"}, {Name: prefixComponent + "VTTablet"}}}},
			want: map[string]map[string][]prInfo{"Bug": {"VTGate": []prInfo{{Title: "pr 1", Number: 1, Labels: []label{{Name: prefixType + "Bug"}, {Name: prefixComponent + "VTGate"}}}}}, "Feature": {"VTTablet": []prInfo{{Title: "pr 2", Number: 2, Labels: []label{{Name: prefixType + "Feature"}, {Name: prefixComponent + "VTTablet"}}}}}}},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := groupPRs(tt.prInfos); !reflect.DeepEqual(got, tt.want) {
				t.Errorf("groupPRs() = %v, want %v", got, tt.want)
			}
		})
	}
}
<commit_msg>fix tests<commit_after>/*
Copyright 2021 The Vitess 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 main

import (
	"testing"

	"vitess.io/vitess/go/test/utils"
)

func Test_groupPRs(t *testing.T) {
	tests := []struct {
		name    string
		prInfos []prInfo
		want    map[string]map[string][]prInfo
	}{
		{
			name:    "Single PR info with no labels",
			prInfos: []prInfo{{Title: "pr 1", Number: 1}},
			want:    map[string]map[string][]prInfo{"Other": {"Other": []prInfo{{Title: "pr 1", Number: 1}}}},
		}, {
			name:    "Single PR info with type label",
			prInfos: []prInfo{{Title: "pr 1", Number: 1, Labels: []label{{Name: prefixType + "Bug"}}}},
			want:    map[string]map[string][]prInfo{"Bug fixes": {"Other": []prInfo{{Title: "pr 1", Number: 1, Labels: []label{{Name: prefixType + "Bug"}}}}}}},
		{
			name:    "Single PR info with type and component labels",
			prInfos: []prInfo{{Title: "pr 1", Number: 1, Labels: []label{{Name: prefixType + "Bug"}, {Name: prefixComponent + "VTGate"}}}},
			want:    map[string]map[string][]prInfo{"Bug fixes": {"VTGate": []prInfo{{Title: "pr 1", Number: 1, Labels: []label{{Name: prefixType + "Bug"}, {Name: prefixComponent + "VTGate"}}}}}}},
		{
			name: "Multiple PR infos with type and component labels", prInfos: []prInfo{
				{Title: "pr 1", Number: 1, Labels: []label{{Name: prefixType + "Bug"}, {Name: prefixComponent + "VTGate"}}},
				{Title: "pr 2", Number: 2, Labels: []label{{Name: prefixType + "Feature"}, {Name: prefixComponent + "VTTablet"}}}},
			want: map[string]map[string][]prInfo{"Bug fixes": {"VTGate": []prInfo{{Title: "pr 1", Number: 1, Labels: []label{{Name: prefixType + "Bug"}, {Name: prefixComponent + "VTGate"}}}}}, "Feature": {"VTTablet": []prInfo{{Title: "pr 2", Number: 2, Labels: []label{{Name: prefixType + "Feature"}, {Name: prefixComponent + "VTTablet"}}}}}}},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got := groupPRs(tt.prInfos)
			utils.MustMatch(t, tt.want, got)
		})
	}
}
<|endoftext|>