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

package oracle

import (
	"strings"

	"github.com/juju/errors"
	oci "github.com/juju/go-oracle-cloud/api"
	"github.com/juju/juju/constraints"
	"github.com/juju/juju/environs/imagemetadata"
	"github.com/juju/juju/environs/instances"
)

func getInstanceTypes(c *oci.Client) ([]instances.InstanceType, error) {
	if c == nil {
		return nil, errors.Errorf("cannot use nil client")
	}

	// make api request to oracle cloud to give us a list of
	// all supported shapes
	shapes, err := c.AllShapes(nil)
	if err != nil {
		return nil, errors.Trace(err)
	}

	// so let's transform these into juju complaint
	// instance types
	onlyArch := []string{"amd64"}
	types := make([]instances.InstanceType, len(shapes.Result), len(shapes.Result))
	for key, val := range shapes.Result {
		types[key].Name = val.Name
		types[key].Arches = onlyArch
		types[key].Mem = val.Ram
		types[key].CpuCores = uint64(val.Cpus)
		types[key].RootDisk = val.Root_disk_size
	}

	return types, nil
}

// findInstanceSpec returns an *InstanceSpec, imagelist name
// satisfying the supplied instanceConstraint
func findInstanceSpec(
	c *oci.Client,
	allImageMetadata []*imagemetadata.ImageMetadata,
	instanceType []instances.InstanceType,
	ic *instances.InstanceConstraint,
) (*instances.InstanceSpec, string, error) {

	logger.Debugf("recived %d image(s)", len(allImageMetadata))

	images := instances.ImageMetadataToImages(allImageMetadata)
	spec, err := instances.FindInstanceSpec(images, ic, instanceType)
	if err != nil {
		return nil, "", errors.Trace(err)
	}

	imagelist, err := getImageName(c, spec.Image.Id)
	if err != nil {
		return nil, "", errors.Trace(err)
	}

	return spec, imagelist, nil
}

// checkImageList creates image metadata from the oracle image list
func checkImageList(
	c *oci.Client,
	cons constraints.Value,
) ([]*imagemetadata.ImageMetadata, error) {

	if c == nil {
		return nil, errors.NotFoundf("oracle client")
	}

	// take a list of all images that are in the oracle cloud account
	resp, err := c.AllImageLists(nil)
	if err != nil {
		return nil, errors.Trace(err)
	}

	// if we don't have any images that are in
	// the oracle cloud account under your username namespace
	// we should let the user know this
	if resp.Result == nil {
		return nil, errors.NotFoundf(
			"iamges under the current client username are",
		)
	}

	images := make([]*imagemetadata.ImageMetadata, 0, len(resp.Result))
	for _, val := range resp.Result {
		list := strings.Split(val.Uri, "/")
		//TODO: parse windows images as well
		//TODO: we expect images to be named in the following format:
		// OS.version.ARCH.timestamp
		// This may fail miserably, and may be an assumption that will not hold
		// in the future. Use simplestreams instead?
		meta := strings.Split(list[len(list)-1], ".")
		if len(meta) < 4 {
			continue
		}

		endpoint := strings.Split(list[2], ".")
		images = append(images, &imagemetadata.ImageMetadata{
			Id:         meta[len(meta)-1],
			Arch:       meta[3],
			Endpoint:   "https://" + list[2],
			RegionName: endpoint[2],
			Version:    meta[1] + "." + meta[2],
		})
	}

	return images, nil
}

// based on the id from the imagemetadata extract only the name of the image
func getImageName(c *oci.Client, id string) (string, error) {
	if id == "" {
		return "", errors.NotFoundf("empty id")
	}

	resp, err := c.AllImageLists(nil)
	if err != nil {
		return "", errors.Trace(err)
	}

	// if we don't have any images that are in
	// the oracle cloud account under your username namespace
	// we should let the user know this
	if resp.Result == nil {
		return "", errors.NotFoundf(
			"iamges under the current client username are",
		)
	}

	for _, val := range resp.Result {
		if strings.Contains(val.Name, id) {
			s := strings.Split(val.Name, "/")
			return s[len(s)-1], nil
		}
	}

	return "", errors.NotFoundf("images found with the id provided are ")
}
<commit_msg>Fix if stmt<commit_after>// Copyright 2017 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package oracle

import (
	"strings"

	"github.com/juju/errors"
	oci "github.com/juju/go-oracle-cloud/api"
	"github.com/juju/juju/constraints"
	"github.com/juju/juju/environs/imagemetadata"
	"github.com/juju/juju/environs/instances"
)

func getInstanceTypes(c *oci.Client) ([]instances.InstanceType, error) {
	if c == nil {
		return nil, errors.Errorf("cannot use nil client")
	}

	// make api request to oracle cloud to give us a list of
	// all supported shapes
	shapes, err := c.AllShapes(nil)
	if err != nil {
		return nil, errors.Trace(err)
	}

	// so let's transform these into juju complaint
	// instance types
	onlyArch := []string{"amd64"}
	types := make([]instances.InstanceType, len(shapes.Result), len(shapes.Result))
	for key, val := range shapes.Result {
		types[key].Name = val.Name
		types[key].Arches = onlyArch
		types[key].Mem = val.Ram
		types[key].CpuCores = uint64(val.Cpus)
		types[key].RootDisk = val.Root_disk_size
	}

	return types, nil
}

// findInstanceSpec returns an *InstanceSpec, imagelist name
// satisfying the supplied instanceConstraint
func findInstanceSpec(
	c *oci.Client,
	allImageMetadata []*imagemetadata.ImageMetadata,
	instanceType []instances.InstanceType,
	ic *instances.InstanceConstraint,
) (*instances.InstanceSpec, string, error) {

	logger.Debugf("recived %d image(s)", len(allImageMetadata))

	images := instances.ImageMetadataToImages(allImageMetadata)
	spec, err := instances.FindInstanceSpec(images, ic, instanceType)
	if err != nil {
		return nil, "", errors.Trace(err)
	}

	imagelist, err := getImageName(c, spec.Image.Id)
	if err != nil {
		return nil, "", errors.Trace(err)
	}

	return spec, imagelist, nil
}

// checkImageList creates image metadata from the oracle image list
func checkImageList(
	c *oci.Client,
	cons constraints.Value,
) ([]*imagemetadata.ImageMetadata, error) {

	if c == nil {
		return nil, errors.NotFoundf("oracle client")
	}

	// take a list of all images that are in the oracle cloud account
	resp, err := c.AllImageLists(nil)
	if err != nil {
		return nil, errors.Trace(err)
	}

	// if we don't have any images that are in
	// the oracle cloud account under your username namespace
	// we should let the user know this
	n := len(resp.Result)
	if n == 0 {
		return nil, errors.NotFoundf(
			"iamges under the current client username are",
		)
	}

	images := make([]*imagemetadata.ImageMetadata, 0, n)
	for _, val := range resp.Result {
		list := strings.Split(val.Uri, "/")
		//TODO: parse windows images as well
		//TODO: we expect images to be named in the following format:
		// OS.version.ARCH.timestamp
		// This may fail miserably, and may be an assumption that will not hold
		// in the future. Use simplestreams instead?
		meta := strings.Split(list[len(list)-1], ".")
		if len(meta) < 4 {
			continue
		}

		endpoint := strings.Split(list[2], ".")
		images = append(images, &imagemetadata.ImageMetadata{
			Id:         meta[len(meta)-1],
			Arch:       meta[3],
			Endpoint:   "https://" + list[2],
			RegionName: endpoint[2],
			Version:    meta[1] + "." + meta[2],
		})
	}

	return images, nil
}

// based on the id from the imagemetadata extract only the name of the image
func getImageName(c *oci.Client, id string) (string, error) {
	if id == "" {
		return "", errors.NotFoundf("empty id")
	}

	resp, err := c.AllImageLists(nil)
	if err != nil {
		return "", errors.Trace(err)
	}

	// if we don't have any images that are in
	// the oracle cloud account under your username namespace
	// we should let the user know this
	if resp.Result == nil {
		return "", errors.NotFoundf(
			"iamges under the current client username are",
		)
	}

	for _, val := range resp.Result {
		if strings.Contains(val.Name, id) {
			s := strings.Split(val.Name, "/")
			return s[len(s)-1], nil
		}
	}

	return "", errors.NotFoundf("images found with the id provided are ")
}
<|endoftext|>


<commit_before><commit_msg>close merger reader despite errors. (#3589)<commit_after><|endoftext|>


<commit_before>//
// Copyright (c) 2014 Juniper Networks, Inc. All rights reserved.
//

package config

import (
	"fmt"
	"net"
	"regexp"
	"strconv"
	"strings"

	"github.com/Juniper/contrail-go-api"
	"github.com/Juniper/contrail-go-api/types"
)

type NetworkInfo struct {
	Uuid         string
	Name         string
	AdminState   bool
	NetworkId    int
	Transit      bool
	Mode         string
	Subnets      []string
	Policies     []string
	RouteTargets []string
}

func buildNetworkInfo(net *types.VirtualNetwork, detail bool) (
	*NetworkInfo, error) {
	var subnets []string
	var policies []string

	refList, err := net.GetNetworkIpamRefs()
	if err != nil {
		return nil, err
	}

	for _, ref := range refList {
		attr := ref.Attr.(types.VnSubnetsType)
		for _, ipamSubnet := range attr.IpamSubnets {
			subnets = append(subnets, fmt.Sprintf("%s/%d",
				ipamSubnet.Subnet.IpPrefix,
				ipamSubnet.Subnet.IpPrefixLen))
		}
	}

	if detail {
		refList, err = net.GetNetworkPolicyRefs()
		for _, ref := range refList {
			policies = append(policies, strings.Join(ref.To, ":"))
		}
	}

	info := &NetworkInfo{
		net.GetUuid(),
		net.GetName(),
		net.GetIdPerms().Enable,
		net.GetVirtualNetworkProperties().NetworkId,
		net.GetVirtualNetworkProperties().AllowTransit,
		net.GetVirtualNetworkProperties().ForwardingMode,
		subnets,
		policies,
		net.GetRouteTargetList().RouteTarget,
	}
	return info, err
}

func NetworkShow(client contrail.ApiClient, uuid string, detail bool) (
	*NetworkInfo, error) {
	obj, err := client.FindByUuid("virtual-network", uuid)
	if err != nil {
		return nil, err
	}
	return buildNetworkInfo(obj.(*types.VirtualNetwork), detail)
}

func NetworkList(client contrail.ApiClient, project_id string, detail bool) (
	[]*NetworkInfo, error) {
	fields := []string{"network_ipams"}
	if detail {
		fields = append(fields, "network_policys")
	}
	networks, err := client.ListDetailByParent(
		"virtual-network", project_id, fields)
	if err != nil {
		return nil, err
	}

	var networkList []*NetworkInfo
	for _, reference := range networks {
		info, err := buildNetworkInfo(
			reference.(*types.VirtualNetwork), detail)
		if err != nil {
			return nil, err
		}
		networkList = append(networkList, info)
	}

	return networkList, nil
}

func makeSubnet(prefix string) (*types.IpamSubnetType, error) {
	expr := regexp.MustCompile(`(([0-9]{1,3}\.){3}[0-9]{1,3})/([0-9]{1,2})`)
	match := expr.FindStringSubmatch(prefix)
	if match == nil {
		return nil, fmt.Errorf("Invalid subnet prefix %s", prefix)
	}
	address := match[1]
	if net.ParseIP(address) == nil {
		return nil, fmt.Errorf("%s is not a valid IP address", address)
	}
	prefixlen, _ := strconv.Atoi(match[3])
	if prefixlen < 0 || prefixlen > 32 {
		return nil, fmt.Errorf("Invalid subnet prefix length %d", prefixlen)
	}

	subnet := &types.IpamSubnetType{
		Subnet: &types.SubnetType{address, prefixlen}}
	return subnet, nil
}

func networkAddSubnet(
	client contrail.ApiClient,
	project *types.Project, network *types.VirtualNetwork,
	subnet *types.IpamSubnetType,
	ipam *types.NetworkIpam) error {

	if ipam != nil {
		obj, err := client.FindByUuid("network-ipam", ipam.GetUuid())
		if err != nil {
			return err
		}
		ipam = obj.(*types.NetworkIpam)
	} else {
		obj, err := client.FindByName("network-ipam",
			"default-domain:default-project:default-network-ipam")
		if err != nil {
			return err
		}
		ipam = obj.(*types.NetworkIpam)
	}

	refs, err := network.GetNetworkIpamRefs()
	if err != nil {
		return err
	}

	var subnets types.VnSubnetsType

	for _, ref := range refs {
		if ref.Uuid == ipam.GetUuid() {
			subnets = ref.Attr.(types.VnSubnetsType)
			network.DeleteNetworkIpam(ref.Uuid)
			break
		}
	}
	subnets.AddIpamSubnets(subnet)
	network.AddNetworkIpam(ipam, subnets)
	return nil
}

func CreateNetworkWithSubnet(
client contrail.ApiClient, project_id, name, prefix string) (
string, error) {

	obj, err := client.FindByUuid("project", project_id)
	if err != nil {
		return "", err
	}

	project := obj.(*types.Project)

	net := new(types.VirtualNetwork)
	net.SetParent(project)
	net.SetName(name)

	subnet, err := makeSubnet(prefix)
	if err != nil {
		return "", err
	}
	err = networkAddSubnet(client, project, net, subnet, nil)
	if err != nil {
		return "", err
	}

	err = client.Create(net)
	if err != nil {
		return "", err
	}
	return net.GetUuid(), nil
}

func CreateNetworkWithIpam(
	client contrail.ApiClient, project_id, name, prefix string, ipam *types.NetworkIpam) (
	string, error) {

	obj, err := client.FindByUuid("project", project_id)
	if err != nil {
		return "", err
	}

	project := obj.(*types.Project)

	net := new(types.VirtualNetwork)
	net.SetParent(project)
	net.SetName(name)

	subnet, err := makeSubnet(prefix)
	if err != nil {
		return "", err
	}
	err = networkAddSubnet(client, project, net, subnet, ipam)
	if err != nil {
		return "", err
	}

	err = client.Create(net)
	if err != nil {
		return "", err
	}
	return net.GetUuid(), nil
}

// AddSubnet
// returns true if the network was modified, false if the subnet already exists
// in the network.
func AddSubnet(
	client contrail.ApiClient, network *types.VirtualNetwork, prefix string) (
	bool, error) {

	ipamRefs, err := network.GetNetworkIpamRefs()
	if err != nil {
		return false, err
	}
	subnet, err := makeSubnet(prefix)
	if err != nil {
		return false, err
	}
	for _, ref := range ipamRefs {
		attr := ref.Attr.(types.VnSubnetsType)
		for _, entry := range attr.IpamSubnets {
			if *subnet.Subnet == *entry.Subnet {
				return false, nil
			}
		}
	}

	fqn := network.GetFQName()
	project, err := types.ProjectByName(client, strings.Join(fqn[:len(fqn)-1], ":"))
	if err != nil {
		return false, err
	}
	err = networkAddSubnet(client, project, network, subnet, nil)
	if err != nil {
		return false, err
	}
	err = client.Update(network)
	if err != nil {
		return false, err
	}
	return true, nil
}

func subnetTypeStringRepr(subnet *types.SubnetType) string {
	return fmt.Sprintf("%s/%d", subnet.IpPrefix, subnet.IpPrefixLen)
}

func RemoveSubnet(client contrail.ApiClient, network *types.VirtualNetwork, prefix string) error {
	ipamRefs, err := network.GetNetworkIpamRefs()
	if err != nil {
		return err
	}

	removeOp := func(ix int, uuid string, attr types.VnSubnetsType) error {
		ipam, err := types.NetworkIpamByUuid(client, uuid)
		if err != nil {
			return err
		}
		attr.IpamSubnets = append(attr.IpamSubnets[0:ix], attr.IpamSubnets[ix+1:]...)
		network.DeleteNetworkIpam(uuid)
		if len(attr.IpamSubnets) > 0 {
			network.AddNetworkIpam(ipam, attr)
		}
		return client.Update(network)
	}

	for _, ref := range ipamRefs {
		attr := ref.Attr.(types.VnSubnetsType)
		for ix, entry := range attr.IpamSubnets {
			entryPrefix := subnetTypeStringRepr(entry.Subnet)
			if entryPrefix == prefix {
				return removeOp(ix, ref.Uuid, attr)
			}
		}
	}

	return fmt.Errorf("Prefix %s not associated with network %s", prefix, network.GetName())
}

func CreateNetwork(client contrail.ApiClient, project_id, name string) (
	string, error) {

	obj, err := client.FindByUuid("project", project_id)
	if err != nil {
		return "", err
	}

	project := obj.(*types.Project)

	net := new(types.VirtualNetwork)
	net.SetParent(project)
	net.SetName(name)

	err = client.Create(net)
	if err != nil {
		return "", err
	}
	return net.GetUuid(), nil
}
<commit_msg>Remove redundant project lookup<commit_after>//
// Copyright (c) 2014 Juniper Networks, Inc. All rights reserved.
//

package config

import (
	"fmt"
	"net"
	"regexp"
	"strconv"
	"strings"

	"github.com/Juniper/contrail-go-api"
	"github.com/Juniper/contrail-go-api/types"
)

type NetworkInfo struct {
	Uuid         string
	Name         string
	AdminState   bool
	NetworkId    int
	Transit      bool
	Mode         string
	Subnets      []string
	Policies     []string
	RouteTargets []string
}

func buildNetworkInfo(net *types.VirtualNetwork, detail bool) (
	*NetworkInfo, error) {
	var subnets []string
	var policies []string

	refList, err := net.GetNetworkIpamRefs()
	if err != nil {
		return nil, err
	}

	for _, ref := range refList {
		attr := ref.Attr.(types.VnSubnetsType)
		for _, ipamSubnet := range attr.IpamSubnets {
			subnets = append(subnets, fmt.Sprintf("%s/%d",
				ipamSubnet.Subnet.IpPrefix,
				ipamSubnet.Subnet.IpPrefixLen))
		}
	}

	if detail {
		refList, err = net.GetNetworkPolicyRefs()
		for _, ref := range refList {
			policies = append(policies, strings.Join(ref.To, ":"))
		}
	}

	info := &NetworkInfo{
		net.GetUuid(),
		net.GetName(),
		net.GetIdPerms().Enable,
		net.GetVirtualNetworkProperties().NetworkId,
		net.GetVirtualNetworkProperties().AllowTransit,
		net.GetVirtualNetworkProperties().ForwardingMode,
		subnets,
		policies,
		net.GetRouteTargetList().RouteTarget,
	}
	return info, err
}

func NetworkShow(client contrail.ApiClient, uuid string, detail bool) (
	*NetworkInfo, error) {
	obj, err := client.FindByUuid("virtual-network", uuid)
	if err != nil {
		return nil, err
	}
	return buildNetworkInfo(obj.(*types.VirtualNetwork), detail)
}

func NetworkList(client contrail.ApiClient, project_id string, detail bool) (
	[]*NetworkInfo, error) {
	fields := []string{"network_ipams"}
	if detail {
		fields = append(fields, "network_policys")
	}
	networks, err := client.ListDetailByParent(
		"virtual-network", project_id, fields)
	if err != nil {
		return nil, err
	}

	var networkList []*NetworkInfo
	for _, reference := range networks {
		info, err := buildNetworkInfo(
			reference.(*types.VirtualNetwork), detail)
		if err != nil {
			return nil, err
		}
		networkList = append(networkList, info)
	}

	return networkList, nil
}

func makeSubnet(prefix string) (*types.IpamSubnetType, error) {
	expr := regexp.MustCompile(`(([0-9]{1,3}\.){3}[0-9]{1,3})/([0-9]{1,2})`)
	match := expr.FindStringSubmatch(prefix)
	if match == nil {
		return nil, fmt.Errorf("Invalid subnet prefix %s", prefix)
	}
	address := match[1]
	if net.ParseIP(address) == nil {
		return nil, fmt.Errorf("%s is not a valid IP address", address)
	}
	prefixlen, _ := strconv.Atoi(match[3])
	if prefixlen < 0 || prefixlen > 32 {
		return nil, fmt.Errorf("Invalid subnet prefix length %d", prefixlen)
	}

	subnet := &types.IpamSubnetType{
		Subnet: &types.SubnetType{address, prefixlen}}
	return subnet, nil
}

func networkAddSubnet(
	client contrail.ApiClient,
	project *types.Project, network *types.VirtualNetwork,
	subnet *types.IpamSubnetType,
	ipam *types.NetworkIpam) error {

	if ipam != nil {
		obj, err := client.FindByUuid("network-ipam", ipam.GetUuid())
		if err != nil {
			return err
		}
		ipam = obj.(*types.NetworkIpam)
	} else {
		obj, err := client.FindByName("network-ipam",
			"default-domain:default-project:default-network-ipam")
		if err != nil {
			return err
		}
		ipam = obj.(*types.NetworkIpam)
	}

	refs, err := network.GetNetworkIpamRefs()
	if err != nil {
		return err
	}

	var subnets types.VnSubnetsType

	for _, ref := range refs {
		if ref.Uuid == ipam.GetUuid() {
			subnets = ref.Attr.(types.VnSubnetsType)
			network.DeleteNetworkIpam(ref.Uuid)
			break
		}
	}
	subnets.AddIpamSubnets(subnet)
	network.AddNetworkIpam(ipam, subnets)
	return nil
}

func CreateNetworkWithSubnet(
client contrail.ApiClient, project_id, name, prefix string) (
string, error) {

	obj, err := client.FindByUuid("project", project_id)
	if err != nil {
		return "", err
	}

	project := obj.(*types.Project)

	net := new(types.VirtualNetwork)
	net.SetParent(project)
	net.SetName(name)

	subnet, err := makeSubnet(prefix)
	if err != nil {
		return "", err
	}
	err = networkAddSubnet(client, project, net, subnet, nil)
	if err != nil {
		return "", err
	}

	err = client.Create(net)
	if err != nil {
		return "", err
	}
	return net.GetUuid(), nil
}

func CreateNetworkWithIpam(
	client contrail.ApiClient, project *types.Project, name, prefix string, ipam *types.NetworkIpam) (
	string, error) {

	net := new(types.VirtualNetwork)
	net.SetParent(project)
	net.SetName(name)

	subnet, err := makeSubnet(prefix)
	if err != nil {
		return "", err
	}
	err = networkAddSubnet(client, project, net, subnet, ipam)
	if err != nil {
		return "", err
	}

	err = client.Create(net)
	if err != nil {
		return "", err
	}
	return net.GetUuid(), nil
}

// AddSubnet
// returns true if the network was modified, false if the subnet already exists
// in the network.
func AddSubnet(
	client contrail.ApiClient, network *types.VirtualNetwork, prefix string) (
	bool, error) {

	ipamRefs, err := network.GetNetworkIpamRefs()
	if err != nil {
		return false, err
	}
	subnet, err := makeSubnet(prefix)
	if err != nil {
		return false, err
	}
	for _, ref := range ipamRefs {
		attr := ref.Attr.(types.VnSubnetsType)
		for _, entry := range attr.IpamSubnets {
			if *subnet.Subnet == *entry.Subnet {
				return false, nil
			}
		}
	}

	fqn := network.GetFQName()
	project, err := types.ProjectByName(client, strings.Join(fqn[:len(fqn)-1], ":"))
	if err != nil {
		return false, err
	}
	err = networkAddSubnet(client, project, network, subnet, nil)
	if err != nil {
		return false, err
	}
	err = client.Update(network)
	if err != nil {
		return false, err
	}
	return true, nil
}

func subnetTypeStringRepr(subnet *types.SubnetType) string {
	return fmt.Sprintf("%s/%d", subnet.IpPrefix, subnet.IpPrefixLen)
}

func RemoveSubnet(client contrail.ApiClient, network *types.VirtualNetwork, prefix string) error {
	ipamRefs, err := network.GetNetworkIpamRefs()
	if err != nil {
		return err
	}

	removeOp := func(ix int, uuid string, attr types.VnSubnetsType) error {
		ipam, err := types.NetworkIpamByUuid(client, uuid)
		if err != nil {
			return err
		}
		attr.IpamSubnets = append(attr.IpamSubnets[0:ix], attr.IpamSubnets[ix+1:]...)
		network.DeleteNetworkIpam(uuid)
		if len(attr.IpamSubnets) > 0 {
			network.AddNetworkIpam(ipam, attr)
		}
		return client.Update(network)
	}

	for _, ref := range ipamRefs {
		attr := ref.Attr.(types.VnSubnetsType)
		for ix, entry := range attr.IpamSubnets {
			entryPrefix := subnetTypeStringRepr(entry.Subnet)
			if entryPrefix == prefix {
				return removeOp(ix, ref.Uuid, attr)
			}
		}
	}

	return fmt.Errorf("Prefix %s not associated with network %s", prefix, network.GetName())
}

func CreateNetwork(client contrail.ApiClient, project_id, name string) (
	string, error) {

	obj, err := client.FindByUuid("project", project_id)
	if err != nil {
		return "", err
	}

	project := obj.(*types.Project)

	net := new(types.VirtualNetwork)
	net.SetParent(project)
	net.SetName(name)

	err = client.Create(net)
	if err != nil {
		return "", err
	}
	return net.GetUuid(), nil
}
<|endoftext|>


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

package redis

import (
	"errors"
	"fmt"
	"strconv"
)

// ErrNil indicates that a reply value is nil.
var ErrNil = errors.New("redigo: nil returned")

// Int is a helper that converts a command reply to an integer. If err is not
// equal to nil, then Int returns 0, err. Otherwise, Int converts the
// reply to an int as follows:
//
//  Reply type    Result
//  integer       int(reply), nil
//  bulk          parsed reply, nil
//  nil           0, ErrNil
//  other         0, error
func Int(reply interface{}, err error) (int, error) {
	if err != nil {
		return 0, err
	}
	switch reply := reply.(type) {
	case int64:
		x := int(reply)
		if int64(x) != reply {
			return 0, strconv.ErrRange
		}
		return x, nil
	case []byte:
		n, err := strconv.ParseInt(string(reply), 10, 0)
		return int(n), err
	case nil:
		return 0, ErrNil
	case Error:
		return 0, reply
	}
	return 0, fmt.Errorf("redigo: unexpected type for Int, got type %T", reply)
}

// Int64 is a helper that converts a command reply to 64 bit integer. If err is
// not equal to nil, then Int returns 0, err. Otherwise, Int64 converts the
// reply to an int64 as follows:
//
//  Reply type    Result
//  integer       reply, nil
//  bulk          parsed reply, nil
//  nil           0, ErrNil
//  other         0, error
func Int64(reply interface{}, err error) (int64, error) {
	if err != nil {
		return 0, err
	}
	switch reply := reply.(type) {
	case int64:
		return reply, nil
	case []byte:
		n, err := strconv.ParseInt(string(reply), 10, 64)
		return n, err
	case nil:
		return 0, ErrNil
	case Error:
		return 0, reply
	}
	return 0, fmt.Errorf("redigo: unexpected type for Int64, got type %T", reply)
}

// Float64 is a helper that converts a command reply to 64 bit float. If err is
// not equal to nil, then Float64 returns 0, err. Otherwise, Float64 converts
// the reply to an int as follows:
//
//  Reply type    Result
//  bulk          parsed reply, nil
//  nil           0, ErrNil
//  other         0, error
func Float64(reply interface{}, err error) (float64, error) {
	if err != nil {
		return 0, err
	}
	switch reply := reply.(type) {
	case []byte:
		n, err := strconv.ParseFloat(string(reply), 64)
		return n, err
	case nil:
		return 0, ErrNil
	case Error:
		return 0, reply
	}
	return 0, fmt.Errorf("redigo: unexpected type for Float64, got type %T", reply)
}

// String is a helper that converts a command reply to a string. If err is not
// equal to nil, then String returns "", err. Otherwise String converts the
// reply to a string as follows:
//
//  Reply type      Result
//  bulk            string(reply), nil
//  string          reply, nil
//  nil             "",  ErrNil
//  other           "",  error
func String(reply interface{}, err error) (string, error) {
	if err != nil {
		return "", err
	}
	switch reply := reply.(type) {
	case []byte:
		return string(reply), nil
	case string:
		return reply, nil
	case nil:
		return "", ErrNil
	case Error:
		return "", reply
	}
	return "", fmt.Errorf("redigo: unexpected type for String, got type %T", reply)
}

// Bytes is a helper that converts a command reply to a slice of bytes. If err
// is not equal to nil, then Bytes returns nil, err. Otherwise Bytes converts
// the reply to a slice of bytes as follows:
//
//  Reply type      Result
//  bulk            reply, nil
//  string          []byte(reply), nil
//  nil             nil, ErrNil
//  other           nil, error
func Bytes(reply interface{}, err error) ([]byte, error) {
	if err != nil {
		return nil, err
	}
	switch reply := reply.(type) {
	case []byte:
		return reply, nil
	case string:
		return []byte(reply), nil
	case nil:
		return nil, ErrNil
	case Error:
		return nil, reply
	}
	return nil, fmt.Errorf("redigo: unexpected type for Bytes, got type %T", reply)
}

// Bool is a helper that converts a command reply to a boolean. If err is not
// equal to nil, then Bool returns false, err. Otherwise Bool converts the
// reply to boolean as follows:
//
//  Reply type      Result
//  integer         value != 0, nil
//  bulk            strconv.ParseBool(reply)
//  nil             false, ErrNil
//  other           false, error
func Bool(reply interface{}, err error) (bool, error) {
	if err != nil {
		return false, err
	}
	switch reply := reply.(type) {
	case int64:
		return reply != 0, nil
	case []byte:
		return strconv.ParseBool(string(reply))
	case nil:
		return false, ErrNil
	case Error:
		return false, reply
	}
	return false, fmt.Errorf("redigo: unexpected type for Bool, got type %T", reply)
}

// MultiBulk is deprecated. Use Values.
func MultiBulk(reply interface{}, err error) ([]interface{}, error) { return Values(reply, err) }

// Values is a helper that converts a multi-bulk command reply to a
// []interface{}. If err is not equal to nil, then Values returns nil, err.
// Otherwise, Multi converts the reply as follows:
//
//  Reply type      Result
//  multi-bulk      reply, nil
//  nil             nil, ErrNil
//  other           nil, error
func Values(reply interface{}, err error) ([]interface{}, error) {
	if err != nil {
		return nil, err
	}
	switch reply := reply.(type) {
	case []interface{}:
		return reply, nil
	case nil:
		return nil, ErrNil
	case Error:
		return nil, reply
	}
	return nil, fmt.Errorf("redigo: unexpected type for Values, got type %T", reply)
}

// Strings is a helper that converts a multi-bulk command reply to a []string.
// If err is not equal to nil, then Strings returns nil, err.  If one if the
// multi-bulk items is not a bulk value or nil, then Strings returns an error.
func Strings(reply interface{}, err error) ([]string, error) {
	if err != nil {
		return nil, err
	}
	switch reply := reply.(type) {
	case []interface{}:
		result := make([]string, len(reply))
		for i := range reply {
			if reply[i] == nil {
				continue
			}
			p, ok := reply[i].([]byte)
			if !ok {
				return nil, fmt.Errorf("redigo: unexpected element type for Strings, got type %T", reply[i])
			}
			result[i] = string(p)
		}
		return result, nil
	case nil:
		return nil, ErrNil
	case Error:
		return nil, reply
	}
	return nil, fmt.Errorf("redigo: unexpected type for Strings, got type %T", reply)
}
<commit_msg>fix documentation nits.<commit_after>// Copyright 2012 Gary Burd
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

package redis

import (
	"errors"
	"fmt"
	"strconv"
)

// ErrNil indicates that a reply value is nil.
var ErrNil = errors.New("redigo: nil returned")

// Int is a helper that converts a command reply to an integer. If err is not
// equal to nil, then Int returns 0, err. Otherwise, Int converts the
// reply to an int as follows:
//
//  Reply type    Result
//  integer       int(reply), nil
//  bulk          parsed reply, nil
//  nil           0, ErrNil
//  other         0, error
func Int(reply interface{}, err error) (int, error) {
	if err != nil {
		return 0, err
	}
	switch reply := reply.(type) {
	case int64:
		x := int(reply)
		if int64(x) != reply {
			return 0, strconv.ErrRange
		}
		return x, nil
	case []byte:
		n, err := strconv.ParseInt(string(reply), 10, 0)
		return int(n), err
	case nil:
		return 0, ErrNil
	case Error:
		return 0, reply
	}
	return 0, fmt.Errorf("redigo: unexpected type for Int, got type %T", reply)
}

// Int64 is a helper that converts a command reply to 64 bit integer. If err is
// not equal to nil, then Int returns 0, err. Otherwise, Int64 converts the
// reply to an int64 as follows:
//
//  Reply type    Result
//  integer       reply, nil
//  bulk          parsed reply, nil
//  nil           0, ErrNil
//  other         0, error
func Int64(reply interface{}, err error) (int64, error) {
	if err != nil {
		return 0, err
	}
	switch reply := reply.(type) {
	case int64:
		return reply, nil
	case []byte:
		n, err := strconv.ParseInt(string(reply), 10, 64)
		return n, err
	case nil:
		return 0, ErrNil
	case Error:
		return 0, reply
	}
	return 0, fmt.Errorf("redigo: unexpected type for Int64, got type %T", reply)
}

// Float64 is a helper that converts a command reply to 64 bit float. If err is
// not equal to nil, then Float64 returns 0, err. Otherwise, Float64 converts
// the reply to an int as follows:
//
//  Reply type    Result
//  bulk          parsed reply, nil
//  nil           0, ErrNil
//  other         0, error
func Float64(reply interface{}, err error) (float64, error) {
	if err != nil {
		return 0, err
	}
	switch reply := reply.(type) {
	case []byte:
		n, err := strconv.ParseFloat(string(reply), 64)
		return n, err
	case nil:
		return 0, ErrNil
	case Error:
		return 0, reply
	}
	return 0, fmt.Errorf("redigo: unexpected type for Float64, got type %T", reply)
}

// String is a helper that converts a command reply to a string. If err is not
// equal to nil, then String returns "", err. Otherwise String converts the
// reply to a string as follows:
//
//  Reply type      Result
//  bulk            string(reply), nil
//  status          reply, nil
//  nil             "",  ErrNil
//  other           "",  error
func String(reply interface{}, err error) (string, error) {
	if err != nil {
		return "", err
	}
	switch reply := reply.(type) {
	case []byte:
		return string(reply), nil
	case string:
		return reply, nil
	case nil:
		return "", ErrNil
	case Error:
		return "", reply
	}
	return "", fmt.Errorf("redigo: unexpected type for String, got type %T", reply)
}

// Bytes is a helper that converts a command reply to a slice of bytes. If err
// is not equal to nil, then Bytes returns nil, err. Otherwise Bytes converts
// the reply to a slice of bytes as follows:
//
//  Reply type      Result
//  bulk            reply, nil
//  status          []byte(reply), nil
//  nil             nil, ErrNil
//  other           nil, error
func Bytes(reply interface{}, err error) ([]byte, error) {
	if err != nil {
		return nil, err
	}
	switch reply := reply.(type) {
	case []byte:
		return reply, nil
	case string:
		return []byte(reply), nil
	case nil:
		return nil, ErrNil
	case Error:
		return nil, reply
	}
	return nil, fmt.Errorf("redigo: unexpected type for Bytes, got type %T", reply)
}

// Bool is a helper that converts a command reply to a boolean. If err is not
// equal to nil, then Bool returns false, err. Otherwise Bool converts the
// reply to boolean as follows:
//
//  Reply type      Result
//  integer         value != 0, nil
//  bulk            strconv.ParseBool(reply)
//  nil             false, ErrNil
//  other           false, error
func Bool(reply interface{}, err error) (bool, error) {
	if err != nil {
		return false, err
	}
	switch reply := reply.(type) {
	case int64:
		return reply != 0, nil
	case []byte:
		return strconv.ParseBool(string(reply))
	case nil:
		return false, ErrNil
	case Error:
		return false, reply
	}
	return false, fmt.Errorf("redigo: unexpected type for Bool, got type %T", reply)
}

// MultiBulk is deprecated. Use Values.
func MultiBulk(reply interface{}, err error) ([]interface{}, error) { return Values(reply, err) }

// Values is a helper that converts a multi-bulk command reply to a
// []interface{}. If err is not equal to nil, then Values returns nil, err.
// Otherwise, Multi converts the reply as follows:
//
//  Reply type      Result
//  multi-bulk      reply, nil
//  nil             nil, ErrNil
//  other           nil, error
func Values(reply interface{}, err error) ([]interface{}, error) {
	if err != nil {
		return nil, err
	}
	switch reply := reply.(type) {
	case []interface{}:
		return reply, nil
	case nil:
		return nil, ErrNil
	case Error:
		return nil, reply
	}
	return nil, fmt.Errorf("redigo: unexpected type for Values, got type %T", reply)
}

// Strings is a helper that converts a multi-bulk command reply to a []string.
// If err is not equal to nil, then Strings returns nil, err.  If one if the
// multi-bulk items is not a bulk value or nil, then Strings returns an error.
func Strings(reply interface{}, err error) ([]string, error) {
	if err != nil {
		return nil, err
	}
	switch reply := reply.(type) {
	case []interface{}:
		result := make([]string, len(reply))
		for i := range reply {
			if reply[i] == nil {
				continue
			}
			p, ok := reply[i].([]byte)
			if !ok {
				return nil, fmt.Errorf("redigo: unexpected element type for Strings, got type %T", reply[i])
			}
			result[i] = string(p)
		}
		return result, nil
	case nil:
		return nil, ErrNil
	case Error:
		return nil, reply
	}
	return nil, fmt.Errorf("redigo: unexpected type for Strings, got type %T", reply)
}
<|endoftext|>


<commit_before>/*
   Copyright (c) 2014, Percona LLC and/or its affiliates. All rights reserved.

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>
*/

package mysql

import (
	"encoding/json"
	"fmt"
	"github.com/percona/cloud-protocol/proto"
	"github.com/percona/percona-agent/instance"
	"github.com/percona/percona-agent/pct"
	"github.com/percona/percona-agent/pt/cmd"
)

const (
	SERVICE_NAME = "mysql"
)

type MySQL struct {
	logger *pct.Logger
	ir     *instance.Repo
}

func NewMySQL(logger *pct.Logger, ir *instance.Repo) *MySQL {
	return &MySQL{
		logger: logger,
		ir:     ir,
	}
}

/////////////////////////////////////////////////////////////////////////////
// Interface
/////////////////////////////////////////////////////////////////////////////

func (m *MySQL) Handle(protoCmd *proto.Cmd) *proto.Reply {
	// Get explain query
	serviceInstance, err := getServiceInstance(protoCmd)
	if err != nil {
		return protoCmd.Reply(nil, err)
	}

	// Load the MySQL instance info (DSN, name, etc.).
	mysqlIt := &proto.MySQLInstance{}
	if err = m.ir.Get(serviceInstance.Service, serviceInstance.InstanceId, mysqlIt); err != nil {
		return protoCmd.Reply(nil, err)
	}

	// @todo parsing DSN should be as a method on proto.MySQLInstance.DSN or at least it should be injected
	// Parse DSN to get user, pass, host, port, socket as separate fields
	dsn, err := NewDSN(mysqlIt.DSN)
	if err != nil {
		return protoCmd.Reply(nil, err)
	}

	// Create params for ptMySQLSummary
	args := []string{}
	if dsn.user != "" {
		args = append(args, "--user", dsn.user)
	}
	if dsn.passwd != "" {
		args = append(args, "--password", dsn.passwd)
	}
	if dsn.net == "unix" {
		args = append(args, "--socket", dsn.addr)
	} else {
		if dsn.addr != "" {
			args = append(args, "--host", dsn.addr)
		}
		if dsn.port != "" {
			args = append(args, "--port", dsn.port)
		}
	}

	// Run ptMySQLSummary with params
	ptMySQLSummary := cmd.New("pt-mysql-summary", args...)
	output, err := ptMySQLSummary.Run()
	if err != nil {
		m.logger.Error("pt-mysql-summary %s: %s", SERVICE_NAME, err)
	}

	return protoCmd.Reply(output, err)
}

/////////////////////////////////////////////////////////////////////////////
// Implementation
/////////////////////////////////////////////////////////////////////////////

func getServiceInstance(protoCmd *proto.Cmd) (serviceInstance *proto.ServiceInstance, err error) {
	if protoCmd.Data == nil {
		return nil, fmt.Errorf("%s.getMySQLInstance:cmd.Data is empty", SERVICE_NAME)
	}

	if err := json.Unmarshal(protoCmd.Data, &serviceInstance); err != nil {
		return nil, fmt.Errorf("%s.getMySQLInstance:json.Unmarshal:%s", SERVICE_NAME, err)
	}

	return serviceInstance, nil
}
<commit_msg>PCT-808: more cleanups<commit_after>/*
   Copyright (c) 2014, Percona LLC and/or its affiliates. All rights reserved.

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>
*/

package mysql

import (
	"encoding/json"
	"fmt"
	"github.com/percona/cloud-protocol/proto"
	"github.com/percona/percona-agent/instance"
	"github.com/percona/percona-agent/pct"
	"github.com/percona/percona-agent/pt/cmd"
)

const (
	SERVICE_NAME = "mysql"
)

type MySQL struct {
	logger *pct.Logger
	ir     *instance.Repo
}

func NewMySQL(logger *pct.Logger, ir *instance.Repo) *MySQL {
	return &MySQL{
		logger: logger,
		ir:     ir,
	}
}

/////////////////////////////////////////////////////////////////////////////
// Interface
/////////////////////////////////////////////////////////////////////////////

func (m *MySQL) Handle(protoCmd *proto.Cmd) *proto.Reply {
	// Get service instance
	serviceInstance, err := getServiceInstance(protoCmd)
	if err != nil {
		return protoCmd.Reply(nil, err)
	}

	// Load the MySQL instance info (DSN, name, etc.).
	mysqlIt := &proto.MySQLInstance{}
	if err = m.ir.Get(serviceInstance.Service, serviceInstance.InstanceId, mysqlIt); err != nil {
		return protoCmd.Reply(nil, err)
	}

	// Parse DSN to get user, pass, host, port, socket as separate fields
	// @todo parsing DSN should be as a method on proto.MySQLInstance.DSN or at least parser should be injected
	dsn, err := NewDSN(mysqlIt.DSN)
	if err != nil {
		return protoCmd.Reply(nil, err)
	}

	// Create params for ptMySQLSummary
	args := createParamsForPtMySQLSummary(dsn)

	// Run ptMySQLSummary with params
	ptMySQLSummary := cmd.New("pt-mysql-summary", args...)
	output, err := ptMySQLSummary.Run()
	if err != nil {
		m.logger.Error("pt-mysql-summary %s: %s", SERVICE_NAME, err)
	}

	return protoCmd.Reply(output, err)
}

/////////////////////////////////////////////////////////////////////////////
// Implementation
/////////////////////////////////////////////////////////////////////////////

func getServiceInstance(protoCmd *proto.Cmd) (serviceInstance *proto.ServiceInstance, err error) {
	if protoCmd.Data == nil {
		return nil, fmt.Errorf("%s.getMySQLInstance:cmd.Data is empty", SERVICE_NAME)
	}

	if err := json.Unmarshal(protoCmd.Data, &serviceInstance); err != nil {
		return nil, fmt.Errorf("%s.getMySQLInstance:json.Unmarshal:%s", SERVICE_NAME, err)
	}

	return serviceInstance, nil
}

func createParamsForPtMySQLSummary(dsn *DSN) (args []string) {
	if dsn.user != "" {
		args = append(args, "--user", dsn.user)
	}
	if dsn.passwd != "" {
		args = append(args, "--password", dsn.passwd)
	}
	if dsn.net == "unix" {
		args = append(args, "--socket", dsn.addr)
	} else {
		if dsn.addr != "" {
			args = append(args, "--host", dsn.addr)
		}
		if dsn.port != "" {
			args = append(args, "--port", dsn.port)
		}
	}

	return args
}
<|endoftext|>


<commit_before>package geocodio

import (
	"errors"
	"strings"
)

// GeocodeResponse
type GeocodeResult struct {
	Input   Input     `json:"input,omitempty"`
	Results []Address `json:"results"`
	Debug   struct {
		RawResponse  []byte `json:"-"`
		RequestedURL string `json:"requested_url"`
		Status       string `json:"status"`
		StatusCode   int    `json:"status_code"`
	} `json:"-"`
}

func (self *GeocodeResult) ResponseAsString() string {
	return string(self.Debug.RawResponse)
}

// Geocode single address
// See: http://geocod.io/docs/#toc_4
func (g *Geocodio) Geocode(address string) (GeocodeResult, error) {
	if address == "" {
		return GeocodeResult{}, ErrAddressIsEmpty
	}

	results, err := g.get("/geocode", map[string]string{"q": address})
	if err != nil {
		return GeocodeResult{}, err
	}

	return results, nil
}

// Geocode batch addresses
func (g *Geocodio) GeocodeBatch(addresses ...string) (GeocodeResult, error) {
	if len(addresses) == 0 {
		return GeocodeResult{}, ErrBatchAddressesIsEmpty
	}

	// TODO: support limit
	results, err := g.post("/geocode", addresses, nil)
	if err != nil {
		return GeocodeResult{}, err
	}

	return results, nil
}

// GeocodeAndReturnTimezone will geocode and include Timezone in the fields response
func (g *Geocodio) GeocodeAndReturnTimezone(address string) (GeocodeResult, error) {
	return g.GeocodeReturnFields(address, "timezone")
}

// GeocodeAndReturnZip4 will geocode and include zip4 in the fields response
func (g *Geocodio) GeocodeAndReturnZip4(address string) (GeocodeResult, error) {
	return g.GeocodeReturnFields(address, "zip4")
}

// GeocodeAndReturnCongressionalDistrict will geocode and include Congressional District in the fields response
func (g *Geocodio) GeocodeAndReturnCongressionalDistrict(address string) (GeocodeResult, error) {
	return g.GeocodeReturnFields(address, "cd")
}

// GeocodeAndReturnStateLegislativeDistricts will geocode and include State Legislative Districts in the fields response
func (g *Geocodio) GeocodeAndReturnStateLegislativeDistricts(address string) (GeocodeResult, error) {
	return g.GeocodeReturnFields(address, "stateleg")
}

// TODO: School District (school)

// GeocodeReturnFields will geocode and includes additional fields in response
/*
 	See: http://geocod.io/docs/#toc_22
	Note:
		Each field counts as an additional lookup each
*/
func (g *Geocodio) GeocodeReturnFields(address string, fields ...string) (GeocodeResult, error) {
	if address == "" {
		return GeocodeResult{}, errors.New("address can not be empty")
	}

	fieldsCommaSeparated := strings.Join(fields, ",")

	result, err := g.Call("/geocode",
		map[string]string{
			"q":      address,
			"fields": fieldsCommaSeparated,
		})
	if err != nil {
		return GeocodeResult{}, err
	}

	return result, nil
}
<commit_msg>Extend result struct to be more complete, clean up<commit_after>package geocodio

import (
	"errors"
	"strings"
)

// GeocodeResponse
type GeocodeResult struct {
	Input   Input    `json:"input,omitempty"`
	Results []Result `json:"results"`
	Debug   struct {
		RawResponse  []byte `json:"-"`
		RequestedURL string `json:"requested_url"`
		Status       string `json:"status"`
		StatusCode   int    `json:"status_code"`
	} `json:"-"`
}

type ErrorResponse struct {
	Message string    `json:"error"`
	Results []Address `json:"results"`
}

type Result struct {
	Address
	Error *ErrorResponse `json:"response,omitempty"`
}

// ResponseAsString helper to return raw response
func (self *GeocodeResult) ResponseAsString() string {
	return string(self.Debug.RawResponse)
}

// Geocode single address
// See: http://geocod.io/docs/#toc_4
func (g *Geocodio) Geocode(address string) (GeocodeResult, error) {
	if address == "" {
		return GeocodeResult{}, ErrAddressIsEmpty
	}

	resp, err := g.get("/geocode", map[string]string{"q": address})
	if err != nil {
		return GeocodeResult{}, err
	}

	if len(resp.Results) == 0 {
		return resp, ErrNoResultsFound
	}

	return resp, nil
}

// GeocodeBatch look up addresses
func (g *Geocodio) GeocodeBatch(addresses ...string) (GeocodeResult, error) {
	if len(addresses) == 0 {
		return GeocodeResult{}, ErrBatchAddressesIsEmpty
	}

	// TODO: support limit
	resp, err := g.post("/geocode", addresses, nil)
	if err != nil {
		return GeocodeResult{}, err
	}

	if len(resp.Results) == 0 {
		return resp, ErrNoResultsFound
	}

	return resp, nil
}

// GeocodeAndReturnTimezone will geocode and include Timezone in the fields response
func (g *Geocodio) GeocodeAndReturnTimezone(address string) (GeocodeResult, error) {
	return g.GeocodeReturnFields(address, "timezone")
}

// GeocodeAndReturnZip4 will geocode and include zip4 in the fields response
func (g *Geocodio) GeocodeAndReturnZip4(address string) (GeocodeResult, error) {
	return g.GeocodeReturnFields(address, "zip4")
}

// GeocodeAndReturnCongressionalDistrict will geocode and include Congressional District in the fields response
func (g *Geocodio) GeocodeAndReturnCongressionalDistrict(address string) (GeocodeResult, error) {
	return g.GeocodeReturnFields(address, "cd")
}

// GeocodeAndReturnStateLegislativeDistricts will geocode and include State Legislative Districts in the fields response
func (g *Geocodio) GeocodeAndReturnStateLegislativeDistricts(address string) (GeocodeResult, error) {
	return g.GeocodeReturnFields(address, "stateleg")
}

// TODO: School District (school)

// GeocodeReturnFields will geocode and includes additional fields in response
/*
 	See: http://geocod.io/docs/#toc_22
	Note:
		Each field counts as an additional lookup each
*/
func (g *Geocodio) GeocodeReturnFields(address string, fields ...string) (GeocodeResult, error) {
	if address == "" {
		return GeocodeResult{}, errors.New("address can not be empty")
	}

	fieldsCommaSeparated := strings.Join(fields, ",")

	resp, err := g.get("/geocode",
		map[string]string{
			"q":      address,
			"fields": fieldsCommaSeparated,
		})
	if err != nil {
		return GeocodeResult{}, err
	}

	if len(resp.Results) == 0 {
		return resp, ErrNoResultsFound
	}

	return resp, nil
}
<|endoftext|>


<commit_before>package radiodan

import (
	"fmt"
	"time"
)

type DebugInfo struct {
	Timestamp          time.Time
	Hostname           string
	Addresses          []string
	InternetConnection bool
	Applications       []RadiodanApplication
}

type RadiodanApplication struct {
	Name      string
	LogTail   string
	Pid       int64
	IsRunning bool
	Deploy    Deploy
}

type Deploy struct {
	Name   string
	Ref    string
	Commit string
}

func (r RadiodanApplication) DeployFile() (path string) {
	path = fmt.Sprintf("/opt/radiodan/apps/%s/current/.deploy", r.Name)
	return
}

func (r RadiodanApplication) LogFile() (path string) {
	path = fmt.Sprintf("/var/log/radiodan-%s.log", r.Name)
	return
}

func (r RadiodanApplication) PidFile() (path string) {
	path = fmt.Sprintf("/var/run/radiodan/radiodan-%s.pid", r.Name)
	return
}
<commit_msg>Update structs<commit_after>package radiodan

import (
	"fmt"
	"time"
)

type DebugInfo struct {
	Timestamp          time.Time
	Hostname           string
	Addresses          []string
	InternetConnection bool
	Applications       []RadiodanApplication
}

type RadiodanApplication struct {
	Name      string
	Pid       int64
	IsRunning bool
	Deploy    Deploy
	LogTail   string
}

type Deploy struct {
	Name      string
	Ref       string
	Commit    string
	CreatedAt string
}

func (r RadiodanApplication) DeployFile() (path string) {
	path = fmt.Sprintf("/opt/radiodan/apps/%s/current/.deploy", r.Name)
	return
}

func (r RadiodanApplication) LogFile() (path string) {
	path = fmt.Sprintf("/var/log/radiodan-%s.log", r.Name)
	return
}

func (r RadiodanApplication) PidFile() (path string) {
	path = fmt.Sprintf("/var/run/radiodan/radiodan-%s.pid", r.Name)
	return
}
<|endoftext|>


<commit_before>// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package securecookie

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/hmac"
	"crypto/rand"
	"crypto/sha256"
	"crypto/subtle"
	"encoding/base64"
	"encoding/gob"
	"errors"
	"fmt"
	"hash"
	"io"
	"strconv"
	"time"
)

var (
	errNoCodecs      = errors.New("securecookie: no codecs provided")
	errHashKeyNotSet = errors.New("securecookie: hash key is not set")

	ErrMacInvalid = errors.New("securecookie: the value is not valid")
)

// Codec defines an interface to encode and decode cookie values.
type Codec interface {
	Encode(name string, value interface{}) (string, error)
	Decode(name, value string, dst interface{}) error
}

// New returns a new SecureCookie.
//
// hashKey is required, used to authenticate values using HMAC. Create it using
// GenerateRandomKey(). It is recommended to use a key with 32 or 64 bytes.
//
// blockKey is optional, used to encrypt values. Create it using
// GenerateRandomKey(). The key length must correspond to the block size
// of the encryption algorithm. For AES, used by default, valid lengths are
// 16, 24, or 32 bytes to select AES-128, AES-192, or AES-256.
func New(hashKey, blockKey []byte) *SecureCookie {
	s := &SecureCookie{
		hashKey:   hashKey,
		blockKey:  blockKey,
		hashFunc:  sha256.New,
		maxAge:    86400 * 30,
		maxLength: 4096,
	}
	if hashKey == nil {
		s.err = errHashKeyNotSet
	}
	if blockKey != nil {
		s.BlockFunc(aes.NewCipher)
	}
	return s
}

// SecureCookie encodes and decodes authenticated and optionally encrypted
// cookie values.
type SecureCookie struct {
	hashKey   []byte
	hashFunc  func() hash.Hash
	blockKey  []byte
	block     cipher.Block
	maxLength int
	maxAge    int64
	minAge    int64
	err       error
	// For testing purposes, the function that returns the current timestamp.
	// If not set, it will use time.Now().UTC().Unix().
	timeFunc func() int64
}

// MaxLength restricts the maximum length, in bytes, for the cookie value.
//
// Default is 4096, which is the maximum value accepted by Internet Explorer.
func (s *SecureCookie) MaxLength(value int) *SecureCookie {
	s.maxLength = value
	return s
}

// MaxAge restricts the maximum age, in seconds, for the cookie value.
//
// Default is 86400 * 30. Set it to 0 for no restriction.
func (s *SecureCookie) MaxAge(value int) *SecureCookie {
	s.maxAge = int64(value)
	return s
}

// MinAge restricts the minimum age, in seconds, for the cookie value.
//
// Default is 0 (no restriction).
func (s *SecureCookie) MinAge(value int) *SecureCookie {
	s.minAge = int64(value)
	return s
}

// HashFunc sets the hash function used to create HMAC.
//
// Default is crypto/sha256.New.
func (s *SecureCookie) HashFunc(f func() hash.Hash) *SecureCookie {
	s.hashFunc = f
	return s
}

// BlockFunc sets the encryption function used to create a cipher.Block.
//
// Default is crypto/aes.New.
func (s *SecureCookie) BlockFunc(f func([]byte) (cipher.Block, error)) *SecureCookie {
	if s.blockKey == nil {
		s.err = errors.New("securecookie: block key is not set")
	} else if block, err := f(s.blockKey); err == nil {
		s.block = block
	} else {
		s.err = err
	}
	return s
}

// Encode encodes a cookie value.
//
// It serializes, optionally encrypts, signs with a message authentication code, and
// finally encodes the value.
//
// The name argument is the cookie name. It is stored with the encoded value.
// The value argument is the value to be encoded. It can be any value that can
// be encoded using encoding/gob. To store special structures, they must be
// registered first using gob.Register().
func (s *SecureCookie) Encode(name string, value interface{}) (string, error) {
	if s.err != nil {
		return "", s.err
	}
	if s.hashKey == nil {
		s.err = errHashKeyNotSet
		return "", s.err
	}
	var err error
	var b []byte
	// 1. Serialize.
	if b, err = serialize(value); err != nil {
		return "", err
	}
	// 2. Encrypt (optional).
	if s.block != nil {
		if b, err = encrypt(s.block, b); err != nil {
			return "", err
		}
	}
	b = encode(b)
	// 3. Create MAC for "name|date|value". Extra pipe to be used later.
	b = []byte(fmt.Sprintf("%s|%d|%s|", name, s.timestamp(), b))
	mac := createMac(hmac.New(s.hashFunc, s.hashKey), b[:len(b)-1])
	// Append mac, remove name.
	b = append(b, mac...)[len(name)+1:]
	// 4. Encode to base64.
	b = encode(b)
	// 5. Check length.
	if s.maxLength != 0 && len(b) > s.maxLength {
		return "", errors.New("securecookie: the value is too long")
	}
	// Done.
	return string(b), nil
}

// Decode decodes a cookie value.
//
// It decodes, verifies a message authentication code, optionally decrypts and
// finally deserializes the value.
//
// The name argument is the cookie name. It must be the same name used when
// it was stored. The value argument is the encoded cookie value. The dst
// argument is where the cookie will be decoded. It must be a pointer.
func (s *SecureCookie) Decode(name, value string, dst interface{}) error {
	if s.err != nil {
		return s.err
	}
	if s.hashKey == nil {
		s.err = errHashKeyNotSet
		return s.err
	}
	// 1. Check length.
	if s.maxLength != 0 && len(value) > s.maxLength {
		return errors.New("securecookie: the value is too long")
	}
	// 2. Decode from base64.
	b, err := decode([]byte(value))
	if err != nil {
		return err
	}
	// 3. Verify MAC. Value is "date|value|mac".
	parts := bytes.SplitN(b, []byte("|"), 3)
	if len(parts) != 3 {
		return ErrMacInvalid
	}
	h := hmac.New(s.hashFunc, s.hashKey)
	b = append([]byte(name+"|"), b[:len(b)-len(parts[2])-1]...)
	if err = verifyMac(h, b, parts[2]); err != nil {
		return err
	}
	// 4. Verify date ranges.
	var t1 int64
	if t1, err = strconv.ParseInt(string(parts[0]), 10, 64); err != nil {
		return errors.New("securecookie: invalid timestamp")
	}
	t2 := s.timestamp()
	if s.minAge != 0 && t1 > t2-s.minAge {
		return errors.New("securecookie: timestamp is too new")
	}
	if s.maxAge != 0 && t1 < t2-s.maxAge {
		return errors.New("securecookie: expired timestamp")
	}
	// 5. Decrypt (optional).
	b, err = decode(parts[1])
	if err != nil {
		return err
	}
	if s.block != nil {
		if b, err = decrypt(s.block, b); err != nil {
			return err
		}
	}
	// 6. Deserialize.
	if err = deserialize(b, dst); err != nil {
		return err
	}
	// Done.
	return nil
}

// timestamp returns the current timestamp, in seconds.
//
// For testing purposes, the function that generates the timestamp can be
// overridden. If not set, it will return time.Now().UTC().Unix().
func (s *SecureCookie) timestamp() int64 {
	if s.timeFunc == nil {
		return time.Now().UTC().Unix()
	}
	return s.timeFunc()
}

// Authentication -------------------------------------------------------------

// createMac creates a message authentication code (MAC).
func createMac(h hash.Hash, value []byte) []byte {
	h.Write(value)
	return h.Sum(nil)
}

// verifyMac verifies that a message authentication code (MAC) is valid.
func verifyMac(h hash.Hash, value []byte, mac []byte) error {
	mac2 := createMac(h, value)
	if len(mac) == len(mac2) && subtle.ConstantTimeCompare(mac, mac2) == 1 {
		return nil
	}
	return ErrMacInvalid
}

// Encryption -----------------------------------------------------------------

// encrypt encrypts a value using the given block in counter mode.
//
// A random initialization vector (http://goo.gl/zF67k) with the length of the
// block size is prepended to the resulting ciphertext.
func encrypt(block cipher.Block, value []byte) ([]byte, error) {
	iv := GenerateRandomKey(block.BlockSize())
	if iv == nil {
		return nil, errors.New("securecookie: failed to generate random iv")
	}
	// Encrypt it.
	stream := cipher.NewCTR(block, iv)
	stream.XORKeyStream(value, value)
	// Return iv + ciphertext.
	return append(iv, value...), nil
}

// decrypt decrypts a value using the given block in counter mode.
//
// The value to be decrypted must be prepended by a initialization vector
// (http://goo.gl/zF67k) with the length of the block size.
func decrypt(block cipher.Block, value []byte) ([]byte, error) {
	size := block.BlockSize()
	if len(value) > size {
		// Extract iv.
		iv := value[:size]
		// Extract ciphertext.
		value = value[size:]
		// Decrypt it.
		stream := cipher.NewCTR(block, iv)
		stream.XORKeyStream(value, value)
		return value, nil
	}
	return nil, errors.New("securecookie: the value could not be decrypted")
}

// Serialization --------------------------------------------------------------

// serialize encodes a value using gob.
func serialize(src interface{}) ([]byte, error) {
	buf := new(bytes.Buffer)
	enc := gob.NewEncoder(buf)
	if err := enc.Encode(src); err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

// deserialize decodes a value using gob.
func deserialize(src []byte, dst interface{}) error {
	dec := gob.NewDecoder(bytes.NewBuffer(src))
	if err := dec.Decode(dst); err != nil {
		return err
	}
	return nil
}

// Encoding -------------------------------------------------------------------

// encode encodes a value using base64.
func encode(value []byte) []byte {
	encoded := make([]byte, base64.URLEncoding.EncodedLen(len(value)))
	base64.URLEncoding.Encode(encoded, value)
	return encoded
}

// decode decodes a cookie using base64.
func decode(value []byte) ([]byte, error) {
	decoded := make([]byte, base64.URLEncoding.DecodedLen(len(value)))
	b, err := base64.URLEncoding.Decode(decoded, value)
	if err != nil {
		return nil, err
	}
	return decoded[:b], nil
}

// Helpers --------------------------------------------------------------------

// GenerateRandomKey creates a random key with the given length in bytes.
func GenerateRandomKey(length int) []byte {
	k := make([]byte, length)
	if _, err := io.ReadFull(rand.Reader, k); err != nil {
		return nil
	}
	return k
}

// CodecsFromPairs returns a slice of SecureCookie instances.
//
// It is a convenience function to create a list of codecs for key rotation.
func CodecsFromPairs(keyPairs ...[]byte) []Codec {
	codecs := make([]Codec, len(keyPairs)/2+len(keyPairs)%2)
	for i := 0; i < len(keyPairs); i += 2 {
		var blockKey []byte
		if i+1 < len(keyPairs) {
			blockKey = keyPairs[i+1]
		}
		codecs[i/2] = New(keyPairs[i], blockKey)
	}
	return codecs
}

// EncodeMulti encodes a cookie value using a group of codecs.
//
// The codecs are tried in order. Multiple codecs are accepted to allow
// key rotation.
func EncodeMulti(name string, value interface{}, codecs ...Codec) (string, error) {
	if len(codecs) == 0 {
		return "", errNoCodecs
	}

	var errors MultiError
	for _, codec := range codecs {
		encoded, err := codec.Encode(name, value)
		if err == nil {
			return encoded, nil
		}
		errors = append(errors, err)
	}
	return "", errors
}

// DecodeMulti decodes a cookie value using a group of codecs.
//
// The codecs are tried in order. Multiple codecs are accepted to allow
// key rotation.
func DecodeMulti(name string, value string, dst interface{}, codecs ...Codec) error {
	if len(codecs) == 0 {
		return errNoCodecs
	}

	var errors MultiError
	for _, codec := range codecs {
		err := codec.Decode(name, value, dst)
		if err == nil {
			return nil
		}
		errors = append(errors, err)
	}
	return errors
}

// MultiError groups multiple errors.
type MultiError []error

func (m MultiError) Error() string {
	s, n := "", 0
	for _, e := range m {
		if e != nil {
			if n == 0 {
				s = e.Error()
			}
			n++
		}
	}
	switch n {
	case 0:
		return "(0 errors)"
	case 1:
		return s
	case 2:
		return s + " (and 1 other error)"
	}
	return fmt.Sprintf("%s (and %d other errors)", s, n-1)
}
<commit_msg>Improve Decode against timing attacks<commit_after>// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package securecookie

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/hmac"
	"crypto/rand"
	"crypto/sha256"
	"crypto/subtle"
	"encoding/base64"
	"encoding/gob"
	"errors"
	"fmt"
	"hash"
	"io"
	"strconv"
	"time"
)

var (
	errNoCodecs      = errors.New("securecookie: no codecs provided")
	errHashKeyNotSet = errors.New("securecookie: hash key is not set")

	ErrMacInvalid = errors.New("securecookie: the value is not valid")
)

// Codec defines an interface to encode and decode cookie values.
type Codec interface {
	Encode(name string, value interface{}) (string, error)
	Decode(name, value string, dst interface{}) error
}

// New returns a new SecureCookie.
//
// hashKey is required, used to authenticate values using HMAC. Create it using
// GenerateRandomKey(). It is recommended to use a key with 32 or 64 bytes.
//
// blockKey is optional, used to encrypt values. Create it using
// GenerateRandomKey(). The key length must correspond to the block size
// of the encryption algorithm. For AES, used by default, valid lengths are
// 16, 24, or 32 bytes to select AES-128, AES-192, or AES-256.
func New(hashKey, blockKey []byte) *SecureCookie {
	s := &SecureCookie{
		hashKey:   hashKey,
		blockKey:  blockKey,
		hashFunc:  sha256.New,
		maxAge:    86400 * 30,
		maxLength: 4096,
	}
	if hashKey == nil {
		s.err = errHashKeyNotSet
	}
	if blockKey != nil {
		s.BlockFunc(aes.NewCipher)
	}
	return s
}

// SecureCookie encodes and decodes authenticated and optionally encrypted
// cookie values.
type SecureCookie struct {
	hashKey   []byte
	hashFunc  func() hash.Hash
	blockKey  []byte
	block     cipher.Block
	maxLength int
	maxAge    int64
	minAge    int64
	err       error
	// For testing purposes, the function that returns the current timestamp.
	// If not set, it will use time.Now().UTC().Unix().
	timeFunc func() int64
}

// MaxLength restricts the maximum length, in bytes, for the cookie value.
//
// Default is 4096, which is the maximum value accepted by Internet Explorer.
func (s *SecureCookie) MaxLength(value int) *SecureCookie {
	s.maxLength = value
	return s
}

// MaxAge restricts the maximum age, in seconds, for the cookie value.
//
// Default is 86400 * 30. Set it to 0 for no restriction.
func (s *SecureCookie) MaxAge(value int) *SecureCookie {
	s.maxAge = int64(value)
	return s
}

// MinAge restricts the minimum age, in seconds, for the cookie value.
//
// Default is 0 (no restriction).
func (s *SecureCookie) MinAge(value int) *SecureCookie {
	s.minAge = int64(value)
	return s
}

// HashFunc sets the hash function used to create HMAC.
//
// Default is crypto/sha256.New.
func (s *SecureCookie) HashFunc(f func() hash.Hash) *SecureCookie {
	s.hashFunc = f
	return s
}

// BlockFunc sets the encryption function used to create a cipher.Block.
//
// Default is crypto/aes.New.
func (s *SecureCookie) BlockFunc(f func([]byte) (cipher.Block, error)) *SecureCookie {
	if s.blockKey == nil {
		s.err = errors.New("securecookie: block key is not set")
	} else if block, err := f(s.blockKey); err == nil {
		s.block = block
	} else {
		s.err = err
	}
	return s
}

// Encode encodes a cookie value.
//
// It serializes, optionally encrypts, signs with a message authentication code, and
// finally encodes the value.
//
// The name argument is the cookie name. It is stored with the encoded value.
// The value argument is the value to be encoded. It can be any value that can
// be encoded using encoding/gob. To store special structures, they must be
// registered first using gob.Register().
func (s *SecureCookie) Encode(name string, value interface{}) (string, error) {
	if s.err != nil {
		return "", s.err
	}
	if s.hashKey == nil {
		s.err = errHashKeyNotSet
		return "", s.err
	}
	var err error
	var b []byte
	// 1. Serialize.
	if b, err = serialize(value); err != nil {
		return "", err
	}
	// 2. Encrypt (optional).
	if s.block != nil {
		if b, err = encrypt(s.block, b); err != nil {
			return "", err
		}
	}
	b = encode(b)
	// 3. Create MAC for "name|date|value". Extra pipe to be used later.
	b = []byte(fmt.Sprintf("%s|%d|%s|", name, s.timestamp(), b))
	mac := createMac(hmac.New(s.hashFunc, s.hashKey), b[:len(b)-1])
	// Append mac, remove name.
	b = append(b, mac...)[len(name)+1:]
	// 4. Encode to base64.
	b = encode(b)
	// 5. Check length.
	if s.maxLength != 0 && len(b) > s.maxLength {
		return "", errors.New("securecookie: the value is too long")
	}
	// Done.
	return string(b), nil
}

// Decode decodes a cookie value.
//
// It decodes, verifies a message authentication code, optionally decrypts and
// finally deserializes the value.
//
// The name argument is the cookie name. It must be the same name used when
// it was stored. The value argument is the encoded cookie value. The dst
// argument is where the cookie will be decoded. It must be a pointer.
func (s *SecureCookie) Decode(name, value string, dst interface{}) error {
	var retErr error
	setErr := func(err error) {
		if retErr == nil {
			retErr = err
		}
	}

	if s.err != nil {
		setErr(s.err)
	}
	if s.hashKey == nil {
		s.err = errHashKeyNotSet
		setErr(s.err)
	}
	// 1. Check length.
	if s.maxLength != 0 && len(value) > s.maxLength {
		setErr(errors.New("securecookie: the value is too long"))
	}
	// 2. Decode from base64.
	b, err := decode([]byte(value))
	if err != nil {
		setErr(err)
		// Dummy b to avoid errors
		b = []byte("||")
	}
	// 3. Verify MAC. Value is "date|value|mac".
	parts := bytes.SplitN(b, []byte("|"), 3)
	if len(parts) != 3 {
		setErr(ErrMacInvalid)
	}
	h := hmac.New(s.hashFunc, s.hashKey)
	b = append([]byte(name+"|"), b[:len(b)-len(parts[2])-1]...)
	if err = verifyMac(h, b, parts[2]); err != nil {
		setErr(err)
	}
	// 4. Verify date ranges.
	var t1 int64
	if t1, err = strconv.ParseInt(string(parts[0]), 10, 64); err != nil {
		setErr(errors.New("securecookie: invalid timestamp"))
	}
	t2 := s.timestamp()
	if s.minAge != 0 && t1 > t2-s.minAge {
		setErr(errors.New("securecookie: timestamp is too new"))
	}
	if s.maxAge != 0 && t1 < t2-s.maxAge {
		setErr(errors.New("securecookie: expired timestamp"))
	}
	// 5. Decrypt (optional).
	b, err = decode(parts[1])
	if err != nil {
		setErr(err)
	}
	if s.block != nil {
		if b, err = decrypt(s.block, b); err != nil {
			setErr(err)
		}
	}

	// Check for errors before deserialization to avoid unwanted side effects
	if retErr != nil {
		return retErr
	}

	// 6. Deserialize.
	return deserialize(b, dst)
}

// timestamp returns the current timestamp, in seconds.
//
// For testing purposes, the function that generates the timestamp can be
// overridden. If not set, it will return time.Now().UTC().Unix().
func (s *SecureCookie) timestamp() int64 {
	if s.timeFunc == nil {
		return time.Now().UTC().Unix()
	}
	return s.timeFunc()
}

// Authentication -------------------------------------------------------------

// createMac creates a message authentication code (MAC).
func createMac(h hash.Hash, value []byte) []byte {
	h.Write(value)
	return h.Sum(nil)
}

// verifyMac verifies that a message authentication code (MAC) is valid.
func verifyMac(h hash.Hash, value []byte, mac []byte) error {
	mac2 := createMac(h, value)
	if len(mac) == len(mac2) && subtle.ConstantTimeCompare(mac, mac2) == 1 {
		return nil
	}
	return ErrMacInvalid
}

// Encryption -----------------------------------------------------------------

// encrypt encrypts a value using the given block in counter mode.
//
// A random initialization vector (http://goo.gl/zF67k) with the length of the
// block size is prepended to the resulting ciphertext.
func encrypt(block cipher.Block, value []byte) ([]byte, error) {
	iv := GenerateRandomKey(block.BlockSize())
	if iv == nil {
		return nil, errors.New("securecookie: failed to generate random iv")
	}
	// Encrypt it.
	stream := cipher.NewCTR(block, iv)
	stream.XORKeyStream(value, value)
	// Return iv + ciphertext.
	return append(iv, value...), nil
}

// decrypt decrypts a value using the given block in counter mode.
//
// The value to be decrypted must be prepended by a initialization vector
// (http://goo.gl/zF67k) with the length of the block size.
func decrypt(block cipher.Block, value []byte) ([]byte, error) {
	size := block.BlockSize()
	if len(value) > size {
		// Extract iv.
		iv := value[:size]
		// Extract ciphertext.
		value = value[size:]
		// Decrypt it.
		stream := cipher.NewCTR(block, iv)
		stream.XORKeyStream(value, value)
		return value, nil
	}
	return nil, errors.New("securecookie: the value could not be decrypted")
}

// Serialization --------------------------------------------------------------

// serialize encodes a value using gob.
func serialize(src interface{}) ([]byte, error) {
	buf := new(bytes.Buffer)
	enc := gob.NewEncoder(buf)
	if err := enc.Encode(src); err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

// deserialize decodes a value using gob.
func deserialize(src []byte, dst interface{}) error {
	dec := gob.NewDecoder(bytes.NewBuffer(src))
	if err := dec.Decode(dst); err != nil {
		return err
	}
	return nil
}

// Encoding -------------------------------------------------------------------

// encode encodes a value using base64.
func encode(value []byte) []byte {
	encoded := make([]byte, base64.URLEncoding.EncodedLen(len(value)))
	base64.URLEncoding.Encode(encoded, value)
	return encoded
}

// decode decodes a cookie using base64.
func decode(value []byte) ([]byte, error) {
	decoded := make([]byte, base64.URLEncoding.DecodedLen(len(value)))
	b, err := base64.URLEncoding.Decode(decoded, value)
	if err != nil {
		return nil, err
	}
	return decoded[:b], nil
}

// Helpers --------------------------------------------------------------------

// GenerateRandomKey creates a random key with the given length in bytes.
func GenerateRandomKey(length int) []byte {
	k := make([]byte, length)
	if _, err := io.ReadFull(rand.Reader, k); err != nil {
		return nil
	}
	return k
}

// CodecsFromPairs returns a slice of SecureCookie instances.
//
// It is a convenience function to create a list of codecs for key rotation.
func CodecsFromPairs(keyPairs ...[]byte) []Codec {
	codecs := make([]Codec, len(keyPairs)/2+len(keyPairs)%2)
	for i := 0; i < len(keyPairs); i += 2 {
		var blockKey []byte
		if i+1 < len(keyPairs) {
			blockKey = keyPairs[i+1]
		}
		codecs[i/2] = New(keyPairs[i], blockKey)
	}
	return codecs
}

// EncodeMulti encodes a cookie value using a group of codecs.
//
// The codecs are tried in order. Multiple codecs are accepted to allow
// key rotation.
func EncodeMulti(name string, value interface{}, codecs ...Codec) (string, error) {
	if len(codecs) == 0 {
		return "", errNoCodecs
	}

	var errors MultiError
	for _, codec := range codecs {
		encoded, err := codec.Encode(name, value)
		if err == nil {
			return encoded, nil
		}
		errors = append(errors, err)
	}
	return "", errors
}

// DecodeMulti decodes a cookie value using a group of codecs.
//
// The codecs are tried in order. Multiple codecs are accepted to allow
// key rotation.
func DecodeMulti(name string, value string, dst interface{}, codecs ...Codec) error {
	if len(codecs) == 0 {
		return errNoCodecs
	}

	var errors MultiError
	for _, codec := range codecs {
		err := codec.Decode(name, value, dst)
		if err == nil {
			return nil
		}
		errors = append(errors, err)
	}
	return errors
}

// MultiError groups multiple errors.
type MultiError []error

func (m MultiError) Error() string {
	s, n := "", 0
	for _, e := range m {
		if e != nil {
			if n == 0 {
				s = e.Error()
			}
			n++
		}
	}
	switch n {
	case 0:
		return "(0 errors)"
	case 1:
		return s
	case 2:
		return s + " (and 1 other error)"
	}
	return fmt.Sprintf("%s (and %d other errors)", s, n-1)
}
<|endoftext|>


<commit_before>// Copyright 2016 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

// Package gce provides wrappers around Google Compute Engine (GCE) APIs.
// It is assumed that the program itself also runs on GCE as APIs operate on the current project/zone.
//
// See https://cloud.google.com/compute/docs for details.
// In particular, API reference:
// https://cloud.google.com/compute/docs/reference/latest
// and Go API wrappers:
// https://godoc.org/google.golang.org/api/compute/v0.beta
package gce

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
	"time"

	"golang.org/x/net/context"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"
	"google.golang.org/api/compute/v0.beta"
	"google.golang.org/api/googleapi"
)

type Context struct {
	ProjectID  string
	ZoneID     string
	Instance   string
	InternalIP string

	computeService *compute.Service

	// apiCallTicker ticks regularly, preventing us from accidentally making
	// GCE API calls too quickly. Our quota is 20 QPS, but we temporarily
	// limit ourselves to less than that.
	apiRateGate <-chan time.Time
}

func NewContext() (*Context, error) {
	ctx := &Context{
		apiRateGate: time.NewTicker(time.Second / 10).C,
	}
	background := context.Background()
	tokenSource, err := google.DefaultTokenSource(background, compute.CloudPlatformScope)
	if err != nil {
		return nil, fmt.Errorf("failed to get a token source: %v", err)
	}
	httpClient := oauth2.NewClient(background, tokenSource)
	ctx.computeService, _ = compute.New(httpClient)
	// Obtain project name, zone and current instance IP address.
	ctx.ProjectID, err = ctx.getMeta("project/project-id")
	if err != nil {
		return nil, fmt.Errorf("failed to query gce project-id: %v", err)
	}
	ctx.ZoneID, err = ctx.getMeta("instance/zone")
	if err != nil {
		return nil, fmt.Errorf("failed to query gce zone: %v", err)
	}
	if i := strings.LastIndexByte(ctx.ZoneID, '/'); i != -1 {
		ctx.ZoneID = ctx.ZoneID[i+1:] // the query returns some nonsense prefix
	}
	instID, err := ctx.getMeta("instance/id")
	if err != nil {
		return nil, fmt.Errorf("failed to query gce instance id: %v", err)
	}
	instances, err := ctx.computeService.Instances.List(ctx.ProjectID, ctx.ZoneID).Do()
	if err != nil {
		return nil, fmt.Errorf("error getting instance list: %v", err)
	}
	// Finds this instance internal IP.
	for _, inst := range instances.Items {
		if fmt.Sprint(inst.Id) != instID {
			continue
		}
		ctx.Instance = inst.Name
		for _, iface := range inst.NetworkInterfaces {
			if strings.HasPrefix(iface.NetworkIP, "10.") {
				ctx.InternalIP = iface.NetworkIP
				break
			}
		}
		break
	}
	if ctx.Instance == "" || ctx.InternalIP == "" {
		return nil, fmt.Errorf("failed to get current instance name and internal IP")
	}
	return ctx, nil
}

func (ctx *Context) CreateInstance(name, machineType, image, sshkey string) (string, error) {
	prefix := "https://www.googleapis.com/compute/v1/projects/" + ctx.ProjectID
	instance := &compute.Instance{
		Name:        name,
		Description: "syzkaller worker",
		MachineType: prefix + "/zones/" + ctx.ZoneID + "/machineTypes/" + machineType,
		Disks: []*compute.AttachedDisk{
			{
				AutoDelete: true,
				Boot:       true,
				Type:       "PERSISTENT",
				InitializeParams: &compute.AttachedDiskInitializeParams{
					DiskName:    name,
					SourceImage: prefix + "/global/images/" + image,
				},
			},
		},
		Metadata: &compute.Metadata{
			Items: []*compute.MetadataItems{
				{
					Key:   "ssh-keys",
					Value: "syzkaller:" + sshkey,
				},
				{
					Key:   "serial-port-enable",
					Value: "1",
				},
			},
		},
		NetworkInterfaces: []*compute.NetworkInterface{
			&compute.NetworkInterface{
				Network: "global/networks/default",
			},
		},
		Scheduling: &compute.Scheduling{
			AutomaticRestart:  false,
			Preemptible:       true,
			OnHostMaintenance: "MIGRATE",
		},
	}

retry:
	<-ctx.apiRateGate
	op, err := ctx.computeService.Instances.Insert(ctx.ProjectID, ctx.ZoneID, instance).Do()
	if err != nil {
		return "", fmt.Errorf("failed to create instance: %v", err)
	}
	if err := ctx.waitForCompletion("zone", "create image", op.Name, false); err != nil {
		if _, ok := err.(resourcePoolExhaustedError); ok && instance.Scheduling.Preemptible {
			instance.Scheduling.Preemptible = false
			goto retry
		}
		return "", err
	}

	<-ctx.apiRateGate
	inst, err := ctx.computeService.Instances.Get(ctx.ProjectID, ctx.ZoneID, name).Do()
	if err != nil {
		return "", fmt.Errorf("error getting instance %s details after creation: %v", name, err)
	}

	// Finds its internal IP.
	ip := ""
	for _, iface := range inst.NetworkInterfaces {
		if strings.HasPrefix(iface.NetworkIP, "10.") {
			ip = iface.NetworkIP
			break
		}
	}
	if ip == "" {
		return "", fmt.Errorf("didn't find instance internal IP address")
	}
	return ip, nil
}

func (ctx *Context) DeleteInstance(name string, wait bool) error {
	<-ctx.apiRateGate
	op, err := ctx.computeService.Instances.Delete(ctx.ProjectID, ctx.ZoneID, name).Do()
	if apiErr, ok := err.(*googleapi.Error); ok && apiErr.Code == 404 {
		return nil
	}
	if err != nil {
		return fmt.Errorf("failed to delete instance: %v", err)
	}
	if wait {
		if err := ctx.waitForCompletion("zone", "delete image", op.Name, true); err != nil {
			return err
		}
	}
	return nil
}

func (ctx *Context) IsInstanceRunning(name string) bool {
	<-ctx.apiRateGate
	instance, err := ctx.computeService.Instances.Get(ctx.ProjectID, ctx.ZoneID, name).Do()
	if err != nil {
		return false
	}
	return instance.Status == "RUNNING"
}

func (ctx *Context) CreateImage(imageName, gcsFile string) error {
	image := &compute.Image{
		Name: imageName,
		RawDisk: &compute.ImageRawDisk{
			Source: "https://storage.googleapis.com/" + gcsFile,
		},
		Licenses: []string{
			"https://www.googleapis.com/compute/v1/projects/vm-options/global/licenses/enable-vmx",
		},
	}
	<-ctx.apiRateGate
	op, err := ctx.computeService.Images.Insert(ctx.ProjectID, image).Do()
	if err != nil {
		// Try again without the vmx license in case it is not supported.
		image.Licenses = nil
		<-ctx.apiRateGate
		op, err = ctx.computeService.Images.Insert(ctx.ProjectID, image).Do()
	}
	if err != nil {
		return fmt.Errorf("failed to create image: %v", err)
	}
	if err := ctx.waitForCompletion("global", "create image", op.Name, false); err != nil {
		return err
	}
	return nil
}

func (ctx *Context) DeleteImage(imageName string) error {
	<-ctx.apiRateGate
	op, err := ctx.computeService.Images.Delete(ctx.ProjectID, imageName).Do()
	if apiErr, ok := err.(*googleapi.Error); ok && apiErr.Code == 404 {
		return nil
	}
	if err != nil {
		return fmt.Errorf("failed to delete image: %v", err)
	}
	if err := ctx.waitForCompletion("global", "delete image", op.Name, true); err != nil {
		return err
	}
	return nil
}

type resourcePoolExhaustedError string

func (err resourcePoolExhaustedError) Error() string {
	return string(err)
}

func (ctx *Context) waitForCompletion(typ, desc, opName string, ignoreNotFound bool) error {
	for {
		time.Sleep(2 * time.Second)
		<-ctx.apiRateGate
		var err error
		var op *compute.Operation
		switch typ {
		case "global":
			op, err = ctx.computeService.GlobalOperations.Get(ctx.ProjectID, opName).Do()
		case "zone":
			op, err = ctx.computeService.ZoneOperations.Get(ctx.ProjectID, ctx.ZoneID, opName).Do()
		default:
			panic("unknown operation type: " + typ)
		}
		if err != nil {
			return fmt.Errorf("failed to get %v operation %v: %v", desc, opName, err)
		}
		switch op.Status {
		case "PENDING", "RUNNING":
			continue
		case "DONE":
			if op.Error != nil {
				reason := ""
				for _, operr := range op.Error.Errors {
					if operr.Code == "ZONE_RESOURCE_POOL_EXHAUSTED" {
						return resourcePoolExhaustedError(fmt.Sprintf("%+v", operr))
					}
					if ignoreNotFound && operr.Code == "RESOURCE_NOT_FOUND" {
						return nil
					}
					reason += fmt.Sprintf("%+v.", operr)
				}
				return fmt.Errorf("%v operation failed: %v", desc, reason)
			}
			return nil
		default:
			return fmt.Errorf("unknown %v operation status %q: %+v", desc, op.Status, op)
		}
	}
}

func (ctx *Context) getMeta(path string) (string, error) {
	req, err := http.NewRequest("GET", "http://metadata.google.internal/computeMetadata/v1/"+path, nil)
	if err != nil {
		return "", err
	}
	req.Header.Add("Metadata-Flavor", "Google")
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}
	return string(body), nil
}
<commit_msg>gce: revert to terminate on migration<commit_after>// Copyright 2016 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

// Package gce provides wrappers around Google Compute Engine (GCE) APIs.
// It is assumed that the program itself also runs on GCE as APIs operate on the current project/zone.
//
// See https://cloud.google.com/compute/docs for details.
// In particular, API reference:
// https://cloud.google.com/compute/docs/reference/latest
// and Go API wrappers:
// https://godoc.org/google.golang.org/api/compute/v0.beta
package gce

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
	"time"

	"golang.org/x/net/context"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"
	"google.golang.org/api/compute/v0.beta"
	"google.golang.org/api/googleapi"
)

type Context struct {
	ProjectID  string
	ZoneID     string
	Instance   string
	InternalIP string

	computeService *compute.Service

	// apiCallTicker ticks regularly, preventing us from accidentally making
	// GCE API calls too quickly. Our quota is 20 QPS, but we temporarily
	// limit ourselves to less than that.
	apiRateGate <-chan time.Time
}

func NewContext() (*Context, error) {
	ctx := &Context{
		apiRateGate: time.NewTicker(time.Second / 10).C,
	}
	background := context.Background()
	tokenSource, err := google.DefaultTokenSource(background, compute.CloudPlatformScope)
	if err != nil {
		return nil, fmt.Errorf("failed to get a token source: %v", err)
	}
	httpClient := oauth2.NewClient(background, tokenSource)
	ctx.computeService, _ = compute.New(httpClient)
	// Obtain project name, zone and current instance IP address.
	ctx.ProjectID, err = ctx.getMeta("project/project-id")
	if err != nil {
		return nil, fmt.Errorf("failed to query gce project-id: %v", err)
	}
	ctx.ZoneID, err = ctx.getMeta("instance/zone")
	if err != nil {
		return nil, fmt.Errorf("failed to query gce zone: %v", err)
	}
	if i := strings.LastIndexByte(ctx.ZoneID, '/'); i != -1 {
		ctx.ZoneID = ctx.ZoneID[i+1:] // the query returns some nonsense prefix
	}
	instID, err := ctx.getMeta("instance/id")
	if err != nil {
		return nil, fmt.Errorf("failed to query gce instance id: %v", err)
	}
	instances, err := ctx.computeService.Instances.List(ctx.ProjectID, ctx.ZoneID).Do()
	if err != nil {
		return nil, fmt.Errorf("error getting instance list: %v", err)
	}
	// Finds this instance internal IP.
	for _, inst := range instances.Items {
		if fmt.Sprint(inst.Id) != instID {
			continue
		}
		ctx.Instance = inst.Name
		for _, iface := range inst.NetworkInterfaces {
			if strings.HasPrefix(iface.NetworkIP, "10.") {
				ctx.InternalIP = iface.NetworkIP
				break
			}
		}
		break
	}
	if ctx.Instance == "" || ctx.InternalIP == "" {
		return nil, fmt.Errorf("failed to get current instance name and internal IP")
	}
	return ctx, nil
}

func (ctx *Context) CreateInstance(name, machineType, image, sshkey string) (string, error) {
	prefix := "https://www.googleapis.com/compute/v1/projects/" + ctx.ProjectID
	instance := &compute.Instance{
		Name:        name,
		Description: "syzkaller worker",
		MachineType: prefix + "/zones/" + ctx.ZoneID + "/machineTypes/" + machineType,
		Disks: []*compute.AttachedDisk{
			{
				AutoDelete: true,
				Boot:       true,
				Type:       "PERSISTENT",
				InitializeParams: &compute.AttachedDiskInitializeParams{
					DiskName:    name,
					SourceImage: prefix + "/global/images/" + image,
				},
			},
		},
		Metadata: &compute.Metadata{
			Items: []*compute.MetadataItems{
				{
					Key:   "ssh-keys",
					Value: "syzkaller:" + sshkey,
				},
				{
					Key:   "serial-port-enable",
					Value: "1",
				},
			},
		},
		NetworkInterfaces: []*compute.NetworkInterface{
			&compute.NetworkInterface{
				Network: "global/networks/default",
			},
		},
		Scheduling: &compute.Scheduling{
			AutomaticRestart:  false,
			Preemptible:       true,
			OnHostMaintenance: "TERMINATE",
		},
	}

retry:
	<-ctx.apiRateGate
	op, err := ctx.computeService.Instances.Insert(ctx.ProjectID, ctx.ZoneID, instance).Do()
	if err != nil {
		return "", fmt.Errorf("failed to create instance: %v", err)
	}
	if err := ctx.waitForCompletion("zone", "create image", op.Name, false); err != nil {
		if _, ok := err.(resourcePoolExhaustedError); ok && instance.Scheduling.Preemptible {
			instance.Scheduling.Preemptible = false
			goto retry
		}
		return "", err
	}

	<-ctx.apiRateGate
	inst, err := ctx.computeService.Instances.Get(ctx.ProjectID, ctx.ZoneID, name).Do()
	if err != nil {
		return "", fmt.Errorf("error getting instance %s details after creation: %v", name, err)
	}

	// Finds its internal IP.
	ip := ""
	for _, iface := range inst.NetworkInterfaces {
		if strings.HasPrefix(iface.NetworkIP, "10.") {
			ip = iface.NetworkIP
			break
		}
	}
	if ip == "" {
		return "", fmt.Errorf("didn't find instance internal IP address")
	}
	return ip, nil
}

func (ctx *Context) DeleteInstance(name string, wait bool) error {
	<-ctx.apiRateGate
	op, err := ctx.computeService.Instances.Delete(ctx.ProjectID, ctx.ZoneID, name).Do()
	if apiErr, ok := err.(*googleapi.Error); ok && apiErr.Code == 404 {
		return nil
	}
	if err != nil {
		return fmt.Errorf("failed to delete instance: %v", err)
	}
	if wait {
		if err := ctx.waitForCompletion("zone", "delete image", op.Name, true); err != nil {
			return err
		}
	}
	return nil
}

func (ctx *Context) IsInstanceRunning(name string) bool {
	<-ctx.apiRateGate
	instance, err := ctx.computeService.Instances.Get(ctx.ProjectID, ctx.ZoneID, name).Do()
	if err != nil {
		return false
	}
	return instance.Status == "RUNNING"
}

func (ctx *Context) CreateImage(imageName, gcsFile string) error {
	image := &compute.Image{
		Name: imageName,
		RawDisk: &compute.ImageRawDisk{
			Source: "https://storage.googleapis.com/" + gcsFile,
		},
		Licenses: []string{
			"https://www.googleapis.com/compute/v1/projects/vm-options/global/licenses/enable-vmx",
		},
	}
	<-ctx.apiRateGate
	op, err := ctx.computeService.Images.Insert(ctx.ProjectID, image).Do()
	if err != nil {
		// Try again without the vmx license in case it is not supported.
		image.Licenses = nil
		<-ctx.apiRateGate
		op, err = ctx.computeService.Images.Insert(ctx.ProjectID, image).Do()
	}
	if err != nil {
		return fmt.Errorf("failed to create image: %v", err)
	}
	if err := ctx.waitForCompletion("global", "create image", op.Name, false); err != nil {
		return err
	}
	return nil
}

func (ctx *Context) DeleteImage(imageName string) error {
	<-ctx.apiRateGate
	op, err := ctx.computeService.Images.Delete(ctx.ProjectID, imageName).Do()
	if apiErr, ok := err.(*googleapi.Error); ok && apiErr.Code == 404 {
		return nil
	}
	if err != nil {
		return fmt.Errorf("failed to delete image: %v", err)
	}
	if err := ctx.waitForCompletion("global", "delete image", op.Name, true); err != nil {
		return err
	}
	return nil
}

type resourcePoolExhaustedError string

func (err resourcePoolExhaustedError) Error() string {
	return string(err)
}

func (ctx *Context) waitForCompletion(typ, desc, opName string, ignoreNotFound bool) error {
	for {
		time.Sleep(2 * time.Second)
		<-ctx.apiRateGate
		var err error
		var op *compute.Operation
		switch typ {
		case "global":
			op, err = ctx.computeService.GlobalOperations.Get(ctx.ProjectID, opName).Do()
		case "zone":
			op, err = ctx.computeService.ZoneOperations.Get(ctx.ProjectID, ctx.ZoneID, opName).Do()
		default:
			panic("unknown operation type: " + typ)
		}
		if err != nil {
			return fmt.Errorf("failed to get %v operation %v: %v", desc, opName, err)
		}
		switch op.Status {
		case "PENDING", "RUNNING":
			continue
		case "DONE":
			if op.Error != nil {
				reason := ""
				for _, operr := range op.Error.Errors {
					if operr.Code == "ZONE_RESOURCE_POOL_EXHAUSTED" {
						return resourcePoolExhaustedError(fmt.Sprintf("%+v", operr))
					}
					if ignoreNotFound && operr.Code == "RESOURCE_NOT_FOUND" {
						return nil
					}
					reason += fmt.Sprintf("%+v.", operr)
				}
				return fmt.Errorf("%v operation failed: %v", desc, reason)
			}
			return nil
		default:
			return fmt.Errorf("unknown %v operation status %q: %+v", desc, op.Status, op)
		}
	}
}

func (ctx *Context) getMeta(path string) (string, error) {
	req, err := http.NewRequest("GET", "http://metadata.google.internal/computeMetadata/v1/"+path, nil)
	if err != nil {
		return "", err
	}
	req.Header.Add("Metadata-Flavor", "Google")
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}
	return string(body), nil
}
<|endoftext|>