<commit_before>/* Copyright 2017 Google Inc.

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 gnmi

import (
	"errors"
	"fmt"
	"time"

	"github.com/google/link022/agent/context"
	"github.com/google/link022/agent/service"
	"github.com/google/link022/agent/syscmd"
	"github.com/google/link022/agent/util/ocutil"
	"github.com/google/link022/generated/ocstruct"
	"github.com/openconfig/ygot/ygot"

	log "github.com/golang/glog"
)

var (
	cmdRunner = syscmd.Runner()
)

// handleSet is the callback function of the GNMI SET call.
// It is triggered by the GNMI server.
func handleSet(updatedConfig ygot.ValidatedGoStruct, existingConfig ygot.ValidatedGoStruct) error {
	// TODO: Handle delta change. Currently the GNMI server only supports replacing root.
	officeAP, ok := updatedConfig.(*ocstruct.Device)
	if !ok {
		return errors.New("new configuration has invalid type")
	}

	configString, err := ygot.EmitJSON(officeAP, &ygot.EmitJSONConfig{
		Format: ygot.RFC7951,
		Indent: "  ",
		RFC7951Config: &ygot.RFC7951JSONConfig{
			AppendModuleName: false,
		},
	})
	if err != nil {
		return err
	}
	log.Infof("Received a new configuration:\n%v\n", configString)

	// TODO: Validate the OpenConfig module.
	deviceConfig := context.GetDeviceConfig()

	// Check and clean up the existing configuration.
	var changedVLANIDs []int
	existingVLANIDs, err := cmdRunner.VLANOnIntf(deviceConfig.ETHINTFName)
	if err != nil {
		return fmt.Errorf("unable to fetch the existing VLAN with error (%v), may need to reboot the device.", err)
	}

	resetIntf := false
	newVLANIDs := ocutil.VLANIDs(officeAP)
	if ocutil.VLANChanged(existingVLANIDs, newVLANIDs) {
		log.Infof("VLAN changes (%v -> %v) on interface %s.", existingVLANIDs, newVLANIDs, deviceConfig.ETHINTFName)
		changedVLANIDs = existingVLANIDs
		resetIntf = true
	} else {
		log.Infof("No VLAN change on interface %s.", deviceConfig.ETHINTFName)
	}

	// Clean up the existing configuration.
	service.CleanupConfig(deviceConfig.ETHINTFName, changedVLANIDs)

	// Wait for link to be available again.
	time.Sleep(5 * time.Second)

	// Process the incoming configuration.
	if err = service.ApplyConfig(officeAP, resetIntf, deviceConfig.ETHINTFName,
		deviceConfig.WLANINTFName); err != nil {
		return err
	}
	log.Info("Device configuration succeeded.")

	// Save the succeeded config file.
	if err := syscmd.SaveToFile(runFolder, apConfigFileName, configString); err != nil {
		return err
	}
	log.Info("Saved the configuration to file.")
	return nil
}
<commit_msg>Fix the build error due to the gnxi lib interface change.<commit_after>/* Copyright 2017 Google Inc.

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 gnmi

import (
	"errors"
	"fmt"
	"time"

	"github.com/google/link022/agent/context"
	"github.com/google/link022/agent/service"
	"github.com/google/link022/agent/syscmd"
	"github.com/google/link022/agent/util/ocutil"
	"github.com/google/link022/generated/ocstruct"
	"github.com/openconfig/ygot/ygot"

	log "github.com/golang/glog"
)

var (
	cmdRunner = syscmd.Runner()
)

// handleSet is the callback function of the GNMI SET call.
// It is triggered by the GNMI server.
func handleSet(updatedConfig ygot.ValidatedGoStruct) error {
	// TODO: Handle delta change. Currently the GNMI server only supports replacing root.
	officeAP, ok := updatedConfig.(*ocstruct.Device)
	if !ok {
		return errors.New("new configuration has invalid type")
	}

	configString, err := ygot.EmitJSON(officeAP, &ygot.EmitJSONConfig{
		Format: ygot.RFC7951,
		Indent: "  ",
		RFC7951Config: &ygot.RFC7951JSONConfig{
			AppendModuleName: false,
		},
	})
	if err != nil {
		return err
	}
	log.Infof("Received a new configuration:\n%v\n", configString)

	// TODO: Validate the OpenConfig module.
	deviceConfig := context.GetDeviceConfig()

	// Check and clean up the existing configuration.
	var changedVLANIDs []int
	existingVLANIDs, err := cmdRunner.VLANOnIntf(deviceConfig.ETHINTFName)
	if err != nil {
		return fmt.Errorf("unable to fetch the existing VLAN with error (%v), may need to reboot the device.", err)
	}

	resetIntf := false
	newVLANIDs := ocutil.VLANIDs(officeAP)
	if ocutil.VLANChanged(existingVLANIDs, newVLANIDs) {
		log.Infof("VLAN changes (%v -> %v) on interface %s.", existingVLANIDs, newVLANIDs, deviceConfig.ETHINTFName)
		changedVLANIDs = existingVLANIDs
		resetIntf = true
	} else {
		log.Infof("No VLAN change on interface %s.", deviceConfig.ETHINTFName)
	}

	// Clean up the existing configuration.
	service.CleanupConfig(deviceConfig.ETHINTFName, changedVLANIDs)

	// Wait for link to be available again.
	time.Sleep(5 * time.Second)

	// Process the incoming configuration.
	if err = service.ApplyConfig(officeAP, resetIntf, deviceConfig.ETHINTFName,
		deviceConfig.WLANINTFName); err != nil {
		return err
	}
	log.Info("Device configuration succeeded.")

	// Save the succeeded config file.
	if err := syscmd.SaveToFile(runFolder, apConfigFileName, configString); err != nil {
		return err
	}
	log.Info("Saved the configuration to file.")
	return nil
}
<|endoftext|>


<commit_before>// Package aphjsapi provides additional interfaces, wrapper and helper functions for original
// jsapi package("github.com/manyminds/api2go/jsapi")
package aphjsonapi

import (
	"fmt"
	"math"
	"reflect"
	"strings"

	"github.com/dictyBase/go-middlewares/middlewares/pagination"
	jsapi "github.com/manyminds/api2go/jsonapi"
)

// RelationshipLink is a container type for having information about
// relationship links
type RelationShipLink struct {
	Name string `validate:"required"`
	// To override the default links, it will be appended to
	// the base url.
	SuffixFragment string
	// The type(type key in JSAONAPI specs) of relationship resource
	Type string `validate:"required"`
}

// MarshalSelfRelations is an interface  for creating self relationship links
type MarshalSelfRelations interface {
	// Validates all instances of RelationshipLink structures, using
	// https://gopkg.in/go-playground/validator.v9 package is recommended
	ValidateSelfLinks() error
	GetSelfLinksInfo() []RelationShipLink
}

// MarshalRelatedRelations is an interface  for creating related relationship
// links
type MarshalRelatedRelations interface {
	// Validates all instances of RelationshipLink structures, using
	// https://gopkg.in/go-playground/validator.v9 package is recommended
	ValidateRelatedLinks() error
	GetRelatedLinksInfo() []RelationShipLink
}

// AttributeToDbRowMapper is an interface to provide mapping between jsapi
// attribute and database row names. This is useful for implementing filter
// query parameter
type AttributeToDbRowMapper interface {
	GetMap() map[string]string
}

// RelationshipAttributes is an interface to provide attribute fields of
// relationship resources. This is mandatory for supporting sparse fieldset
// query parameter.
type RelationshipAttribute interface {
	GetAttributeFields(string) []string
}

// MarshalWithPagination adds pagination information for collection resource
func MarshalWithPagination(data interface{}, ep jsapi.ServerInformation, opt *pagination.Props) (*jsapi.Document, error) {
	var jst *jsapi.Document
	if reflect.TypeOf(data).Kind() != reflect.Slice {
		return jst, fmt.Errorf("%s\n", "Only slice type is allowed for pagination")
	}
	jst, err := MarshalToStructWrapper(data, ep)
	if err != nil {
		return jst, err
	}
	baseLink := jst.Links.Self
	pageLink := &jsapi.Links{}
	pageLink.Self = generatePaginatedResourceLink(baseLink, opt.Current, opt.Entries)
	pageLink.First = generatePaginatedResourceLink(baseLink, 1, opt.Entries)
	if opt.Current != 1 {
		pageLink.Previous = generatePaginatedResourceLink(baseLink, opt.Current-1, opt.Entries)
	}
	lastPage := int(math.Floor(float64(opt.Records) / float64(opt.Entries)))
	pageLink.Last = generatePaginatedResourceLink(baseLink, lastPage, opt.Entries)
	if opt.Current != lastPage {
		pageLink.Next = generatePaginatedResourceLink(baseLink, opt.Current+1, opt.Entries)
	}
	jst.Links = pageLink
	jst.Meta = map[string]interface{}{
		"pagination": map[string]int{
			"records": opt.Records,
			"total":   lastPage,
			"size":    opt.Entries,
			"number":  opt.Current,
		},
	}
	return jst, nil
}

// MarshalToStructWrapper adds relationship information and returns a
// jsapi.Document structure for further json encoding
func MarshalToStructWrapper(data interface{}, ep jsapi.ServerInformation) (*jsapi.Document, error) {
	jst, err := jsapi.MarshalToStruct(data, ep)
	if err != nil {
		return jst, err
	}
	if len(jst.Data.DataArray) > 0 { //array resource objects
		// picking first element both from the generated and given typed structures
		elem := jst.Data.DataArray[0]
		value := reflect.ValueOf(data).Index(0).Interface()
		// link for the array resource itself
		jst.Links = &jsapi.Links{Self: generateMultiResourceLink(&elem, ep)}
		for i, d := range jst.Data.DataArray {
			// link for individual resource
			jst.Data.DataArray[i].Links = &jsapi.Links{Self: generateSingleResourceLink(&d, ep)}
			// Add relationships to every member
			r := generateRelationshipLinks(value, &d, ep)
			jst.Data.DataArray[i].Relationships = r
		}
	} else {
		jst.Links = &jsapi.Links{Self: generateSingleResourceLink(jst.Data.DataObject, ep)}
		relationships := generateRelationshipLinks(data, jst.Data.DataObject, ep)
		if len(relationships) > 0 {
			jst.Data.DataObject.Relationships = relationships
		}
	}
	return jst, nil
}

func generateBaseLink(ep jsapi.ServerInformation) string {
	return fmt.Sprintf(
		"%s/%s",
		strings.Trim(ep.GetBaseURL(), "/"),
		strings.Trim(ep.GetPrefix(), "/"),
	)
}

func generatePaginatedResourceLink(baseurl string, pagenum, pagesize int) string {
	return fmt.Sprintf(
		"%s?page[number]=%d&page[size]=%d",
		baseurl,
		pagenum,
		pagesize,
	)
}

func generateSingleResourceLink(jdata *jsapi.Data, ep jsapi.ServerInformation) string {
	return fmt.Sprintf(
		"%s/%s/%s",
		generateBaseLink(ep),
		jdata.Type,
		jdata.ID,
	)
}

func generateMultiResourceLink(jdata *jsapi.Data, ep jsapi.ServerInformation) string {
	return fmt.Sprintf(
		"%s/%s",
		generateBaseLink(ep),
		jdata.Type,
	)
}

func generateRelationshipLinks(data interface{}, jdata *jsapi.Data, ep jsapi.ServerInformation) map[string]jsapi.Relationship {
	relationships := make(map[string]jsapi.Relationship)
	baselink := generateBaseLink(ep)
	self, ok := data.(MarshalSelfRelations)
	if ok {
		for _, rel := range self.GetSelfLinksInfo() {
			links := &jsapi.Links{}
			if len(rel.SuffixFragment) > 0 {
				links.Self = fmt.Sprintf("%s/%s", baselink, strings.Trim(rel.SuffixFragment, "/"))
			} else {
				links.Self = fmt.Sprintf("%s/%s/%s/relationships/%s",
					baselink,
					jdata.Type,
					jdata.ID,
					rel.Name,
				)
			}
			relationships[rel.Name] = jsapi.Relationship{Links: links}
		}
	}
	related, ok := data.(MarshalRelatedRelations)
	if ok {
		for _, rel := range related.GetRelatedLinksInfo() {
			var rlink string
			if len(rel.SuffixFragment) > 0 {
				rlink = fmt.Sprintf("%s/%s", baselink, strings.Trim(rel.SuffixFragment, "/"))
			} else {
				rlink = fmt.Sprintf("%s/%s/%s/%s",
					baselink,
					jdata.Type,
					jdata.ID, rel.Name,
				)
			}
			if _, ok := relationships[rel.Name]; ok {
				relationships[rel.Name].Links.Related = rlink
			} else {
				relationships[rel.Name] = jsapi.Relationship{Links: &jsapi.Links{Related: rlink}}
			}
		}
	}
	return relationships
}

// MapFieldsToDbRow maps jsapi attributes to database row names
func MapFieldsToDbRow(data interface{}) map[string]string {
	m, ok := data.(AttributeToDbRowMapper)
	if ok {
		return m.GetMap()
	}
	frow := make(map[string]string)
	t := reflect.TypeOf(data)
	for i := 0; i < t.NumField(); i++ {
		tag := t.Field(i).Tag
		v, ok := tag.Lookup("json")
		if ok && v != "-" {
			r, dbok := tag.Lookup("db")
			if dbok && r != "-" {
				frow[v] = r
			}
		}
	}
	return frow
}

// GetTypeName gets the type name(type field) from a jsapi implementing
// interface. It is recommended to implement jsapi.EntityNamer interface to
// reduce the use of reflection
func GetTypeName(data interface{}) string {
	entity, ok := data.(jsapi.EntityNamer)
	if ok {
		return entity.GetName()
	}
	rType := reflect.TypeOf(data)
	if rType.Kind() == reflect.Ptr {
		return jsapi.Pluralize(jsapi.Jsonify(rType.Elem().Name()))
	}
	return jsapi.Pluralize(jsapi.Jsonify(rType.Name()))
}

// AttributeNames returns all JSAONAPI attribute names of data interface
func GetAttributeFields(data interface{}) []string {
	var attr []string
	t := reflect.TypeOf(data)
	for i := 0; i < t.NumField(); i++ {
		v, ok := t.Field(i).Tag.Lookup("json")
		if ok && v != "-" {
			attr = append(attr, v)
		}
	}
	return attr
}

// GetAllRelationships returns all relationships of data interface
func GetAllRelationships(data interface{}) []RelationShipLink {
	var r []RelationShipLink
	self, ok := data.(MarshalSelfRelations)
	if ok {
		r = append(r, self.GetSelfLinksInfo()...)
	}
	related, ok := data.(MarshalRelatedRelations)
	if ok {
		r = append(r, related.GetRelatedLinksInfo()...)
	}
	return r
}

//GetRelatedTypes returns a map jsapi types of the related resources using
//reflection
func getRelatedTypeNames(data interface{}) []string {
	var names []string
	mtype := reflect.TypeOf((*jsapi.MarshalIdentifier)(nil)).Elem()
	t := reflect.TypeOf(data)
	for i := 0; i < t.NumField(); i++ {
		ftype := t.Field(i).Type
		if ftype.Kind() == reflect.Slice {
			if ftype.Elem().Implements(mtype) {
				names = append(
					names,
					jsapi.Pluralize(
						jsapi.Jsonify(
							ftype.Elem().Name(),
						),
					),
				)
				continue
			}
		}
		if ftype.Implements(mtype) {
			names = append(
				names,
				jsapi.Pluralize(
					jsapi.Jsonify(
						ftype.Name(),
					),
				),
			)
		}
	}
	return names
}
<commit_msg>added check for pointer and non-pointer interfaces<commit_after>// Package aphjsapi provides additional interfaces, wrapper and helper functions for original
// jsapi package("github.com/manyminds/api2go/jsapi")
package aphjsonapi

import (
	"fmt"
	"math"
	"reflect"
	"strings"

	"github.com/dictyBase/go-middlewares/middlewares/pagination"
	jsapi "github.com/manyminds/api2go/jsonapi"
)

// RelationshipLink is a container type for having information about
// relationship links
type RelationShipLink struct {
	Name string `validate:"required"`
	// To override the default links, it will be appended to
	// the base url.
	SuffixFragment string
	// The type(type key in JSAONAPI specs) of relationship resource
	Type string `validate:"required"`
}

// MarshalSelfRelations is an interface  for creating self relationship links
type MarshalSelfRelations interface {
	// Validates all instances of RelationshipLink structures, using
	// https://gopkg.in/go-playground/validator.v9 package is recommended
	ValidateSelfLinks() error
	GetSelfLinksInfo() []RelationShipLink
}

// MarshalRelatedRelations is an interface  for creating related relationship
// links
type MarshalRelatedRelations interface {
	// Validates all instances of RelationshipLink structures, using
	// https://gopkg.in/go-playground/validator.v9 package is recommended
	ValidateRelatedLinks() error
	GetRelatedLinksInfo() []RelationShipLink
}

// AttributeToDbRowMapper is an interface to provide mapping between jsapi
// attribute and database row names. This is useful for implementing filter
// query parameter
type AttributeToDbRowMapper interface {
	GetMap() map[string]string
}

// RelationshipAttributes is an interface to provide attribute fields of
// relationship resources. This is mandatory for supporting sparse fieldset
// query parameter.
type RelationshipAttribute interface {
	GetAttributeFields(string) []string
}

// MarshalWithPagination adds pagination information for collection resource
func MarshalWithPagination(data interface{}, ep jsapi.ServerInformation, opt *pagination.Props) (*jsapi.Document, error) {
	var jst *jsapi.Document
	if reflect.TypeOf(data).Kind() != reflect.Slice {
		return jst, fmt.Errorf("%s\n", "Only slice type is allowed for pagination")
	}
	jst, err := MarshalToStructWrapper(data, ep)
	if err != nil {
		return jst, err
	}
	baseLink := jst.Links.Self
	pageLink := &jsapi.Links{}
	pageLink.Self = generatePaginatedResourceLink(baseLink, opt.Current, opt.Entries)
	pageLink.First = generatePaginatedResourceLink(baseLink, 1, opt.Entries)
	if opt.Current != 1 {
		pageLink.Previous = generatePaginatedResourceLink(baseLink, opt.Current-1, opt.Entries)
	}
	lastPage := int(math.Floor(float64(opt.Records) / float64(opt.Entries)))
	pageLink.Last = generatePaginatedResourceLink(baseLink, lastPage, opt.Entries)
	if opt.Current != lastPage {
		pageLink.Next = generatePaginatedResourceLink(baseLink, opt.Current+1, opt.Entries)
	}
	jst.Links = pageLink
	jst.Meta = map[string]interface{}{
		"pagination": map[string]int{
			"records": opt.Records,
			"total":   lastPage,
			"size":    opt.Entries,
			"number":  opt.Current,
		},
	}
	return jst, nil
}

// MarshalToStructWrapper adds relationship information and returns a
// jsapi.Document structure for further json encoding
func MarshalToStructWrapper(data interface{}, ep jsapi.ServerInformation) (*jsapi.Document, error) {
	jst, err := jsapi.MarshalToStruct(data, ep)
	if err != nil {
		return jst, err
	}
	if len(jst.Data.DataArray) > 0 { //array resource objects
		// picking first element both from the generated and given typed structures
		elem := jst.Data.DataArray[0]
		value := reflect.ValueOf(data).Index(0).Interface()
		// link for the array resource itself
		jst.Links = &jsapi.Links{Self: generateMultiResourceLink(&elem, ep)}
		for i, d := range jst.Data.DataArray {
			// link for individual resource
			jst.Data.DataArray[i].Links = &jsapi.Links{Self: generateSingleResourceLink(&d, ep)}
			// Add relationships to every member
			r := generateRelationshipLinks(value, &d, ep)
			jst.Data.DataArray[i].Relationships = r
		}
	} else {
		jst.Links = &jsapi.Links{Self: generateSingleResourceLink(jst.Data.DataObject, ep)}
		relationships := generateRelationshipLinks(data, jst.Data.DataObject, ep)
		if len(relationships) > 0 {
			jst.Data.DataObject.Relationships = relationships
		}
	}
	return jst, nil
}

func generateBaseLink(ep jsapi.ServerInformation) string {
	return fmt.Sprintf(
		"%s/%s",
		strings.Trim(ep.GetBaseURL(), "/"),
		strings.Trim(ep.GetPrefix(), "/"),
	)
}

func generatePaginatedResourceLink(baseurl string, pagenum, pagesize int) string {
	return fmt.Sprintf(
		"%s?page[number]=%d&page[size]=%d",
		baseurl,
		pagenum,
		pagesize,
	)
}

func generateSingleResourceLink(jdata *jsapi.Data, ep jsapi.ServerInformation) string {
	return fmt.Sprintf(
		"%s/%s/%s",
		generateBaseLink(ep),
		jdata.Type,
		jdata.ID,
	)
}

func generateMultiResourceLink(jdata *jsapi.Data, ep jsapi.ServerInformation) string {
	return fmt.Sprintf(
		"%s/%s",
		generateBaseLink(ep),
		jdata.Type,
	)
}

func generateRelationshipLinks(data interface{}, jdata *jsapi.Data, ep jsapi.ServerInformation) map[string]jsapi.Relationship {
	relationships := make(map[string]jsapi.Relationship)
	baselink := generateBaseLink(ep)
	self, ok := data.(MarshalSelfRelations)
	if ok {
		for _, rel := range self.GetSelfLinksInfo() {
			links := &jsapi.Links{}
			if len(rel.SuffixFragment) > 0 {
				links.Self = fmt.Sprintf("%s/%s", baselink, strings.Trim(rel.SuffixFragment, "/"))
			} else {
				links.Self = fmt.Sprintf("%s/%s/%s/relationships/%s",
					baselink,
					jdata.Type,
					jdata.ID,
					rel.Name,
				)
			}
			relationships[rel.Name] = jsapi.Relationship{Links: links}
		}
	}
	related, ok := data.(MarshalRelatedRelations)
	if ok {
		for _, rel := range related.GetRelatedLinksInfo() {
			var rlink string
			if len(rel.SuffixFragment) > 0 {
				rlink = fmt.Sprintf("%s/%s", baselink, strings.Trim(rel.SuffixFragment, "/"))
			} else {
				rlink = fmt.Sprintf("%s/%s/%s/%s",
					baselink,
					jdata.Type,
					jdata.ID, rel.Name,
				)
			}
			if _, ok := relationships[rel.Name]; ok {
				relationships[rel.Name].Links.Related = rlink
			} else {
				relationships[rel.Name] = jsapi.Relationship{Links: &jsapi.Links{Related: rlink}}
			}
		}
	}
	return relationships
}

// MapFieldsToDbRow maps jsapi attributes to database row names
func MapFieldsToDbRow(data interface{}) map[string]string {
	m, ok := data.(AttributeToDbRowMapper)
	if ok {
		return m.GetMap()
	}
	frow := make(map[string]string)
	t := reflect.TypeOf(data)
	for i := 0; i < t.NumField(); i++ {
		tag := t.Field(i).Tag
		v, ok := tag.Lookup("json")
		if ok && v != "-" {
			r, dbok := tag.Lookup("db")
			if dbok && r != "-" {
				frow[v] = r
			}
		}
	}
	return frow
}

// GetTypeName gets the type name(type field) from a jsapi implementing
// interface. It is recommended to implement jsapi.EntityNamer interface to
// reduce the use of reflection
func GetTypeName(data interface{}) string {
	entity, ok := data.(jsapi.EntityNamer)
	if ok {
		return entity.GetName()
	}
	rType := reflect.TypeOf(data)
	if rType.Kind() == reflect.Ptr {
		return jsapi.Pluralize(jsapi.Jsonify(rType.Elem().Name()))
	}
	return jsapi.Pluralize(jsapi.Jsonify(rType.Name()))
}

// AttributeNames returns all JSAONAPI attribute names of data interface
func GetAttributeFields(data interface{}) ([]string, error) {
	var attr []string
	t := reflect.TypeOf(data)
	if t == nil {
		return attr, fmt.Errorf("received an nil interface")
	}
	var st reflect.Type
	if t.Kind() == reflect.Ptr {
		st = t.Elem()
	} else {
		st = t
	}
	for i := 0; i < st.NumField(); i++ {
		v, ok := st.Field(i).Tag.Lookup("json")
		if ok && v != "-" {
			attr = append(attr, v)
		}
	}
	return attr, nil
}

// GetAllRelationships returns all relationships of data interface
func GetAllRelationships(data interface{}) []RelationShipLink {
	var r []RelationShipLink
	self, ok := data.(MarshalSelfRelations)
	if ok {
		r = append(r, self.GetSelfLinksInfo()...)
	}
	related, ok := data.(MarshalRelatedRelations)
	if ok {
		r = append(r, related.GetRelatedLinksInfo()...)
	}
	return r
}

//GetRelatedTypes returns a map jsapi types of the related resources using
//reflection
func getRelatedTypeNames(data interface{}) []string {
	var names []string
	mtype := reflect.TypeOf((*jsapi.MarshalIdentifier)(nil)).Elem()
	t := reflect.TypeOf(data)
	for i := 0; i < t.NumField(); i++ {
		ftype := t.Field(i).Type
		if ftype.Kind() == reflect.Slice {
			if ftype.Elem().Implements(mtype) {
				names = append(
					names,
					jsapi.Pluralize(
						jsapi.Jsonify(
							ftype.Elem().Name(),
						),
					),
				)
				continue
			}
		}
		if ftype.Implements(mtype) {
			names = append(
				names,
				jsapi.Pluralize(
					jsapi.Jsonify(
						ftype.Name(),
					),
				),
			)
		}
	}
	return names
}
<|endoftext|>


<commit_before>// Copyright 2015, David Howden
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package httpauth provides a wrapper for http.Handler implementing basic HTTP authentication.
package httpauth

import "net/http"

// Checker defines the Check method which provides username-password checking.
type Checker interface {
	// Check returns true if and only if the username-password pair is valid.
	Check(username, password string) bool
}

// Creds implements Checker and is a basic mapping of usernames and passwords.
type Creds map[string]string

// Check implements Checker.
func (c Creds) Check(username, password string) bool {
	if c == nil {
		return false
	}
	if p, ok := c[username]; ok && p == password {
		return true
	}
	return false
}

// None is an implementation of Checker in which Check always returns true.
type None struct{}

// Check implements Checker.
func (n None) Check(username, password string) bool { return true }

// HandlerFunc returns an http.HandlerFunc which checks basic HTTP authentication header
// values using Checker and passes requests to the given http.HandlerFunc when Check returns
// true (responds with http.StatusUnauthorized if the call to Check returns false).
func HandlerFunc(c Checker, f http.HandlerFunc) http.HandlerFunc {
	h := NewHandler(c, f)
	return http.HandlerFunc(h.ServeHTTP)
}

type handler struct {
	http.Handler
	c Checker
}

// NewHandler returns an http.Handler which checks basic HTTP authentication header values
// using the Checker and passes requests to the given http.Handler when Check returns true
// (responds with http.StatusUnauthorized if the call to Check returns false).
func NewHandler(c Checker, h http.Handler) http.Handler {
	return &handler{
		Handler: h,
		c:       c,
	}
}

// ServeHTTP implements http.Handler.
func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	username, password, _ := r.BasicAuth()
	if !h.c.Check(username, password) {
		w.Header().Add("WWW-Authenticate", "Basic")
		w.WriteHeader(http.StatusUnauthorized)
		w.Write([]byte(http.StatusText(http.StatusUnauthorized)))
		return
	}
	h.Handler.ServeHTTP(w, r)
}

// Handle is a convenience function which calls http.Handle with the pattern and wrapped
// http.Handler (see NewHandler).
func Handle(c Checker, pattern string, h http.Handler) {
	http.Handle(pattern, NewHandler(c, h))
}

// HandleFunc is a convenience function which calls http.HandleFunc with the pattern and
// wrapped http.HandlerFunc (see HandlerFunc).
func HandleFunc(c Checker, pattern string, h http.HandlerFunc) {
	http.HandleFunc(pattern, HandlerFunc(c, h))
}

// ServeMux is a convenience type which wraps Handle and HandleFunc calls on an http.ServeMux
// for the same Checker.
type ServeMux struct {
	Checker
	*http.ServeMux
}

// NewServeMux creates a new http.ServeMux which wraps calls to Handle and Handler for the
// same Checker.
func NewServeMux(c Checker, m *http.ServeMux) ServeMux {
	return ServeMux{c, m}
}

func (m ServeMux) Handle(pattern string, h http.Handler) {
	m.ServeMux.Handle(pattern, NewHandler(m.Checker, h))
}

func (m ServeMux) HandleFunc(pattern string, h http.HandlerFunc) {
	m.ServeMux.Handle(pattern, HandlerFunc(m.Checker, h))
}
<commit_msg>update Creds to obscure user/pass map<commit_after>// Copyright 2015, David Howden
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package httpauth provides a wrapper for http.Handler implementing basic HTTP authentication.
package httpauth

import "net/http"

// Checker defines the Check method which provides username-password checking.
type Checker interface {
	// Check returns true if and only if the username-password pair is valid.
	Check(username, password string) bool
}

// Creds creates a Checker which uses the map of user-password pairs.
func Creds(m map[string]string) Checker {
	return creds{
		m: m,
	}
}

type creds struct {
	m map[string]string
}

// Check implements Checker.
func (c creds) Check(username, password string) bool {
	p, ok := c.m[username]
	return ok && p == password
}

// None is an implementation of Checker in which Check always returns true.
type None struct{}

// Check implements Checker.
func (n None) Check(username, password string) bool { return true }

// HandlerFunc returns an http.HandlerFunc which checks basic HTTP authentication header
// values using Checker and passes requests to the given http.HandlerFunc when Check returns
// true (responds with http.StatusUnauthorized if the call to Check returns false).
func HandlerFunc(c Checker, f http.HandlerFunc) http.HandlerFunc {
	h := NewHandler(c, f)
	return http.HandlerFunc(h.ServeHTTP)
}

type handler struct {
	http.Handler
	c Checker
}

// NewHandler returns an http.Handler which checks basic HTTP authentication header values
// using the Checker and passes requests to the given http.Handler when Check returns true
// (responds with http.StatusUnauthorized if the call to Check returns false).
func NewHandler(c Checker, h http.Handler) http.Handler {
	return &handler{
		Handler: h,
		c:       c,
	}
}

// ServeHTTP implements http.Handler.
func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	username, password, _ := r.BasicAuth()
	if !h.c.Check(username, password) {
		w.Header().Add("WWW-Authenticate", "Basic")
		w.WriteHeader(http.StatusUnauthorized)
		w.Write([]byte(http.StatusText(http.StatusUnauthorized)))
		return
	}
	h.Handler.ServeHTTP(w, r)
}

// Handle is a convenience function which calls http.Handle with the pattern and wrapped
// http.Handler (see NewHandler).
func Handle(c Checker, pattern string, h http.Handler) {
	http.Handle(pattern, NewHandler(c, h))
}

// HandleFunc is a convenience function which calls http.HandleFunc with the pattern and
// wrapped http.HandlerFunc (see HandlerFunc).
func HandleFunc(c Checker, pattern string, h http.HandlerFunc) {
	http.HandleFunc(pattern, HandlerFunc(c, h))
}

// ServeMux is a convenience type which wraps Handle and HandleFunc calls on an http.ServeMux
// for the same Checker.
type ServeMux struct {
	Checker
	*http.ServeMux
}

// NewServeMux creates a new http.ServeMux which wraps calls to Handle and Handler for the
// same Checker.
func NewServeMux(c Checker, m *http.ServeMux) ServeMux {
	return ServeMux{c, m}
}

func (m ServeMux) Handle(pattern string, h http.Handler) {
	m.ServeMux.Handle(pattern, NewHandler(m.Checker, h))
}

func (m ServeMux) HandleFunc(pattern string, h http.HandlerFunc) {
	m.ServeMux.Handle(pattern, HandlerFunc(m.Checker, h))
}
<|endoftext|>


<commit_before>package main

import (
    "fmt"
    "log"
    "net"
    "path/filepath"

    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"

    flag "github.com/ogier/pflag"
    "github.com/jaypipes/gsr"

    pb "github.com/jaypipes/procession/proto"

    "github.com/jaypipes/procession/pkg/cfg"
    "github.com/jaypipes/procession/pkg/context"
    "github.com/jaypipes/procession/pkg/env"

    "github.com/jaypipes/procession/pkg/iam/db"
    "github.com/jaypipes/procession/pkg/iam/rpc"
)

const (
    cfgPath = "/etc/procession/iam"
    defaultUseTls = false
    defaultPort = 10000
)

var (
    registry *gsr.Registry
    defaultCertPath = filepath.Join(cfgPath, "server.pem")
    defaultKeyPath = filepath.Join(cfgPath, "server.key")
    optUseTls = flag.Bool(
        "tls",
        env.EnvOrDefaultBool(
            "PROCESSION_USE_TLS", defaultUseTls,
        ),
        "Connection uses TLS if true, else plain TCP",
    )
    optCertPath = flag.String(
        "cert-path",
        env.EnvOrDefaultStr(
            "PROCESSION_CERT_PATH", defaultCertPath,
        ),
        "Path to the TLS cert file",
    )
    optKeyPath = flag.String(
        "key-path",
        env.EnvOrDefaultStr(
            "PROCESSION_KEY_PATH", defaultKeyPath,
        ),
        "Path to the TLS key file",
    )
    optPort = flag.Int(
        "port",
        env.EnvOrDefaultInt(
            "PROCESSION_PORT", defaultPort,
        ),
        "The server port",
    )
)

func main() {
    var err error
    var opts []grpc.ServerOption
    srv := rpc.Server{}

    registry, err = gsr.New()
    if err != nil {
        log.Fatalf("failed to create gsr.Registry object: %v", err)
    }
    info("connected to gsr service registry.")

    ctx := context.New()

    db, err := db.New(ctx)
    if err != nil {
        log.Fatalf("failed to ping iam database: %v", err)
    }
    ctx.Db = db
    defer ctx.Close()
    info("connected to DB.")

    srv.Ctx = ctx

    cfg.ParseCliOpts()
    if *optUseTls {
        creds, err := credentials.NewServerTLSFromFile(
            *optCertPath,
            *optKeyPath,
        )
        if  err != nil {
            log.Fatalf("failed to generate credentials: %v", err)
        }
        opts = []grpc.ServerOption{grpc.Creds(creds)}
        debug("using credentials file %v", *optKeyPath)
    }
    lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *optPort))
    if err != nil {
        log.Fatalf("failed to listen: %v", err)
    }
    info("listening on TCP port %v", *optPort)
    grpcServer := grpc.NewServer(opts...)
    pb.RegisterIAMServer(grpcServer, &srv)
    grpcServer.Serve(lis)
}

func debug(message string, args ...interface{}) {
    if cfg.LogLevel() > 1 {
        log.Printf("[iam] debug: " + message, args...)
    }
}

func info(message string, args ...interface{}) {
    if cfg.LogLevel() > 0 {
        log.Printf("[iam] " + message, args...)
    }
}
<commit_msg>logging: use Context logging in iam/main.go<commit_after>package main

import (
    "fmt"
    "log"
    "net"
    "path/filepath"

    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"

    flag "github.com/ogier/pflag"
    "github.com/jaypipes/gsr"

    pb "github.com/jaypipes/procession/proto"

    "github.com/jaypipes/procession/pkg/cfg"
    "github.com/jaypipes/procession/pkg/context"
    "github.com/jaypipes/procession/pkg/env"

    "github.com/jaypipes/procession/pkg/iam/db"
    "github.com/jaypipes/procession/pkg/iam/rpc"
)

const (
    cfgPath = "/etc/procession/iam"
    defaultUseTls = false
    defaultPort = 10000
)

var (
    registry *gsr.Registry
    defaultCertPath = filepath.Join(cfgPath, "server.pem")
    defaultKeyPath = filepath.Join(cfgPath, "server.key")
    optUseTls = flag.Bool(
        "tls",
        env.EnvOrDefaultBool(
            "PROCESSION_USE_TLS", defaultUseTls,
        ),
        "Connection uses TLS if true, else plain TCP",
    )
    optCertPath = flag.String(
        "cert-path",
        env.EnvOrDefaultStr(
            "PROCESSION_CERT_PATH", defaultCertPath,
        ),
        "Path to the TLS cert file",
    )
    optKeyPath = flag.String(
        "key-path",
        env.EnvOrDefaultStr(
            "PROCESSION_KEY_PATH", defaultKeyPath,
        ),
        "Path to the TLS key file",
    )
    optPort = flag.Int(
        "port",
        env.EnvOrDefaultInt(
            "PROCESSION_PORT", defaultPort,
        ),
        "The server port",
    )
)

func main() {
    var err error

    ctx := context.New()
    reset := ctx.LogSection("iam")
    defer reset()

    var opts []grpc.ServerOption
    srv := rpc.Server{}

    registry, err = gsr.New()
    if err != nil {
        log.Fatalf("failed to create gsr.Registry object: %v", err)
    }
    ctx.L2("connected to gsr service registry.")

    db, err := db.New(ctx)
    if err != nil {
        log.Fatalf("failed to ping iam database: %v", err)
    }
    ctx.Db = db
    defer ctx.Close()
    ctx.L2("connected to DB.")

    srv.Ctx = ctx

    cfg.ParseCliOpts()
    if *optUseTls {
        creds, err := credentials.NewServerTLSFromFile(
            *optCertPath,
            *optKeyPath,
        )
        if  err != nil {
            log.Fatalf("failed to generate credentials: %v", err)
        }
        opts = []grpc.ServerOption{grpc.Creds(creds)}
        ctx.L2("using credentials file %v", *optKeyPath)
    }
    lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *optPort))
    if err != nil {
        log.Fatalf("failed to listen: %v", err)
    }
    ctx.L2("listening on TCP port %v", *optPort)
    grpcServer := grpc.NewServer(opts...)
    pb.RegisterIAMServer(grpcServer, &srv)
    grpcServer.Serve(lis)
}
<|endoftext|>


<commit_before>package main

import (
    "fmt"
    "io"
    "log"
    "net"
    "net/http"
    "regexp"
)

func isCli(userAgent string) bool {
    match, _ := regexp.MatchString("^(?i)(curl|wget|fetch\\slibfetch)\\/.*$",
        userAgent)
    return match
}

func handler(w http.ResponseWriter, req *http.Request) {
    if req.Method != "GET" {
        http.Error(w, "Invalid request method", 405)
        return
    }

    host, _, err := net.SplitHostPort(req.RemoteAddr)
    if err != nil {
        log.Printf("Failed to parse remote address: %s\n", req.RemoteAddr)
        http.Error(w, "Failed to parse remote address", 500)
        return
    }

    if isCli(req.UserAgent()) {
        io.WriteString(w, fmt.Sprintf("%s\n", host))
    } else {
        // XXX: Render HTML
    }
}

func main() {
    http.HandleFunc("/", handler)
    err := http.ListenAndServe(":8080", nil)
    if err != nil {
        log.Fatal("ListenAndServe: ", err)
    }
}
<commit_msg>Render HTML template if User-Agent is a regular browser<commit_after>package main

import (
    "fmt"
    "html/template"
    "io"
    "log"
    "net"
    "net/http"
    "regexp"
)

type Client struct {
    Host string
}

func isCli(userAgent string) bool {
    match, _ := regexp.MatchString("^(?i)(curl|wget|fetch\\slibfetch)\\/.*$",
        userAgent)
    return match
}

func handler(w http.ResponseWriter, req *http.Request) {
    if req.Method != "GET" {
        http.Error(w, "Invalid request method", 405)
        return
    }

    host, _, err := net.SplitHostPort(req.RemoteAddr)
    if err != nil {
        log.Printf("Failed to parse remote address: %s\n", req.RemoteAddr)
        http.Error(w, "Failed to parse remote address", 500)
        return
    }

    if isCli(req.UserAgent()) {
        io.WriteString(w, fmt.Sprintf("%s\n", host))
    } else {
        t, _ := template.ParseFiles("index.html")
        client := &Client{Host: host}
        t.Execute(w, client)
    }
}

func main() {
    http.HandleFunc("/", handler)
    err := http.ListenAndServe(":8080", nil)
    if err != nil {
        log.Fatal("ListenAndServe: ", err)
    }
}
<|endoftext|>


<commit_before>package metrics

import (
	"encoding/json"
	"os"
	"sync"
	"syscall"

	gmetrics "github.com/armon/go-metrics"
	"github.com/mistifyio/mistify-operator-admin/config"
)

// Keep track of metrics objects
var metricsObjects map[string]*gmetrics.Metrics = make(map[string]*gmetrics.Metrics)
var mutex sync.Mutex

// Get a metrics object with a particular config, or reuse one that matches
func GetObject(apiConfig *config.Metrics, overrideSink gmetrics.MetricSink) (*gmetrics.Metrics, error) {
	apiConfig = fetchConfig(apiConfig)
	lookup, err := json.Marshal(apiConfig)
	if err != nil {
		return nil, err
	}
	metricsObj, ok := metricsObjects[string(lookup)]
	if ok {
		return metricsObj, nil
	}
	metricsObj, err = buildMetricsObject(apiConfig, overrideSink)
	if err != nil {
		return nil, err
	}
	metricsObjects[string(lookup)] = metricsObj
	return metricsObj, nil
}

// Get a new metrics object with a particular config
func NewObject(apiConfig *config.Metrics, overrideSink gmetrics.MetricSink) (*gmetrics.Metrics, error) {
	apiConfig = fetchConfig(apiConfig)
	mutex.Lock()
	defer mutex.Unlock()
	metricsObj, err := buildMetricsObject(apiConfig, overrideSink)
	if err != nil {
		return nil, err
	}
	return metricsObj, nil
}

// fetchConfig gets the config from arguments or loads the default if one is not provided
func fetchConfig(apiConfig *config.Metrics) *config.Metrics {
	if apiConfig == nil {
		conf := config.Get()
		apiConfig = &conf.Metrics
	}
	return apiConfig
}

// buildMetricsObject generates the metrics object defined by the config
func buildMetricsObject(apiConfig *config.Metrics, overrideSink gmetrics.MetricSink) (*gmetrics.Metrics, error) {
	metricsConfig := buildMetricsObjectConfig(apiConfig)
	var mainSink gmetrics.FanoutSink
	if overrideSink != nil {
		mainSink = make(gmetrics.FanoutSink, 1)
		mainSink[0] = overrideSink
	} else {
		mainSink = make(gmetrics.FanoutSink, len(apiConfig.Sinks))
		for i, sinkConfig := range apiConfig.Sinks {
			sink, err := buildSink(sinkConfig)
			if err != nil {
				return nil, err
			}
			mainSink[i] = sink
		}
	}
	return gmetrics.New(metricsConfig, mainSink)
}

// buildMetricsObjectConfig generates the config object used by go-metrics
func buildMetricsObjectConfig(apiConfig *config.Metrics) *gmetrics.Config {
	metricsConfig := gmetrics.DefaultConfig(apiConfig.ServiceName)
	myHostName := apiConfig.HostName
	if myHostName != "" && myHostName != "auto" {
		metricsConfig.HostName = myHostName
	}
	if apiConfig.EnableTypePrefix != "" {
		metricsConfig.EnableHostname = config.EnableFlags[apiConfig.EnableHostname]
	}
	if apiConfig.EnableRuntimeMetrics != "" {
		metricsConfig.EnableRuntimeMetrics = config.EnableFlags[apiConfig.EnableRuntimeMetrics]
	}
	if apiConfig.EnableTypePrefix != "" {
		metricsConfig.EnableTypePrefix = config.EnableFlags[apiConfig.EnableTypePrefix]
	}
	if apiConfig.TimerGranularity != "" {
		duration, _ := apiConfig.TimerGranularityDuration()
		metricsConfig.TimerGranularity = duration
	}
	if apiConfig.ProfileInterval != "" {
		duration, _ := apiConfig.ProfileIntervalDuration()
		metricsConfig.ProfileInterval = duration
	}
	return metricsConfig
}

// buildSink creates a sink from the config options
func buildSink(sinkConfig config.MetricSink) (gmetrics.MetricSink, error) {
	if sinkConfig.SinkType == "Statsd" {
		sink, err := gmetrics.NewStatsdSink(sinkConfig.Address)
		if err != nil {
			return nil, err
		}
		return sink, nil
	}
	if sinkConfig.SinkType == "Statsite" {
		sink, err := gmetrics.NewStatsiteSink(sinkConfig.Address)
		if err != nil {
			return nil, err
		}
		return sink, nil
	}
	if sinkConfig.SinkType == "Inmem" {
		interval, _ := sinkConfig.IntervalDuration()
		retain, _ := sinkConfig.RetainDuration()
		sink := gmetrics.NewInmemSink(interval, retain)
		return sink, nil
	}
	if sinkConfig.SinkType == "Test" {
		interval, _ := sinkConfig.IntervalDuration()
		retain, _ := sinkConfig.RetainDuration()
		sink := gmetrics.NewInmemSink(interval, retain)
		gmetrics.NewInmemSignal(sink, syscall.SIGQUIT, os.Stdout)
		return sink, nil
	}
	return &gmetrics.BlackholeSink{}, nil
}
<commit_msg>Bug fix: mutex lock should be on GetObject, not NewObject<commit_after>package metrics

import (
	"encoding/json"
	"os"
	"sync"
	"syscall"

	gmetrics "github.com/armon/go-metrics"
	"github.com/mistifyio/mistify-operator-admin/config"
)

// Keep track of metrics objects
var metricsObjects map[string]*gmetrics.Metrics = make(map[string]*gmetrics.Metrics)
var mutex sync.Mutex

// Get a metrics object with a particular config, or reuse one that matches
func GetObject(apiConfig *config.Metrics, overrideSink gmetrics.MetricSink) (*gmetrics.Metrics, error) {
	apiConfig = fetchConfig(apiConfig)
	lookup, err := json.Marshal(apiConfig)
	if err != nil {
		return nil, err
	}
	metricsObj, ok := metricsObjects[string(lookup)]
	if ok {
		return metricsObj, nil
	}
	mutex.Lock()
	defer mutex.Unlock()
	metricsObj, err = buildMetricsObject(apiConfig, overrideSink)
	if err != nil {
		return nil, err
	}
	metricsObjects[string(lookup)] = metricsObj
	return metricsObj, nil
}

// Get a new metrics object with a particular config
func NewObject(apiConfig *config.Metrics, overrideSink gmetrics.MetricSink) (*gmetrics.Metrics, error) {
	apiConfig = fetchConfig(apiConfig)
	metricsObj, err := buildMetricsObject(apiConfig, overrideSink)
	if err != nil {
		return nil, err
	}
	return metricsObj, nil
}

// fetchConfig gets the config from arguments or loads the default if one is not provided
func fetchConfig(apiConfig *config.Metrics) *config.Metrics {
	if apiConfig == nil {
		conf := config.Get()
		apiConfig = &conf.Metrics
	}
	return apiConfig
}

// buildMetricsObject generates the metrics object defined by the config
func buildMetricsObject(apiConfig *config.Metrics, overrideSink gmetrics.MetricSink) (*gmetrics.Metrics, error) {
	metricsConfig := buildMetricsObjectConfig(apiConfig)
	var mainSink gmetrics.FanoutSink
	if overrideSink != nil {
		mainSink = make(gmetrics.FanoutSink, 1)
		mainSink[0] = overrideSink
	} else {
		mainSink = make(gmetrics.FanoutSink, len(apiConfig.Sinks))
		for i, sinkConfig := range apiConfig.Sinks {
			sink, err := buildSink(sinkConfig)
			if err != nil {
				return nil, err
			}
			mainSink[i] = sink
		}
	}
	return gmetrics.New(metricsConfig, mainSink)
}

// buildMetricsObjectConfig generates the config object used by go-metrics
func buildMetricsObjectConfig(apiConfig *config.Metrics) *gmetrics.Config {
	metricsConfig := gmetrics.DefaultConfig(apiConfig.ServiceName)
	myHostName := apiConfig.HostName
	if myHostName != "" && myHostName != "auto" {
		metricsConfig.HostName = myHostName
	}
	if apiConfig.EnableTypePrefix != "" {
		metricsConfig.EnableHostname = config.EnableFlags[apiConfig.EnableHostname]
	}
	if apiConfig.EnableRuntimeMetrics != "" {
		metricsConfig.EnableRuntimeMetrics = config.EnableFlags[apiConfig.EnableRuntimeMetrics]
	}
	if apiConfig.EnableTypePrefix != "" {
		metricsConfig.EnableTypePrefix = config.EnableFlags[apiConfig.EnableTypePrefix]
	}
	if apiConfig.TimerGranularity != "" {
		duration, _ := apiConfig.TimerGranularityDuration()
		metricsConfig.TimerGranularity = duration
	}
	if apiConfig.ProfileInterval != "" {
		duration, _ := apiConfig.ProfileIntervalDuration()
		metricsConfig.ProfileInterval = duration
	}
	return metricsConfig
}

// buildSink creates a sink from the config options
func buildSink(sinkConfig config.MetricSink) (gmetrics.MetricSink, error) {
	if sinkConfig.SinkType == "Statsd" {
		sink, err := gmetrics.NewStatsdSink(sinkConfig.Address)
		if err != nil {
			return nil, err
		}
		return sink, nil
	}
	if sinkConfig.SinkType == "Statsite" {
		sink, err := gmetrics.NewStatsiteSink(sinkConfig.Address)
		if err != nil {
			return nil, err
		}
		return sink, nil
	}
	if sinkConfig.SinkType == "Inmem" {
		interval, _ := sinkConfig.IntervalDuration()
		retain, _ := sinkConfig.RetainDuration()
		sink := gmetrics.NewInmemSink(interval, retain)
		return sink, nil
	}
	if sinkConfig.SinkType == "Test" {
		interval, _ := sinkConfig.IntervalDuration()
		retain, _ := sinkConfig.RetainDuration()
		sink := gmetrics.NewInmemSink(interval, retain)
		gmetrics.NewInmemSignal(sink, syscall.SIGQUIT, os.Stdout)
		return sink, nil
	}
	return &gmetrics.BlackholeSink{}, nil
}
<|endoftext|>


<commit_before>package middleware

import (
	"fmt"
	jwt "github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"

	"github.com/techjanitor/pram-post/config"
	e "github.com/techjanitor/pram-post/errors"
	u "github.com/techjanitor/pram-post/utils"
)

// checks for session cookie and handles permissions
func Auth(perms Permissions) gin.HandlerFunc {
	return func(c *gin.Context) {

		// set default anonymous user
		user := u.User{
			Id:    1,
			Group: 0,
		}

		// parse jwt token if its there
		token, err := jwt.ParseFromRequest(c.Request, func(token *jwt.Token) (interface{}, error) {

			// check alg
			_, ok := token.Method.(*jwt.SigningMethodHMAC)
			if !ok {
				return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
			}

			return []byte(config.Settings.Session.Secret), nil
		})
		// if the error is anything but no token
		if err != nil && err != jwt.ErrNoTokenInRequest {
			c.JSON(e.ErrorMessage(e.ErrUnauthorized))
			c.Error(err)
			c.Abort()
			return
		}

		// if the token is valid set the data
		if err == nil && token.Valid {

			uid, ok := token.Claims["user_id"].(float64)
			if !ok {
				c.JSON(e.ErrorMessage(e.ErrInternalError))
				c.Error(err)
				c.Abort()
				return
			}

			// set user id
			user.Id = uint(uid)

			// get the rest of the user info
			err = user.Info()
			if err == e.ErrNotFound {
				c.JSON(http.StatusBadRequest, gin.H{"error_message": e.ErrInvalidUser.Error()})
				c.Error(err)
				return
			} else if err != nil {
				c.JSON(e.ErrorMessage(e.ErrInternalError))
				c.Error(err)
				return
			}

		}

		// check if user meets set permissions
		if user.Group < perms.Minimum {
			c.JSON(e.ErrorMessage(e.ErrUnauthorized))
			c.Error(e.ErrUnauthorized)
			c.Abort()
			return
		}

		// set user data
		c.Set("userdata", user)

		c.Next()

	}

}

// permissions data
type Permissions struct {
	Minimum uint
}

func SetAuthLevel() Permissions {
	return Permissions{}
}

// All users
func (p Permissions) All() Permissions {
	p.Minimum = 0
	return p
}

// registered users
func (p Permissions) Registered() Permissions {
	p.Minimum = 1
	return p
}

// moderators
func (p Permissions) Moderators() Permissions {
	p.Minimum = 2
	return p
}

// admins
func (p Permissions) Admins() Permissions {
	p.Minimum = 3
	return p
}
<commit_msg>get user name and group from the database on jwt verification<commit_after>package middleware

import (
	"fmt"
	jwt "github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	"net/http"

	"github.com/techjanitor/pram-post/config"
	e "github.com/techjanitor/pram-post/errors"
	u "github.com/techjanitor/pram-post/utils"
)

// checks for session cookie and handles permissions
func Auth(perms Permissions) gin.HandlerFunc {
	return func(c *gin.Context) {

		// set default anonymous user
		user := u.User{
			Id:    1,
			Group: 0,
		}

		// parse jwt token if its there
		token, err := jwt.ParseFromRequest(c.Request, func(token *jwt.Token) (interface{}, error) {

			// check alg
			_, ok := token.Method.(*jwt.SigningMethodHMAC)
			if !ok {
				return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
			}

			return []byte(config.Settings.Session.Secret), nil
		})
		// if the error is anything but no token
		if err != nil && err != jwt.ErrNoTokenInRequest {
			c.JSON(e.ErrorMessage(e.ErrUnauthorized))
			c.Error(err)
			c.Abort()
			return
		}

		// if the token is valid set the data
		if err == nil && token.Valid {

			uid, ok := token.Claims["user_id"].(float64)
			if !ok {
				c.JSON(e.ErrorMessage(e.ErrInternalError))
				c.Error(err)
				c.Abort()
				return
			}

			// set user id
			user.Id = uint(uid)

			// get the rest of the user info
			err = user.Info()
			if err == e.ErrNotFound {
				c.JSON(http.StatusBadRequest, gin.H{"error_message": e.ErrInvalidUser.Error()})
				c.Error(err)
				return
			} else if err != nil {
				c.JSON(e.ErrorMessage(e.ErrInternalError))
				c.Error(err)
				return
			}

		}

		// check if user meets set permissions
		if user.Group < perms.Minimum {
			c.JSON(e.ErrorMessage(e.ErrUnauthorized))
			c.Error(e.ErrUnauthorized)
			c.Abort()
			return
		}

		// set user data
		c.Set("userdata", user)

		c.Next()

	}

}

// permissions data
type Permissions struct {
	Minimum uint
}

func SetAuthLevel() Permissions {
	return Permissions{}
}

// All users
func (p Permissions) All() Permissions {
	p.Minimum = 0
	return p
}

// registered users
func (p Permissions) Registered() Permissions {
	p.Minimum = 1
	return p
}

// moderators
func (p Permissions) Moderators() Permissions {
	p.Minimum = 2
	return p
}

// admins
func (p Permissions) Admins() Permissions {
	p.Minimum = 3
	return p
}
<|endoftext|>


<commit_before>package main

import "honnef.co/go/js/dom"

func WrapEvent(f func(...dom.Element), c ...dom.Element) func(dom.Event) {
	return func(dom.Event) {
		go f(c...)
	}
}
<commit_msg>Added ReadError, WriteString and ReadString to utils<commit_after>package main

import (
	"errors"
	"io"

	"github.com/MJKWoolnough/byteio"
	"honnef.co/go/js/dom"
)

func WrapEvent(f func(...dom.Element), c ...dom.Element) func(dom.Event) {
	return func(dom.Event) {
		go f(c...)
	}
}

func ReadError(r *byteio.StickyReader) error {
	s := readString(r)
	if r.Err != nil {
		return r.Err
	}
	return errors.New(s)
}

func WriteString(w *byteio.StickyWriter, s string) {
	w.WriteUInt16(uint16(len(s)))
	w.Write([]byte(s))
}

func ReadString(r *byteio.StickyReader) string {
	length := r.ReadUint16()
	str := make([]byte, int(length))
	io.ReadFull(r, str)
	return string(str)
}
<|endoftext|>


<commit_before>// This is a "stub" file.  It's a little start on your solution.
// It's not a complete solution though; you have to write some code.

// Package twofer should have a package comment that summarizes what it's about.
// https://golang.org/doc/effective_go.html#commentary
package twofer

// ShareWith should have a comment documenting it.
func ShareWith(name string) string {
	// Write some code here to pass the test suite.
	// Then remove all the stock comments.
	// They're here to help you get started but they only clutter a finished solution.
	// If you leave them in, reviewers may protest!
	return ""
}
<commit_msg>WIP - Exercice two-fer de Exercism dans la track Go<commit_after>// Package twofer should have a package comment that summarizes what it's about.
// https://golang.org/doc/effective_go.html#commentary
// The package twofer is an implementation of "Two-fer"
// "Two-fer" or "2-fer" is short for two for one. One for you and one for me.
package twofer

/*
ShareWith given a string representing a name, return a string with the message:

"One for X, one for me.""

Where X is the given name.

However, if the variable name is missing, this is a null value, an empty string or a blank string, it returns the string:

"One for you, one for me.""

*/
func ShareWith(name string) string {
	return ""
}
<|endoftext|>


<commit_before>package flac

import (
	"fmt"
	"io"

	"github.com/faiface/beep"
	"github.com/mewkiz/flac"
	"github.com/pkg/errors"
)

// Decode takes a ReadCloser containing audio data in FLAC format and returns a StreamSeekCloser,
// which streams that audio. The Seek method will panic if rc is not io.Seeker.
//
// Do not close the supplied ReadSeekCloser, instead, use the Close method of the returned
// StreamSeekCloser when you want to release the resources.
func Decode(rc io.ReadCloser) (s beep.StreamSeekCloser, format beep.Format, err error) {
	d := decoder{rc: rc}
	defer func() { // hacky way to always close rc if an error occured
		if err != nil {
			d.rc.Close()
		}
	}()
	d.stream, err = flac.New(rc)
	if err != nil {
		return nil, beep.Format{}, errors.Wrap(err, "flac")
	}
	format = beep.Format{
		SampleRate:  beep.SampleRate(d.stream.Info.SampleRate),
		NumChannels: int(d.stream.Info.NChannels),
		Precision:   int(d.stream.Info.BitsPerSample / 8),
	}
	return &d, format, nil
}

type decoder struct {
	rc     io.ReadCloser
	stream *flac.Stream
	buf    [][2]float64
	pos    int
	err    error
}

func (d *decoder) Stream(samples [][2]float64) (n int, ok bool) {
	if d.err != nil {
		return 0, false
	}
	// Copy samples from buffer.
	j := 0
	for i := range samples {
		if j >= len(d.buf) {
			// refill buffer.
			if err := d.refill(); err != nil {
				d.err = err
				d.pos += n
				return n, n > 0
			}
			j = 0
		}
		samples[i] = d.buf[j]
		j++
		n++
	}
	d.buf = d.buf[j:]
	d.pos += n
	return n, true
}

// refill decodes audio samples to fill the decode buffer.
func (d *decoder) refill() error {
	// Empty buffer.
	d.buf = d.buf[:0]
	// Parse audio frame.
	frame, err := d.stream.ParseNext()
	if err != nil {
		return err
	}
	// Expand buffer size if needed.
	n := len(frame.Subframes[0].Samples)
	if cap(d.buf) < n {
		d.buf = make([][2]float64, n)
	} else {
		d.buf = d.buf[:n]
	}
	// Decode audio samples.
	bps := d.stream.Info.BitsPerSample
	nchannels := d.stream.Info.NChannels
	switch {
	case bps == 8 && nchannels == 1:
		for i := 0; i < n; i++ {
			d.buf[i][0] = float64(int8(frame.Subframes[0].Samples[i])) / (1<<7 - 1)
			d.buf[i][1] = float64(int8(frame.Subframes[0].Samples[i])) / (1<<7 - 1)
		}
	case bps == 16 && nchannels == 1:
		for i := 0; i < n; i++ {
			d.buf[i][0] = float64(int16(frame.Subframes[0].Samples[i])) / (1<<15 - 1)
			d.buf[i][1] = float64(int16(frame.Subframes[0].Samples[i])) / (1<<15 - 1)
		}
	case bps == 24 && nchannels == 1:
		for i := 0; i < n; i++ {
			d.buf[i][0] = float64(int32(frame.Subframes[0].Samples[i])) / (1<<23 - 1)
			d.buf[i][1] = float64(int32(frame.Subframes[0].Samples[i])) / (1<<23 - 1)
		}
	case bps == 8 && nchannels >= 2:
		for i := 0; i < n; i++ {
			d.buf[i][0] = float64(int8(frame.Subframes[0].Samples[i])) / (1<<7 - 1)
			d.buf[i][1] = float64(int8(frame.Subframes[1].Samples[i])) / (1<<7 - 1)
		}
	case bps == 16 && nchannels >= 2:
		for i := 0; i < n; i++ {
			d.buf[i][0] = float64(int16(frame.Subframes[0].Samples[i])) / (1<<15 - 1)
			d.buf[i][1] = float64(int16(frame.Subframes[1].Samples[i])) / (1<<15 - 1)
		}
	case bps == 24 && nchannels >= 2:
		for i := 0; i < n; i++ {
			d.buf[i][0] = float64(int32(frame.Subframes[0].Samples[i])) / (1<<23 - 1)
			d.buf[i][1] = float64(int32(frame.Subframes[1].Samples[i])) / (1<<23 - 1)
		}
	default:
		panic(fmt.Errorf("support for %d bits-per-sample and %d channels combination not yet implemented", bps, nchannels))
	}
	return nil
}

func (d *decoder) Err() error {
	return d.err
}

func (d *decoder) Len() int {
	return int(d.stream.Info.NSamples)
}

func (d *decoder) Position() int {
	return d.pos
}

func (d *decoder) Seek(p int) error {
	return errors.New("flac.decoder.Seek: not yet implemented")
}

func (d *decoder) Close() error {
	err := d.rc.Close()
	if err != nil {
		return errors.Wrap(err, "flac")
	}
	return nil
}
<commit_msg>flac: fix off-by-one in sample conversion<commit_after>package flac

import (
	"fmt"
	"io"

	"github.com/faiface/beep"
	"github.com/mewkiz/flac"
	"github.com/pkg/errors"
)

// Decode takes a ReadCloser containing audio data in FLAC format and returns a StreamSeekCloser,
// which streams that audio. The Seek method will panic if rc is not io.Seeker.
//
// Do not close the supplied ReadSeekCloser, instead, use the Close method of the returned
// StreamSeekCloser when you want to release the resources.
func Decode(rc io.ReadCloser) (s beep.StreamSeekCloser, format beep.Format, err error) {
	d := decoder{rc: rc}
	defer func() { // hacky way to always close rc if an error occured
		if err != nil {
			d.rc.Close()
		}
	}()
	d.stream, err = flac.New(rc)
	if err != nil {
		return nil, beep.Format{}, errors.Wrap(err, "flac")
	}
	format = beep.Format{
		SampleRate:  beep.SampleRate(d.stream.Info.SampleRate),
		NumChannels: int(d.stream.Info.NChannels),
		Precision:   int(d.stream.Info.BitsPerSample / 8),
	}
	return &d, format, nil
}

type decoder struct {
	rc     io.ReadCloser
	stream *flac.Stream
	buf    [][2]float64
	pos    int
	err    error
}

func (d *decoder) Stream(samples [][2]float64) (n int, ok bool) {
	if d.err != nil {
		return 0, false
	}
	// Copy samples from buffer.
	j := 0
	for i := range samples {
		if j >= len(d.buf) {
			// refill buffer.
			if err := d.refill(); err != nil {
				d.err = err
				d.pos += n
				return n, n > 0
			}
			j = 0
		}
		samples[i] = d.buf[j]
		j++
		n++
	}
	d.buf = d.buf[j:]
	d.pos += n
	return n, true
}

// refill decodes audio samples to fill the decode buffer.
func (d *decoder) refill() error {
	// Empty buffer.
	d.buf = d.buf[:0]
	// Parse audio frame.
	frame, err := d.stream.ParseNext()
	if err != nil {
		return err
	}
	// Expand buffer size if needed.
	n := len(frame.Subframes[0].Samples)
	if cap(d.buf) < n {
		d.buf = make([][2]float64, n)
	} else {
		d.buf = d.buf[:n]
	}
	// Decode audio samples.
	bps := d.stream.Info.BitsPerSample
	nchannels := d.stream.Info.NChannels
	s := 1 << (bps - 1)
	q := 1 / float64(s)
	switch {
	case bps == 8 && nchannels == 1:
		for i := 0; i < n; i++ {
			d.buf[i][0] = float64(int8(frame.Subframes[0].Samples[i])) * q
			d.buf[i][1] = float64(int8(frame.Subframes[0].Samples[i])) * q
		}
	case bps == 16 && nchannels == 1:
		for i := 0; i < n; i++ {
			d.buf[i][0] = float64(int16(frame.Subframes[0].Samples[i])) * q
			d.buf[i][1] = float64(int16(frame.Subframes[0].Samples[i])) * q
		}
	case bps == 24 && nchannels == 1:
		for i := 0; i < n; i++ {
			d.buf[i][0] = float64(int32(frame.Subframes[0].Samples[i])) * q
			d.buf[i][1] = float64(int32(frame.Subframes[0].Samples[i])) * q
		}
	case bps == 8 && nchannels >= 2:
		for i := 0; i < n; i++ {
			d.buf[i][0] = float64(int8(frame.Subframes[0].Samples[i])) * q
			d.buf[i][1] = float64(int8(frame.Subframes[1].Samples[i])) * q
		}
	case bps == 16 && nchannels >= 2:
		for i := 0; i < n; i++ {
			d.buf[i][0] = float64(int16(frame.Subframes[0].Samples[i])) * q
			d.buf[i][1] = float64(int16(frame.Subframes[1].Samples[i])) * q
		}
	case bps == 24 && nchannels >= 2:
		for i := 0; i < n; i++ {
			d.buf[i][0] = float64(frame.Subframes[0].Samples[i]) * q
			d.buf[i][1] = float64(frame.Subframes[1].Samples[i]) * q
		}
	default:
		panic(fmt.Errorf("support for %d bits-per-sample and %d channels combination not yet implemented", bps, nchannels))
	}
	return nil
}

func (d *decoder) Err() error {
	return d.err
}

func (d *decoder) Len() int {
	return int(d.stream.Info.NSamples)
}

func (d *decoder) Position() int {
	return d.pos
}

func (d *decoder) Seek(p int) error {
	return errors.New("flac.decoder.Seek: not yet implemented")
}

func (d *decoder) Close() error {
	err := d.rc.Close()
	if err != nil {
		return errors.Wrap(err, "flac")
	}
	return nil
}
<|endoftext|>


<commit_before>package rancher

import (
	"fmt"
	"strings"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/docker/docker/api/types/container"
	"github.com/docker/libcompose/config"
	"github.com/docker/libcompose/docker/service"
	"github.com/docker/libcompose/utils"
	"github.com/docker/libcompose/yaml"
	"github.com/rancher/go-rancher/v2"
)

const (
	defaultLoadBalancerImage = "rancher/lb-service-haproxy"
)

func createLaunchConfigs(r *RancherService) (client.LaunchConfig, []client.SecondaryLaunchConfig, error) {
	secondaryLaunchConfigs := []client.SecondaryLaunchConfig{}
	launchConfig, err := createLaunchConfig(r, r.Name(), r.Config())
	if err != nil {
		return launchConfig, nil, err
	}
	launchConfig.HealthCheck = r.HealthCheck("")

	if secondaries, ok := r.Context().SidekickInfo.primariesToSidekicks[r.Name()]; ok {
		for _, secondaryName := range secondaries {
			serviceConfig, ok := r.Context().Project.ServiceConfigs.Get(secondaryName)
			if !ok {
				return launchConfig, nil, fmt.Errorf("Failed to find sidekick: %s", secondaryName)
			}

			launchConfig, err := createLaunchConfig(r, secondaryName, serviceConfig)
			if err != nil {
				return launchConfig, nil, err
			}
			launchConfig.HealthCheck = r.HealthCheck(secondaryName)

			var secondaryLaunchConfig client.SecondaryLaunchConfig
			utils.Convert(launchConfig, &secondaryLaunchConfig)
			secondaryLaunchConfig.Name = secondaryName

			if secondaryLaunchConfig.Labels == nil {
				secondaryLaunchConfig.Labels = map[string]interface{}{}
			}
			secondaryLaunchConfigs = append(secondaryLaunchConfigs, secondaryLaunchConfig)
		}
	}

	return launchConfig, secondaryLaunchConfigs, nil
}

func createLaunchConfig(r *RancherService, name string, serviceConfig *config.ServiceConfig) (client.LaunchConfig, error) {
	var result client.LaunchConfig

	rancherConfig := r.context.RancherConfig[name]

	schemasUrl := strings.SplitN(r.Context().Client.GetSchemas().Links["self"], "/schemas", 2)[0]
	scriptsUrl := schemasUrl + "/scripts/transform"

	tempImage := serviceConfig.Image
	tempLabels := serviceConfig.Labels
	newLabels := yaml.SliceorMap{}
	if serviceConfig.Image == "rancher/load-balancer-service" {
		serviceConfig.Image = defaultLoadBalancerImage
		for k, v := range serviceConfig.Labels {
			if !strings.HasPrefix(k, "io.rancher.loadbalancer") {
				newLabels[k] = v
			}
		}
		serviceConfig.Labels = newLabels
	}

	config, hostConfig, err := service.Convert(serviceConfig, r.context.Context)
	if err != nil {
		return result, err
	}

	serviceConfig.Image = tempImage
	serviceConfig.Labels = tempLabels

	dockerContainer := &ContainerInspect{
		Config:     config,
		HostConfig: hostConfig,
	}

	dockerContainer.HostConfig.NetworkMode = container.NetworkMode("")
	dockerContainer.Name = "/" + name

	err = r.Context().Client.Post(scriptsUrl, dockerContainer, &result)
	if err != nil {
		return result, err
	}

	result.VolumeDriver = hostConfig.VolumeDriver

	setupNetworking(serviceConfig.NetworkMode, &result)
	setupVolumesFrom(serviceConfig.VolumesFrom, &result)

	err = setupBuild(r, name, &result, serviceConfig)

	if result.Labels == nil {
		result.Labels = map[string]interface{}{}
	}

	result.Kind = rancherConfig.Type
	result.Vcpu = int64(rancherConfig.Vcpu)
	result.Userdata = rancherConfig.Userdata
	result.MemoryMb = int64(rancherConfig.Memory)
	result.Disks = rancherConfig.Disks

	if strings.EqualFold(result.Kind, "virtual_machine") || strings.EqualFold(result.Kind, "virtualmachine") {
		result.Kind = "virtualMachine"
	}

	if result.LogConfig.Config == nil {
		result.LogConfig.Config = map[string]interface{}{}
	}

	return result, err
}

func setupNetworking(netMode string, launchConfig *client.LaunchConfig) {
	if netMode == "" {
		launchConfig.NetworkMode = "managed"
	} else if container.IpcMode(netMode).IsContainer() {
		// For some reason NetworkMode object is gone runconfig, but IpcMode works the same for this
		launchConfig.NetworkMode = "container"
		launchConfig.NetworkLaunchConfig = strings.TrimPrefix(netMode, "container:")
	} else {
		launchConfig.NetworkMode = netMode
	}
}

func setupVolumesFrom(volumesFrom []string, launchConfig *client.LaunchConfig) {
	launchConfig.DataVolumesFromLaunchConfigs = volumesFrom
}

func setupBuild(r *RancherService, name string, result *client.LaunchConfig, serviceConfig *config.ServiceConfig) error {
	if serviceConfig.Build.Context != "" {
		result.Build = &client.DockerBuild{
			Remote:     serviceConfig.Build.Context,
			Dockerfile: serviceConfig.Build.Dockerfile,
		}

		needBuild := true
		if config.IsValidRemote(serviceConfig.Build.Context) {
			needBuild = false
		}

		if needBuild {
			image, url, err := Upload(r.Context(), name)
			if err != nil {
				return err
			}
			logrus.Infof("Build for %s available at %s", name, url)
			serviceConfig.Build.Context = url

			if serviceConfig.Image == "" {
				serviceConfig.Image = image
			}

			result.Build = &client.DockerBuild{
				Context:    url,
				Dockerfile: serviceConfig.Build.Dockerfile,
			}
			result.ImageUuid = "docker:" + image
		} else if result.ImageUuid == "" {
			result.ImageUuid = fmt.Sprintf("docker:%s_%s_%d", r.Context().ProjectName, name, time.Now().UnixNano()/int64(time.Millisecond))
		}
	}

	return nil
}
<commit_msg>Lookup default load balancer image<commit_after>package rancher

import (
	"fmt"
	"strings"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/docker/docker/api/types/container"
	"github.com/docker/libcompose/config"
	"github.com/docker/libcompose/docker/service"
	"github.com/docker/libcompose/utils"
	"github.com/docker/libcompose/yaml"
	"github.com/rancher/go-rancher/v2"
)

func createLaunchConfigs(r *RancherService) (client.LaunchConfig, []client.SecondaryLaunchConfig, error) {
	secondaryLaunchConfigs := []client.SecondaryLaunchConfig{}
	launchConfig, err := createLaunchConfig(r, r.Name(), r.Config())
	if err != nil {
		return launchConfig, nil, err
	}
	launchConfig.HealthCheck = r.HealthCheck("")

	if secondaries, ok := r.Context().SidekickInfo.primariesToSidekicks[r.Name()]; ok {
		for _, secondaryName := range secondaries {
			serviceConfig, ok := r.Context().Project.ServiceConfigs.Get(secondaryName)
			if !ok {
				return launchConfig, nil, fmt.Errorf("Failed to find sidekick: %s", secondaryName)
			}

			launchConfig, err := createLaunchConfig(r, secondaryName, serviceConfig)
			if err != nil {
				return launchConfig, nil, err
			}
			launchConfig.HealthCheck = r.HealthCheck(secondaryName)

			var secondaryLaunchConfig client.SecondaryLaunchConfig
			utils.Convert(launchConfig, &secondaryLaunchConfig)
			secondaryLaunchConfig.Name = secondaryName

			if secondaryLaunchConfig.Labels == nil {
				secondaryLaunchConfig.Labels = map[string]interface{}{}
			}
			secondaryLaunchConfigs = append(secondaryLaunchConfigs, secondaryLaunchConfig)
		}
	}

	return launchConfig, secondaryLaunchConfigs, nil
}

func createLaunchConfig(r *RancherService, name string, serviceConfig *config.ServiceConfig) (client.LaunchConfig, error) {
	var result client.LaunchConfig

	rancherConfig := r.context.RancherConfig[name]

	schemasUrl := strings.SplitN(r.Context().Client.GetSchemas().Links["self"], "/schemas", 2)[0]
	scriptsUrl := schemasUrl + "/scripts/transform"

	tempImage := serviceConfig.Image
	tempLabels := serviceConfig.Labels
	newLabels := yaml.SliceorMap{}
	if serviceConfig.Image == "rancher/load-balancer-service" {
		// Lookup default load balancer image
		lbImageSetting, err := r.Client().Setting.ById("lb.instance.image")
		if err != nil {
			return result, err
		}
		serviceConfig.Image = lbImageSetting.Value

		// Strip off legacy load balancer labels
		for k, v := range serviceConfig.Labels {
			if !strings.HasPrefix(k, "io.rancher.loadbalancer") {
				newLabels[k] = v
			}
		}
		serviceConfig.Labels = newLabels
	}

	config, hostConfig, err := service.Convert(serviceConfig, r.context.Context)
	if err != nil {
		return result, err
	}

	serviceConfig.Image = tempImage
	serviceConfig.Labels = tempLabels

	dockerContainer := &ContainerInspect{
		Config:     config,
		HostConfig: hostConfig,
	}

	dockerContainer.HostConfig.NetworkMode = container.NetworkMode("")
	dockerContainer.Name = "/" + name

	err = r.Context().Client.Post(scriptsUrl, dockerContainer, &result)
	if err != nil {
		return result, err
	}

	result.VolumeDriver = hostConfig.VolumeDriver

	setupNetworking(serviceConfig.NetworkMode, &result)
	setupVolumesFrom(serviceConfig.VolumesFrom, &result)

	err = setupBuild(r, name, &result, serviceConfig)

	if result.Labels == nil {
		result.Labels = map[string]interface{}{}
	}

	result.Kind = rancherConfig.Type
	result.Vcpu = int64(rancherConfig.Vcpu)
	result.Userdata = rancherConfig.Userdata
	result.MemoryMb = int64(rancherConfig.Memory)
	result.Disks = rancherConfig.Disks

	if strings.EqualFold(result.Kind, "virtual_machine") || strings.EqualFold(result.Kind, "virtualmachine") {
		result.Kind = "virtualMachine"
	}

	if result.LogConfig.Config == nil {
		result.LogConfig.Config = map[string]interface{}{}
	}

	return result, err
}

func setupNetworking(netMode string, launchConfig *client.LaunchConfig) {
	if netMode == "" {
		launchConfig.NetworkMode = "managed"
	} else if container.IpcMode(netMode).IsContainer() {
		// For some reason NetworkMode object is gone runconfig, but IpcMode works the same for this
		launchConfig.NetworkMode = "container"
		launchConfig.NetworkLaunchConfig = strings.TrimPrefix(netMode, "container:")
	} else {
		launchConfig.NetworkMode = netMode
	}
}

func setupVolumesFrom(volumesFrom []string, launchConfig *client.LaunchConfig) {
	launchConfig.DataVolumesFromLaunchConfigs = volumesFrom
}

func setupBuild(r *RancherService, name string, result *client.LaunchConfig, serviceConfig *config.ServiceConfig) error {
	if serviceConfig.Build.Context != "" {
		result.Build = &client.DockerBuild{
			Remote:     serviceConfig.Build.Context,
			Dockerfile: serviceConfig.Build.Dockerfile,
		}

		needBuild := true
		if config.IsValidRemote(serviceConfig.Build.Context) {
			needBuild = false
		}

		if needBuild {
			image, url, err := Upload(r.Context(), name)
			if err != nil {
				return err
			}
			logrus.Infof("Build for %s available at %s", name, url)
			serviceConfig.Build.Context = url

			if serviceConfig.Image == "" {
				serviceConfig.Image = image
			}

			result.Build = &client.DockerBuild{
				Context:    url,
				Dockerfile: serviceConfig.Build.Dockerfile,
			}
			result.ImageUuid = "docker:" + image
		} else if result.ImageUuid == "" {
			result.ImageUuid = fmt.Sprintf("docker:%s_%s_%d", r.Context().ProjectName, name, time.Now().UnixNano()/int64(time.Millisecond))
		}
	}

	return nil
}
<|endoftext|>


<commit_before>// +build !nautilus

// Initially, we're only providing mirroring related functions for octopus as
// that version of ceph deprecated a number of the functions in nautilus. If
// you need mirroring on an earlier supported version of ceph please file an
// issue in our tracker.

package rbd

import (
	"fmt"
	"testing"

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

func TestGetMirrorMode(t *testing.T) {
	conn := radosConnect(t)
	poolName := GetUUID()
	err := conn.MakePool(poolName)
	require.NoError(t, err)
	defer func() {
		assert.NoError(t, conn.DeletePool(poolName))
		conn.Shutdown()
	}()

	ioctx, err := conn.OpenIOContext(poolName)
	assert.NoError(t, err)
	defer func() {
		ioctx.Destroy()
	}()

	t.Run("mirrorModeDisabled", func(t *testing.T) {
		m, err := GetMirrorMode(ioctx)
		assert.NoError(t, err)
		assert.Equal(t, m, MirrorModeDisabled)
	})
	t.Run("mirrorModeEnabled", func(t *testing.T) {
		err = SetMirrorMode(ioctx, MirrorModeImage)
		require.NoError(t, err)
		m, err := GetMirrorMode(ioctx)
		assert.NoError(t, err)
		assert.Equal(t, m, MirrorModeImage)
	})
	t.Run("ioctxNil", func(t *testing.T) {
		assert.Panics(t, func() {
			GetMirrorMode(nil)
		})
	})

}

func TestMirroring(t *testing.T) {
	conn := radosConnect(t)
	poolName := GetUUID()
	err := conn.MakePool(poolName)
	require.NoError(t, err)
	defer func() {
		assert.NoError(t, conn.DeletePool(poolName))
		conn.Shutdown()
	}()

	ioctx, err := conn.OpenIOContext(poolName)
	assert.NoError(t, err)
	defer func() {
		ioctx.Destroy()
	}()

	// verify that mirroring is not enabled on this new pool
	m, err := GetMirrorMode(ioctx)
	assert.NoError(t, err)
	assert.Equal(t, m, MirrorModeDisabled)

	// enable per-image mirroring for this pool
	err = SetMirrorMode(ioctx, MirrorModeImage)
	require.NoError(t, err)

	name1 := GetUUID()
	options := NewRbdImageOptions()
	assert.NoError(t,
		options.SetUint64(ImageOptionOrder, uint64(testImageOrder)))
	err = CreateImage(ioctx, name1, testImageSize, options)
	require.NoError(t, err)

	t.Run("enableDisable", func(t *testing.T) {
		img, err := OpenImage(ioctx, name1, NoSnapshot)
		assert.NoError(t, err)
		defer func() {
			assert.NoError(t, img.Close())
		}()

		err = img.MirrorEnable(ImageMirrorModeSnapshot)
		assert.NoError(t, err)

		mode, err := img.GetImageMirrorMode()
		assert.NoError(t, err)
		assert.Equal(t, mode, ImageMirrorModeSnapshot)

		err = img.MirrorDisable(false)
		assert.NoError(t, err)
	})
	t.Run("enableDisableInvalid", func(t *testing.T) {
		img, err := OpenImage(ioctx, name1, NoSnapshot)
		assert.NoError(t, err)
		assert.NoError(t, img.Close())

		err = img.MirrorEnable(ImageMirrorModeSnapshot)
		assert.Error(t, err)
		err = img.MirrorDisable(false)
		assert.Error(t, err)
		_, err = img.GetImageMirrorMode()
		assert.Error(t, err)
	})
	t.Run("promoteDemote", func(t *testing.T) {
		img, err := OpenImage(ioctx, name1, NoSnapshot)
		assert.NoError(t, err)
		defer func() {
			assert.NoError(t, img.Close())
		}()

		err = img.MirrorEnable(ImageMirrorModeSnapshot)
		assert.NoError(t, err)
		err = img.MirrorDemote()
		assert.NoError(t, err)
		err = img.MirrorPromote(false)
		assert.NoError(t, err)
		err = img.MirrorDisable(false)
		assert.NoError(t, err)
	})
	t.Run("promoteDemoteInvalid", func(t *testing.T) {
		img, err := OpenImage(ioctx, name1, NoSnapshot)
		assert.NoError(t, err)
		assert.NoError(t, img.Close())

		err = img.MirrorDemote()
		assert.Error(t, err)
		err = img.MirrorPromote(false)
		assert.Error(t, err)
	})
	t.Run("resync", func(t *testing.T) {
		img, err := OpenImage(ioctx, name1, NoSnapshot)
		assert.NoError(t, err)
		defer func() {
			assert.NoError(t, img.Close())
		}()

		err = img.MirrorEnable(ImageMirrorModeSnapshot)
		assert.NoError(t, err)
		err = img.MirrorDemote()
		assert.NoError(t, err)
		err = img.MirrorResync()
		assert.NoError(t, err)
		err = img.MirrorDisable(true)
		assert.NoError(t, err)
	})
	t.Run("resyncInvalid", func(t *testing.T) {
		img, err := OpenImage(ioctx, name1, NoSnapshot)
		assert.NoError(t, err)
		assert.NoError(t, img.Close())

		err = img.MirrorResync()
		assert.Error(t, err)
	})
	t.Run("instanceId", func(t *testing.T) {
		img, err := OpenImage(ioctx, name1, NoSnapshot)
		assert.NoError(t, err)
		defer func() {
			assert.NoError(t, img.Close())
		}()

		err = img.MirrorEnable(ImageMirrorModeSnapshot)
		assert.NoError(t, err)
		miid, err := img.MirrorInstanceID()
		// this is not currently testable for the "success" case
		// see also the ceph tree where nothing is asserted except
		// that the error is raised.
		// TODO(?): figure out how to test this
		assert.Error(t, err)
		assert.Equal(t, "", miid)
		err = img.MirrorDisable(false)
		assert.NoError(t, err)
	})
	t.Run("instanceIdInvalid", func(t *testing.T) {
		img, err := OpenImage(ioctx, name1, NoSnapshot)
		assert.NoError(t, err)
		assert.NoError(t, img.Close())

		_, err = img.MirrorInstanceID()
		assert.Error(t, err)
	})
}

func TestGetMirrorImageInfo(t *testing.T) {
	conn := radosConnect(t)
	poolName := GetUUID()
	err := conn.MakePool(poolName)
	require.NoError(t, err)
	defer func() {
		assert.NoError(t, conn.DeletePool(poolName))
		conn.Shutdown()
	}()

	ioctx, err := conn.OpenIOContext(poolName)
	assert.NoError(t, err)
	defer func() {
		ioctx.Destroy()
	}()

	// enable per-image mirroring for this pool
	err = SetMirrorMode(ioctx, MirrorModeImage)
	require.NoError(t, err)

	imgName := GetUUID()
	options := NewRbdImageOptions()
	assert.NoError(t, options.SetUint64(ImageOptionOrder, uint64(testImageOrder)))
	err = CreateImage(ioctx, imgName, testImageSize, options)
	require.NoError(t, err)

	t.Run("closedImage", func(t *testing.T) {
		img := GetImage(ioctx, imgName)
		_, err = img.GetMirrorImageInfo()
		assert.Error(t, err)
	})

	t.Run("getInfo", func(t *testing.T) {
		// open image, enable, mirroring.
		img, err := OpenImage(ioctx, imgName, NoSnapshot)
		assert.NoError(t, err)
		defer func() {
			assert.NoError(t, img.Close())
		}()

		err = img.MirrorEnable(ImageMirrorModeSnapshot)
		assert.NoError(t, err)
		mii, err := img.GetMirrorImageInfo()
		assert.NoError(t, err)
		assert.NotNil(t, mii.GlobalID)
		assert.Equal(t, mii.State, MirrorImageEnabled)
		assert.Equal(t, mii.Primary, true)
	})
}

func TestMirrorConstantStrings(t *testing.T) {
	x := []struct {
		s fmt.Stringer
		t string
	}{
		{MirrorModeDisabled, "disabled"},
		{MirrorModeImage, "image"},
		{MirrorModePool, "pool"},
		{MirrorMode(9999), "<unknown>"},
		{ImageMirrorModeJournal, "journal"},
		{ImageMirrorModeSnapshot, "snapshot"},
		{ImageMirrorMode(9999), "<unknown>"},
		{MirrorImageDisabling, "disabling"},
		{MirrorImageEnabled, "enabled"},
		{MirrorImageDisabled, "disabled"},
		{MirrorImageState(9999), "<unknown>"},
	}
	for _, v := range x {
		assert.Equal(t, v.s.String(), v.t)
	}
}

func TestGetGlobalMirrorStatus(t *testing.T) {
	conn := radosConnect(t)
	poolName := GetUUID()
	err := conn.MakePool(poolName)
	require.NoError(t, err)
	defer func() {
		assert.NoError(t, conn.DeletePool(poolName))
		conn.Shutdown()
	}()

	ioctx, err := conn.OpenIOContext(poolName)
	assert.NoError(t, err)
	defer func() {
		ioctx.Destroy()
	}()

	// enable per-image mirroring for this pool
	err = SetMirrorMode(ioctx, MirrorModeImage)
	require.NoError(t, err)

	imgName := GetUUID()
	options := NewRbdImageOptions()
	assert.NoError(t, options.SetUint64(ImageOptionOrder, uint64(testImageOrder)))
	err = CreateImage(ioctx, imgName, testImageSize, options)
	require.NoError(t, err)

	t.Run("closedImage", func(t *testing.T) {
		img := GetImage(ioctx, imgName)
		_, err = img.GetGlobalMirrorStatus()
		assert.Error(t, err)
	})

	t.Run("getStatus", func(t *testing.T) {
		// open image, enable, mirroring.
		img, err := OpenImage(ioctx, imgName, NoSnapshot)
		assert.NoError(t, err)
		defer func() {
			assert.NoError(t, img.Close())
		}()

		err = img.MirrorEnable(ImageMirrorModeSnapshot)
		assert.NoError(t, err)
		gms, err := img.GetGlobalMirrorStatus()
		assert.NoError(t, err)
		assert.NotEqual(t, "", gms.Name)
		assert.NotEqual(t, "", gms.Info.GlobalID)
		assert.Equal(t, gms.Info.State, MirrorImageEnabled)
		assert.Equal(t, gms.Info.Primary, true)
		if assert.Len(t, gms.SiteStatuses, 1) {
			ss := gms.SiteStatuses[0]
			assert.Equal(t, "", ss.MirrorUUID)
			assert.Equal(t, MirrorImageStatusStateUnknown, ss.State, ss.State)
			assert.Equal(t, "status not found", ss.Description)
			assert.Equal(t, int64(0), ss.LastUpdate)
			assert.False(t, ss.Up)
			ls, err := gms.LocalStatus()
			assert.NoError(t, err)
			assert.Equal(t, ss, ls)
		}
	})
}
<commit_msg>rbd: add tests for GetGlobalMirrorStatus based on two ceph clusters<commit_after>// +build !nautilus

// Initially, we're only providing mirroring related functions for octopus as
// that version of ceph deprecated a number of the functions in nautilus. If
// you need mirroring on an earlier supported version of ceph please file an
// issue in our tracker.

package rbd

import (
	"fmt"
	"os"
	"testing"
	"time"

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

func TestGetMirrorMode(t *testing.T) {
	conn := radosConnect(t)
	poolName := GetUUID()
	err := conn.MakePool(poolName)
	require.NoError(t, err)
	defer func() {
		assert.NoError(t, conn.DeletePool(poolName))
		conn.Shutdown()
	}()

	ioctx, err := conn.OpenIOContext(poolName)
	assert.NoError(t, err)
	defer func() {
		ioctx.Destroy()
	}()

	t.Run("mirrorModeDisabled", func(t *testing.T) {
		m, err := GetMirrorMode(ioctx)
		assert.NoError(t, err)
		assert.Equal(t, m, MirrorModeDisabled)
	})
	t.Run("mirrorModeEnabled", func(t *testing.T) {
		err = SetMirrorMode(ioctx, MirrorModeImage)
		require.NoError(t, err)
		m, err := GetMirrorMode(ioctx)
		assert.NoError(t, err)
		assert.Equal(t, m, MirrorModeImage)
	})
	t.Run("ioctxNil", func(t *testing.T) {
		assert.Panics(t, func() {
			GetMirrorMode(nil)
		})
	})

}

func TestMirroring(t *testing.T) {
	conn := radosConnect(t)
	poolName := GetUUID()
	err := conn.MakePool(poolName)
	require.NoError(t, err)
	defer func() {
		assert.NoError(t, conn.DeletePool(poolName))
		conn.Shutdown()
	}()

	ioctx, err := conn.OpenIOContext(poolName)
	assert.NoError(t, err)
	defer func() {
		ioctx.Destroy()
	}()

	// verify that mirroring is not enabled on this new pool
	m, err := GetMirrorMode(ioctx)
	assert.NoError(t, err)
	assert.Equal(t, m, MirrorModeDisabled)

	// enable per-image mirroring for this pool
	err = SetMirrorMode(ioctx, MirrorModeImage)
	require.NoError(t, err)

	name1 := GetUUID()
	options := NewRbdImageOptions()
	assert.NoError(t,
		options.SetUint64(ImageOptionOrder, uint64(testImageOrder)))
	err = CreateImage(ioctx, name1, testImageSize, options)
	require.NoError(t, err)

	t.Run("enableDisable", func(t *testing.T) {
		img, err := OpenImage(ioctx, name1, NoSnapshot)
		assert.NoError(t, err)
		defer func() {
			assert.NoError(t, img.Close())
		}()

		err = img.MirrorEnable(ImageMirrorModeSnapshot)
		assert.NoError(t, err)

		mode, err := img.GetImageMirrorMode()
		assert.NoError(t, err)
		assert.Equal(t, mode, ImageMirrorModeSnapshot)

		err = img.MirrorDisable(false)
		assert.NoError(t, err)
	})
	t.Run("enableDisableInvalid", func(t *testing.T) {
		img, err := OpenImage(ioctx, name1, NoSnapshot)
		assert.NoError(t, err)
		assert.NoError(t, img.Close())

		err = img.MirrorEnable(ImageMirrorModeSnapshot)
		assert.Error(t, err)
		err = img.MirrorDisable(false)
		assert.Error(t, err)
		_, err = img.GetImageMirrorMode()
		assert.Error(t, err)
	})
	t.Run("promoteDemote", func(t *testing.T) {
		img, err := OpenImage(ioctx, name1, NoSnapshot)
		assert.NoError(t, err)
		defer func() {
			assert.NoError(t, img.Close())
		}()

		err = img.MirrorEnable(ImageMirrorModeSnapshot)
		assert.NoError(t, err)
		err = img.MirrorDemote()
		assert.NoError(t, err)
		err = img.MirrorPromote(false)
		assert.NoError(t, err)
		err = img.MirrorDisable(false)
		assert.NoError(t, err)
	})
	t.Run("promoteDemoteInvalid", func(t *testing.T) {
		img, err := OpenImage(ioctx, name1, NoSnapshot)
		assert.NoError(t, err)
		assert.NoError(t, img.Close())

		err = img.MirrorDemote()
		assert.Error(t, err)
		err = img.MirrorPromote(false)
		assert.Error(t, err)
	})
	t.Run("resync", func(t *testing.T) {
		img, err := OpenImage(ioctx, name1, NoSnapshot)
		assert.NoError(t, err)
		defer func() {
			assert.NoError(t, img.Close())
		}()

		err = img.MirrorEnable(ImageMirrorModeSnapshot)
		assert.NoError(t, err)
		err = img.MirrorDemote()
		assert.NoError(t, err)
		err = img.MirrorResync()
		assert.NoError(t, err)
		err = img.MirrorDisable(true)
		assert.NoError(t, err)
	})
	t.Run("resyncInvalid", func(t *testing.T) {
		img, err := OpenImage(ioctx, name1, NoSnapshot)
		assert.NoError(t, err)
		assert.NoError(t, img.Close())

		err = img.MirrorResync()
		assert.Error(t, err)
	})
	t.Run("instanceId", func(t *testing.T) {
		img, err := OpenImage(ioctx, name1, NoSnapshot)
		assert.NoError(t, err)
		defer func() {
			assert.NoError(t, img.Close())
		}()

		err = img.MirrorEnable(ImageMirrorModeSnapshot)
		assert.NoError(t, err)
		miid, err := img.MirrorInstanceID()
		// this is not currently testable for the "success" case
		// see also the ceph tree where nothing is asserted except
		// that the error is raised.
		// TODO(?): figure out how to test this
		assert.Error(t, err)
		assert.Equal(t, "", miid)
		err = img.MirrorDisable(false)
		assert.NoError(t, err)
	})
	t.Run("instanceIdInvalid", func(t *testing.T) {
		img, err := OpenImage(ioctx, name1, NoSnapshot)
		assert.NoError(t, err)
		assert.NoError(t, img.Close())

		_, err = img.MirrorInstanceID()
		assert.Error(t, err)
	})
}

func TestGetMirrorImageInfo(t *testing.T) {
	conn := radosConnect(t)
	poolName := GetUUID()
	err := conn.MakePool(poolName)
	require.NoError(t, err)
	defer func() {
		assert.NoError(t, conn.DeletePool(poolName))
		conn.Shutdown()
	}()

	ioctx, err := conn.OpenIOContext(poolName)
	assert.NoError(t, err)
	defer func() {
		ioctx.Destroy()
	}()

	// enable per-image mirroring for this pool
	err = SetMirrorMode(ioctx, MirrorModeImage)
	require.NoError(t, err)

	imgName := GetUUID()
	options := NewRbdImageOptions()
	assert.NoError(t, options.SetUint64(ImageOptionOrder, uint64(testImageOrder)))
	err = CreateImage(ioctx, imgName, testImageSize, options)
	require.NoError(t, err)

	t.Run("closedImage", func(t *testing.T) {
		img := GetImage(ioctx, imgName)
		_, err = img.GetMirrorImageInfo()
		assert.Error(t, err)
	})

	t.Run("getInfo", func(t *testing.T) {
		// open image, enable, mirroring.
		img, err := OpenImage(ioctx, imgName, NoSnapshot)
		assert.NoError(t, err)
		defer func() {
			assert.NoError(t, img.Close())
		}()

		err = img.MirrorEnable(ImageMirrorModeSnapshot)
		assert.NoError(t, err)
		mii, err := img.GetMirrorImageInfo()
		assert.NoError(t, err)
		assert.NotNil(t, mii.GlobalID)
		assert.Equal(t, mii.State, MirrorImageEnabled)
		assert.Equal(t, mii.Primary, true)
	})
}

func TestMirrorConstantStrings(t *testing.T) {
	x := []struct {
		s fmt.Stringer
		t string
	}{
		{MirrorModeDisabled, "disabled"},
		{MirrorModeImage, "image"},
		{MirrorModePool, "pool"},
		{MirrorMode(9999), "<unknown>"},
		{ImageMirrorModeJournal, "journal"},
		{ImageMirrorModeSnapshot, "snapshot"},
		{ImageMirrorMode(9999), "<unknown>"},
		{MirrorImageDisabling, "disabling"},
		{MirrorImageEnabled, "enabled"},
		{MirrorImageDisabled, "disabled"},
		{MirrorImageState(9999), "<unknown>"},
	}
	for _, v := range x {
		assert.Equal(t, v.s.String(), v.t)
	}
}

func TestGetGlobalMirrorStatus(t *testing.T) {
	conn := radosConnect(t)
	poolName := GetUUID()
	err := conn.MakePool(poolName)
	require.NoError(t, err)
	defer func() {
		assert.NoError(t, conn.DeletePool(poolName))
		conn.Shutdown()
	}()

	ioctx, err := conn.OpenIOContext(poolName)
	assert.NoError(t, err)
	defer func() {
		ioctx.Destroy()
	}()

	// enable per-image mirroring for this pool
	err = SetMirrorMode(ioctx, MirrorModeImage)
	require.NoError(t, err)

	imgName := GetUUID()
	options := NewRbdImageOptions()
	assert.NoError(t, options.SetUint64(ImageOptionOrder, uint64(testImageOrder)))
	err = CreateImage(ioctx, imgName, testImageSize, options)
	require.NoError(t, err)

	t.Run("closedImage", func(t *testing.T) {
		img := GetImage(ioctx, imgName)
		_, err = img.GetGlobalMirrorStatus()
		assert.Error(t, err)
	})

	t.Run("getStatus", func(t *testing.T) {
		// open image, enable, mirroring.
		img, err := OpenImage(ioctx, imgName, NoSnapshot)
		assert.NoError(t, err)
		defer func() {
			assert.NoError(t, img.Close())
		}()

		err = img.MirrorEnable(ImageMirrorModeSnapshot)
		assert.NoError(t, err)
		gms, err := img.GetGlobalMirrorStatus()
		assert.NoError(t, err)
		assert.NotEqual(t, "", gms.Name)
		assert.NotEqual(t, "", gms.Info.GlobalID)
		assert.Equal(t, gms.Info.State, MirrorImageEnabled)
		assert.Equal(t, gms.Info.Primary, true)
		if assert.Len(t, gms.SiteStatuses, 1) {
			ss := gms.SiteStatuses[0]
			assert.Equal(t, "", ss.MirrorUUID)
			assert.Equal(t, MirrorImageStatusStateUnknown, ss.State, ss.State)
			assert.Equal(t, "status not found", ss.Description)
			assert.Equal(t, int64(0), ss.LastUpdate)
			assert.False(t, ss.Up)
			ls, err := gms.LocalStatus()
			assert.NoError(t, err)
			assert.Equal(t, ss, ls)
		}
	})
}

func mirrorConfig() string {
	return os.Getenv("MIRROR_CONF")
}

func TestGetGlobalMirrorStatusMirroredPool(t *testing.T) {
	mconfig := mirrorConfig()
	if mconfig == "" {
		t.Skip("no mirror config env var set")
	}
	conn := radosConnect(t)
	// this test assumes the rbd pool already exists and is mirrored
	// this must be set up previously by the CI or manually
	poolName := "rbd"

	ioctx, err := conn.OpenIOContext(poolName)
	assert.NoError(t, err)
	defer func() {
		ioctx.Destroy()
	}()

	imgName := GetUUID()
	options := NewRbdImageOptions()
	assert.NoError(t, options.SetUint64(ImageOptionOrder, uint64(testImageOrder)))
	err = CreateImage(ioctx, imgName, testImageSize, options)
	require.NoError(t, err)

	defer func() {
		err = RemoveImage(ioctx, imgName)
		assert.NoError(t, err)
	}()

	// this next section is not a t.Run because it must be unconditionally
	// executed. It is wrapped in a func to use defer to close the img.
	func() {
		img, err := OpenImage(ioctx, imgName, NoSnapshot)
		assert.NoError(t, err)
		defer func() {
			assert.NoError(t, img.Close())
		}()

		err = img.MirrorEnable(ImageMirrorModeSnapshot)
		assert.NoError(t, err)

		mid, err := img.CreateMirrorSnapshot()
		assert.NoError(t, err)
		assert.NotEqual(t, 0, mid)

		// wait for site statuses to get updated
		for i := 0; i < 30; i++ {
			gms, err := img.GetGlobalMirrorStatus()
			assert.NoError(t, err)
			if len(gms.SiteStatuses) > 1 {
				break
			}
			time.Sleep(time.Second)
		}

		gms, err := img.GetGlobalMirrorStatus()
		assert.NoError(t, err)
		assert.NotEqual(t, "", gms.Name)
		assert.NotEqual(t, "", gms.Info.GlobalID)
		assert.Equal(t, gms.Info.State, MirrorImageEnabled)
		assert.Equal(t, gms.Info.Primary, true)
		if assert.Len(t, gms.SiteStatuses, 2) {
			ss1 := gms.SiteStatuses[0]
			assert.Equal(t, "", ss1.MirrorUUID)
			assert.Equal(t, MirrorImageStatusStateStopped, ss1.State, ss1.State)
			assert.Equal(t, "local image is primary", ss1.Description)
			assert.Greater(t, ss1.LastUpdate, int64(0))
			assert.True(t, ss1.Up)
			ls, err := gms.LocalStatus()
			assert.NoError(t, err)
			assert.Equal(t, ss1, ls)

			ss2 := gms.SiteStatuses[1]
			assert.NotEqual(t, "", ss2.MirrorUUID)
			assert.Equal(t, MirrorImageStatusStateReplaying, ss2.State, ss2.State)
			assert.Contains(t, ss2.Description, "replaying,")
			assert.Greater(t, ss2.LastUpdate, int64(0))
			assert.True(t, ss2.Up)
		}
	}()

	// test the results of GetGlobalMirrorStatus using the "other"
	// mirror+pool as a source
	t.Run("fromMirror", func(t *testing.T) {
		conn := radosConnectConfig(t, mconfig)
		ioctx2, err := conn.OpenIOContext(poolName)
		assert.NoError(t, err)
		defer func() {
			ioctx2.Destroy()
		}()

		img, err := OpenImage(ioctx2, imgName, NoSnapshot)
		assert.NoError(t, err)
		defer func() {
			assert.NoError(t, img.Close())
		}()

		// wait for site statuses to get updated
		for i := 0; i < 30; i++ {
			gms, err := img.GetGlobalMirrorStatus()
			assert.NoError(t, err)
			if len(gms.SiteStatuses) > 1 {
				break
			}
			time.Sleep(time.Second)
		}

		gms, err := img.GetGlobalMirrorStatus()
		assert.NoError(t, err)
		assert.NotEqual(t, "", gms.Name)
		assert.NotEqual(t, "", gms.Info.GlobalID)
		assert.Equal(t, gms.Info.State, MirrorImageEnabled)
		assert.Equal(t, gms.Info.Primary, false)
		if assert.Len(t, gms.SiteStatuses, 2) {
			ls, err := gms.LocalStatus()
			assert.NoError(t, err)
			assert.Equal(t, "", ls.MirrorUUID)
			assert.Equal(t, MirrorImageStatusStateReplaying, ls.State, ls.State)
			assert.Contains(t, ls.Description, "replaying,")
			assert.Greater(t, ls.LastUpdate, int64(0))
			assert.True(t, ls.Up)

			assert.Equal(t, ls, gms.SiteStatuses[0])

			ss2 := gms.SiteStatuses[1]
			assert.NotEqual(t, "", ss2.MirrorUUID)
			assert.Equal(t, MirrorImageStatusStateStopped, ss2.State, ss2.State)

			assert.Equal(t, "local image is primary", ss2.Description)
			assert.Greater(t, ss2.LastUpdate, int64(0))
			assert.True(t, ss2.Up)
		}
	})
}
<|endoftext|>


<commit_before>package flatmap

type Map map[string]string
<commit_msg>flatmap: remove Map for now<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2020 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package atomic

import (
	"math"
	"strconv"
)

//go:generate bin/gen-atomicwrapper -name=Float64 -type=float64 -wrapped=Uint64 -pack=math.Float64bits -unpack=math.Float64frombits -swap -json -imports math -file=float64.go

// Add atomically adds to the wrapped float64 and returns the new value.
func (f *Float64) Add(delta float64) float64 {
	for {
		old := f.Load()
		new := old + delta
		if f.CAS(old, new) {
			return new
		}
	}
}

// Sub atomically subtracts from the wrapped float64 and returns the new value.
func (f *Float64) Sub(delta float64) float64 {
	return f.Add(-delta)
}

// CAS is an atomic compare-and-swap for float64 values.
//
// Note: CAS handles NaN incorrectly. NaN != NaN using Go's inbuilt operators
// but CAS allows a stored NaN to compare equal to a passed in NaN.
// This avoids typical CAS loops from blocking forever, e.g.,
//
//   for {
//     old := atom.Load()
//     new = f(old)
//     if atom.CAS(old, new) {
//       break
//     }
//   }
//
// If CAS did not match NaN to match, then the above would loop forever.
func (x *Float64) CAS(old, new float64) (swapped bool) {
	return x.v.CAS(math.Float64bits(old), math.Float64bits(new))
}

// String encodes the wrapped value as a string.
func (f *Float64) String() string {
	// 'g' is the behavior for floats with %v.
	return strconv.FormatFloat(f.Load(), 'g', -1, 64)
}
<commit_msg>Fix lint error on float64_ext.go (#97)<commit_after>// Copyright (c) 2020 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package atomic

import (
	"math"
	"strconv"
)

//go:generate bin/gen-atomicwrapper -name=Float64 -type=float64 -wrapped=Uint64 -pack=math.Float64bits -unpack=math.Float64frombits -swap -json -imports math -file=float64.go

// Add atomically adds to the wrapped float64 and returns the new value.
func (f *Float64) Add(delta float64) float64 {
	for {
		old := f.Load()
		new := old + delta
		if f.CAS(old, new) {
			return new
		}
	}
}

// Sub atomically subtracts from the wrapped float64 and returns the new value.
func (f *Float64) Sub(delta float64) float64 {
	return f.Add(-delta)
}

// CAS is an atomic compare-and-swap for float64 values.
//
// Note: CAS handles NaN incorrectly. NaN != NaN using Go's inbuilt operators
// but CAS allows a stored NaN to compare equal to a passed in NaN.
// This avoids typical CAS loops from blocking forever, e.g.,
//
//   for {
//     old := atom.Load()
//     new = f(old)
//     if atom.CAS(old, new) {
//       break
//     }
//   }
//
// If CAS did not match NaN to match, then the above would loop forever.
func (f *Float64) CAS(old, new float64) (swapped bool) {
	return f.v.CAS(math.Float64bits(old), math.Float64bits(new))
}

// String encodes the wrapped value as a string.
func (f *Float64) String() string {
	// 'g' is the behavior for floats with %v.
	return strconv.FormatFloat(f.Load(), 'g', -1, 64)
}
<|endoftext|>