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

package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"

	"github.com/01org/ciao/ciao-controller/api"
	"github.com/01org/ciao/ciao-controller/types"
	"github.com/01org/ciao/openstack/compute"
	"github.com/01org/ciao/payloads"

	"gopkg.in/yaml.v2"
)

var workloadCommand = &command{
	SubCommands: map[string]subCommand{
		"list":   new(workloadListCommand),
		"create": new(workloadCreateCommand),
	},
}

type workloadListCommand struct {
	Flag     flag.FlagSet
	template string
}

func (cmd *workloadListCommand) usage(...string) {
	fmt.Fprintf(os.Stderr, `usage: ciao-cli [options] workload list

List all workloads

`)
	cmd.Flag.PrintDefaults()
	fmt.Fprintf(os.Stderr, `
The template passed to the -f option operates on a

[]struct {
	OSFLVDISABLEDDisabled  bool    // Not used
	Disk                   string  // Backing images associated with workload
	OSFLVEXTDATAEphemeral  int     // Not currently used
	OsFlavorAccessIsPublic bool    // Indicates whether the workload is available to all tenants
	ID                     string  // ID of the workload
	Links                  []Link  // Not currently used
	Name                   string  // Name of the workload
	RAM                    int     // Amount of RAM allocated to instances of this workload
	Swap                   string  // Not currently used
	Vcpus                  int     // Number of Vcpus allocated to instances of this workload
}
`)
	fmt.Fprintln(os.Stderr, templateFunctionHelp)
	os.Exit(2)
}

func (cmd *workloadListCommand) parseArgs(args []string) []string {
	cmd.Flag.StringVar(&cmd.template, "f", "", "Template used to format output")
	cmd.Flag.Usage = func() { cmd.usage() }
	cmd.Flag.Parse(args)
	return cmd.Flag.Args()
}

func (cmd *workloadListCommand) run(args []string) error {
	if *tenantID == "" {
		fatalf("Missing required -tenant-id parameter")
	}

	var flavors compute.FlavorsDetails
	if *tenantID == "" {
		*tenantID = "faketenant"
	}

	url := buildComputeURL("%s/flavors/detail", *tenantID)

	resp, err := sendHTTPRequest("GET", url, nil, nil)
	if err != nil {
		fatalf(err.Error())
	}

	err = unmarshalHTTPResponse(resp, &flavors)
	if err != nil {
		fatalf(err.Error())
	}

	if cmd.template != "" {
		return outputToTemplate("workload-list", cmd.template,
			&flavors.Flavors)
	}

	for i, flavor := range flavors.Flavors {
		fmt.Printf("Workload %d\n", i+1)
		fmt.Printf("\tName: %s\n\tUUID:%s\n\tImage UUID: %s\n\tCPUs: %d\n\tMemory: %d MB\n",
			flavor.Name, flavor.ID, flavor.Disk, flavor.Vcpus, flavor.RAM)
	}
	return nil
}

type workloadCreateCommand struct {
	Flag     flag.FlagSet
	yamlFile string
}

func (cmd *workloadCreateCommand) parseArgs(args []string) []string {
	cmd.Flag.StringVar(&cmd.yamlFile, "yaml", "", "filename for yaml which describes the workload")
	cmd.Flag.Usage = func() { cmd.usage() }
	cmd.Flag.Parse(args)
	return cmd.Flag.Args()
}

func (cmd *workloadCreateCommand) usage(...string) {
	fmt.Fprintf(os.Stderr, `usage: ciao-cli [options] workload create [flags]

Create a new workload

The create flags are:

`)
	cmd.Flag.PrintDefaults()
	os.Exit(2)
}

func getCiaoWorkloadsResource() (string, error) {
	return getCiaoResource("workloads", api.WorkloadsV1)
}

type source struct {
	Type types.SourceType `json:"service"`
	ID   string           `json:"id"`
}

type disk struct {
	ID        *string `yaml:"volume_id"`
	Size      int     `yaml:"size"`
	Bootable  bool    `yaml:"bootable"`
	Source    *source `yaml:"source"`
	Ephemeral bool    `yaml:"ephemeral"`
}

type defaultResources struct {
	VCPUs  int `yaml:"vcpus"`
	MemMB  int `yaml:"mem_mb"`
	DiskMB int `yaml:"disk_mb"`
}

// we currently only use the first disk due to lack of support
// in types.Workload for multiple storage resources.
type workloadOptions struct {
	Description     string           `yaml:"description"`
	VMType          string           `yaml:"vm_type"`
	FWType          string           `yaml:"fw_type"`
	ImageName       string           `yaml:"image_name"`
	ImageID         string           `yaml:"image_id"`
	Defaults        defaultResources `yaml:"defaults"`
	CloudConfigFile string           `yaml:"cloud_init"`
	Disks           []disk           `yaml:"disks"`
}

func optToReq(opt workloadOptions, req *types.Workload) error {
	b, err := ioutil.ReadFile(opt.CloudConfigFile)
	if err != nil {
		return err
	}

	config := string(b)

	// this is where you'd validate that the options make
	// sense.
	req.Description = opt.Description
	req.VMType = payloads.Hypervisor(opt.VMType)
	req.FWType = opt.FWType
	req.ImageName = opt.ImageName
	req.ImageID = opt.ImageID
	req.Config = config
	req.Storage = []types.StorageResource{}

	for _, disk := range opt.Disks {
		res := types.StorageResource{
			Size:      disk.Size,
			Bootable:  disk.Bootable,
			Ephemeral: disk.Ephemeral,
		}

		if disk.ID != nil {
			res.ID = *disk.ID
		} else if disk.Size == 0 {
			// source had better exist.
			if disk.Source == nil {
				return errors.New("Invalid workload yaml: disk source may not be nil")
			}

			res.SourceType = disk.Source.Type
			res.SourceID = disk.Source.ID
		} else {
			if disk.Bootable == true {
				// you may not request a bootable drive
				// from an empty source
				return errors.New("Invalid workload yaml: empty disk source may not be bootable")
			}

			res.SourceType = types.Empty
		}

		req.Storage = append(req.Storage, res)
	}

	// all default resources are required.
	defaults := opt.Defaults

	r := payloads.RequestedResource{
		Type:  payloads.VCPUs,
		Value: defaults.VCPUs,
	}
	req.Defaults = append(req.Defaults, r)

	r = payloads.RequestedResource{
		Type:  payloads.MemMB,
		Value: defaults.MemMB,
	}
	req.Defaults = append(req.Defaults, r)

	r = payloads.RequestedResource{
		Type:  payloads.DiskMB,
		Value: defaults.DiskMB,
	}
	req.Defaults = append(req.Defaults, r)

	return nil
}

func (cmd *workloadCreateCommand) run(args []string) error {
	var opt workloadOptions
	var req types.Workload

	if cmd.yamlFile == "" {
		cmd.usage()
	}

	f, err := ioutil.ReadFile(cmd.yamlFile)
	if err != nil {
		fatalf("Unable to read workload config file: %s\n", err)
	}

	err = yaml.Unmarshal(f, &opt)
	if err != nil {
		fatalf("Config file invalid: %s\n", err)
	}

	err = optToReq(opt, &req)
	if err != nil {
		fatalf(err.Error())
	}

	b, err := json.Marshal(req)
	if err != nil {
		fatalf(err.Error())
	}

	body := bytes.NewReader(b)

	url, err := getCiaoWorkloadsResource()
	if err != nil {
		fatalf(err.Error())
	}

	ver := api.WorkloadsV1

	resp, err := sendCiaoRequest("POST", url, nil, body, &ver)
	if err != nil {
		fatalf(err.Error())
	}

	if resp.StatusCode != http.StatusCreated {
		fatalf("Workload creation failed: %s", resp.Status)
	}

	var workload types.WorkloadResponse

	err = unmarshalHTTPResponse(resp, &workload)
	if err != nil {
		fatalf(err.Error())
	}

	fmt.Printf("Created new workload: %s\n", workload.Workload.ID)

	return nil
}
<commit_msg>ciao-cli: Fix workload yaml parsing<commit_after>//
// Copyright (c) 2016 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"

	"github.com/01org/ciao/ciao-controller/api"
	"github.com/01org/ciao/ciao-controller/types"
	"github.com/01org/ciao/openstack/compute"
	"github.com/01org/ciao/payloads"

	"gopkg.in/yaml.v2"
)

var workloadCommand = &command{
	SubCommands: map[string]subCommand{
		"list":   new(workloadListCommand),
		"create": new(workloadCreateCommand),
	},
}

type workloadListCommand struct {
	Flag     flag.FlagSet
	template string
}

func (cmd *workloadListCommand) usage(...string) {
	fmt.Fprintf(os.Stderr, `usage: ciao-cli [options] workload list

List all workloads

`)
	cmd.Flag.PrintDefaults()
	fmt.Fprintf(os.Stderr, `
The template passed to the -f option operates on a

[]struct {
	OSFLVDISABLEDDisabled  bool    // Not used
	Disk                   string  // Backing images associated with workload
	OSFLVEXTDATAEphemeral  int     // Not currently used
	OsFlavorAccessIsPublic bool    // Indicates whether the workload is available to all tenants
	ID                     string  // ID of the workload
	Links                  []Link  // Not currently used
	Name                   string  // Name of the workload
	RAM                    int     // Amount of RAM allocated to instances of this workload
	Swap                   string  // Not currently used
	Vcpus                  int     // Number of Vcpus allocated to instances of this workload
}
`)
	fmt.Fprintln(os.Stderr, templateFunctionHelp)
	os.Exit(2)
}

func (cmd *workloadListCommand) parseArgs(args []string) []string {
	cmd.Flag.StringVar(&cmd.template, "f", "", "Template used to format output")
	cmd.Flag.Usage = func() { cmd.usage() }
	cmd.Flag.Parse(args)
	return cmd.Flag.Args()
}

func (cmd *workloadListCommand) run(args []string) error {
	if *tenantID == "" {
		fatalf("Missing required -tenant-id parameter")
	}

	var flavors compute.FlavorsDetails
	if *tenantID == "" {
		*tenantID = "faketenant"
	}

	url := buildComputeURL("%s/flavors/detail", *tenantID)

	resp, err := sendHTTPRequest("GET", url, nil, nil)
	if err != nil {
		fatalf(err.Error())
	}

	err = unmarshalHTTPResponse(resp, &flavors)
	if err != nil {
		fatalf(err.Error())
	}

	if cmd.template != "" {
		return outputToTemplate("workload-list", cmd.template,
			&flavors.Flavors)
	}

	for i, flavor := range flavors.Flavors {
		fmt.Printf("Workload %d\n", i+1)
		fmt.Printf("\tName: %s\n\tUUID:%s\n\tImage UUID: %s\n\tCPUs: %d\n\tMemory: %d MB\n",
			flavor.Name, flavor.ID, flavor.Disk, flavor.Vcpus, flavor.RAM)
	}
	return nil
}

type workloadCreateCommand struct {
	Flag     flag.FlagSet
	yamlFile string
}

func (cmd *workloadCreateCommand) parseArgs(args []string) []string {
	cmd.Flag.StringVar(&cmd.yamlFile, "yaml", "", "filename for yaml which describes the workload")
	cmd.Flag.Usage = func() { cmd.usage() }
	cmd.Flag.Parse(args)
	return cmd.Flag.Args()
}

func (cmd *workloadCreateCommand) usage(...string) {
	fmt.Fprintf(os.Stderr, `usage: ciao-cli [options] workload create [flags]

Create a new workload

The create flags are:

`)
	cmd.Flag.PrintDefaults()
	os.Exit(2)
}

func getCiaoWorkloadsResource() (string, error) {
	return getCiaoResource("workloads", api.WorkloadsV1)
}

type source struct {
	Type types.SourceType `yaml:"service"`
	ID   string           `yaml:"id"`
}

type disk struct {
	ID        *string `yaml:"volume_id"`
	Size      int     `yaml:"size"`
	Bootable  bool    `yaml:"bootable"`
	Source    *source `yaml:"source"`
	Ephemeral bool    `yaml:"ephemeral"`
}

type defaultResources struct {
	VCPUs  int `yaml:"vcpus"`
	MemMB  int `yaml:"mem_mb"`
	DiskMB int `yaml:"disk_mb"`
}

// we currently only use the first disk due to lack of support
// in types.Workload for multiple storage resources.
type workloadOptions struct {
	Description     string           `yaml:"description"`
	VMType          string           `yaml:"vm_type"`
	FWType          string           `yaml:"fw_type"`
	ImageName       string           `yaml:"image_name"`
	ImageID         string           `yaml:"image_id"`
	Defaults        defaultResources `yaml:"defaults"`
	CloudConfigFile string           `yaml:"cloud_init"`
	Disks           []disk           `yaml:"disks"`
}

func optToReq(opt workloadOptions, req *types.Workload) error {
	b, err := ioutil.ReadFile(opt.CloudConfigFile)
	if err != nil {
		return err
	}

	config := string(b)

	// this is where you'd validate that the options make
	// sense.
	req.Description = opt.Description
	req.VMType = payloads.Hypervisor(opt.VMType)
	req.FWType = opt.FWType
	req.ImageName = opt.ImageName
	req.ImageID = opt.ImageID
	req.Config = config
	req.Storage = []types.StorageResource{}

	for _, disk := range opt.Disks {
		res := types.StorageResource{
			Size:      disk.Size,
			Bootable:  disk.Bootable,
			Ephemeral: disk.Ephemeral,
		}

		if disk.ID != nil {
			res.ID = *disk.ID
		} else if disk.Size == 0 {
			// source had better exist.
			if disk.Source == nil {
				return errors.New("Invalid workload yaml: disk source may not be nil")
			}

			res.SourceType = disk.Source.Type
			res.SourceID = disk.Source.ID
		} else {
			if disk.Bootable == true {
				// you may not request a bootable drive
				// from an empty source
				return errors.New("Invalid workload yaml: empty disk source may not be bootable")
			}

			res.SourceType = types.Empty
		}

		req.Storage = append(req.Storage, res)
	}

	// all default resources are required.
	defaults := opt.Defaults

	r := payloads.RequestedResource{
		Type:  payloads.VCPUs,
		Value: defaults.VCPUs,
	}
	req.Defaults = append(req.Defaults, r)

	r = payloads.RequestedResource{
		Type:  payloads.MemMB,
		Value: defaults.MemMB,
	}
	req.Defaults = append(req.Defaults, r)

	r = payloads.RequestedResource{
		Type:  payloads.DiskMB,
		Value: defaults.DiskMB,
	}
	req.Defaults = append(req.Defaults, r)

	return nil
}

func (cmd *workloadCreateCommand) run(args []string) error {
	var opt workloadOptions
	var req types.Workload

	if cmd.yamlFile == "" {
		cmd.usage()
	}

	f, err := ioutil.ReadFile(cmd.yamlFile)
	if err != nil {
		fatalf("Unable to read workload config file: %s\n", err)
	}

	err = yaml.Unmarshal(f, &opt)
	if err != nil {
		fatalf("Config file invalid: %s\n", err)
	}

	err = optToReq(opt, &req)
	if err != nil {
		fatalf(err.Error())
	}

	b, err := json.Marshal(req)
	if err != nil {
		fatalf(err.Error())
	}

	body := bytes.NewReader(b)

	url, err := getCiaoWorkloadsResource()
	if err != nil {
		fatalf(err.Error())
	}

	ver := api.WorkloadsV1

	resp, err := sendCiaoRequest("POST", url, nil, body, &ver)
	if err != nil {
		fatalf(err.Error())
	}

	if resp.StatusCode != http.StatusCreated {
		fatalf("Workload creation failed: %s", resp.Status)
	}

	var workload types.WorkloadResponse

	err = unmarshalHTTPResponse(resp, &workload)
	if err != nil {
		fatalf(err.Error())
	}

	fmt.Printf("Created new workload: %s\n", workload.Workload.ID)

	return nil
}
<|endoftext|>


<commit_before>package model

// StatusResponse - Represents status information of the already requested notifications.
type StatusResponse interface {
	GetID() string
	GetStatus() string
}

type statusResponse struct {
	_ID     string
	_status string
}

func (p *statusResponse) GetID() string {
	return p._ID
}

func (p *statusResponse) GetStatus() string {
	return p._status
}

func (p *statusResponse) Build(id string, status string) (statusResponse, error) {

	var res statusResponse
	var err error

	res._ID = id
	res._status = status

	return res, err
}
<commit_msg>Aligning to interface<commit_after>package model

// StatusResponse - Represents status information of the already requested notifications.
type StatusResponse interface {
	GetID() string
	GetStatus() string
	Build(string, string) (statusResponse, error)
}

type statusResponse struct {
	_ID     string
	_status string
}

func (p *statusResponse) GetID() string {
	return p._ID
}

func (p *statusResponse) GetStatus() string {
	return p._status
}

func (p *statusResponse) Build(id string, status string) (statusResponse, error) {

	var res statusResponse
	var err error

	res._ID = id
	res._status = status

	return res, err
}
<|endoftext|>


<commit_before>// Copyright (c) Facebook, Inc. and its affiliates.
//
// 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 redhat

import (
	"log"

	"github.com/facebookincubator/nvdtools/providers/redhat/schema"
	"github.com/facebookincubator/nvdtools/rpm"
	"github.com/facebookincubator/nvdtools/wfn"
	"github.com/pkg/errors"
)

// packageFeed is an association between package names and the list of CVEs,
// fixed or not, that have been recording against that package.
// Packages are identified by their base package names without any epoch,
// version, release.
type packageFeed map[string][]*schema.CVE

// addPackage adds pkg to the list of packages only if not already there.
func addPackage(pkgs []string, pkg string) []string {
	for _, p := range pkgs {
		if p == pkg {
			return pkgs
		}
	}
	return append(pkgs, pkg)
}

// packageFeed transforms a Feed into a packageFeed.
func (feed *Feed) packageFeed() packageFeed {
	if feed.pkg2CVE != nil {
		return feed.pkg2CVE
	}

	pkgFeed := packageFeed{}

	for _, cve := range feed.data {
		var pkgs []string

		// 1. look at AffectedRelease.
		for _, ar := range cve.AffectedRelease {
			if ar.Package == "" {
				continue
			}
			// Failing to parse a package isn't fatal, but we want to surface the error
			rpmPkg, err := rpm.Parse(ar.Package)
			if err != nil {
				log.Printf("feed: failed to parse package: %q", ar.Package)
				continue
			}
			pkgs = addPackage(pkgs, rpmPkg.Name)
		}

		// 2. look at PackageState.
		for _, ps := range cve.PackageState {
			if ps.PackageName == "" {
				continue
			}
			pkgs = addPackage(pkgs, ps.PackageName)

		}

		for _, pkg := range pkgs {
			pkgFeed[pkg] = append(pkgFeed[pkg], cve)

		}
	}

	feed.pkg2CVE = pkgFeed

	return pkgFeed
}

// ListFixedCVEs will return the list of CVEs that aren't applicable for the
// given (distro, package). Those CVEs could be not applicable for various
// reasons. For instance for packaged version isn't vulnerable or a fix has
// been backported.
// distro is a CPE identifying a distribution.
// pkg is the full package name as reported, for instance by rpm -qa.
func (feed *Feed) ListFixedCVEs(d *wfn.Attributes, p *rpm.Package) ([]string, error) {
	pkgFeed := feed.packageFeed()
	checker, err := feed.Checker()
	if err != nil {
		return nil, errors.Wrapf(err, "list")
	}

	var cves []string
	for _, cve := range pkgFeed[p.Name] {
		if checker.Check(p, d, cve.Name) {
			cves = append(cves, cve.Name)
		}
	}

	return cves, nil
}
<commit_msg>[redhat] Sort the list of fixed CVEs to<commit_after>// Copyright (c) Facebook, Inc. and its affiliates.
//
// 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 redhat

import (
	"log"
	"sort"

	"github.com/facebookincubator/nvdtools/providers/redhat/schema"
	"github.com/facebookincubator/nvdtools/rpm"
	"github.com/facebookincubator/nvdtools/wfn"
	"github.com/pkg/errors"
)

// packageFeed is an association between package names and the list of CVEs,
// fixed or not, that have been recording against that package.
// Packages are identified by their base package names without any epoch,
// version, release.
type packageFeed map[string][]*schema.CVE

// addPackage adds pkg to the list of packages only if not already there.
func addPackage(pkgs []string, pkg string) []string {
	for _, p := range pkgs {
		if p == pkg {
			return pkgs
		}
	}
	return append(pkgs, pkg)
}

// packageFeed transforms a Feed into a packageFeed.
func (feed *Feed) packageFeed() packageFeed {
	if feed.pkg2CVE != nil {
		return feed.pkg2CVE
	}

	pkgFeed := packageFeed{}

	for _, cve := range feed.data {
		var pkgs []string

		// 1. look at AffectedRelease.
		for _, ar := range cve.AffectedRelease {
			if ar.Package == "" {
				continue
			}
			// Failing to parse a package isn't fatal, but we want to surface the error
			rpmPkg, err := rpm.Parse(ar.Package)
			if err != nil {
				log.Printf("feed: failed to parse package: %q", ar.Package)
				continue
			}
			pkgs = addPackage(pkgs, rpmPkg.Name)
		}

		// 2. look at PackageState.
		for _, ps := range cve.PackageState {
			if ps.PackageName == "" {
				continue
			}
			pkgs = addPackage(pkgs, ps.PackageName)

		}

		for _, pkg := range pkgs {
			pkgFeed[pkg] = append(pkgFeed[pkg], cve)

		}
	}

	feed.pkg2CVE = pkgFeed

	return pkgFeed
}

// ListFixedCVEs will return the list of CVEs that aren't applicable for the
// given (distro, package). Those CVEs could be not applicable for various
// reasons. For instance for packaged version isn't vulnerable or a fix has
// been backported.
// distro is a CPE identifying a distribution.
// pkg is the full package name as reported, for instance by rpm -qa.
func (feed *Feed) ListFixedCVEs(d *wfn.Attributes, p *rpm.Package) ([]string, error) {
	pkgFeed := feed.packageFeed()
	checker, err := feed.Checker()
	if err != nil {
		return nil, errors.Wrapf(err, "list")
	}

	var cves []string
	for _, cve := range pkgFeed[p.Name] {
		if checker.Check(p, d, cve.Name) {
			cves = append(cves, cve.Name)
		}
	}

	// Sort for deterministic output.
	sort.Strings(cves)

	return cves, nil
}
<|endoftext|>


<commit_before>// This package implements a provisioner for Packer that executes
// shell scripts within the remote machine.
package shell

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"github.com/mitchellh/iochan"
	"github.com/mitchellh/mapstructure"
	"github.com/mitchellh/packer/packer"
	"io"
	"io/ioutil"
	"log"
	"os"
	"sort"
	"strings"
	"text/template"
)

const DefaultRemotePath = "/tmp/script.sh"

type config struct {
	// An inline script to execute. Multiple strings are all executed
	// in the context of a single shell.
	Inline []string

	// The shebang value used when running inline scripts.
	InlineShebang string `mapstructure:"inline_shebang"`

	// The local path of the shell script to upload and execute.
	Script string

	// An array of multiple scripts to run.
	Scripts []string

	// An array of environment variables that will be injected before
	// your command(s) are executed.
	Vars []string `mapstructure:"environment_vars"`

	// The remote path where the local shell script will be uploaded to.
	// This should be set to a writable file that is in a pre-existing directory.
	RemotePath string `mapstructure:"remote_path"`

	// The command used to execute the script. The '{{ .Path }}' variable
	// should be used to specify where the script goes, {{ .Vars }}
	// can be used to inject the environment_vars into the environment.
	ExecuteCommand string `mapstructure:"execute_command"`

	// Packer configurations, these come from Packer itself
	PackerBuildName   string `mapstructure:"packer_build_name"`
	PackerBuilderType string `mapstructure:"packer_builder_type"`
}

type Provisioner struct {
	config config
}

type ExecuteCommandTemplate struct {
	Vars string
	Path string
}

func (p *Provisioner) Prepare(raws ...interface{}) error {
	var md mapstructure.Metadata
	decoderConfig := &mapstructure.DecoderConfig{
		Metadata: &md,
		Result:   &p.config,
	}

	decoder, err := mapstructure.NewDecoder(decoderConfig)
	if err != nil {
		return err
	}

	for _, raw := range raws {
		err := decoder.Decode(raw)
		if err != nil {
			return err
		}
	}

	// Accumulate any errors
	errs := make([]error, 0)

	// Unused keys are errors
	if len(md.Unused) > 0 {
		sort.Strings(md.Unused)
		for _, unused := range md.Unused {
			if unused != "type" && !strings.HasPrefix(unused, "packer_") {
				errs = append(
					errs, fmt.Errorf("Unknown configuration key: %s", unused))
			}
		}
	}

	if p.config.ExecuteCommand == "" {
		p.config.ExecuteCommand = "chmod +x {{.Path}}; {{.Vars}} {{.Path}}"
	}

	if p.config.Inline != nil && len(p.config.Inline) == 0 {
		p.config.Inline = nil
	}

	if p.config.InlineShebang == "" {
		p.config.InlineShebang = "/bin/sh"
	}

	if p.config.RemotePath == "" {
		p.config.RemotePath = DefaultRemotePath
	}

	if p.config.Scripts == nil {
		p.config.Scripts = make([]string, 0)
	}

	if p.config.Vars == nil {
		p.config.Vars = make([]string, 0)
	}

	if p.config.Script != "" && len(p.config.Scripts) > 0 {
		errs = append(errs, errors.New("Only one of script or scripts can be specified."))
	}

	if p.config.Script != "" {
		p.config.Scripts = []string{p.config.Script}
	}

	if len(p.config.Scripts) == 0 && p.config.Inline == nil {
		errs = append(errs, errors.New("Either a script file or inline script must be specified."))
	} else if len(p.config.Scripts) > 0 && p.config.Inline != nil {
		errs = append(errs, errors.New("Only a script file or an inline script can be specified, not both."))
	}

	for _, path := range p.config.Scripts {
		if _, err := os.Stat(path); err != nil {
			errs = append(errs, fmt.Errorf("Bad script '%s': %s", path, err))
		}
	}

	// Do a check for bad environment variables, such as '=foo', 'foobar'
	for _, kv := range p.config.Vars {
		vs := strings.Split(kv, "=")
		if len(vs) != 2 || vs[0] == "" {
			errs = append(
				errs,
				fmt.Errorf("Environment variable not in format 'key=value': %s", kv))
		}
	}

	if len(errs) > 0 {
		return &packer.MultiError{errs}
	}

	return nil
}

func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error {
	scripts := make([]string, len(p.config.Scripts))
	copy(scripts, p.config.Scripts)

	// If we have an inline script, then turn that into a temporary
	// shell script and use that.
	if p.config.Inline != nil {
		tf, err := ioutil.TempFile("", "packer-shell")
		if err != nil {
			return fmt.Errorf("Error preparing shell script: %s", err)
		}
		defer os.Remove(tf.Name())

		// Set the path to the temporary file
		scripts = append(scripts, tf.Name())

		// Write our contents to it
		writer := bufio.NewWriter(tf)
		writer.WriteString(fmt.Sprintf("#!%s\n", p.config.InlineShebang))
		for _, command := range p.config.Inline {
			if _, err := writer.WriteString(command + "\n"); err != nil {
				return fmt.Errorf("Error preparing shell script: %s", err)
			}
		}

		if err := writer.Flush(); err != nil {
			return fmt.Errorf("Error preparing shell script: %s", err)
		}

		tf.Close()
	}

	// Build our variables up by adding in the build name and builder type
	envVars := make([]string, len(p.config.Vars)+2)
	envVars[0] = "PACKER_BUILD_NAME=" + p.config.PackerBuildName
	envVars[1] = "PACKER_BUILDER_TYPE=" + p.config.PackerBuilderType
	copy(envVars[2:], p.config.Vars)

	for _, path := range scripts {
		ui.Say(fmt.Sprintf("Provisioning with shell script: %s", path))

		log.Printf("Opening %s for reading", path)
		f, err := os.Open(path)
		if err != nil {
			return fmt.Errorf("Error opening shell script: %s", err)
		}
		defer f.Close()

		log.Printf("Uploading %s => %s", path, p.config.RemotePath)
		err = comm.Upload(p.config.RemotePath, f)
		if err != nil {
			return fmt.Errorf("Error uploading shell script: %s", err)
		}

		// Close the original file since we copied it
		f.Close()

		// Flatten the environment variables
		flattendVars := strings.Join(envVars, " ")

		// Compile the command
		var command bytes.Buffer
		t := template.Must(template.New("command").Parse(p.config.ExecuteCommand))
		t.Execute(&command, &ExecuteCommandTemplate{flattendVars, p.config.RemotePath})

		// Setup the remote command
		stdout_r, stdout_w := io.Pipe()
		stderr_r, stderr_w := io.Pipe()

		var cmd packer.RemoteCmd
		cmd.Command = command.String()
		cmd.Stdout = stdout_w
		cmd.Stderr = stderr_w

		log.Printf("Executing command: %s", cmd.Command)
		err = comm.Start(&cmd)
		if err != nil {
			return fmt.Errorf("Failed executing command: %s", err)
		}

		exitChan := make(chan int, 1)
		stdoutChan := iochan.DelimReader(stdout_r, '\n')
		stderrChan := iochan.DelimReader(stderr_r, '\n')

		go func() {
			defer stdout_w.Close()
			defer stderr_w.Close()

			cmd.Wait()
			exitChan <- cmd.ExitStatus
		}()

	OutputLoop:
		for {
			select {
			case output := <-stderrChan:
				ui.Message(strings.TrimSpace(output))
			case output := <-stdoutChan:
				ui.Message(strings.TrimSpace(output))
			case exitStatus := <-exitChan:
				log.Printf("shell provisioner exited with status %d", exitStatus)

				if exitStatus != 0 {
					return fmt.Errorf("Script exited with non-zero exit status: %d", exitStatus)
				}

				break OutputLoop
			}
		}

		// Make sure we finish off stdout/stderr because we may have gotten
		// a message from the exit channel first.
		for output := range stdoutChan {
			ui.Message(output)
		}

		for output := range stderrChan {
			ui.Message(output)
		}
	}

	return nil
}
<commit_msg>provisioner/shell: use StartWithUi<commit_after>// This package implements a provisioner for Packer that executes
// shell scripts within the remote machine.
package shell

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"github.com/mitchellh/mapstructure"
	"github.com/mitchellh/packer/packer"
	"io/ioutil"
	"log"
	"os"
	"sort"
	"strings"
	"text/template"
)

const DefaultRemotePath = "/tmp/script.sh"

type config struct {
	// An inline script to execute. Multiple strings are all executed
	// in the context of a single shell.
	Inline []string

	// The shebang value used when running inline scripts.
	InlineShebang string `mapstructure:"inline_shebang"`

	// The local path of the shell script to upload and execute.
	Script string

	// An array of multiple scripts to run.
	Scripts []string

	// An array of environment variables that will be injected before
	// your command(s) are executed.
	Vars []string `mapstructure:"environment_vars"`

	// The remote path where the local shell script will be uploaded to.
	// This should be set to a writable file that is in a pre-existing directory.
	RemotePath string `mapstructure:"remote_path"`

	// The command used to execute the script. The '{{ .Path }}' variable
	// should be used to specify where the script goes, {{ .Vars }}
	// can be used to inject the environment_vars into the environment.
	ExecuteCommand string `mapstructure:"execute_command"`

	// Packer configurations, these come from Packer itself
	PackerBuildName   string `mapstructure:"packer_build_name"`
	PackerBuilderType string `mapstructure:"packer_builder_type"`
}

type Provisioner struct {
	config config
}

type ExecuteCommandTemplate struct {
	Vars string
	Path string
}

func (p *Provisioner) Prepare(raws ...interface{}) error {
	var md mapstructure.Metadata
	decoderConfig := &mapstructure.DecoderConfig{
		Metadata: &md,
		Result:   &p.config,
	}

	decoder, err := mapstructure.NewDecoder(decoderConfig)
	if err != nil {
		return err
	}

	for _, raw := range raws {
		err := decoder.Decode(raw)
		if err != nil {
			return err
		}
	}

	// Accumulate any errors
	errs := make([]error, 0)

	// Unused keys are errors
	if len(md.Unused) > 0 {
		sort.Strings(md.Unused)
		for _, unused := range md.Unused {
			if unused != "type" && !strings.HasPrefix(unused, "packer_") {
				errs = append(
					errs, fmt.Errorf("Unknown configuration key: %s", unused))
			}
		}
	}

	if p.config.ExecuteCommand == "" {
		p.config.ExecuteCommand = "chmod +x {{.Path}}; {{.Vars}} {{.Path}}"
	}

	if p.config.Inline != nil && len(p.config.Inline) == 0 {
		p.config.Inline = nil
	}

	if p.config.InlineShebang == "" {
		p.config.InlineShebang = "/bin/sh"
	}

	if p.config.RemotePath == "" {
		p.config.RemotePath = DefaultRemotePath
	}

	if p.config.Scripts == nil {
		p.config.Scripts = make([]string, 0)
	}

	if p.config.Vars == nil {
		p.config.Vars = make([]string, 0)
	}

	if p.config.Script != "" && len(p.config.Scripts) > 0 {
		errs = append(errs, errors.New("Only one of script or scripts can be specified."))
	}

	if p.config.Script != "" {
		p.config.Scripts = []string{p.config.Script}
	}

	if len(p.config.Scripts) == 0 && p.config.Inline == nil {
		errs = append(errs, errors.New("Either a script file or inline script must be specified."))
	} else if len(p.config.Scripts) > 0 && p.config.Inline != nil {
		errs = append(errs, errors.New("Only a script file or an inline script can be specified, not both."))
	}

	for _, path := range p.config.Scripts {
		if _, err := os.Stat(path); err != nil {
			errs = append(errs, fmt.Errorf("Bad script '%s': %s", path, err))
		}
	}

	// Do a check for bad environment variables, such as '=foo', 'foobar'
	for _, kv := range p.config.Vars {
		vs := strings.Split(kv, "=")
		if len(vs) != 2 || vs[0] == "" {
			errs = append(
				errs,
				fmt.Errorf("Environment variable not in format 'key=value': %s", kv))
		}
	}

	if len(errs) > 0 {
		return &packer.MultiError{errs}
	}

	return nil
}

func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error {
	scripts := make([]string, len(p.config.Scripts))
	copy(scripts, p.config.Scripts)

	// If we have an inline script, then turn that into a temporary
	// shell script and use that.
	if p.config.Inline != nil {
		tf, err := ioutil.TempFile("", "packer-shell")
		if err != nil {
			return fmt.Errorf("Error preparing shell script: %s", err)
		}
		defer os.Remove(tf.Name())

		// Set the path to the temporary file
		scripts = append(scripts, tf.Name())

		// Write our contents to it
		writer := bufio.NewWriter(tf)
		writer.WriteString(fmt.Sprintf("#!%s\n", p.config.InlineShebang))
		for _, command := range p.config.Inline {
			if _, err := writer.WriteString(command + "\n"); err != nil {
				return fmt.Errorf("Error preparing shell script: %s", err)
			}
		}

		if err := writer.Flush(); err != nil {
			return fmt.Errorf("Error preparing shell script: %s", err)
		}

		tf.Close()
	}

	// Build our variables up by adding in the build name and builder type
	envVars := make([]string, len(p.config.Vars)+2)
	envVars[0] = "PACKER_BUILD_NAME=" + p.config.PackerBuildName
	envVars[1] = "PACKER_BUILDER_TYPE=" + p.config.PackerBuilderType
	copy(envVars[2:], p.config.Vars)

	for _, path := range scripts {
		ui.Say(fmt.Sprintf("Provisioning with shell script: %s", path))

		log.Printf("Opening %s for reading", path)
		f, err := os.Open(path)
		if err != nil {
			return fmt.Errorf("Error opening shell script: %s", err)
		}
		defer f.Close()

		log.Printf("Uploading %s => %s", path, p.config.RemotePath)
		err = comm.Upload(p.config.RemotePath, f)
		if err != nil {
			return fmt.Errorf("Error uploading shell script: %s", err)
		}

		// Close the original file since we copied it
		f.Close()

		// Flatten the environment variables
		flattendVars := strings.Join(envVars, " ")

		// Compile the command
		var command bytes.Buffer
		t := template.Must(template.New("command").Parse(p.config.ExecuteCommand))
		t.Execute(&command, &ExecuteCommandTemplate{flattendVars, p.config.RemotePath})

		cmd := &packer.RemoteCmd{Command: command.String()}
		log.Printf("Executing command: %s", cmd.Command)
		if err := cmd.StartWithUi(comm, ui); err != nil {
			return fmt.Errorf("Failed executing command: %s", err)
		}

		if cmd.ExitStatus != 0 {
			return fmt.Errorf("Script exited with non-zero exit status: %d", cmd.ExitStatus)
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package outbound

//go:generate go run $GOPATH/src/v2ray.com/core/common/errors/errorgen/main.go -pkg outbound -path Proxy,VMess,Outbound

import (
	"context"
	"time"

	"v2ray.com/core"
	"v2ray.com/core/common"
	"v2ray.com/core/common/buf"
	"v2ray.com/core/common/net"
	"v2ray.com/core/common/protocol"
	"v2ray.com/core/common/retry"
	"v2ray.com/core/common/signal"
	"v2ray.com/core/proxy"
	"v2ray.com/core/proxy/vmess"
	"v2ray.com/core/proxy/vmess/encoding"
	"v2ray.com/core/transport/internet"
	"v2ray.com/core/transport/ray"
)

// Handler is an outbound connection handler for VMess protocol.
type Handler struct {
	serverList   *protocol.ServerList
	serverPicker protocol.ServerPicker
	v            *core.Instance
}

func New(ctx context.Context, config *Config) (*Handler, error) {
	serverList := protocol.NewServerList()
	for _, rec := range config.Receiver {
		serverList.AddServer(protocol.NewServerSpecFromPB(*rec))
	}
	handler := &Handler{
		serverList:   serverList,
		serverPicker: protocol.NewRoundRobinServerPicker(serverList),
		v:            core.FromContext(ctx),
	}

	if handler.v == nil {
		return nil, newError("V is not in context.")
	}

	return handler, nil
}

// Process implements proxy.Outbound.Process().
func (v *Handler) Process(ctx context.Context, outboundRay ray.OutboundRay, dialer proxy.Dialer) error {
	var rec *protocol.ServerSpec
	var conn internet.Connection

	err := retry.ExponentialBackoff(5, 200).On(func() error {
		rec = v.serverPicker.PickServer()
		rawConn, err := dialer.Dial(ctx, rec.Destination())
		if err != nil {
			return err
		}
		conn = rawConn

		return nil
	})
	if err != nil {
		return newError("failed to find an available destination").Base(err).AtWarning()
	}
	defer conn.Close()

	target, ok := proxy.TargetFromContext(ctx)
	if !ok {
		return newError("target not specified").AtError()
	}
	newError("tunneling request to ", target, " via ", rec.Destination()).WriteToLog()

	command := protocol.RequestCommandTCP
	if target.Network == net.Network_UDP {
		command = protocol.RequestCommandUDP
	}
	//if target.Address.Family().IsDomain() && target.Address.Domain() == "v1.mux.cool" {
	//	command = protocol.RequestCommandMux
	//}
	request := &protocol.RequestHeader{
		Version: encoding.Version,
		User:    rec.PickUser(),
		Command: command,
		Address: target.Address,
		Port:    target.Port,
		Option:  protocol.RequestOptionChunkStream,
	}

	rawAccount, err := request.User.GetTypedAccount()
	if err != nil {
		return newError("failed to get user account").Base(err).AtWarning()
	}
	account := rawAccount.(*vmess.InternalAccount)
	request.Security = account.Security

	if request.Security.Is(protocol.SecurityType_AES128_GCM) || request.Security.Is(protocol.SecurityType_NONE) || request.Security.Is(protocol.SecurityType_CHACHA20_POLY1305) {
		request.Option.Set(protocol.RequestOptionChunkMasking)
	}

	input := outboundRay.OutboundInput()
	output := outboundRay.OutboundOutput()

	session := encoding.NewClientSession(protocol.DefaultIDHash)
	sessionPolicy := v.v.PolicyManager().ForLevel(request.User.Level)

	ctx, cancel := context.WithCancel(ctx)
	timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)

	requestDone := signal.ExecuteAsync(func() error {
		writer := buf.NewBufferedWriter(buf.NewWriter(conn))
		if err := session.EncodeRequestHeader(request, writer); err != nil {
			return newError("failed to encode request").Base(err).AtWarning()
		}

		bodyWriter := session.EncodeRequestBody(request, writer)
		firstPayload, err := input.ReadTimeout(time.Millisecond * 500)
		if err != nil && err != buf.ErrReadTimeout {
			return newError("failed to get first payload").Base(err)
		}
		if !firstPayload.IsEmpty() {
			if err := bodyWriter.WriteMultiBuffer(firstPayload); err != nil {
				return newError("failed to write first payload").Base(err)
			}
			firstPayload.Release()
		}

		if err := writer.SetBuffered(false); err != nil {
			return err
		}

		if err := buf.Copy(input, bodyWriter, buf.UpdateActivity(timer)); err != nil {
			return err
		}

		if request.Option.Has(protocol.RequestOptionChunkStream) {
			if err := bodyWriter.WriteMultiBuffer(buf.MultiBuffer{}); err != nil {
				return err
			}
		}
		timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
		return nil
	})

	responseDone := signal.ExecuteAsync(func() error {
		defer output.Close()
		defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)

		reader := buf.NewBufferedReader(buf.NewReader(conn))
		header, err := session.DecodeResponseHeader(reader)
		if err != nil {
			return err
		}
		v.handleCommand(rec.Destination(), header.Command)

		reader.SetBuffered(false)
		bodyReader := session.DecodeResponseBody(request, reader)
		return buf.Copy(bodyReader, output, buf.UpdateActivity(timer))
	})

	if err := signal.ErrorOrFinish2(ctx, requestDone, responseDone); err != nil {
		return newError("connection ends").Base(err)
	}

	return nil
}

func init() {
	common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
		return New(ctx, config.(*Config))
	}))
}
<commit_msg>enable mux command for next version<commit_after>package outbound

//go:generate go run $GOPATH/src/v2ray.com/core/common/errors/errorgen/main.go -pkg outbound -path Proxy,VMess,Outbound

import (
	"context"
	"time"

	"v2ray.com/core"
	"v2ray.com/core/common"
	"v2ray.com/core/common/buf"
	"v2ray.com/core/common/net"
	"v2ray.com/core/common/protocol"
	"v2ray.com/core/common/retry"
	"v2ray.com/core/common/signal"
	"v2ray.com/core/proxy"
	"v2ray.com/core/proxy/vmess"
	"v2ray.com/core/proxy/vmess/encoding"
	"v2ray.com/core/transport/internet"
	"v2ray.com/core/transport/ray"
)

// Handler is an outbound connection handler for VMess protocol.
type Handler struct {
	serverList   *protocol.ServerList
	serverPicker protocol.ServerPicker
	v            *core.Instance
}

func New(ctx context.Context, config *Config) (*Handler, error) {
	serverList := protocol.NewServerList()
	for _, rec := range config.Receiver {
		serverList.AddServer(protocol.NewServerSpecFromPB(*rec))
	}
	handler := &Handler{
		serverList:   serverList,
		serverPicker: protocol.NewRoundRobinServerPicker(serverList),
		v:            core.FromContext(ctx),
	}

	if handler.v == nil {
		return nil, newError("V is not in context.")
	}

	return handler, nil
}

// Process implements proxy.Outbound.Process().
func (v *Handler) Process(ctx context.Context, outboundRay ray.OutboundRay, dialer proxy.Dialer) error {
	var rec *protocol.ServerSpec
	var conn internet.Connection

	err := retry.ExponentialBackoff(5, 200).On(func() error {
		rec = v.serverPicker.PickServer()
		rawConn, err := dialer.Dial(ctx, rec.Destination())
		if err != nil {
			return err
		}
		conn = rawConn

		return nil
	})
	if err != nil {
		return newError("failed to find an available destination").Base(err).AtWarning()
	}
	defer conn.Close()

	target, ok := proxy.TargetFromContext(ctx)
	if !ok {
		return newError("target not specified").AtError()
	}
	newError("tunneling request to ", target, " via ", rec.Destination()).WriteToLog()

	command := protocol.RequestCommandTCP
	if target.Network == net.Network_UDP {
		command = protocol.RequestCommandUDP
	}
	if target.Address.Family().IsDomain() && target.Address.Domain() == "v1.mux.cool" {
		command = protocol.RequestCommandMux
	}

	request := &protocol.RequestHeader{
		Version: encoding.Version,
		User:    rec.PickUser(),
		Command: command,
		Address: target.Address,
		Port:    target.Port,
		Option:  protocol.RequestOptionChunkStream,
	}

	rawAccount, err := request.User.GetTypedAccount()
	if err != nil {
		return newError("failed to get user account").Base(err).AtWarning()
	}
	account := rawAccount.(*vmess.InternalAccount)
	request.Security = account.Security

	if request.Security.Is(protocol.SecurityType_AES128_GCM) || request.Security.Is(protocol.SecurityType_NONE) || request.Security.Is(protocol.SecurityType_CHACHA20_POLY1305) {
		request.Option.Set(protocol.RequestOptionChunkMasking)
	}

	input := outboundRay.OutboundInput()
	output := outboundRay.OutboundOutput()

	session := encoding.NewClientSession(protocol.DefaultIDHash)
	sessionPolicy := v.v.PolicyManager().ForLevel(request.User.Level)

	ctx, cancel := context.WithCancel(ctx)
	timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)

	requestDone := signal.ExecuteAsync(func() error {
		writer := buf.NewBufferedWriter(buf.NewWriter(conn))
		if err := session.EncodeRequestHeader(request, writer); err != nil {
			return newError("failed to encode request").Base(err).AtWarning()
		}

		bodyWriter := session.EncodeRequestBody(request, writer)
		firstPayload, err := input.ReadTimeout(time.Millisecond * 500)
		if err != nil && err != buf.ErrReadTimeout {
			return newError("failed to get first payload").Base(err)
		}
		if !firstPayload.IsEmpty() {
			if err := bodyWriter.WriteMultiBuffer(firstPayload); err != nil {
				return newError("failed to write first payload").Base(err)
			}
			firstPayload.Release()
		}

		if err := writer.SetBuffered(false); err != nil {
			return err
		}

		if err := buf.Copy(input, bodyWriter, buf.UpdateActivity(timer)); err != nil {
			return err
		}

		if request.Option.Has(protocol.RequestOptionChunkStream) {
			if err := bodyWriter.WriteMultiBuffer(buf.MultiBuffer{}); err != nil {
				return err
			}
		}
		timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
		return nil
	})

	responseDone := signal.ExecuteAsync(func() error {
		defer output.Close()
		defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)

		reader := buf.NewBufferedReader(buf.NewReader(conn))
		header, err := session.DecodeResponseHeader(reader)
		if err != nil {
			return err
		}
		v.handleCommand(rec.Destination(), header.Command)

		reader.SetBuffered(false)
		bodyReader := session.DecodeResponseBody(request, reader)
		return buf.Copy(bodyReader, output, buf.UpdateActivity(timer))
	})

	if err := signal.ErrorOrFinish2(ctx, requestDone, responseDone); err != nil {
		return newError("connection ends").Base(err)
	}

	return nil
}

func init() {
	common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
		return New(ctx, config.(*Config))
	}))
}
<|endoftext|>


<commit_before>package command

import (
	"context"
	"fmt"
	"math/big"
	"regexp"

	"github.com/spolu/settle/cli"
	"github.com/spolu/settle/lib/errors"
	"github.com/spolu/settle/lib/out"
	"github.com/spolu/settle/mint"
)

const (
	// CmdNmTrust is the command name.
	CmdNmTrust cli.CmdName = "trust"
)

func init() {
	cli.Registrar[CmdNmTrust] = NewTrust
}

// Trust a user up to a certain amount of a given asset they issued.
type Trust struct {
	BaseAsset  string
	QuoteAsset string
	Amount     big.Int
	Price      string
}

// NewTrust constructs and initializes the command.
func NewTrust() cli.Command {
	return &Trust{}
}

// Name returns the command name.
func (c *Trust) Name() cli.CmdName {
	return CmdNmTrust
}

// Help prints out the help message for the command.
func (c *Trust) Help(
	ctx context.Context,
) {
	out.Normf("\nUsage: ")
	out.Boldf("settle trust <user> <quote_asset> <amount> [with <base_asset> at <price>]\n")
	out.Normf("\n")
	out.Normf("  Trusting user's asset (quote_asset) expresses your commitment to issue your\n")
	out.Normf("  own asset (base_asset) in exchange for the quote asset at the specified\n")
	out.Normf("  exchange price and up to the specified amount.\n")
	out.Normf("\n")
	out.Normf("  Once your tustline is created, anyone will be able to credit you with user's\n")
	out.Normf("  asset (quote_asset) in exchange for your own asset (base_asset). Your mint\n")
	out.Normf("  will automatically issue the required amount of your asset (base_asset) to\n")
	out.Normf("  satisfy the exchange at the specified price. Your mint will stop accepting\n")
	out.Normf("  exchanges or issuing your asset once the trustline is consumed (you exchanged\n")
	out.Normf("  all of the specified amount in one or many transactions).\n")
	out.Normf("\n")
	out.Normf("  The last two arguments can be ommitted in which case: the same asset code and\n")
	out.Normf("  scale will be used for your asset (which requires that you have minted that\n")
	out.Normf("  asset); the price 1/1 will be used by default (exchange at parity).\n")
	out.Normf("\n")
	out.Normf("Arguments:\n")
	out.Boldf("  user\n")
	out.Normf("    The user you are committing to trust.\n")
	out.Valuf("    von.neuman@ias.edu elon@settle.network\n")
	out.Normf("\n")
	out.Boldf("  quote_asset\n")
	out.Normf("    The asset from user that you are committing to trust of the form\n")
	out.Normf("    `{code}.{scale}`.\n")
	out.Valuf("    USD.2 HOUR-OF-WORK.0 BTC.7 EUR.2 DRINK.0\n")
	out.Normf("\n")
	out.Boldf("  amount\n")
	out.Normf("    The amount of user's asset (quote_asset) that you are committing to trust.\n")
	out.Normf("    Amount is expressed in the asset you are trusting using the asset scale\n")
	out.Normf("    (USD.2 199 represents $1.99, HOUR-OF-WORK.0 1 represents 1 hour of work,\n")
	out.Normf("    and BTC.8 252912 represents 0.00252912 BTC).\n")
	out.Valuf("    42\n")
	out.Normf("\n")
	out.Boldf("  base_asset\n")
	out.Normf("    One of your assets that you are committing to issue in exchange for user's\n")
	out.Normf("    asset, of the form `{code}.{scale}`. If the asset was not minted previously\n")
	out.Normf("    it will be created.\n")
	out.Valuf("    USD.2 HOUR-OF-WORK.0 BTC.7 EUR.2 DRINK.0\n")
	out.Normf("\n")
	out.Boldf("  price\n")
	out.Normf("    The price at which you are committing to exchange the user asset for your\n")
	out.Normf("    asset. The price is expressed in {base_asset}/{quote_asset}.\n")
	out.Valuf("    1/1 100/125 4500/1\n")
	out.Normf("\n")
	out.Normf("Examples:\n")
	out.Valuf("  settle trust von.neumann@ias.edu USD.2 150\n")
	out.Valuf("  settle trust kurt@princetown.edu USD.2 150 with USD.2 at 1/1\n")
	out.Valuf("  settle trust alan@npl.co.uk GBP.2 120 with USD.2 at 125/100\n")
	out.Valuf("  settle trust venture@risky.co USD.2 1200 with USD.2 at 100/75\n")
	out.Normf("\n")
}

// PriceRegexp is used to validate and parse a price.
var PriceRegexp = regexp.MustCompile(
	"^([0-9]+)\\/([0-9]+)$")

// Parse parses the arguments passed to the command.
func (c *Trust) Parse(
	ctx context.Context,
	args []string,
) error {
	creds := cli.GetCredentials(ctx)
	if creds == nil {
		return errors.Trace(
			errors.Newf("You need to be logged in (try `settle help login`)."))
	}

	if len(args) == 0 {
		return errors.Trace(
			errors.Newf("User required."))
	}
	user, args := args[0], args[1:]

	_, _, err := mint.UsernameAndMintHostFromAddress(ctx, user)
	if err != nil {
		return errors.Trace(err)
	}

	if len(args) == 0 {
		return errors.Trace(
			errors.Newf("Quote asset required."))
	}
	asset, args := args[0], args[1:]

	qA, err := mint.AssetResourceFromName(ctx,
		fmt.Sprintf("%s[%s]", user, asset))
	if err != nil {
		return errors.Trace(err)
	}
	c.QuoteAsset = qA.Name

	if len(args) == 0 {
		return errors.Trace(
			errors.Newf("Amount required."))
	}
	amount, args := args[0], args[1:]

	var amt big.Int
	if _, success := amt.SetString(amount, 10); !success {
		return errors.Newf("Invalid amount: %s", amount)
	}
	c.Amount = amt

	// Accept `with`.
	if len(args) > 0 && args[0] == "with" {
		args = args[1:]
	}

	// Default `base_asset` and `price`.
	if len(args) == 0 {
		c.BaseAsset = fmt.Sprintf("%s@%s[%s.%d]",
			creds.Username, creds.Host, qA.Code, qA.Scale)
		c.Price = "1/1"
		return nil
	}

	asset, args = args[0], args[1:]
	bA, err := mint.AssetResourceFromName(ctx,
		fmt.Sprintf("%s@%s[%s]", creds.Username, creds.Host, asset))
	if err != nil {
		return errors.Trace(err)
	}
	c.BaseAsset = bA.Name

	// Accept `at`.
	if len(args) > 0 && args[0] == "at" {
		args = args[1:]
	}

	// Default `price`.
	if len(args) == 0 {
		c.Price = "1/1"
		return nil
	}

	price, args := args[0], args[1:]
	m := PriceRegexp.FindStringSubmatch(price)
	if len(m) == 0 {
		return errors.Trace(errors.Newf("Invalid price: %s", price))
	}
	c.Price = price

	return nil
}

// Execute the command or return a human-friendly error.
func (c *Trust) Execute(
	ctx context.Context,
) error {
	// Retrieve base asset to check existence
	asset, err := RetrieveAsset(ctx, c.BaseAsset)
	if err != nil {
		return errors.Trace(err)
	} else if asset == nil {
		bA, err := mint.AssetResourceFromName(ctx, c.BaseAsset)
		if err != nil {
			return errors.Trace(err)
		}
		return errors.Trace(
			errors.Newf("You need to mint %s.%d first "+
				"(see `settle help mint`).",
				bA.Code, bA.Scale))
	}
	// Retrieve quote asset to check existence
	asset, err = RetrieveAsset(ctx, c.QuoteAsset)
	if err != nil {
		return errors.Trace(err)
	} else if asset == nil {
		qA, err := mint.AssetResourceFromName(ctx, c.QuoteAsset)
		if err != nil {
			return errors.Trace(err)
		}
		return errors.Trace(
			errors.Newf("%s does not exists, ask %s to mint %s.%d "+
				"first (see `settle help mint`).",
				qA.Name, qA.Owner, qA.Code, qA.Scale))
	}

	out.Boldf("Proposed trustline:\n")
	out.Normf("  Pair      : ")
	out.Valuf("%s\n", fmt.Sprintf("%s/%s", c.BaseAsset, c.QuoteAsset))
	out.Normf("  Price     : ")
	out.Valuf("%s\n", c.Price)
	out.Normf("  Amount    : ")
	out.Valuf("%s\n", c.Amount.String())

	if err := Confirm(ctx, "trust"); err != nil {
		return errors.Trace(err)
	}

	// Create offer.
	offer, err := CreateOffer(ctx,
		fmt.Sprintf("%s/%s", c.BaseAsset, c.QuoteAsset),
		c.Amount,
		c.Price,
	)
	if err != nil {
		return errors.Trace(err)
	}

	out.Boldf("Trustline created:\n")
	out.Normf("  ID        : ")
	out.Valuf("%s\n", offer.ID)
	out.Normf("  Created   : ")
	out.Valuf("%d\n", offer.Created)
	out.Normf("  Owner     : ")
	out.Valuf("%s\n", offer.Owner)
	out.Normf("  Pair      : ")
	out.Valuf("%s\n", offer.Pair)
	out.Normf("  Price     : ")
	out.Valuf("%s\n", offer.Price)
	out.Normf("  Amount    : ")
	out.Valuf("%s\n", offer.Amount.String())
	out.Normf("  Status    : ")
	out.Valuf("%s\n", offer.Status)
	out.Normf("  Remainder : ")
	out.Valuf("%s\n", offer.Remainder.String())

	return nil
}
<commit_msg>Fix settle trust example<commit_after>package command

import (
	"context"
	"fmt"
	"math/big"
	"regexp"

	"github.com/spolu/settle/cli"
	"github.com/spolu/settle/lib/errors"
	"github.com/spolu/settle/lib/out"
	"github.com/spolu/settle/mint"
)

const (
	// CmdNmTrust is the command name.
	CmdNmTrust cli.CmdName = "trust"
)

func init() {
	cli.Registrar[CmdNmTrust] = NewTrust
}

// Trust a user up to a certain amount of a given asset they issued.
type Trust struct {
	BaseAsset  string
	QuoteAsset string
	Amount     big.Int
	Price      string
}

// NewTrust constructs and initializes the command.
func NewTrust() cli.Command {
	return &Trust{}
}

// Name returns the command name.
func (c *Trust) Name() cli.CmdName {
	return CmdNmTrust
}

// Help prints out the help message for the command.
func (c *Trust) Help(
	ctx context.Context,
) {
	out.Normf("\nUsage: ")
	out.Boldf("settle trust <user> <quote_asset> <amount> [with <base_asset> at <price>]\n")
	out.Normf("\n")
	out.Normf("  Trusting user's asset (quote_asset) expresses your commitment to issue your\n")
	out.Normf("  own asset (base_asset) in exchange for the quote asset at the specified\n")
	out.Normf("  exchange price and up to the specified amount.\n")
	out.Normf("\n")
	out.Normf("  Once your tustline is created, anyone will be able to credit you with user's\n")
	out.Normf("  asset (quote_asset) in exchange for your own asset (base_asset). Your mint\n")
	out.Normf("  will automatically issue the required amount of your asset (base_asset) to\n")
	out.Normf("  satisfy the exchange at the specified price. Your mint will stop accepting\n")
	out.Normf("  exchanges or issuing your asset once the trustline is consumed (you exchanged\n")
	out.Normf("  all of the specified amount in one or many transactions).\n")
	out.Normf("\n")
	out.Normf("  The last two arguments can be ommitted in which case: the same asset code and\n")
	out.Normf("  scale will be used for your asset (which requires that you have minted that\n")
	out.Normf("  asset); the price 1/1 will be used by default (exchange at parity).\n")
	out.Normf("\n")
	out.Normf("Arguments:\n")
	out.Boldf("  user\n")
	out.Normf("    The user you are committing to trust.\n")
	out.Valuf("    von.neuman@ias.edu elon@settle.network\n")
	out.Normf("\n")
	out.Boldf("  quote_asset\n")
	out.Normf("    The asset from user that you are committing to trust of the form\n")
	out.Normf("    `{code}.{scale}`.\n")
	out.Valuf("    USD.2 HOUR-OF-WORK.0 BTC.7 EUR.2 DRINK.0\n")
	out.Normf("\n")
	out.Boldf("  amount\n")
	out.Normf("    The amount of user's asset (quote_asset) that you are committing to trust.\n")
	out.Normf("    Amount is expressed in the asset you are trusting using the asset scale\n")
	out.Normf("    (USD.2 199 represents $1.99, HOUR-OF-WORK.0 1 represents 1 hour of work,\n")
	out.Normf("    and BTC.8 252912 represents 0.00252912 BTC).\n")
	out.Valuf("    42\n")
	out.Normf("\n")
	out.Boldf("  base_asset\n")
	out.Normf("    One of your assets that you are committing to issue in exchange for user's\n")
	out.Normf("    asset, of the form `{code}.{scale}`. If the asset was not minted previously\n")
	out.Normf("    it will be created.\n")
	out.Valuf("    USD.2 HOUR-OF-WORK.0 BTC.7 EUR.2 DRINK.0\n")
	out.Normf("\n")
	out.Boldf("  price\n")
	out.Normf("    The price at which you are committing to exchange the user asset for your\n")
	out.Normf("    asset. The price is expressed in {base_asset}/{quote_asset}.\n")
	out.Valuf("    1/1 100/125 4500/1\n")
	out.Normf("\n")
	out.Normf("Examples:\n")
	out.Valuf("  settle trust von.neumann@ias.edu USD.2 150\n")
	out.Valuf("  settle trust kurt@princetown.edu USD.2 150 with USD.2 at 1/1\n")
	out.Valuf("  settle trust alan@npl.co.uk GBP.2 120 with USD.2 at 125/100\n")
	out.Valuf("  settle trust venture@risky.co USD.2 1200 with USD.2 at 75/100\n")
	out.Normf("\n")
}

// PriceRegexp is used to validate and parse a price.
var PriceRegexp = regexp.MustCompile(
	"^([0-9]+)\\/([0-9]+)$")

// Parse parses the arguments passed to the command.
func (c *Trust) Parse(
	ctx context.Context,
	args []string,
) error {
	creds := cli.GetCredentials(ctx)
	if creds == nil {
		return errors.Trace(
			errors.Newf("You need to be logged in (try `settle help login`)."))
	}

	if len(args) == 0 {
		return errors.Trace(
			errors.Newf("User required."))
	}
	user, args := args[0], args[1:]

	_, _, err := mint.UsernameAndMintHostFromAddress(ctx, user)
	if err != nil {
		return errors.Trace(err)
	}

	if len(args) == 0 {
		return errors.Trace(
			errors.Newf("Quote asset required."))
	}
	asset, args := args[0], args[1:]

	qA, err := mint.AssetResourceFromName(ctx,
		fmt.Sprintf("%s[%s]", user, asset))
	if err != nil {
		return errors.Trace(err)
	}
	c.QuoteAsset = qA.Name

	if len(args) == 0 {
		return errors.Trace(
			errors.Newf("Amount required."))
	}
	amount, args := args[0], args[1:]

	var amt big.Int
	if _, success := amt.SetString(amount, 10); !success {
		return errors.Newf("Invalid amount: %s", amount)
	}
	c.Amount = amt

	// Accept `with`.
	if len(args) > 0 && args[0] == "with" {
		args = args[1:]
	}

	// Default `base_asset` and `price`.
	if len(args) == 0 {
		c.BaseAsset = fmt.Sprintf("%s@%s[%s.%d]",
			creds.Username, creds.Host, qA.Code, qA.Scale)
		c.Price = "1/1"
		return nil
	}

	asset, args = args[0], args[1:]
	bA, err := mint.AssetResourceFromName(ctx,
		fmt.Sprintf("%s@%s[%s]", creds.Username, creds.Host, asset))
	if err != nil {
		return errors.Trace(err)
	}
	c.BaseAsset = bA.Name

	// Accept `at`.
	if len(args) > 0 && args[0] == "at" {
		args = args[1:]
	}

	// Default `price`.
	if len(args) == 0 {
		c.Price = "1/1"
		return nil
	}

	price, args := args[0], args[1:]
	m := PriceRegexp.FindStringSubmatch(price)
	if len(m) == 0 {
		return errors.Trace(errors.Newf("Invalid price: %s", price))
	}
	c.Price = price

	return nil
}

// Execute the command or return a human-friendly error.
func (c *Trust) Execute(
	ctx context.Context,
) error {
	// Retrieve base asset to check existence
	asset, err := RetrieveAsset(ctx, c.BaseAsset)
	if err != nil {
		return errors.Trace(err)
	} else if asset == nil {
		bA, err := mint.AssetResourceFromName(ctx, c.BaseAsset)
		if err != nil {
			return errors.Trace(err)
		}
		return errors.Trace(
			errors.Newf("You need to mint %s.%d first "+
				"(see `settle help mint`).",
				bA.Code, bA.Scale))
	}
	// Retrieve quote asset to check existence
	asset, err = RetrieveAsset(ctx, c.QuoteAsset)
	if err != nil {
		return errors.Trace(err)
	} else if asset == nil {
		qA, err := mint.AssetResourceFromName(ctx, c.QuoteAsset)
		if err != nil {
			return errors.Trace(err)
		}
		return errors.Trace(
			errors.Newf("%s does not exists, ask %s to mint %s.%d "+
				"first (see `settle help mint`).",
				qA.Name, qA.Owner, qA.Code, qA.Scale))
	}

	out.Boldf("Proposed trustline:\n")
	out.Normf("  Pair      : ")
	out.Valuf("%s\n", fmt.Sprintf("%s/%s", c.BaseAsset, c.QuoteAsset))
	out.Normf("  Price     : ")
	out.Valuf("%s\n", c.Price)
	out.Normf("  Amount    : ")
	out.Valuf("%s\n", c.Amount.String())

	if err := Confirm(ctx, "trust"); err != nil {
		return errors.Trace(err)
	}

	// Create offer.
	offer, err := CreateOffer(ctx,
		fmt.Sprintf("%s/%s", c.BaseAsset, c.QuoteAsset),
		c.Amount,
		c.Price,
	)
	if err != nil {
		return errors.Trace(err)
	}

	out.Boldf("Trustline created:\n")
	out.Normf("  ID        : ")
	out.Valuf("%s\n", offer.ID)
	out.Normf("  Created   : ")
	out.Valuf("%d\n", offer.Created)
	out.Normf("  Owner     : ")
	out.Valuf("%s\n", offer.Owner)
	out.Normf("  Pair      : ")
	out.Valuf("%s\n", offer.Pair)
	out.Normf("  Price     : ")
	out.Valuf("%s\n", offer.Price)
	out.Normf("  Amount    : ")
	out.Valuf("%s\n", offer.Amount.String())
	out.Normf("  Status    : ")
	out.Valuf("%s\n", offer.Status)
	out.Normf("  Remainder : ")
	out.Valuf("%s\n", offer.Remainder.String())

	return nil
}
<|endoftext|>


<commit_before>package hybrid

import (
	"github.com/ready-steady/adapt/algorithm/external"
	"github.com/ready-steady/adapt/algorithm/internal"
)

// Strategy controls the interpolation process.
type strategy interface {
	// Done checks if the stopping criteria have been satisfied.
	Done() bool

	// Next consumes the result of the current iteration and configures the
	// level and nodal indices for the next iteration.
	Next(*state, *external.Surrogate) *state
}

type basicStrategy struct {
	internal.Active

	ni uint
	no uint

	grid Grid

	lmin uint
	lmax uint

	εt float64
	εl float64

	k uint

	hash     *internal.Hash
	unique   *internal.Unique
	position map[string]uint

	offset []uint
	global []float64
	local  []float64
}

func newStrategy(ni, no uint, grid Grid, config *Config) *basicStrategy {
	return &basicStrategy{
		Active: *internal.NewActive(ni),

		ni: ni,
		no: no,

		grid: grid,

		lmin: config.MinLevel,
		lmax: config.MaxLevel,

		εt: config.TotalError,
		εl: config.LocalError,

		k: ^uint(0),

		hash:     internal.NewHash(ni),
		unique:   internal.NewUnique(ni),
		position: make(map[string]uint),
	}
}

func (self *basicStrategy) Done() bool {
	ng := uint(len(self.global))
	if ng == 0 {
		return false
	}
	total := 0.0
	for i := range self.Positions {
		if i >= ng {
			continue
		}
		total += self.global[i]
	}
	return total <= self.εt
}

func (self *basicStrategy) Next(current *state, surrogate *external.Surrogate) *state {
	if current == nil {
		next := &state{}
		next.Lindices = self.Active.Next(self.k)
		next.Indices, next.Counts = internal.Index(self.grid, next.Lindices, self.ni)
		return next
	}

	self.consume(current)

	for {
		self.Active.Drop(self.k)
		if len(self.Positions) == 0 {
			return nil
		}
		self.k = internal.LocateMaxFloat64s(self.global, self.Positions)
		if self.Norms[self.k] < uint64(self.lmax) {
			break
		}
	}

	next := &state{}
	next.Lindices = self.Active.Next(self.k)
	next.Indices, next.Counts = self.indexSet(next.Lindices, surrogate)
	return next
}

func (self *basicStrategy) consume(state *state) {
	ni, ng, nl := self.ni, uint(len(self.global)), uint(len(self.local))
	nn := uint(len(state.Counts))
	for i, offset := uint(0), uint(0); i < nn; i++ {
		global := 0.0
		for _, ε := range state.Scores[offset:(offset + state.Counts[i])] {
			global += ε
		}
		self.position[self.hash.Key(state.Lindices[i*ni:(i+1)*ni])] = ng + i
		self.offset = append(self.offset, nl+offset)
		self.global = append(self.global, global)
		offset += state.Counts[i]
	}
	self.local = append(self.local, state.Scores...)
}

func (self *basicStrategy) indexSet(lindices []uint64,
	surrogate *external.Surrogate) ([]uint64, []uint) {

	ni := self.ni
	nn := uint(len(lindices)) / ni
	indices, counts := []uint64(nil), make([]uint, nn)
	for i, offset := uint(0), uint(0); i < nn; i++ {
		indices = append(indices, self.indexOne(lindices[i*ni:(i+1)*ni], surrogate)...)
		counts[i] = uint(len(indices))/ni - offset
		offset += counts[i]
	}
	return indices, counts
}

func (self *basicStrategy) indexOne(lindex []uint64, surrogate *external.Surrogate) []uint64 {
	ni := self.ni
	indices := []uint64(nil)
	for i := uint(0); i < ni; i++ {
		level := lindex[i]
		if level == 0 {
			continue
		}

		lindex[i] = level - 1
		k, ok := self.position[self.hash.Key(lindex)]
		lindex[i] = level
		if !ok {
			continue
		}

		var from, till uint
		from = self.offset[k]
		if uint(len(self.offset)) > k+1 {
			till = self.offset[k+1]
		} else {
			till = uint(len(self.local))
		}

		for j := from; j < till; j++ {
			if self.local[j] < self.εl {
				continue
			}
			indices = append(indices, self.unique.Distil(self.grid.ChildrenToward(
				surrogate.Indices[j*ni:(j+1)*ni], i))...)
		}
	}
	return indices
}
<commit_msg>a/hybrid: merge indexSet and indexOne<commit_after>package hybrid

import (
	"github.com/ready-steady/adapt/algorithm/external"
	"github.com/ready-steady/adapt/algorithm/internal"
)

// Strategy controls the interpolation process.
type strategy interface {
	// Done checks if the stopping criteria have been satisfied.
	Done() bool

	// Next consumes the result of the current iteration and configures the
	// level and nodal indices for the next iteration.
	Next(*state, *external.Surrogate) *state
}

type basicStrategy struct {
	internal.Active

	ni uint
	no uint

	grid Grid

	lmin uint
	lmax uint

	εt float64
	εl float64

	k uint

	hash     *internal.Hash
	unique   *internal.Unique
	position map[string]uint

	offset []uint
	global []float64
	local  []float64
}

func newStrategy(ni, no uint, grid Grid, config *Config) *basicStrategy {
	return &basicStrategy{
		Active: *internal.NewActive(ni),

		ni: ni,
		no: no,

		grid: grid,

		lmin: config.MinLevel,
		lmax: config.MaxLevel,

		εt: config.TotalError,
		εl: config.LocalError,

		k: ^uint(0),

		hash:     internal.NewHash(ni),
		unique:   internal.NewUnique(ni),
		position: make(map[string]uint),
	}
}

func (self *basicStrategy) Done() bool {
	ng := uint(len(self.global))
	if ng == 0 {
		return false
	}
	total := 0.0
	for i := range self.Positions {
		if i >= ng {
			continue
		}
		total += self.global[i]
	}
	return total <= self.εt
}

func (self *basicStrategy) Next(current *state, surrogate *external.Surrogate) *state {
	if current == nil {
		next := &state{}
		next.Lindices = self.Active.Next(self.k)
		next.Indices, next.Counts = internal.Index(self.grid, next.Lindices, self.ni)
		return next
	}

	self.consume(current)

	for {
		self.Active.Drop(self.k)
		if len(self.Positions) == 0 {
			return nil
		}
		self.k = internal.LocateMaxFloat64s(self.global, self.Positions)
		if self.Norms[self.k] < uint64(self.lmax) {
			break
		}
	}

	next := &state{}
	next.Lindices = self.Active.Next(self.k)
	next.Indices, next.Counts = self.index(next.Lindices, surrogate)
	return next
}

func (self *basicStrategy) consume(state *state) {
	ni, ng, nl := self.ni, uint(len(self.global)), uint(len(self.local))
	nn := uint(len(state.Counts))
	for i, offset := uint(0), uint(0); i < nn; i++ {
		global := 0.0
		for _, ε := range state.Scores[offset:(offset + state.Counts[i])] {
			global += ε
		}
		self.position[self.hash.Key(state.Lindices[i*ni:(i+1)*ni])] = ng + i
		self.offset = append(self.offset, nl+offset)
		self.global = append(self.global, global)
		offset += state.Counts[i]
	}
	self.local = append(self.local, state.Scores...)
}

func (self *basicStrategy) index(lindices []uint64,
	surrogate *external.Surrogate) ([]uint64, []uint) {

	ni := self.ni
	nn := uint(len(lindices)) / ni

	indices, counts := []uint64(nil), make([]uint, nn)
	for i, offset := uint(0), uint(0); i < nn; i++ {
		lindex := lindices[i*ni : (i+1)*ni]
		for j := uint(0); j < ni; j++ {
			level := lindex[j]
			if level == 0 {
				continue
			}

			lindex[j] = level - 1
			k, ok := self.position[self.hash.Key(lindex)]
			lindex[j] = level
			if !ok {
				continue
			}

			var from, till uint
			from = self.offset[k]
			if uint(len(self.offset)) > k+1 {
				till = self.offset[k+1]
			} else {
				till = uint(len(self.local))
			}

			for k := from; k < till; k++ {
				if self.local[k] < self.εl {
					continue
				}
				indices = append(indices, self.unique.Distil(self.grid.ChildrenToward(
					surrogate.Indices[k*ni:(k+1)*ni], j))...)
			}
		}
		counts[i] = uint(len(indices))/ni - offset
		offset += counts[i]
	}

	return indices, counts
}
<|endoftext|>


<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2017 Shannon Wynter
 *
 * 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 backends

import (
	_ "github.com/freman/caddy-reauth/backends/gitlabci"
	_ "github.com/freman/caddy-reauth/backends/refresh"
	_ "github.com/freman/caddy-reauth/backends/simple"
	_ "github.com/freman/caddy-reauth/backends/upstream"
)

// This page intentionally left blank ;)
<commit_msg>Add missing import in backends<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2017 Shannon Wynter
 *
 * 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 backends

import (
	_ "github.com/freman/caddy-reauth/backends/gitlabci"
	_ "github.com/freman/caddy-reauth/backends/ldap"
	_ "github.com/freman/caddy-reauth/backends/refresh"
	_ "github.com/freman/caddy-reauth/backends/simple"
	_ "github.com/freman/caddy-reauth/backends/upstream"
)

// This page intentionally left blank ;)
<|endoftext|>


<commit_before>package kloud

import (
	"encoding/json"
	"errors"
	"fmt"
	"koding/db/mongodb/modelhelper"
	"koding/kites/kloud/contexthelper/session"
	"koding/kites/kloud/terraformer"
	tf "koding/kites/terraformer"
	"strconv"
	"time"

	"labix.org/v2/mgo/bson"

	"golang.org/x/net/context"

	"github.com/koding/kite"
	"github.com/mitchellh/goamz/aws"
	"github.com/mitchellh/goamz/iam"
	"github.com/mitchellh/mapstructure"
)

type AwsBootstrapOutput struct {
	ACL       string `json:"acl" mapstructure:"acl"`
	CidrBlock string `json:"cidr_block" mapstructure:"cidr_block"`
	IGW       string `json:"igw" mapstructure:"igw"`
	KeyPair   string `json:"key_pair" mapstructure:"key_pair"`
	RTB       string `json:"rtb" mapstructure:"rtb"`
	SG        string `json:"sg" mapstructure:"sg"`
	Subnet    string `json:"subnet" mapstructure:"subnet"`
	VPC       string `json:"vpc" mapstructure:"vpc"`
	AMI       string `json:"ami" mapstructure:"ami"`
}

type TerraformBootstrapRequest struct {
	// Identifiers contains identifers to be used with terraform
	Identifiers []string `json:"identifiers"`

	GroupName string `json:"groupName"`

	// Destroy destroys the bootstrap resource associated with the given
	// identifiers
	Destroy bool
}

func (k *Kloud) Bootstrap(r *kite.Request) (interface{}, error) {
	if r.Args == nil {
		return nil, NewError(ErrNoArguments)
	}

	var args *TerraformBootstrapRequest
	if err := r.Args.One().Unmarshal(&args); err != nil {
		return nil, err
	}

	if len(args.Identifiers) == 0 {
		return nil, errors.New("identifiers are not passed")
	}

	if args.GroupName == "" {
		return nil, errors.New("group name is not passed")
	}

	ctx := k.ContextCreator(context.Background())
	sess, ok := session.FromContext(ctx)
	if !ok {
		return nil, errors.New("session context is not passed")
	}

	data, err := fetchTerraformData(r.Username, args.GroupName, sess.DB, args.Identifiers)
	if err != nil {
		return nil, err
	}

	k.Log.Debug("Connecting to terraformer kite")
	tfKite, err := terraformer.Connect(sess.Kite)
	if err != nil {
		return nil, err
	}
	defer tfKite.Close()

	k.Log.Debug("Iterating over credentials")
	for _, cred := range data.Creds {
		// We are going to support more providers in the future, for now only allow aws
		if cred.Provider != "aws" {
			return nil, fmt.Errorf("Bootstrap is only supported for 'aws' provider. Got: '%s'", cred.Provider)
		}

		k.Log.Debug("parsing the template")
		template, err := newTerraformTemplate(awsBootstrap)
		if err != nil {
			return nil, err
		}

		k.Log.Debug("Injecting variables from credential data identifiers, such as aws, custom, etc..")
		if err := template.injectCustomVariables(cred.Provider, cred.Data); err != nil {
			return nil, err
		}

		var awsCred struct {
			Region    string `mapstructure:"region"`
			AccessKey string `mapstructure:"access_key"`
			SecretKey string `mapstructure:"secret_key"`
		}

		if err := mapstructure.Decode(cred.Data, &awsCred); err != nil {
			return nil, err
		}

		fmt.Printf("aws = %+v\n", awsCred)

		iamClient := iam.New(
			aws.Auth{
				AccessKey: awsCred.AccessKey,
				SecretKey: awsCred.SecretKey,
			},
			aws.Regions[awsCred.Region],
		)

		k.Log.Debug("Fetching the AWS user information to get the account ID")
		user, err := iamClient.GetDefaultUser() // will default to username making the request
		if err != nil {
			return nil, err
		}

		awsAccountID, err := parseAccountID(user.User.Arn)
		if err != nil {
			return nil, err
		}

		contentID := fmt.Sprintf("%s-%s-%s", awsAccountID, args.GroupName, awsCred.Region)
		k.Log.Debug("Going to use the contentID: %s", contentID)

		keyName := "koding-deployment-" + r.Username + "-" + strconv.FormatInt(time.Now().UTC().UnixNano(), 10)

		finalBootstrap, err := template.jsonOutput()
		if err != nil {
			return nil, err
		}

		finalBootstrap, err = appendAWSTemplateData(finalBootstrap, &awsTemplateData{
			KeyPairName:     keyName,
			PublicKey:       k.PublicKeys.PublicKey,
			EnvironmentName: fmt.Sprintf("Koding-%s-Bootstrap", args.GroupName),
		})
		if err != nil {
			return nil, err
		}

		k.Log.Debug("[%s] Final bootstrap:", cred.Identifier)
		k.Log.Debug(finalBootstrap)

		// Important so bootstraping is distributed amongs multiple users. If I
		// use these keys to bootstrap, any other user should be not create
		// again, instead they should be fetch and use the existing bootstrap
		// data.

		awsOutput := &AwsBootstrapOutput{}

		// this is custom because we need to remove the fields if we get a
		// destroy. So the operator changes from $set to $unset.
		mongodDBOperator := "$set"

		if args.Destroy {
			mongodDBOperator = "$unset"
			k.Log.Info("Destroying bootstrap resources belonging to identifier '%s'", cred.Identifier)
			_, err := tfKite.Destroy(&tf.TerraformRequest{
				Content:   finalBootstrap,
				ContentID: contentID,
			})
			if err != nil {
				return nil, err
			}
		} else {
			k.Log.Info("Creating bootstrap resources belonging to identifier '%s'", cred.Identifier)
			state, err := tfKite.Apply(&tf.TerraformRequest{
				Content:   finalBootstrap,
				ContentID: contentID,
			})
			if err != nil {
				return nil, err
			}

			k.Log.Debug("[%s] state.RootModule().Outputs = %+v\n", cred.Identifier, state.RootModule().Outputs)
			if err := mapstructure.Decode(state.RootModule().Outputs, &awsOutput); err != nil {
				return nil, err
			}
		}

		k.Log.Debug("[%s] Aws Output: %+v", cred.Identifier, awsOutput)
		if err := modelhelper.UpdateCredentialData(cred.Identifier, bson.M{
			mongodDBOperator: bson.M{
				"meta.acl":        awsOutput.ACL,
				"meta.cidr_block": awsOutput.CidrBlock,
				"meta.igw":        awsOutput.IGW,
				"meta.key_pair":   awsOutput.KeyPair,
				"meta.rtb":        awsOutput.RTB,
				"meta.sg":         awsOutput.SG,
				"meta.subnet":     awsOutput.Subnet,
				"meta.vpc":        awsOutput.VPC,
				"meta.ami":        awsOutput.AMI,
			},
		}); err != nil {
			return nil, err
		}
	}

	return true, nil
}

func appendAWSTemplateData(template string, awsData *awsTemplateData) (string, error) {
	var data struct {
		Output   map[string]map[string]interface{} `json:"output,omitempty"`
		Resource map[string]map[string]interface{} `json:"resource,omitempty"`
		Provider map[string]map[string]interface{} `json:"provider,omitempty"`
		Variable map[string]map[string]interface{} `json:"variable,omitempty"`
	}

	if err := json.Unmarshal([]byte(template), &data); err != nil {
		return "", err
	}

	data.Variable["key_name"] = map[string]interface{}{
		"default": awsData.KeyPairName,
	}

	data.Variable["public_key"] = map[string]interface{}{
		"default": awsData.PublicKey,
	}

	data.Variable["environment_name"] = map[string]interface{}{
		"default": awsData.EnvironmentName,
	}

	out, err := json.MarshalIndent(data, "", "  ")
	if err != nil {
		return "", err
	}

	return string(out), nil
}

// awsTemplateData is being used to format the bootstrap before we pass it to
// terraformer
type awsTemplateData struct {
	KeyPairName     string
	PublicKey       string
	EnvironmentName string
}

var awsBootstrap = `{
    "provider": {
        "aws": {
            "access_key": "${var.aws_access_key}",
            "secret_key": "${var.aws_secret_key}",
            "region": "${var.region}"
        }
    },
    "output": {
        "vpc": {
            "value": "${aws_vpc.vpc.id}"
        },
        "cidr_block": {
            "value": "${aws_vpc.vpc.cidr_block}"
        },
        "rtb": {
            "value": "${aws_vpc.vpc.main_route_table_id}"
        },
        "acl": {
            "value": "${aws_vpc.vpc.default_network_acl_id}"
        },
        "igw": {
            "value": "${aws_internet_gateway.main_vpc_igw.id}"
        },
        "subnet": {
            "value": "${aws_subnet.main_koding_subnet.id}"
        },
        "sg": {
            "value": "${aws_security_group.allow_all.id}"
        },
        "ami": {
            "value": "${lookup(var.aws_amis, var.region)}"
        },
        "key_pair": {
            "value": "${aws_key_pair.koding_key_pair.key_name}"
        }
    },
    "resource": {
        "aws_vpc": {
            "vpc": {
                "cidr_block": "${var.cidr_block}",
                "tags": {
                    "Name": "${var.environment_name}"
                }
            }
        },
        "aws_internet_gateway": {
            "main_vpc_igw": {
                "tags": {
                    "Name": "${var.environment_name}"
                },
                "vpc_id": "${aws_vpc.vpc.id}"
            }
        },
        "aws_subnet": {
            "main_koding_subnet": {
                "availability_zone": "${lookup(var.aws_availability_zones, var.region)}",
                "cidr_block": "${var.cidr_block}",
                "map_public_ip_on_launch": true,
                "tags": {
                    "Name": "${var.environment_name}",
                    "subnet": "public"
                },
                "vpc_id": "${aws_vpc.vpc.id}"
            }
        },
        "aws_route_table": {
            "public": {
                "route": {
                    "cidr_block": "0.0.0.0/0",
                    "gateway_id": "${aws_internet_gateway.main_vpc_igw.id}"
                },
                "tags": {
                    "Name": "${var.environment_name}",
                    "routeTable": "koding",
                    "subnet": "public"
                },
                "vpc_id": "${aws_vpc.vpc.id}"
            }
        },
        "aws_route_table_association": {
            "public-1": {
                "route_table_id": "${aws_route_table.public.id}",
                "subnet_id": "${aws_subnet.main_koding_subnet.id}"
            }
        },
        "aws_security_group": {
            "allow_all": {
                "description": "Allow all inbound and outbound traffic",
                "ingress": {
                    "from_port": 0,
                    "to_port": 0,
                    "protocol": "-1",
                    "cidr_blocks": ["0.0.0.0/0"],
                    "self": true
                },
                "egress": {
                    "from_port": 0,
                    "to_port": 0,
                    "protocol": "-1",
                    "self": true,
                    "cidr_blocks": ["0.0.0.0/0"]
                },
                "name": "allow_all",
                "tags": {
                    "Name": "${var.environment_name}"
                },
                "vpc_id": "${aws_vpc.vpc.id}"
            }
        },
        "aws_key_pair": {
            "koding_key_pair": {
                "key_name": "${var.key_name}",
                "public_key": "${var.public_key}"
            }
        }
    },
    "variable": {
        "cidr_block": {
            "default": "10.0.0.0/16"
        },
        "environment_name": {
            "default": "Koding-Bootstrap"
        },
        "aws_availability_zones": {
            "default": {
                "ap-northeast-1": "ap-northeast-1b",
                "ap-southeast-1": "ap-southeast-1b",
                "ap-southeast-2": "ap-southeast-2b",
                "eu-central-1": "eu-central-1b",
                "eu-west-1": "eu-west-1b",
                "sa-east-1": "sa-east-1b",
                "us-east-1": "us-east-1b",
                "us-west-1": "us-west-1b",
                "us-west-2": "us-west-2b"
            }
        },
        "aws_amis": {
            "default": {
                "ap-northeast-1": "ami-9e5cff9e",
                "ap-southeast-1": "ami-ec7879be",
                "ap-southeast-2": "ami-2fce8b15",
                "eu-central-1": "ami-60f9c27d",
                "eu-west-1": "ami-7c4b0a0b",
                "sa-east-1": "ami-cd9518d0",
                "us-east-1": "ami-cf35f3a4",
                "us-west-1": "ami-b33dccf7",
                "us-west-2": "ami-8d5b5dbd"
            }
        }
    }
}`
<commit_msg>kloud: fix bootstrap region<commit_after>package kloud

import (
	"encoding/json"
	"errors"
	"fmt"
	"koding/db/mongodb/modelhelper"
	"koding/kites/kloud/contexthelper/session"
	"koding/kites/kloud/terraformer"
	tf "koding/kites/terraformer"
	"strconv"
	"time"

	"labix.org/v2/mgo/bson"

	"golang.org/x/net/context"

	"github.com/koding/kite"
	"github.com/mitchellh/goamz/aws"
	"github.com/mitchellh/goamz/iam"
	"github.com/mitchellh/mapstructure"
)

type AwsBootstrapOutput struct {
	ACL       string `json:"acl" mapstructure:"acl"`
	CidrBlock string `json:"cidr_block" mapstructure:"cidr_block"`
	IGW       string `json:"igw" mapstructure:"igw"`
	KeyPair   string `json:"key_pair" mapstructure:"key_pair"`
	RTB       string `json:"rtb" mapstructure:"rtb"`
	SG        string `json:"sg" mapstructure:"sg"`
	Subnet    string `json:"subnet" mapstructure:"subnet"`
	VPC       string `json:"vpc" mapstructure:"vpc"`
	AMI       string `json:"ami" mapstructure:"ami"`
}

type TerraformBootstrapRequest struct {
	// Identifiers contains identifers to be used with terraform
	Identifiers []string `json:"identifiers"`

	GroupName string `json:"groupName"`

	// Destroy destroys the bootstrap resource associated with the given
	// identifiers
	Destroy bool
}

func (k *Kloud) Bootstrap(r *kite.Request) (interface{}, error) {
	if r.Args == nil {
		return nil, NewError(ErrNoArguments)
	}

	var args *TerraformBootstrapRequest
	if err := r.Args.One().Unmarshal(&args); err != nil {
		return nil, err
	}

	if len(args.Identifiers) == 0 {
		return nil, errors.New("identifiers are not passed")
	}

	if args.GroupName == "" {
		return nil, errors.New("group name is not passed")
	}

	ctx := k.ContextCreator(context.Background())
	sess, ok := session.FromContext(ctx)
	if !ok {
		return nil, errors.New("session context is not passed")
	}

	data, err := fetchTerraformData(r.Username, args.GroupName, sess.DB, args.Identifiers)
	if err != nil {
		return nil, err
	}

	k.Log.Debug("Connecting to terraformer kite")
	tfKite, err := terraformer.Connect(sess.Kite)
	if err != nil {
		return nil, err
	}
	defer tfKite.Close()

	k.Log.Debug("Iterating over credentials")
	for _, cred := range data.Creds {
		// We are going to support more providers in the future, for now only allow aws
		if cred.Provider != "aws" {
			return nil, fmt.Errorf("Bootstrap is only supported for 'aws' provider. Got: '%s'", cred.Provider)
		}

		k.Log.Debug("parsing the template")
		template, err := newTerraformTemplate(awsBootstrap)
		if err != nil {
			return nil, err
		}

		k.Log.Debug("Injecting variables from credential data identifiers, such as aws, custom, etc..")
		if err := template.injectCustomVariables(cred.Provider, cred.Data); err != nil {
			return nil, err
		}

		var awsCred struct {
			Region    string `mapstructure:"region"`
			AccessKey string `mapstructure:"access_key"`
			SecretKey string `mapstructure:"secret_key"`
		}

		if err := mapstructure.Decode(cred.Data, &awsCred); err != nil {
			return nil, err
		}

		fmt.Printf("aws = %+v\n", awsCred)

		iamClient := iam.New(
			aws.Auth{
				AccessKey: awsCred.AccessKey,
				SecretKey: awsCred.SecretKey,
			},
			aws.Regions[awsCred.Region],
		)

		k.Log.Debug("Fetching the AWS user information to get the account ID")
		user, err := iamClient.GetDefaultUser() // will default to username making the request
		if err != nil {
			return nil, err
		}

		awsAccountID, err := parseAccountID(user.User.Arn)
		if err != nil {
			return nil, err
		}

		contentID := fmt.Sprintf("%s-%s-%s", awsAccountID, args.GroupName, awsCred.Region)
		k.Log.Debug("Going to use the contentID: %s", contentID)

		keyName := "koding-deployment-" + r.Username + "-" + strconv.FormatInt(time.Now().UTC().UnixNano(), 10)

		finalBootstrap, err := template.jsonOutput()
		if err != nil {
			return nil, err
		}

		finalBootstrap, err = appendAWSTemplateData(finalBootstrap, &awsTemplateData{
			KeyPairName:     keyName,
			PublicKey:       k.PublicKeys.PublicKey,
			EnvironmentName: fmt.Sprintf("Koding-%s-Bootstrap", args.GroupName),
		})
		if err != nil {
			return nil, err
		}

		k.Log.Debug("[%s] Final bootstrap:", cred.Identifier)
		k.Log.Debug(finalBootstrap)

		// Important so bootstraping is distributed amongs multiple users. If I
		// use these keys to bootstrap, any other user should be not create
		// again, instead they should be fetch and use the existing bootstrap
		// data.

		awsOutput := &AwsBootstrapOutput{}

		// this is custom because we need to remove the fields if we get a
		// destroy. So the operator changes from $set to $unset.
		mongodDBOperator := "$set"

		if args.Destroy {
			mongodDBOperator = "$unset"
			k.Log.Info("Destroying bootstrap resources belonging to identifier '%s'", cred.Identifier)
			_, err := tfKite.Destroy(&tf.TerraformRequest{
				Content:   finalBootstrap,
				ContentID: contentID,
			})
			if err != nil {
				return nil, err
			}
		} else {
			k.Log.Info("Creating bootstrap resources belonging to identifier '%s'", cred.Identifier)
			state, err := tfKite.Apply(&tf.TerraformRequest{
				Content:   finalBootstrap,
				ContentID: contentID,
			})
			if err != nil {
				return nil, err
			}

			k.Log.Debug("[%s] state.RootModule().Outputs = %+v\n", cred.Identifier, state.RootModule().Outputs)
			if err := mapstructure.Decode(state.RootModule().Outputs, &awsOutput); err != nil {
				return nil, err
			}
		}

		k.Log.Debug("[%s] Aws Output: %+v", cred.Identifier, awsOutput)
		if err := modelhelper.UpdateCredentialData(cred.Identifier, bson.M{
			mongodDBOperator: bson.M{
				"meta.acl":        awsOutput.ACL,
				"meta.cidr_block": awsOutput.CidrBlock,
				"meta.igw":        awsOutput.IGW,
				"meta.key_pair":   awsOutput.KeyPair,
				"meta.rtb":        awsOutput.RTB,
				"meta.sg":         awsOutput.SG,
				"meta.subnet":     awsOutput.Subnet,
				"meta.vpc":        awsOutput.VPC,
				"meta.ami":        awsOutput.AMI,
			},
		}); err != nil {
			return nil, err
		}
	}

	return true, nil
}

func appendAWSTemplateData(template string, awsData *awsTemplateData) (string, error) {
	var data struct {
		Output   map[string]map[string]interface{} `json:"output,omitempty"`
		Resource map[string]map[string]interface{} `json:"resource,omitempty"`
		Provider map[string]map[string]interface{} `json:"provider,omitempty"`
		Variable map[string]map[string]interface{} `json:"variable,omitempty"`
	}

	if err := json.Unmarshal([]byte(template), &data); err != nil {
		return "", err
	}

	data.Variable["key_name"] = map[string]interface{}{
		"default": awsData.KeyPairName,
	}

	data.Variable["public_key"] = map[string]interface{}{
		"default": awsData.PublicKey,
	}

	data.Variable["environment_name"] = map[string]interface{}{
		"default": awsData.EnvironmentName,
	}

	out, err := json.MarshalIndent(data, "", "  ")
	if err != nil {
		return "", err
	}

	return string(out), nil
}

// awsTemplateData is being used to format the bootstrap before we pass it to
// terraformer
type awsTemplateData struct {
	KeyPairName     string
	PublicKey       string
	EnvironmentName string
}

var awsBootstrap = `{
    "provider": {
        "aws": {
            "access_key": "${var.aws_access_key}",
            "secret_key": "${var.aws_secret_key}",
            "region": "${var.aws_region}"
        }
    },
    "output": {
        "vpc": {
            "value": "${aws_vpc.vpc.id}"
        },
        "cidr_block": {
            "value": "${aws_vpc.vpc.cidr_block}"
        },
        "rtb": {
            "value": "${aws_vpc.vpc.main_route_table_id}"
        },
        "acl": {
            "value": "${aws_vpc.vpc.default_network_acl_id}"
        },
        "igw": {
            "value": "${aws_internet_gateway.main_vpc_igw.id}"
        },
        "subnet": {
            "value": "${aws_subnet.main_koding_subnet.id}"
        },
        "sg": {
            "value": "${aws_security_group.allow_all.id}"
        },
        "ami": {
            "value": "${lookup(var.aws_amis, var.aws_region)}"
        },
        "key_pair": {
            "value": "${aws_key_pair.koding_key_pair.key_name}"
        }
    },
    "resource": {
        "aws_vpc": {
            "vpc": {
                "cidr_block": "${var.cidr_block}",
                "tags": {
                    "Name": "${var.environment_name}"
                }
            }
        },
        "aws_internet_gateway": {
            "main_vpc_igw": {
                "tags": {
                    "Name": "${var.environment_name}"
                },
                "vpc_id": "${aws_vpc.vpc.id}"
            }
        },
        "aws_subnet": {
            "main_koding_subnet": {
                "availability_zone": "${lookup(var.aws_availability_zones, var.aws_region)}",
                "cidr_block": "${var.cidr_block}",
                "map_public_ip_on_launch": true,
                "tags": {
                    "Name": "${var.environment_name}",
                    "subnet": "public"
                },
                "vpc_id": "${aws_vpc.vpc.id}"
            }
        },
        "aws_route_table": {
            "public": {
                "route": {
                    "cidr_block": "0.0.0.0/0",
                    "gateway_id": "${aws_internet_gateway.main_vpc_igw.id}"
                },
                "tags": {
                    "Name": "${var.environment_name}",
                    "routeTable": "koding",
                    "subnet": "public"
                },
                "vpc_id": "${aws_vpc.vpc.id}"
            }
        },
        "aws_route_table_association": {
            "public-1": {
                "route_table_id": "${aws_route_table.public.id}",
                "subnet_id": "${aws_subnet.main_koding_subnet.id}"
            }
        },
        "aws_security_group": {
            "allow_all": {
                "description": "Allow all inbound and outbound traffic",
                "ingress": {
                    "from_port": 0,
                    "to_port": 0,
                    "protocol": "-1",
                    "cidr_blocks": ["0.0.0.0/0"],
                    "self": true
                },
                "egress": {
                    "from_port": 0,
                    "to_port": 0,
                    "protocol": "-1",
                    "self": true,
                    "cidr_blocks": ["0.0.0.0/0"]
                },
                "name": "allow_all",
                "tags": {
                    "Name": "${var.environment_name}"
                },
                "vpc_id": "${aws_vpc.vpc.id}"
            }
        },
        "aws_key_pair": {
            "koding_key_pair": {
                "key_name": "${var.key_name}",
                "public_key": "${var.public_key}"
            }
        }
    },
    "variable": {
        "cidr_block": {
            "default": "10.0.0.0/16"
        },
        "environment_name": {
            "default": "Koding-Bootstrap"
        },
        "aws_availability_zones": {
            "default": {
                "ap-northeast-1": "ap-northeast-1b",
                "ap-southeast-1": "ap-southeast-1b",
                "ap-southeast-2": "ap-southeast-2b",
                "eu-central-1": "eu-central-1b",
                "eu-west-1": "eu-west-1b",
                "sa-east-1": "sa-east-1b",
                "us-east-1": "us-east-1b",
                "us-west-1": "us-west-1b",
                "us-west-2": "us-west-2b"
            }
        },
        "aws_amis": {
            "default": {
                "ap-northeast-1": "ami-9e5cff9e",
                "ap-southeast-1": "ami-ec7879be",
                "ap-southeast-2": "ami-2fce8b15",
                "eu-central-1": "ami-60f9c27d",
                "eu-west-1": "ami-7c4b0a0b",
                "sa-east-1": "ami-cd9518d0",
                "us-east-1": "ami-cf35f3a4",
                "us-west-1": "ami-b33dccf7",
                "us-west-2": "ami-8d5b5dbd"
            }
        }
    }
}`
<|endoftext|>