<commit_before>package main

import (
	dbModule "github.com/notegio/openrelay/db"
	"github.com/notegio/openrelay/common"
	"log"
	"os"
	"fmt"
	"strings"
)

func main() {
	db, err := dbModule.GetDB(os.Args[1], os.Args[2])
	if err != nil {
		log.Fatalf("Could not open database connection: %v", err.Error())
	}
	if err := db.AutoMigrate(&dbModule.Order{}).Error; err != nil {
		log.Fatalf("Error migrating order table: %v", err.Error())
	}
	if err := db.AutoMigrate(&dbModule.Cancellation{}).Error; err != nil {
		log.Fatalf("Error migrating cancellation table: %v", err.Error())
	}
	if err := db.AutoMigrate(&dbModule.Exchange{}).Error; err != nil {
		log.Fatalf("Error migrating cancellation table: %v", err.Error())
	}
	kovanAddress := common.HexToAddress("0xa458ec0709468996ef2ef668f5e52f37ceb66627")
	db.Where(
		&db.Exchange{Network: 42},
	).FirstOrCreate(&db.Exchange{Network: 42, Address: kovanAddress })
	ganacheAddress := common.HexToAddress("0x48bacb9266a570d521063ef5dd96e61686dbe788")
	db.Where(
		&db.Exchange{Network: 50},
	).FirstOrCreate(&db.Exchange{Network: 50, Address: ganacheAddress })

	if err := db.Model(&dbModule.Order{}).AddIndex("idx_order_maker_asset_taker_asset_data", "maker_asset_data", "taker_asset_data").Error; err != nil {
		log.Fatalf("Error adding token pair index: %v", err.Error())
	}
	for _, credString := range(os.Args[3:]) {
		creds := strings.Split(credString, ";")
		if len(creds) != 3 {
			log.Printf("Malformed credential string: %v", credString)
			continue
		}
		username, passwordURI, permissions := creds[0], creds[1], creds[2]
		password := common.GetSecret(passwordURI)
		if dialect := db.Dialect().GetName(); dialect == "postgres" {
			// I don't like using string formatting instead of paramterization, but I
			// don't know of a way to parameterize the username in this statement. It
			// should still be fairly safe, because if you're able to execute this
			// command you already have administrative database access.
			if err = db.Exec(fmt.Sprintf("CREATE USER %v WITH PASSWORD '%v'", username, password)).Error; err != nil {
				log.Printf(err.Error())
			}
			for _, permission := range(strings.Split(permissions, ",")) {
				permArray := strings.Split(permission, ".")
				if len(permArray) != 2 {
					log.Printf("Malformed permission string '$v'", permission)
					continue
				}
				table, permission := permArray[0], permArray[1]
				// I don't like using string formatting instead of paramterization, but I
				// don't know of a way to parameterize the elements in this statement. It
				// should still be fairly safe, because if you're able to execute this
				// command you already have administrative database access.
				if err = db.Exec(fmt.Sprintf("GRANT %v ON TABLE %v TO %v", permission, table, username)).Error; err != nil {
					log.Printf(err.Error())
				}
			}
		} else if dialect == "mysql" {
			if err := db.Exec(fmt.Sprintf("CREATE USER '%v' IDENTIFIED BY '%v'", username, password)).Error; err != nil {
				log.Printf(err.Error())
			}
			result := make(map[string]string)
			if err := db.Exec("SELECT DATABASE()").Row().Scan(result); err != nil {
				log.Printf(err.Error())
			}
			log.Printf("'%v'", result)
			databaseName := result["DATABASE()"]
			log.Printf("Database name: %v", databaseName)
			for _, permission := range(strings.Split(permissions, ",")) {
				permArray := strings.Split(permission, ".")
				if len(permArray) != 2 {
					log.Printf("Malformed permission string '$v'", permission)
					continue
				}
				table, permission := permArray[0], permArray[1]
				// I don't like using string formatting instead of paramterization, but I
				// don't know of a way to parameterize the elements in this statement. It
				// should still be fairly safe, because if you're able to execute this
				// command you already have administrative database access.
				if err = db.Exec(fmt.Sprintf("GRANT %v ON %v.%v TO '%v'", permission, databaseName, table, username)).Error; err != nil {
					log.Printf(err.Error())
				}
			}
			if err := db.Exec("FLUSH PRIVILEGES;").Error; err != nil {
				log.Printf(err.Error());
			}
		}
		log.Printf("Created '%v'", credString)
	}
}
<commit_msg>Fix issues in automigrate<commit_after>package main

import (
	dbModule "github.com/notegio/openrelay/db"
	"github.com/notegio/openrelay/common"
	"log"
	"os"
	"fmt"
	"strings"
)

func main() {
	db, err := dbModule.GetDB(os.Args[1], os.Args[2])
	if err != nil {
		log.Fatalf("Could not open database connection: %v", err.Error())
	}
	if err := db.AutoMigrate(&dbModule.Order{}).Error; err != nil {
		log.Fatalf("Error migrating order table: %v", err.Error())
	}
	if err := db.AutoMigrate(&dbModule.Cancellation{}).Error; err != nil {
		log.Fatalf("Error migrating cancellation table: %v", err.Error())
	}
	if err := db.AutoMigrate(&dbModule.Exchange{}).Error; err != nil {
		log.Fatalf("Error migrating cancellation table: %v", err.Error())
	}
	kovanAddress, _ := common.HexToAddress("0xa458ec0709468996ef2ef668f5e52f37ceb66627")
	db.Where(
		&dbModule.Exchange{Network: 42},
	).FirstOrCreate(&dbModule.Exchange{Network: 42, Address: kovanAddress })
	ganacheAddress, _ := common.HexToAddress("0x48bacb9266a570d521063ef5dd96e61686dbe788")
	db.Where(
		&dbModule.Exchange{Network: 50},
	).FirstOrCreate(&dbModule.Exchange{Network: 50, Address: ganacheAddress })

	if err := db.Model(&dbModule.Order{}).AddIndex("idx_order_maker_asset_taker_asset_data", "maker_asset_data", "taker_asset_data").Error; err != nil {
		log.Fatalf("Error adding token pair index: %v", err.Error())
	}
	for _, credString := range(os.Args[3:]) {
		creds := strings.Split(credString, ";")
		if len(creds) != 3 {
			log.Printf("Malformed credential string: %v", credString)
			continue
		}
		username, passwordURI, permissions := creds[0], creds[1], creds[2]
		password := common.GetSecret(passwordURI)
		if dialect := db.Dialect().GetName(); dialect == "postgres" {
			// I don't like using string formatting instead of paramterization, but I
			// don't know of a way to parameterize the username in this statement. It
			// should still be fairly safe, because if you're able to execute this
			// command you already have administrative database access.
			if err = db.Exec(fmt.Sprintf("CREATE USER %v WITH PASSWORD '%v'", username, password)).Error; err != nil {
				log.Printf(err.Error())
			}
			for _, permission := range(strings.Split(permissions, ",")) {
				permArray := strings.Split(permission, ".")
				if len(permArray) != 2 {
					log.Printf("Malformed permission string '$v'", permission)
					continue
				}
				table, permission := permArray[0], permArray[1]
				// I don't like using string formatting instead of paramterization, but I
				// don't know of a way to parameterize the elements in this statement. It
				// should still be fairly safe, because if you're able to execute this
				// command you already have administrative database access.
				if err = db.Exec(fmt.Sprintf("GRANT %v ON TABLE %v TO %v", permission, table, username)).Error; err != nil {
					log.Printf(err.Error())
				}
			}
		} else if dialect == "mysql" {
			if err := db.Exec(fmt.Sprintf("CREATE USER '%v' IDENTIFIED BY '%v'", username, password)).Error; err != nil {
				log.Printf(err.Error())
			}
			result := make(map[string]string)
			if err := db.Exec("SELECT DATABASE()").Row().Scan(result); err != nil {
				log.Printf(err.Error())
			}
			log.Printf("'%v'", result)
			databaseName := result["DATABASE()"]
			log.Printf("Database name: %v", databaseName)
			for _, permission := range(strings.Split(permissions, ",")) {
				permArray := strings.Split(permission, ".")
				if len(permArray) != 2 {
					log.Printf("Malformed permission string '$v'", permission)
					continue
				}
				table, permission := permArray[0], permArray[1]
				// I don't like using string formatting instead of paramterization, but I
				// don't know of a way to parameterize the elements in this statement. It
				// should still be fairly safe, because if you're able to execute this
				// command you already have administrative database access.
				if err = db.Exec(fmt.Sprintf("GRANT %v ON %v.%v TO '%v'", permission, databaseName, table, username)).Error; err != nil {
					log.Printf(err.Error())
				}
			}
			if err := db.Exec("FLUSH PRIVILEGES;").Error; err != nil {
				log.Printf(err.Error());
			}
		}
		log.Printf("Created '%v'", credString)
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2021 The Kubernetes Authors.

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

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

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

package cmd

import (
	"fmt"
	"net/url"
	"os"

	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
	"k8s.io/release/pkg/spdx"
	"sigs.k8s.io/release-utils/util"
)

var genOpts = &generateOptions{}

var generateCmd = &cobra.Command{
	Short: "bom generate → Create SPDX manifests",
	Long: `bom → Create SPDX manifests

generate is the bom subcommand to generate SPDX manifests.
Currently supports creating SBOM for files, images, and docker
archives (images in tarballs). Supports pulling images from
registries.

bom can take a deeper look into images using a growing number
of analyzers designed to add more sense to common base images.

`,
	Use:               "generate",
	SilenceUsage:      true,
	SilenceErrors:     true,
	PersistentPreRunE: initLogging,
	RunE: func(cmd *cobra.Command, args []string) error {
		for i, arg := range args {
			if util.Exists(arg) {
				file, err := os.Open(arg)
				if err != nil {
					return errors.Wrapf(err, "checking argument %d", i)
				}
				fileInfo, err := file.Stat()
				if err != nil {
					return errors.Wrapf(err, "calling stat on argument %d", i)
				}
				if fileInfo.IsDir() {
					genOpts.directories = append(genOpts.directories, arg)
				}
			}
		}
		return generateBOM(genOpts)
	},
}

type generateOptions struct {
	analyze        bool
	noGitignore    bool
	noGoModules    bool
	noGoTransient  bool
	namespace      string
	outputFile     string
	configFile     string
	images         []string
	tarballs       []string
	files          []string
	directories    []string
	ignorePatterns []string
}

// Validate verify options consistency
func (opts *generateOptions) Validate() error {
	if opts.configFile == "" &&
		len(opts.images) == 0 &&
		len(opts.files) == 0 &&
		len(opts.tarballs) == 0 &&
		len(opts.directories) == 0 {
		return errors.New("to generate a SPDX BOM you have to provide at least one image or file")
	}

	// A namespace URL is required
	if opts.configFile == "" && opts.namespace == "" {
		msg := "Error. No namespace defined\n\n"
		msg += "You did not specify a namespace for your document. This is an error.\n"
		msg += "To produce a valid SPDX SBOM, the document has to have an URI as its\n"
		msg += "namespace.\n\nIf you are testing, you can use http://example.com/ for now but your\n"
		msg += "final document must have a namespace URI pointing to the location where\n"
		msg += "your SBOM will be referenced in the future.\n\n"
		msg += "For more details, check the SPDX documentation here:\n"
		msg += "https://spdx.github.io/spdx-spec/2-document-creation-information/#25-spdx-document-namespace\n\n"
		msg += "Hint: --namespace is your friend here\n\n"
		logrus.Info(msg)

		return errors.New("A namespace URI must be defined to have a compliant SPDX BOM")
	}

	// Check namespace is a valid URL
	if _, err := url.Parse(opts.namespace); err != nil {
		return errors.Wrap(err, "parsing the namespace URL")
	}

	return nil
}

func init() {
	generateCmd.PersistentFlags().StringSliceVarP(
		&genOpts.images,
		"image",
		"i",
		[]string{},
		"list of images",
	)

	generateCmd.PersistentFlags().StringSliceVarP(
		&genOpts.files,
		"file",
		"f",
		[]string{},
		"list of files to include",
	)

	generateCmd.PersistentFlags().StringSliceVarP(
		&genOpts.tarballs,
		"tarball",
		"t",
		[]string{},
		"list of docker archive tarballs to include in the manifest",
	)

	generateCmd.PersistentFlags().StringSliceVarP(
		&genOpts.directories,
		"dirs",
		"d",
		[]string{},
		"list of directories to include in the manifest as packages",
	)

	generateCmd.PersistentFlags().StringSliceVar(
		&genOpts.ignorePatterns,
		"ignore",
		[]string{},
		"list of regexp patterns to ignore when scanning directories",
	)

	generateCmd.PersistentFlags().BoolVar(
		&genOpts.noGitignore,
		"no-gitignore",
		false,
		"don't use exclusions from .gitignore files",
	)

	generateCmd.PersistentFlags().BoolVar(
		&genOpts.noGitignore,
		"no-gomod",
		false,
		"don't perform go.mod analysis, sbom will not include data about go packages",
	)

	generateCmd.PersistentFlags().BoolVar(
		&genOpts.noGoTransient,
		"no-transient",
		false,
		"don't include transient go dependencies, only direct deps from go.mod",
	)

	generateCmd.PersistentFlags().StringVarP(
		&genOpts.namespace,
		"namespace",
		"n",
		"",
		"an URI that servers as namespace for the SPDX doc",
	)

	generateCmd.PersistentFlags().StringVarP(
		&genOpts.outputFile,
		"output",
		"o",
		"",
		"path to the file where the document will be written (defaults to STDOUT)",
	)

	generateCmd.PersistentFlags().BoolVarP(
		&genOpts.analyze,
		"analyze-images",
		"a",
		false,
		"go deeper into images using the available analyzers",
	)

	generateCmd.PersistentFlags().StringVarP(
		&genOpts.configFile,
		"config",
		"c",
		"",
		"path to yaml SBOM configuration file",
	)
}

func generateBOM(opts *generateOptions) error {
	if err := opts.Validate(); err != nil {
		return errors.Wrap(err, "validating command line options")
	}
	logrus.Info("Generating SPDX Bill of Materials")

	builder := spdx.NewDocBuilder()
	builderOpts := &spdx.DocGenerateOptions{
		Tarballs:         opts.tarballs,
		Files:            opts.files,
		Images:           opts.images,
		Directories:      opts.directories,
		OutputFile:       opts.outputFile,
		Namespace:        opts.namespace,
		AnalyseLayers:    opts.analyze,
		ProcessGoModules: !opts.noGoModules,
		OnlyDirectDeps:   !opts.noGoTransient,
		ConfigFile:       opts.configFile,
	}

	// We only replace the ignore patterns one or more where defined
	if len(opts.ignorePatterns) > 0 {
		builderOpts.IgnorePatterns = opts.ignorePatterns
	}
	doc, err := builder.Generate(builderOpts)
	if err != nil {
		return errors.Wrap(err, "generating doc")
	}

	if opts.outputFile == "" {
		markup, err := doc.Render()
		if err != nil {
			return errors.Wrap(err, "rendering document")
		}
		fmt.Println(markup)
	}
	return nil
}
<commit_msg>Fix error in go modules flag<commit_after>/*
Copyright 2021 The Kubernetes Authors.

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

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

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

package cmd

import (
	"fmt"
	"net/url"
	"os"

	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
	"k8s.io/release/pkg/spdx"
	"sigs.k8s.io/release-utils/util"
)

var genOpts = &generateOptions{}

var generateCmd = &cobra.Command{
	Short: "bom generate → Create SPDX manifests",
	Long: `bom → Create SPDX manifests

generate is the bom subcommand to generate SPDX manifests.
Currently supports creating SBOM for files, images, and docker
archives (images in tarballs). Supports pulling images from
registries.

bom can take a deeper look into images using a growing number
of analyzers designed to add more sense to common base images.

`,
	Use:               "generate",
	SilenceUsage:      true,
	SilenceErrors:     true,
	PersistentPreRunE: initLogging,
	RunE: func(cmd *cobra.Command, args []string) error {
		for i, arg := range args {
			if util.Exists(arg) {
				file, err := os.Open(arg)
				if err != nil {
					return errors.Wrapf(err, "checking argument %d", i)
				}
				fileInfo, err := file.Stat()
				if err != nil {
					return errors.Wrapf(err, "calling stat on argument %d", i)
				}
				if fileInfo.IsDir() {
					genOpts.directories = append(genOpts.directories, arg)
				}
			}
		}
		return generateBOM(genOpts)
	},
}

type generateOptions struct {
	analyze        bool
	noGitignore    bool
	noGoModules    bool
	noGoTransient  bool
	namespace      string
	outputFile     string
	configFile     string
	images         []string
	tarballs       []string
	files          []string
	directories    []string
	ignorePatterns []string
}

// Validate verify options consistency
func (opts *generateOptions) Validate() error {
	if opts.configFile == "" &&
		len(opts.images) == 0 &&
		len(opts.files) == 0 &&
		len(opts.tarballs) == 0 &&
		len(opts.directories) == 0 {
		return errors.New("to generate a SPDX BOM you have to provide at least one image or file")
	}

	// A namespace URL is required
	if opts.configFile == "" && opts.namespace == "" {
		msg := "Error. No namespace defined\n\n"
		msg += "You did not specify a namespace for your document. This is an error.\n"
		msg += "To produce a valid SPDX SBOM, the document has to have an URI as its\n"
		msg += "namespace.\n\nIf you are testing, you can use http://example.com/ for now but your\n"
		msg += "final document must have a namespace URI pointing to the location where\n"
		msg += "your SBOM will be referenced in the future.\n\n"
		msg += "For more details, check the SPDX documentation here:\n"
		msg += "https://spdx.github.io/spdx-spec/2-document-creation-information/#25-spdx-document-namespace\n\n"
		msg += "Hint: --namespace is your friend here\n\n"
		logrus.Info(msg)

		return errors.New("A namespace URI must be defined to have a compliant SPDX BOM")
	}

	// Check namespace is a valid URL
	if _, err := url.Parse(opts.namespace); err != nil {
		return errors.Wrap(err, "parsing the namespace URL")
	}

	return nil
}

func init() {
	generateCmd.PersistentFlags().StringSliceVarP(
		&genOpts.images,
		"image",
		"i",
		[]string{},
		"list of images",
	)

	generateCmd.PersistentFlags().StringSliceVarP(
		&genOpts.files,
		"file",
		"f",
		[]string{},
		"list of files to include",
	)

	generateCmd.PersistentFlags().StringSliceVarP(
		&genOpts.tarballs,
		"tarball",
		"t",
		[]string{},
		"list of docker archive tarballs to include in the manifest",
	)

	generateCmd.PersistentFlags().StringSliceVarP(
		&genOpts.directories,
		"dirs",
		"d",
		[]string{},
		"list of directories to include in the manifest as packages",
	)

	generateCmd.PersistentFlags().StringSliceVar(
		&genOpts.ignorePatterns,
		"ignore",
		[]string{},
		"list of regexp patterns to ignore when scanning directories",
	)

	generateCmd.PersistentFlags().BoolVar(
		&genOpts.noGitignore,
		"no-gitignore",
		false,
		"don't use exclusions from .gitignore files",
	)

	generateCmd.PersistentFlags().BoolVar(
		&genOpts.noGoModules,
		"no-gomod",
		false,
		"don't perform go.mod analysis, sbom will not include data about go packages",
	)

	generateCmd.PersistentFlags().BoolVar(
		&genOpts.noGoTransient,
		"no-transient",
		false,
		"don't include transient go dependencies, only direct deps from go.mod",
	)

	generateCmd.PersistentFlags().StringVarP(
		&genOpts.namespace,
		"namespace",
		"n",
		"",
		"an URI that servers as namespace for the SPDX doc",
	)

	generateCmd.PersistentFlags().StringVarP(
		&genOpts.outputFile,
		"output",
		"o",
		"",
		"path to the file where the document will be written (defaults to STDOUT)",
	)

	generateCmd.PersistentFlags().BoolVarP(
		&genOpts.analyze,
		"analyze-images",
		"a",
		false,
		"go deeper into images using the available analyzers",
	)

	generateCmd.PersistentFlags().StringVarP(
		&genOpts.configFile,
		"config",
		"c",
		"",
		"path to yaml SBOM configuration file",
	)
}

func generateBOM(opts *generateOptions) error {
	if err := opts.Validate(); err != nil {
		return errors.Wrap(err, "validating command line options")
	}
	logrus.Info("Generating SPDX Bill of Materials")

	builder := spdx.NewDocBuilder()
	builderOpts := &spdx.DocGenerateOptions{
		Tarballs:         opts.tarballs,
		Files:            opts.files,
		Images:           opts.images,
		Directories:      opts.directories,
		OutputFile:       opts.outputFile,
		Namespace:        opts.namespace,
		AnalyseLayers:    opts.analyze,
		ProcessGoModules: !opts.noGoModules,
		OnlyDirectDeps:   !opts.noGoTransient,
		ConfigFile:       opts.configFile,
	}

	// We only replace the ignore patterns one or more where defined
	if len(opts.ignorePatterns) > 0 {
		builderOpts.IgnorePatterns = opts.ignorePatterns
	}
	doc, err := builder.Generate(builderOpts)
	if err != nil {
		return errors.Wrap(err, "generating doc")
	}

	if opts.outputFile == "" {
		markup, err := doc.Render()
		if err != nil {
			return errors.Wrap(err, "rendering document")
		}
		fmt.Println(markup)
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"github.com/eaigner/hood"
	"os"
	"path"
	"reflect"
	"sort"
	"strconv"
	"strings"
)

import (
	"fmt"
)

type M struct{}

type environments map[string]config
type config map[string]string

func main() {
	v := reflect.ValueOf(&M{})
	numMethods := v.NumMethod()
	stamps := make([]int, 0, numMethods)
	ups := make(map[int]reflect.Value)
	downs := make(map[int]reflect.Value)
	for i := 0; i < numMethods; i++ {
		method := v.Type().Method(i)
		chunks := strings.Split(method.Name, "_")
		if l := len(chunks); l >= 3 {
			ts, _ := strconv.Atoi(chunks[l-2])
			direction := chunks[l-1]
			if strings.ToLower(direction) == "up" {
				ups[ts] = method.Func
				stamps = append(stamps, ts)
			} else {
				downs[ts] = method.Func
			}
		}
	}
	sort.Ints(stamps)
	env := readConfig()
	fmt.Println(env)
	for _, ts := range stamps {
		// TODO: check if was already run
		// TODO: pass real hood instance
		hood := &hood.Hood{}
		ups[ts].Call([]reflect.Value{v, reflect.ValueOf(hood)})
		downs[ts].Call([]reflect.Value{v, reflect.ValueOf(hood)})
	}
}

func readConfig() environments {
	wd, err := os.Getwd()
	if err != nil {
		panic(err)
	}
	sf, err := os.Open(path.Join(wd, "db", "config.json"))
	if err != nil {
		panic(err)
	}
	defer sf.Close()
	dec := json.NewDecoder(sf)
	var env environments
	err = dec.Decode(&env)
	if err != nil {
		panic(err)
	}
	return env
}
<commit_msg>create migration table<commit_after>package main

import (
	"encoding/json"
	"github.com/eaigner/hood"
	"os"
	"path"
	"reflect"
	"sort"
	"strconv"
	"strings"
)

import (
	"fmt"
)

type M struct{}

type environments map[string]config
type config map[string]string

type Migrations struct {
	Current int
}

func main() {
	// Get up/down migration methods
	v := reflect.ValueOf(&M{})
	numMethods := v.NumMethod()
	stamps := make([]int, 0, numMethods)
	ups := make(map[int]reflect.Value)
	downs := make(map[int]reflect.Value)
	for i := 0; i < numMethods; i++ {
		method := v.Type().Method(i)
		chunks := strings.Split(method.Name, "_")
		if l := len(chunks); l >= 3 {
			ts, _ := strconv.Atoi(chunks[l-2])
			direction := chunks[l-1]
			if strings.ToLower(direction) == "up" {
				ups[ts] = method.Func
				stamps = append(stamps, ts)
			} else {
				downs[ts] = method.Func
			}
		}
	}
	sort.Ints(stamps)
	// Get config for set environment
	env := "development"
	if x := os.Getenv("HOOD_ENV"); x != "" {
		env = x
	}
	cfg := readConfig()[env]
	// Open hood
	hd, err := hood.Open(cfg["driver"], cfg["source"])
	if err != nil {
		panic(err)
	}
	// Check migration table
	err = hd.CreateTableIfNotExists(&Migrations{})
	if err != nil {
		panic(err)
	}
	var rows []Migrations
	err = hd.Find(&rows)
	if err != nil {
		panic(err)
	}
	fmt.Println("rows", rows)
	// TODO: implement

	// TODO: Migrate up or down
	for _, ts := range stamps {
		// TODO: check if was already run
		tx := hd.Begin()
		ups[ts].Call([]reflect.Value{v, reflect.ValueOf(tx)})
		err = tx.Commit()
		if err != nil {
			panic(err)
		}
		// downs[ts].Call([]reflect.Value{v, reflect.ValueOf(hd)})
	}
}

func readConfig() environments {
	wd, err := os.Getwd()
	if err != nil {
		panic(err)
	}
	sf, err := os.Open(path.Join(wd, "db", "config.json"))
	if err != nil {
		panic(err)
	}
	defer sf.Close()
	dec := json.NewDecoder(sf)
	var env environments
	err = dec.Decode(&env)
	if err != nil {
		panic(err)
	}
	return env
}
<|endoftext|>


<commit_before>package handlers

import (
	"github.com/dmonay/okra/authentication"
	"github.com/dmonay/okra/common"
	"github.com/gin-gonic/gin"
	"gopkg.in/mgo.v2/bson"
	"os"
)

func (dw *DoWorkResource) GetAllUsers(c *gin.Context) {
	user := c.Params.ByName("user")

	var results []common.UsersObj
	err := dw.mongo.C("Users").Find(bson.M{"username": bson.M{"$regex": bson.RegEx{Pattern: user, Options: "i"}}}).All(&results)
	if err != nil {
		CheckErr(err, "Failed to get all users", c)
		return
	}
	result := make(map[string][]byte)
	count := 0
	for _, value := range results {
		count++
		rawKey := os.Getenv("SECRET")
		key := []byte(rawKey) // 32 bytes
		plaintext := []byte(value.Id)

		ciphertext, err2 := authentication.Encrypt(key, plaintext)
		if err2 != nil {
			CheckErr(err2, "Failed to encrypt key", c)
			return
		}
		result[value.Username] = ciphertext
		if count == 7 {
			break
		}
	}

	c.JSON(200, SuccessMsg{result})
}
<commit_msg>return mongo id as plaintext<commit_after>package handlers

import (
	"github.com/dmonay/okra/common"
	"github.com/gin-gonic/gin"
	"gopkg.in/mgo.v2/bson"
)

func (dw *DoWorkResource) GetAllUsers(c *gin.Context) {
	user := c.Params.ByName("user")

	var results []common.UsersObj
	err := dw.mongo.C("Users").Find(bson.M{"username": bson.M{"$regex": bson.RegEx{Pattern: user, Options: "i"}}}).All(&results)
	if err != nil {
		CheckErr(err, "Failed to get all users", c)
		return
	}
	result := make(map[string]bson.ObjectId)
	count := 0
	for _, value := range results {
		count++
		result[value.Username] = value.Id
		if count == 7 {
			break
		}
	}

	c.JSON(200, SuccessMsg{result})
}
<|endoftext|>


<commit_before>package cart

import (
	"sync"
	"net/http"
	"os"
	"time"
	"strings"
)

type Engine struct {
	Router
	routers			map[string]*Router	//saved routers
	engine			*Engine
	pool        	sync.Pool
	tree			*node 	//match trees

	NotFound		HandlerFinal
	TemplatePath	string
}

var _ http.Handler = &Engine{}

var server *http.Server

func (e *Engine) allocateContext() *Context {
	return &Context{}
}

func (e *Engine) findRouter(absolutePath string) (*Router, bool) {
	router := e.routers[absolutePath]
	if router == nil {
		return nil, false
	}
	return router, true
}

func (e *Engine) getRouter(absolutePath string) (*Router, bool) {
	router := e.routers[absolutePath]
	find := true
	if router == nil {
		find = false
		router = &Router{
			engine:e,
			Path:absolutePath,
			methods:make([]method,0),
		}
	}
	return router, find
}

func (e *Engine) addRoute(router *Router) {
	if router.Path[0] != '/' {
		panic("Path must begin with '/' in path '" + router.Path + "'")
	}
	if e.tree == nil {
		e.tree = &node{}
	}
	if _, found := e.tree.findCaseInsensitivePath(router.Path, true); !found {
		debugPrint("Add Router %s",router.Path)
		e.routers[router.Path] = router
		e.tree.addRoute(router.Path, router)
	}
}

func (e *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	c := e.pool.Get().(*Context)
	c.reset(w, req)
	e.serveHTTP(c)
	e.pool.Put(c)
}

func (e *Engine) mixMethods(httpMethod string, r *Router) HandlerCompose {
	//http method find any
	var methods HandlerCompose
	if m, find := r.getMethod("ANY"); find {
		methods = compose(m)
	}
	if m, find := r.getMethod(httpMethod); find {
		if methods != nil {
			methods = compose(methods,m)
		} else {
			methods = compose(m)
		}
	}
	return methods
}

func (e *Engine) serveHTTP(c *Context) {
	path := c.Request.URL.Path
	httpMethod := c.Request.Method

	final404 := func() {
		// 404 error
		// make temp router
		c.Router,_ = e.getRouter(path)
		if c.Response.Size() == -1 && c.Response.Status() == 200 {
			if e.NotFound != nil {
				e.NotFound(c);
			} else {
				c.Response.WriteString("404 Not Found")
			}
		}
	}

	if root := e.tree; root != nil {
		if r, ps, tsr := root.getValue(path); r != nil {
			router := r.(*Router)
			c.Router = router
			c.Params = ps

			//methods
			methods := e.mixMethods(httpMethod, router)
			//middleware

			composed := router.composed
			if composed != nil && methods != nil {
				composed = compose(composed, methods)
			} else if composed == nil && methods != nil {
				composed = methods
			}
			if composed != nil {
				composed(c,final404)()
			} else {
				final404()
			}
			c.Response.WriteHeaderNow()
			return
		} else if httpMethod != "CONNECT" && path != "/" {
			code := 301 // Permanent redirect, request with GET method
			if httpMethod != "GET" {
				code = 307
			}
			if tsr {
				if len(path) > 1 && path[len(path)-1] == '/' {
					c.Request.URL.Path = path[:len(path)-1]
				} else {
					c.Request.URL.Path = path + "/"
				}
				http.Redirect(c.Response, c.Request, c.Request.URL.String(), code)
				return
			}
		}
	}
	//find / middleware
	r, composed := e.mixComposed(path)
	if composed != nil {
		c.Router = r
		composed(c,final404)()
	} else {
		final404()
	}
	//if r, find := e.findRouter("/"); find {
	//	if r.composed!=nil {
	//		c.Router = r
	//		r.composed(c,final404)()
	//	} else {
	//		final404()
	//	}
	//} else {
	//	final404()
	//}
	c.Response.WriteHeaderNow()
}

func (e *Engine) mixComposed(absolutePath string) (*Router, HandlerCompose) {
	sp := strings.Split(absolutePath,"/")
	for i, _ := range sp {
		//find it's self first ..... last is root path / router
		tempPath := strings.Join(sp[0:len(sp)-i], "/")
		if tempPath == "" {
			tempPath = "/"
		}
		if pr, find := e.findRouter(tempPath); find {
			return pr, pr.composed
		}
		//auto add slash then find
		if tempPath[len(tempPath)-1] != '/' && tempPath != absolutePath && tempPath != "/" {
			tempPath = tempPath+"/"
			if pr, find := e.findRouter(tempPath); find {
				return pr, pr.composed
			}
		}

	}
	return nil, nil
}
/*
init new Engine
 */
func (e *Engine) init() {
	e.Router = Router{
		Path: "/",
	}
	e.Router.engine = e
	e.pool.New = func() interface{} {
		return e.allocateContext()
	}
	e.tree = &node{}
	e.routers = make(map[string]*Router)
}
/*
Run the server
 */
func (e *Engine) Run(addr ...string) (err error) {
	defer func() { debugError(err) }()
	address := resolveAddress(addr)
	debugPrint("PID:%d Listening and serving HTTP on %s\n", os.Getpid(), address)

	server = &http.Server{
		Addr: address,
		Handler: e,
		ReadTimeout: time.Second * 90,
		//ReadHeaderTimeout: time.Second * 90,
		WriteTimeout: time.Second * 90,
		//IdleTimeout: time.Second * 90,
	}
	err = server.ListenAndServe()
	return
}

<commit_msg>add html Layout<commit_after>package cart

import (
	"sync"
	"net/http"
	"os"
	"time"
	"strings"
)

type Engine struct {
	Router
	routers			map[string]*Router	//saved routers
	engine			*Engine
	pool        	sync.Pool
	tree			*node 	//match trees

	NotFound		HandlerFinal
	TemplatePath	string
}

var _ http.Handler = &Engine{}

var server *http.Server

func (e *Engine) allocateContext() *Context {
	return &Context{}
}

func (e *Engine) findRouter(absolutePath string) (*Router, bool) {
	router := e.routers[absolutePath]
	if router == nil {
		return nil, false
	}
	return router, true
}

func (e *Engine) getRouter(absolutePath string) (*Router, bool) {
	router := e.routers[absolutePath]
	find := true
	if router == nil {
		find = false
		router = &Router{
			engine:e,
			Path:absolutePath,
			methods:make([]method,0),
		}
	}
	return router, find
}

func (e *Engine) addRoute(router *Router) {
	if router.Path[0] != '/' {
		panic("Path must begin with '/' in path '" + router.Path + "'")
	}
	if e.tree == nil {
		e.tree = &node{}
	}
	if _, found := e.tree.findCaseInsensitivePath(router.Path, true); !found {
		debugPrint("Add Router %s",router.Path)
		e.routers[router.Path] = router
		e.tree.addRoute(router.Path, router)
	}
}

func (e *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	c := e.pool.Get().(*Context)
	c.reset(w, req)
	e.serveHTTP(c)
	e.pool.Put(c)
}

func (e *Engine) mixMethods(httpMethod string, r *Router) HandlerCompose {
	//http method find any
	var methods HandlerCompose
	if m, find := r.getMethod("ANY"); find {
		methods = compose(m)
	}
	if m, find := r.getMethod(httpMethod); find {
		if methods != nil {
			methods = compose(methods,m)
		} else {
			methods = compose(m)
		}
	}
	return methods
}

func (e *Engine) serveHTTP(c *Context) {
	path := c.Request.URL.Path
	httpMethod := c.Request.Method

	final404 := func() {
		// 404 error
		// make temp router
		c.Router,_ = e.getRouter(path)
		if c.Response.Size() == -1 && c.Response.Status() == 200 {
			if e.NotFound != nil {
				e.NotFound(c);
			} else {
				c.String(404,"404 Not Found")
			}
		}
	}

	if root := e.tree; root != nil {
		if r, ps, tsr := root.getValue(path); r != nil {
			router := r.(*Router)
			c.Router = router
			c.Params = ps

			//methods
			methods := e.mixMethods(httpMethod, router)
			//middleware

			composed := router.composed
			if composed != nil && methods != nil {
				composed = compose(composed, methods)
			} else if composed == nil && methods != nil {
				composed = methods
			}
			if composed != nil {
				composed(c,final404)()
			} else {
				final404()
			}
			c.Response.WriteHeaderNow()
			return
		} else if httpMethod != "CONNECT" && path != "/" {
			code := 301 // Permanent redirect, request with GET method
			if httpMethod != "GET" {
				code = 307
			}
			if tsr {
				if len(path) > 1 && path[len(path)-1] == '/' {
					c.Request.URL.Path = path[:len(path)-1]
				} else {
					c.Request.URL.Path = path + "/"
				}
				http.Redirect(c.Response, c.Request, c.Request.URL.String(), code)
				return
			}
		}
	}
	//find / middleware
	r, composed := e.mixComposed(path)
	if composed != nil {
		c.Router = r
		composed(c,final404)()
	} else {
		final404()
	}
	//if r, find := e.findRouter("/"); find {
	//	if r.composed!=nil {
	//		c.Router = r
	//		r.composed(c,final404)()
	//	} else {
	//		final404()
	//	}
	//} else {
	//	final404()
	//}
	c.Response.WriteHeaderNow()
}

func (e *Engine) mixComposed(absolutePath string) (*Router, HandlerCompose) {
	sp := strings.Split(absolutePath,"/")
	for i, _ := range sp {
		//find it's self first ..... last is root path / router
		tempPath := strings.Join(sp[0:len(sp)-i], "/")
		if tempPath == "" {
			tempPath = "/"
		}
		if pr, find := e.findRouter(tempPath); find {
			return pr, pr.composed
		}
		//auto add slash then find
		if tempPath[len(tempPath)-1] != '/' && tempPath != absolutePath && tempPath != "/" {
			tempPath = tempPath+"/"
			if pr, find := e.findRouter(tempPath); find {
				return pr, pr.composed
			}
		}

	}
	return nil, nil
}
/*
init new Engine
 */
func (e *Engine) init() {
	e.Router = Router{
		Path: "/",
	}
	e.Router.engine = e
	e.pool.New = func() interface{} {
		return e.allocateContext()
	}
	e.tree = &node{}
	e.routers = make(map[string]*Router)
}
/*
Run the server
 */
func (e *Engine) Run(addr ...string) (err error) {
	defer func() { debugError(err) }()
	address := resolveAddress(addr)
	debugPrint("PID:%d Listening and serving HTTP on %s\n", os.Getpid(), address)

	server = &http.Server{
		Addr: address,
		Handler: e,
		ReadTimeout: time.Second * 90,
		//ReadHeaderTimeout: time.Second * 90,
		WriteTimeout: time.Second * 90,
		//IdleTimeout: time.Second * 90,
	}
	err = server.ListenAndServe()
	return
}

<|endoftext|>


<commit_before>// Package testlog creates a *log.Logger backed by *testing.T to ease logging
// in tests. This allows logs from components being tested to only be printed
// if the test fails (or the verbose flag is specified).
package testlog

import (
	"io"
	"log"
)

// LogPrinter is the methods of testing.T (or testing.B) needed by the test
// logger.
type LogPrinter interface {
	Logf(format string, args ...interface{})
}

// writer implements io.Writer on top of a Logger.
type writer struct {
	t LogPrinter
}

// Write to an underlying Logger. Never returns an error.
func (w *writer) Write(p []byte) (n int, err error) {
	w.t.Logf(string(p))
	return len(p), nil
}

// NewWriter creates a new io.Writer backed by a Logger.
func NewWriter(t LogPrinter) io.Writer {
	return &writer{t}
}

// New returns a new test logger. See https://golang.org/pkg/log/#New
func New(t LogPrinter, prefix string, flag int) *log.Logger {
	return log.New(&writer{t}, prefix, flag)
}

// WithPrefix returns a new test logger with the Lmicroseconds flag set.
func WithPrefix(t LogPrinter, prefix string) *log.Logger {
	return New(t, prefix, log.Lmicroseconds)
}

// NewLog logger with "TEST" prefix and the Lmicroseconds flag.
func Logger(t LogPrinter) *log.Logger {
	return WithPrefix(t, "")
}
<commit_msg>testlog: override testlogger with envvar<commit_after>// Package testlog creates a *log.Logger backed by *testing.T to ease logging
// in tests. This allows logs from components being tested to only be printed
// if the test fails (or the verbose flag is specified).
package testlog

import (
	"io"
	"log"
	"os"
)

// UseStdout returns true if NOMAD_TEST_STDOUT=1 and sends logs to stdout.
func UseStdout() bool {
	return os.Getenv("NOMAD_TEST_STDOUT") == "1"
}

// LogPrinter is the methods of testing.T (or testing.B) needed by the test
// logger.
type LogPrinter interface {
	Logf(format string, args ...interface{})
}

// writer implements io.Writer on top of a Logger.
type writer struct {
	t LogPrinter
}

// Write to an underlying Logger. Never returns an error.
func (w *writer) Write(p []byte) (n int, err error) {
	w.t.Logf(string(p))
	return len(p), nil
}

// NewWriter creates a new io.Writer backed by a Logger.
func NewWriter(t LogPrinter) io.Writer {
	if UseStdout() {
		return os.Stdout
	}
	return &writer{t}
}

// New returns a new test logger. See https://golang.org/pkg/log/#New
func New(t LogPrinter, prefix string, flag int) *log.Logger {
	if UseStdout() {
		return log.New(os.Stdout, prefix, flag)
	}
	return log.New(&writer{t}, prefix, flag)
}

// WithPrefix returns a new test logger with the Lmicroseconds flag set.
func WithPrefix(t LogPrinter, prefix string) *log.Logger {
	return New(t, prefix, log.Lmicroseconds)
}

// NewLog logger with "TEST" prefix and the Lmicroseconds flag.
func Logger(t LogPrinter) *log.Logger {
	return WithPrefix(t, "")
}
<|endoftext|>


<commit_before><commit_msg>Log query id on timeout<commit_after><|endoftext|>


<commit_before><commit_msg>repository: golint error fixed (comment had the wrong name as first entry).<commit_after><|endoftext|>


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

package digitalocean

import (
	"net/url"
	"strconv"
	"strings"
	"time"

	"github.com/digitalocean/godo"
	"github.com/pkg/errors"
	"github.com/tsuru/tsuru/iaas"
	"github.com/tsuru/tsuru/net"
	"golang.org/x/oauth2"
)

func init() {
	iaas.RegisterIaasProvider("digitalocean", newDigitalOceanIaas)
}

type digitalOceanIaas struct {
	base   iaas.UserDataIaaS
	client *godo.Client
}

func newDigitalOceanIaas(name string) iaas.IaaS {
	baseIaas := iaas.UserDataIaaS{NamedIaaS: iaas.NamedIaaS{BaseIaaSName: "digitalocean", IaaSName: name}}
	return &digitalOceanIaas{base: baseIaas}
}

func (i *digitalOceanIaas) Auth() error {
	u, _ := i.base.GetConfigString("url")
	token, err := i.base.GetConfigString("token")
	if err != nil {
		return err
	}
	client := *net.Dial5Full300Client
	client.Transport = &oauth2.Transport{
		Source: oauth2.StaticTokenSource(&oauth2.Token{AccessToken: token}),
		Base:   net.Dial5Full300Client.Transport,
	}
	i.client = godo.NewClient(&client)
	if u != "" {
		i.client.BaseURL, err = url.Parse(u)
		if err != nil {
			return err
		}
	}
	return nil
}

func (i *digitalOceanIaas) CreateMachine(params map[string]string) (*iaas.Machine, error) {
	i.Auth()
	image := godo.DropletCreateImage{Slug: params["image"]}
	userData, err := i.base.ReadUserData()
	if err != nil {
		return nil, err
	}
	var sshKeys []godo.DropletCreateSSHKey
	if rawSSHKeys, ok := params["ssh-keys"]; ok {
		for _, key := range strings.Split(rawSSHKeys, ",") {
			if keyID, atoiErr := strconv.Atoi(key); atoiErr == nil {
				sshKeys = append(sshKeys, godo.DropletCreateSSHKey{ID: keyID})
			} else {
				sshKeys = append(sshKeys, godo.DropletCreateSSHKey{Fingerprint: key})
			}
		}
	}
	privNetworking, _ := strconv.ParseBool(params["private-networking"])
	createRequest := &godo.DropletCreateRequest{
		Name:              params["name"],
		Region:            params["region"],
		Size:              params["size"],
		PrivateNetworking: privNetworking,
		Image:             image,
		SSHKeys:           sshKeys,
		UserData:          userData,
	}
	droplet, _, err := i.client.Droplets.Create(createRequest)
	if err != nil {
		return nil, err
	}
	droplet, err = i.waitNetworkCreated(droplet)
	if err != nil {
		return nil, err
	}
	ipAddress := droplet.Networks.V4[0].IPAddress
	if privNetworking && droplet.Networks.V4[0].Type != "private" {
		for _, network := range droplet.Networks.V4[1:] {
			if network.Type == "private" {
				ipAddress = network.IPAddress
				break
			}
		}
	}
	m := &iaas.Machine{
		Address: ipAddress,
		Id:      strconv.Itoa(droplet.ID),
		Status:  droplet.Status,
	}
	return m, nil
}

func (i *digitalOceanIaas) waitNetworkCreated(droplet *godo.Droplet) (*godo.Droplet, error) {
	rawTimeout, _ := i.base.GetConfigString("wait-timeout")
	timeout, _ := strconv.Atoi(rawTimeout)
	if timeout == 0 {
		timeout = 120
	}
	quit := make(chan struct{})
	errs := make(chan error, 1)
	droplets := make(chan *godo.Droplet, 1)
	go func() {
		for {
			select {
			case <-quit:
				return
			default:
				d, _, err := i.client.Droplets.Get(droplet.ID)
				if err != nil {
					errs <- err
					return
				}
				if len(d.Networks.V4) > 0 {
					droplets <- d
					return
				}
			}
		}
	}()
	select {
	case droplet = <-droplets:
		return droplet, nil
	case err := <-errs:
		return nil, err
	case <-time.After(time.Duration(timeout) * time.Second):
		return nil, errors.New("timed out waiting for machine network")
	}
}

func (i *digitalOceanIaas) DeleteMachine(m *iaas.Machine) error {
	i.Auth()
	machineId, _ := strconv.Atoi(m.Id)
	resp, err := i.client.Droplets.Delete(machineId)
	if err != nil {
		return err
	}
	if resp.StatusCode != 204 {
		return errors.New("failed to delete machine")
	}
	return nil
}

func (i *digitalOceanIaas) Describe() string {
	return `DigitalOcean IaaS required params:
  name=<name>                Name of the droplet
  region=<region>            Chosen region from DigitalOcean (e.g.: nyc3)
  size=<size>                Your machine size (e.g.: 512mb)
  image=<image>              The image ID of a public or private image

There are also some optional parameters:

  private-networking=1/0     Whether to use private networking in this instance.
  ssh-keys=<keys>            Comma separated list of keys. The key can be identified
                             by its ID or fingerprint.
			     (e.g.: ssh_keys=5050,2032,07:b9:a1:65:1b,13 will result in
		             the key IDs 5050, 2032 and 13, along with the fingerprint
		             07:b9:a1:65:1b)
`
}
<commit_msg>shutdown droplet before remove<commit_after>// Copyright 2016 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package digitalocean

import (
	"net/url"
	"strconv"
	"strings"
	"time"

	"github.com/digitalocean/godo"
	"github.com/pkg/errors"
	"github.com/tsuru/tsuru/iaas"
	"github.com/tsuru/tsuru/net"
	"golang.org/x/oauth2"
)

func init() {
	iaas.RegisterIaasProvider("digitalocean", newDigitalOceanIaas)
}

type digitalOceanIaas struct {
	base   iaas.UserDataIaaS
	client *godo.Client
}

func newDigitalOceanIaas(name string) iaas.IaaS {
	baseIaas := iaas.UserDataIaaS{NamedIaaS: iaas.NamedIaaS{BaseIaaSName: "digitalocean", IaaSName: name}}
	return &digitalOceanIaas{base: baseIaas}
}

func (i *digitalOceanIaas) Auth() error {
	u, _ := i.base.GetConfigString("url")
	token, err := i.base.GetConfigString("token")
	if err != nil {
		return err
	}
	client := *net.Dial5Full300Client
	client.Transport = &oauth2.Transport{
		Source: oauth2.StaticTokenSource(&oauth2.Token{AccessToken: token}),
		Base:   net.Dial5Full300Client.Transport,
	}
	i.client = godo.NewClient(&client)
	if u != "" {
		i.client.BaseURL, err = url.Parse(u)
		if err != nil {
			return err
		}
	}
	return nil
}

func (i *digitalOceanIaas) CreateMachine(params map[string]string) (*iaas.Machine, error) {
	i.Auth()
	image := godo.DropletCreateImage{Slug: params["image"]}
	userData, err := i.base.ReadUserData()
	if err != nil {
		return nil, err
	}
	var sshKeys []godo.DropletCreateSSHKey
	if rawSSHKeys, ok := params["ssh-keys"]; ok {
		for _, key := range strings.Split(rawSSHKeys, ",") {
			if keyID, atoiErr := strconv.Atoi(key); atoiErr == nil {
				sshKeys = append(sshKeys, godo.DropletCreateSSHKey{ID: keyID})
			} else {
				sshKeys = append(sshKeys, godo.DropletCreateSSHKey{Fingerprint: key})
			}
		}
	}
	privNetworking, _ := strconv.ParseBool(params["private-networking"])
	createRequest := &godo.DropletCreateRequest{
		Name:              params["name"],
		Region:            params["region"],
		Size:              params["size"],
		PrivateNetworking: privNetworking,
		Image:             image,
		SSHKeys:           sshKeys,
		UserData:          userData,
	}
	droplet, _, err := i.client.Droplets.Create(createRequest)
	if err != nil {
		return nil, err
	}
	droplet, err = i.waitNetworkCreated(droplet)
	if err != nil {
		return nil, err
	}
	ipAddress := droplet.Networks.V4[0].IPAddress
	if privNetworking && droplet.Networks.V4[0].Type != "private" {
		for _, network := range droplet.Networks.V4[1:] {
			if network.Type == "private" {
				ipAddress = network.IPAddress
				break
			}
		}
	}
	m := &iaas.Machine{
		Address: ipAddress,
		Id:      strconv.Itoa(droplet.ID),
		Status:  droplet.Status,
	}
	return m, nil
}

func (i *digitalOceanIaas) waitNetworkCreated(droplet *godo.Droplet) (*godo.Droplet, error) {
	rawTimeout, _ := i.base.GetConfigString("wait-timeout")
	timeout, _ := strconv.Atoi(rawTimeout)
	if timeout == 0 {
		timeout = 120
	}
	quit := make(chan struct{})
	errs := make(chan error, 1)
	droplets := make(chan *godo.Droplet, 1)
	go func() {
		for {
			select {
			case <-quit:
				return
			default:
				d, _, err := i.client.Droplets.Get(droplet.ID)
				if err != nil {
					errs <- err
					return
				}
				if len(d.Networks.V4) > 0 {
					droplets <- d
					return
				}
			}
		}
	}()
	select {
	case droplet = <-droplets:
		return droplet, nil
	case err := <-errs:
		return nil, err
	case <-time.After(time.Duration(timeout) * time.Second):
		return nil, errors.New("timed out waiting for machine network")
	}
}

func (i *digitalOceanIaas) DeleteMachine(m *iaas.Machine) error {
	i.Auth()
	machineId, _ := strconv.Atoi(m.Id)
	_, _, err := i.client.DropletActions.Shutdown(machineId)
	if err != nil {
		// PowerOff force the shutdown
		_, _, err = i.client.DropletActions.PowerOff(machineId)
		if err != nil {
			return err
		}
	}
	resp, err := i.client.Droplets.Delete(machineId)
	if err != nil {
		return err
	}
	if resp.StatusCode != 204 {
		return errors.New("failed to delete machine")
	}
	return nil
}

func (i *digitalOceanIaas) Describe() string {
	return `DigitalOcean IaaS required params:
  name=<name>                Name of the droplet
  region=<region>            Chosen region from DigitalOcean (e.g.: nyc3)
  size=<size>                Your machine size (e.g.: 512mb)
  image=<image>              The image ID of a public or private image

There are also some optional parameters:

  private-networking=1/0     Whether to use private networking in this instance.
  ssh-keys=<keys>            Comma separated list of keys. The key can be identified
                             by its ID or fingerprint.
			     (e.g.: ssh_keys=5050,2032,07:b9:a1:65:1b,13 will result in
		             the key IDs 5050, 2032 and 13, along with the fingerprint
		             07:b9:a1:65:1b)
`
}
<|endoftext|>


<commit_before>/*
   Copyright 2014 Maciej Chałapuk

   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.
*/

// vim: sw=2 ts=2 expandtab

package precond

import "fmt"

func CheckTrue(predicate bool,  message string, args ...interface{}) error {
  if !predicate {
    return fmt.Errorf(message, args)
  }
  return nil
}

func CheckFalse(antiPredicate bool, message string, args ...interface{}) error {
  return CheckTrue(!antiPredicate, message, args);
}

func CheckNotNil(value interface{}, message string, args ...interface{}) error {
  return CheckTrue(value != nil, message, args)
}

func CheckInRangeEpsilon(value float64, lower float64, upper float64,
        epsilon float64, message string, args ...interface{}) error {
  predicate := value - lower + epsilon > 0 && upper - value + epsilon > 0
  return CheckTrue(predicate, message, args)
}

func CheckInRange(value float64, lower float64, upper float64,
                  message string, args ...interface{}) error {
  return CheckInRangeEpsilon(value, lower, upper, .00001, message, args)
}

<commit_msg>+ documentation for all checks<commit_after>/*
   Copyright 2014 Maciej Chałapuk

   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.
*/

// vim: sw=2 ts=2 expandtab

package precond

import "fmt"

/*
  Returns nil if given predicate is true, otherwise returns error
*/
func CheckTrue(predicate bool, message string, args ...interface{}) error {
  if !predicate {
    return fmt.Errorf(message, args)
  }
  return nil
}

/*
  Returns nil if given predicate is false, otherwise returns error
*/
func CheckFalse(antiPredicate bool, message string, args ...interface{}) error {
  return CheckTrue(!antiPredicate, message, args);
}

/*
  Returns nil if given value is not nil, otherwise returns error
*/
func CheckNotNil(value interface{}, message string, args ...interface{}) error {
  return CheckTrue(value != nil, message, args)
}

/*
  Returns nil if given value is contained in given range <lower, upper>,
  otherwise returns error. Uses given epsilon for float comparison.
*/
func CheckInRangeEpsilon(value float64, lower float64, upper float64,
        epsilon float64, message string, args ...interface{}) error {
  predicate := value - lower + epsilon > 0 && upper - value + epsilon > 0
  return CheckTrue(predicate, message, args)
}

/*
  Returns nil if given value is contained in given range <lower, upper>,
  otherwise returns error. Uses epsilon value of 0.00001.
*/
func CheckInRange(value float64, lower float64, upper float64,
                  message string, args ...interface{}) error {
  return CheckInRangeEpsilon(value, lower, upper, .00001, message, args)
}

<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"path/filepath"

	log "github.com/Sirupsen/logrus"
)

type cargo struct {
	params *params
	logger *log.Entry
}

func newCargo(params *params) *cargo {
	log := log.WithFields(log.Fields{
		"params": params.params,
	})
	return &cargo{
		params: params,
		logger: log,
	}
}

func (c cargo) store(queue chan *params) error {
	storage := newStorage(c.params)

	// exist?
	if storage.isExist() {
		return aleadyExistsError{}
	}

	// store in build queue
	queue <- c.params
	c.logger.Info("stored")

	return nil
}

func (c cargo) build() error {

	var err error
	workspace, err := ioutil.TempDir("workspace", "")
	if err != nil {
		return err
	}
	c.logger.Infof("build start on %s", workspace)

	storage := newStorage(c.params)

	// exist?
	if storage.isExist() {
		c.logger.Warn("already exists")
		return aleadyExistsError{}
	}

	// clone
	repo := newRepository(c.params, workspace)
	err = repo.clone("https")
	if err != nil {
		c.logger.Warnf("git clone error: %v", err)
		return buildError{err}
	}

	// build
	builder := newBuilder(c.params)
	err = builder.build(workspace)
	if err != nil {
		c.logger.Warnf("build error: %v", err)
		return buildError{err}
	}

	// diff archive
	err = repo.diffArchive("app", "tar.gz")
	if err != nil {
		c.logger.Warnf("diff archive error: %v", err)
		return buildError{err}
	}

	// save
	err = storage.save(filepath.Join(workspace, c.params.repo, "app.tar.gz"))
	if err != nil {
		c.logger.Warnf("save error: %v", err)
		return buildError{err}
	}
	return nil
}

func (c cargo) isExist() bool {
	return newStorage(c.params).isExist()
}

func (c cargo) get() (string, error) {
	return newStorage(c.params).get("app.tar.gz")
}

func (c cargo) downloadFileName() string {
	return fmt.Sprintf(
		"%s_%s_%s.tar.gz",
		c.params.repo,
		c.params.goos,
		c.params.goarch,
	)
}
<commit_msg>Added success log.<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"path/filepath"

	log "github.com/Sirupsen/logrus"
)

type cargo struct {
	params *params
	logger *log.Entry
}

func newCargo(params *params) *cargo {
	log := log.WithFields(log.Fields{
		"params": params.params,
	})
	return &cargo{
		params: params,
		logger: log,
	}
}

func (c cargo) store(queue chan *params) error {
	storage := newStorage(c.params)

	// exist?
	if storage.isExist() {
		return aleadyExistsError{}
	}

	// store in build queue
	queue <- c.params
	c.logger.Info("stored")

	return nil
}

func (c cargo) build() error {

	var err error
	workspace, err := ioutil.TempDir("workspace", "")
	if err != nil {
		return err
	}
	c.logger.Infof("build start on %s", workspace)

	storage := newStorage(c.params)

	// exist?
	if storage.isExist() {
		c.logger.Warn("already exists")
		return aleadyExistsError{}
	}

	// clone
	repo := newRepository(c.params, workspace)
	err = repo.clone("https")
	if err != nil {
		c.logger.Warnf("git clone error: %v", err)
		return buildError{err}
	}

	// build
	builder := newBuilder(c.params)
	err = builder.build(workspace)
	if err != nil {
		c.logger.Warnf("build error: %v", err)
		return buildError{err}
	}

	// diff archive
	err = repo.diffArchive("app", "tar.gz")
	if err != nil {
		c.logger.Warnf("diff archive error: %v", err)
		return buildError{err}
	}

	// save
	err = storage.save(filepath.Join(workspace, c.params.repo, "app.tar.gz"))
	if err != nil {
		c.logger.Warnf("save error: %v", err)
		return buildError{err}
	}
	c.logger.Info("build success")
	return nil
}

func (c cargo) isExist() bool {
	return newStorage(c.params).isExist()
}

func (c cargo) get() (string, error) {
	return newStorage(c.params).get("app.tar.gz")
}

func (c cargo) downloadFileName() string {
	return fmt.Sprintf(
		"%s_%s_%s.tar.gz",
		c.params.repo,
		c.params.goos,
		c.params.goarch,
	)
}
<|endoftext|>


<commit_before>// Copyright 2013 Prometheus Team
// 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 web

import (
	"net/http"

	"github.com/prometheus/alertmanager/manager"
)

type AlertStatus struct {
	AlertAggregates manager.AlertAggregates
	SilenceForAlert func(*manager.Alert) *manager.Silence
}

type AlertsHandler struct {
	Manager                manager.AlertManager
	IsSilencedInterrogator manager.IsSilencedInterrogator
	PathPrefix             string
}

func (h *AlertsHandler) silenceForAlert(a *manager.Alert) *manager.Silence {
	_, silence := h.IsSilencedInterrogator.IsSilenced(a.Labels)
	return silence
}

func (h *AlertsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	alertStatus := &AlertStatus{
		AlertAggregates: h.Manager.GetAll(nil),
		SilenceForAlert: h.silenceForAlert,
	}
	executeTemplate(w, "alerts", alertStatus, h.PathPrefix)
}
<commit_msg>Sort alerts consistently in web UI.<commit_after>// Copyright 2013 Prometheus Team
// 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 web

import (
	"net/http"
	"sort"

	"github.com/prometheus/alertmanager/manager"
)

type AlertStatus struct {
	AlertAggregates manager.AlertAggregates
	SilenceForAlert func(*manager.Alert) *manager.Silence
}

type AlertsHandler struct {
	Manager                manager.AlertManager
	IsSilencedInterrogator manager.IsSilencedInterrogator
	PathPrefix             string
}

func (h *AlertsHandler) silenceForAlert(a *manager.Alert) *manager.Silence {
	_, silence := h.IsSilencedInterrogator.IsSilenced(a.Labels)
	return silence
}

type aggregatesByLabelset struct {
	manager.AlertAggregates
}

func (aggs aggregatesByLabelset) Less(i, j int) bool {
	iAlert := aggs.AlertAggregates[i].Alert
	jAlert := aggs.AlertAggregates[j].Alert
	if iAlert.Name() == jAlert.Name() {
		return iAlert.Fingerprint() < jAlert.Fingerprint()
	}
	return iAlert.Name() < jAlert.Name()
}

func (h *AlertsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	aggs := h.Manager.GetAll(nil)
	sort.Sort(aggregatesByLabelset{aggs})

	alertStatus := &AlertStatus{
		AlertAggregates: aggs,
		SilenceForAlert: h.silenceForAlert,
	}
	executeTemplate(w, "alerts", alertStatus, h.PathPrefix)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"os/exec"
	"strings"
	"time"

	"github.com/streadway/amqp"
)

type RadiodanCommand struct {
	Action        string
	CorrelationId string
}

var dryRun bool
var conn *amqp.Connection

func main() {
	host, port := parseArgs()
	listenForCommand(host, port)
}

func parseArgs() (host string, port int) {
	flag.StringVar(&host, "host", "localhost", "Hostname for RabbitMQ")
	flag.IntVar(&port, "port", 5672, "Port for RabbitMQ")
	flag.BoolVar(&dryRun, "dry-run", false, "Dry Run (do not execute command)")

	flag.Parse()

	return
}

func listenForCommand(host string, port int) {
	amqpUri := fmt.Sprintf("amqp://%s:%d", host, port)
	exchangeName := "radiodan"
	routingKey := "command.device.shutdown"
	connected := false

	for connected != true {
		tryConn, err := amqp.Dial(amqpUri)
		if err != nil {
			log.Printf("[!] Cannot connect", err)
			log.Printf("[*] Retry in 3 seconds")
			time.Sleep(3 * time.Second)
		} else {
			log.Printf("[*] Connected to %s", amqpUri)

			connected = true
			conn = tryConn
			defer conn.Close()
		}
	}

	ch, err := conn.Channel()
	failOnError(err, "Failed to open a channel")
	defer ch.Close()

	err = ch.ExchangeDeclare(
		exchangeName, // name
		"topic",      // type
		true,         // durable
		false,        // auto-deleted
		false,        // internal
		false,        // no-wait
		nil,          // arguments
	)
	failOnError(err, "Failed to declare an exchange")

	q, err := ch.QueueDeclare(
		"",    // name
		false, // durable
		false, // delete when usused
		true,  // exclusive
		false, // no-wait
		nil,   // arguments
	)
	failOnError(err, "Failed to declare a queue")

	err = ch.QueueBind(
		q.Name,     // queue name
		routingKey, // routing key
		"radiodan", // exchange
		false,
		nil)
	failOnError(err, "Failed to bind a queue")

	msgs, err := ch.Consume(
		q.Name, // queue
		"",     // consumer
		true,   // auto ack
		false,  // exclusive
		false,  // no local
		false,  // no wait
		nil,    // args
	)
	failOnError(err, "Failed to register a consumer")

	log.Println("[*] Consuming", q.Name)

	forever := make(chan bool)

	go func() {
		for m := range msgs {
			cmd, err := processMessage(m)

			if err == nil {
				replyToMessage(m, cmd)
				execCmd(cmd)
			}
		}
	}()

	log.Printf("[*] Waiting for commands")
	<-forever
}

func processMessage(msg amqp.Delivery) (RadiodanCommand, error) {
	defer func() {
		if r := recover(); r != nil {
			log.Println("[!] Msg processing failed:", r)
		}
	}()

	cmd := RadiodanCommand{}

	err := json.Unmarshal(msg.Body, &cmd)
	failOnError(err, "Malformed Radiodan Command")

	log.Printf("[x] Received action: %s", cmd.Action)

	return cmd, err
}

func replyToMessage(msg amqp.Delivery, cmd RadiodanCommand) {
	var err error

	response := "{\"error\": false, \"correlationId\": \"" + cmd.CorrelationId + "\"}"

	replyChannel, err := conn.Channel()
	failOnError(err, "[!] Could not create reply channel")

	reply := amqp.Publishing{
		DeliveryMode: amqp.Persistent,
		Timestamp:    time.Now(),
		ContentType:  "text/plain",
		Body:         []byte(response),
	}

	err = replyChannel.Publish(
		"",          // exchange
		msg.ReplyTo, // key
		false,       // mandatory
		false,       // thing
		reply,       // immediate
	)

	failOnError(err, "[!] Could not reply to command")
	log.Println("[*] Replying to message", response)
}

func execCmd(cmd RadiodanCommand) {
	var shutdownFlag, path string
	var args []string

	switch cmd.Action {
	case "restart":
		shutdownFlag = "-r"
	case "shutdown":
		shutdownFlag = "-h"
	default:
		panic("Action " + cmd.Action + " is neither restart nor shutdown")
	}

	if dryRun {
		path = "/bin/echo"
		args = []string{"shutdown", path, shutdownFlag, "now"}
	} else {
		path = "/sbin/shutdown"
		args = []string{path, shutdownFlag, "now"}
	}

	shutdown := exec.Cmd{
		Path: path,
		Args: args,
	}

	output, err := shutdown.CombinedOutput()
	outputStr := strings.TrimRight(string(output), "\n")

	failOnError(err, "Could not exec shutdown")
	log.Println("[x] exec:", outputStr)
}

func failOnError(err error, msg string) {
	if err != nil {
		log.Fatalf("%s: %s", msg, err)
		panic(fmt.Sprintf("%s: %s", msg, err))
	}
}
<commit_msg>Pass replyChannel in to reply function<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"os/exec"
	"strings"
	"time"

	"github.com/streadway/amqp"
)

type RadiodanCommand struct {
	Action        string
	CorrelationId string
}

var dryRun bool

func main() {
	host, port := parseArgs()
	listenForCommand(host, port)
}

func parseArgs() (host string, port int) {
	flag.StringVar(&host, "host", "localhost", "Hostname for RabbitMQ")
	flag.IntVar(&port, "port", 5672, "Port for RabbitMQ")
	flag.BoolVar(&dryRun, "dry-run", false, "Dry Run (do not execute command)")

	flag.Parse()

	return
}

func listenForCommand(host string, port int) {
	var conn *amqp.Connection

	amqpUri := fmt.Sprintf("amqp://%s:%d", host, port)
	exchangeName := "radiodan"
	routingKey := "command.device.shutdown"
	connected := false

	for connected != true {
		tryConn, err := amqp.Dial(amqpUri)
		if err != nil {
			log.Printf("[!] Cannot connect", err)
			log.Printf("[*] Retry in 3 seconds")
			time.Sleep(3 * time.Second)
		} else {
			log.Printf("[*] Connected to %s", amqpUri)

			connected = true
			conn = tryConn
			defer conn.Close()
		}
	}

	consumeChannel, err := conn.Channel()
	failOnError(err, "[!] Failed to open a channel")
	defer consumeChannel.Close()

	replyChannel, err := conn.Channel()
	failOnError(err, "[!] Could not create reply channel")
	defer replyChannel.Close()

	err = consumeChannel.ExchangeDeclare(
		exchangeName, // name
		"topic",      // type
		true,         // durable
		false,        // auto-deleted
		false,        // internal
		false,        // no-wait
		nil,          // arguments
	)
	failOnError(err, "[!] Failed to declare an exchange")

	queue, err := consumeChannel.QueueDeclare(
		"",    // name
		false, // durable
		false, // delete when usused
		true,  // exclusive
		false, // no-wait
		nil,   // arguments
	)
	failOnError(err, "[!] Failed to declare a queue")

	err = consumeChannel.QueueBind(
		queue.Name, // queue name
		routingKey, // routing key
		"radiodan", // exchange
		false,
		nil,
	)
	failOnError(err, "[!] Failed to bind a queue")

	msgs, err := consumeChannel.Consume(
		queue.Name, // queue
		"",         // consumer
		true,       // auto ack
		false,      // exclusive
		false,      // no local
		false,      // no wait
		nil,        // args
	)
	failOnError(err, "[!] Failed to register a consumer")

	log.Println("[*] Consuming", queue.Name)

	forever := make(chan bool)

	go func() {
		for m := range msgs {
			cmd, err := processMessage(m)

			if err == nil {
				replyToMessage(replyChannel, m, cmd, false)
				execCmd(cmd)
			} else {
				replyToMessage(replyChannel, m, cmd, true)
			}
		}
	}()

	log.Printf("[*] Waiting for commands")
	<-forever
}

func processMessage(msg amqp.Delivery) (RadiodanCommand, error) {
	defer func() {
		if r := recover(); r != nil {
			log.Println("[!] Msg processing failed:", r)
		}
	}()

	cmd := RadiodanCommand{}

	err := json.Unmarshal(msg.Body, &cmd)
	failOnError(err, "[!] Malformed Radiodan Command")

	log.Printf("[x] Received action: %s", cmd.Action)

	return cmd, err
}

func replyToMessage(replyChannel *amqp.Channel, msg amqp.Delivery,
	cmd RadiodanCommand, parseError bool) {
	response := fmt.Sprintf(
		"{\"error\": %t, \"correlationId\": \"%s\"}",
		parseError, cmd.CorrelationId)

	reply := amqp.Publishing{
		DeliveryMode: amqp.Persistent,
		Timestamp:    time.Now(),
		ContentType:  "text/plain",
		Body:         []byte(response),
	}

	err := replyChannel.Publish(
		"",          // exchange
		msg.ReplyTo, // key
		false,       // mandatory
		false,       // thing
		reply,       // immediate
	)

	failOnError(err, "[!] Could not reply to message")
	log.Println("[*] Replying to message", response)
}

func execCmd(cmd RadiodanCommand) {
	var shutdownFlag, path string
	var args []string

	switch cmd.Action {
	case "restart":
		shutdownFlag = "-r"
	case "shutdown":
		shutdownFlag = "-h"
	default:
		panic("Action " + cmd.Action + " is neither restart nor shutdown")
	}

	if dryRun {
		path = "/bin/echo"
		args = []string{path, "shutdown", shutdownFlag, "now"}
	} else {
		path = "/sbin/shutdown"
		args = []string{path, shutdownFlag, "now"}
	}

	shutdown := exec.Cmd{
		Path: path,
		Args: args,
	}

	output, err := shutdown.CombinedOutput()
	outputStr := strings.TrimRight(string(output), "\n")

	failOnError(err, "Could not exec shutdown")
	log.Println("[x] exec:", outputStr)
}

func failOnError(err error, msg string) {
	if err != nil {
		log.Fatalf("%s: %s", msg, err)
		panic(fmt.Sprintf("%s: %s", msg, err))
	}
}
<|endoftext|>


<commit_before>package controllerLXD

import (
	"flag"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"time"

	"github.com/harrowio/harrow/activities"
	"github.com/harrowio/harrow/bus/activity"
	"github.com/harrowio/harrow/bus/broadcast"
	"github.com/harrowio/harrow/cast"
	"github.com/jmoiron/sqlx"
	"github.com/rs/zerolog"
	"golang.org/x/crypto/ssh"

	"github.com/harrowio/harrow/config"
	"github.com/harrowio/harrow/stores"
)

const ProgramName = "controller-lxd"

var log zerolog.Logger = zerolog.New(os.Stdout).With().Str("harrow", ProgramName).Timestamp().Logger()

func Main() {

	var conf *config.Config = config.GetConfig()
	operationUuid := flag.String("operation-uuid", "", "The operation to run")
	containerId := flag.String("container-id", "", "The id of the container to run the operation in")
	connectTo := flag.String("connect", "", "The URL to connect with")
	entrypoint := flag.String("entrypoint", "", "The command to run")

	flag.Parse()

	go func() {
		listener, err := net.Listen("tcp", ":0")
		if err != nil {
			panic(err)
		}
		log.Info().Msgf("debug http server on port %d", listener.Addr().(*net.TCPAddr).Port)
		http.Serve(listener, nil)
	}()

	connectionInfo, err := url.Parse(*connectTo)
	if err != nil {
		panic(err)
	}

	host := connectionInfo.Host
	user := connectionInfo.User.Username()
	if user == "" {
		user = "root"
	}

	db, err := conf.DB()
	if err != nil {
		log.Fatal().Msgf("unable to open db: %s", err)
	}
	defer db.Close()

	consumerId := fmt.Sprintf("controller-pid-%d", os.Getpid())
	activityBus := activity.NewAMQPTransport(conf.AmqpConnectionString(), consumerId)
	activitySink := NewBusActivitySink(activityBus)
	activitySink.log = log

	defer activityBus.Close()
	if *operationUuid == "" || host == "" || *entrypoint == "" {
		fmt.Fprint(os.Stderr, "Usage:\n")
		flag.PrintDefaults()
		os.Exit(2)
	}
	log.Info().Msgf("operationuuid=%q host=%q entrypoint=%q\n", *operationUuid, host, *entrypoint)
	deadline := time.After(config.InstanceDeadline)
	go func() {
		<-deadline
		deadlineReached(db, conf, *connectTo, *operationUuid)
	}()

	tx := mustBeginTx(db)
	defer tx.Rollback()

	store := stores.NewDbOperationStore(tx)
	log.Debug().Msg("looking up operation...")
	operation, err := store.FindByUuid(*operationUuid)
	if err != nil {
		log.Fatal().Msgf("operation not found: %s", err)
	}
	log.Debug().Msg("looking up operation... (done)")

	log.Debug().Msg("checking if operation cancelled...")
	if operation.Status() == "canceled" {
		log.Info().Msgf("yes, operation canceled at %s. exiting.", operation.CanceledAt)
		os.Exit(0)
	} else {
		log.Debug().Msg("not cancelled, continuing")
	}

	operation.StartedAt = func() *time.Time { now := time.Now(); return &now }()
	mustCommitTx(tx)

	log.Debug().Msg("broadcasting op started")
	activitySink.EmitActivity(activities.OperationStarted(operation))
	log.Debug().Msg("broadcasting op started (done)")

	log.Debug().Msg("getting ssh config")
	addr := fmt.Sprintf("%s", host)
	sshConf, err := conf.GetSshConfig()
	if err != nil {
		log.Fatal().Msgf("unable to get ssh config: %s", err)
	}
	sshConf.User = user
	log.Debug().Msgf("done, dialing ssh %s %v", addr, sshConf)
	client, err := ssh.Dial("tcp", addr, sshConf)
	if err != nil {
		log.Fatal().Msgf("unable to open ssh connection: %s", err)
	}
	defer client.Close()

	log.Debug().Msg("starting upload user script")
	usu := userScriptUploader{log: log}
	if err := usu.uploadUserScript(client, *containerId); err != nil {
		fatalError := fmt.Errorf("unable to upload user script: %s", err)
		mustMarkFatal(db, *operationUuid, fatalError.Error())
		log.Fatal().Msgf("%s", fatalError)
	}
	log.Debug().Msg("user script uploaded")

	go watchForCancellations(conf, db, activitySink, *operationUuid)

	log.Debug().Msg("running user script")
	err = runUserScript(log, client, activitySink, db, *operationUuid, *entrypoint, conf)
	log.Debug().Msg("done, checking response type")
	switch e := err.(type) {
	case FatalError:
		mustMarkFatal(db, *operationUuid, e.Error())
		log.Fatal().Msgf("Fatal error: %s", e)
	case *ssh.ExitError:
		if n := e.ExitStatus(); n != 0 {
			log.Debug().Msgf("exit status: %d", n)
		}
	}
	log.Debug().Msgf("exiting cleanly")
}

func markFatal(db *sqlx.DB, operationUuid string, fatal string) error {
	tx := mustBeginTx(db)
	defer tx.Rollback()
	store := stores.NewDbOperationStore(tx)
	err := store.MarkAsFailed(operationUuid)
	if err != nil {
		return fmt.Errorf("MarkAsFailed: %s", err)
	}
	if err := store.MarkFatalError(operationUuid, fatal); err != nil {
		return fmt.Errorf("MarkFatalError: %s", err)
	}
	mustCommitTx(tx)

	return nil
}

func mustMarkFatal(db *sqlx.DB, operationUuid string, fatal string) {
	if err := markFatal(db, operationUuid, fatal); err != nil {
		log.Fatal().Msgf("markFatal: %s", err)
	}
}

func mustBeginTx(db *sqlx.DB) *sqlx.Tx {
	tx, err := db.Beginx()
	if err != nil {
		log.Fatal().Msgf("Unable to begin tx: %s", err)
	}
	return tx
}

func mustCommitTx(tx *sqlx.Tx) {
	log.Debug().Msg("entering mustCommitTx")
	if err := tx.Commit(); err != nil {
		log.Fatal().Msgf("Unable to commit tx: %s", err)
	}
	log.Debug().Msg("leaving mustCommitTx")
}

func deadlineReached(db *sqlx.DB, c *config.Config, connect string, operationUuid string) {
	log.Error().Msgf("operation(%s) timed out, aborting", operationUuid)
	tx := mustBeginTx(db)
	store := stores.NewDbOperationStore(tx)
	store.MarkAsTimedOut(operationUuid)
	mustCommitTx(tx)

	activityBus := activity.NewAMQPTransport(c.AmqpConnectionString(), "harrow/fsbuilder")
	defer activityBus.Close()
	activityBus.Publish(activities.OperationTimedOut(operationUuid))

	// deleteContainer(connect, operationUuid)

	// sysexits.h: #define EX_TEMPFAIL	75	/* temp failure; user is invited to retry */
	os.Exit(75)
}

func watchForCancellations(c *config.Config, db *sqlx.DB, activitySink ActivitySink, operationUuid string) {
	consumerId := fmt.Sprintf("controller-%s", operationUuid)
	broadcastBus := broadcast.NewAutoDeletingAMQPTransport(c.AmqpConnectionString(), consumerId)
	broadcastBus.OnlyTable("activities")
	creations, err := broadcastBus.Consume(broadcast.Create)
	if err != nil {
		mustMarkFatal(db, operationUuid, "Listening to activity creations: "+err.Error())
		return
	}

	go func() {
		defer broadcastBus.Close()

		for message := range creations {
			if message.Table() != "activities" {
				message.Acknowledge()
				continue
			}
			id, _ := strconv.Atoi(message.UUID())
			log.Debug().Msgf("received message id=%d table=%s", id, message.Table())
			tx := mustBeginTx(db)
			activityStore := stores.NewDbActivityStore(tx)
			activity, err := activityStore.FindActivityById(id)
			if err != nil {
				log.Warn().Msg("activity not found")
				if err := message.RejectForever(); err != nil {
					log.Warn().Msgf("message.RejectForever(): %s", err)
				}
				tx.Rollback()
				continue
			}

			if err := message.Acknowledge(); err != nil {
				log.Warn().Msgf("message.Acknowledge(): %s", err)
			}

			if activity.Name != "operation.canceled-by-user" {
				tx.Rollback()
				continue
			}

			log.Debug().Msgf("processing %s@%d", activity.Name, activity.Id)

			payload, ok := activity.Payload.(*activities.OperationCanceledByUserPayload)
			if !ok {
				log.Fatal().Msgf("invalid payload for activity: expected %t, got %t", payload, activity.Payload)
			}

			if payload.Uuid != operationUuid {
				tx.Rollback()
				continue
			}

			operationStore := stores.NewDbOperationStore(tx)
			if err := operationStore.MarkAsCanceled(operationUuid); err != nil {
				log.Error().Msgf("failed to mark operation as canceled: %s", err)
			}
			tx.Commit()

			statusLogEntry := cast.NewStatusLogEntry("user.canceled", "Operation canceled by user")
			handleEvent(db, statusLogEntry, activitySink, operationUuid)

			broadcastBus.Close()
			os.Exit(0)
		}
	}()
}
<commit_msg>Ensure no unsafe pointer dereference<commit_after>package controllerLXD

import (
	"flag"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"time"

	"github.com/harrowio/harrow/activities"
	"github.com/harrowio/harrow/bus/activity"
	"github.com/harrowio/harrow/bus/broadcast"
	"github.com/harrowio/harrow/cast"
	"github.com/jmoiron/sqlx"
	"github.com/rs/zerolog"
	"golang.org/x/crypto/ssh"

	"github.com/harrowio/harrow/config"
	"github.com/harrowio/harrow/stores"
)

const ProgramName = "controller-lxd"

var log zerolog.Logger = zerolog.New(os.Stdout).With().Str("harrow", ProgramName).Timestamp().Logger()

func Main() {

	var conf *config.Config = config.GetConfig()
	operationUuid := flag.String("operation-uuid", "", "The operation to run")
	containerId := flag.String("container-id", "", "The id of the container to run the operation in")
	connectTo := flag.String("connect", "", "The URL to connect with")
	entrypoint := flag.String("entrypoint", "", "The command to run")

	flag.Parse()

	go func() {
		listener, err := net.Listen("tcp", ":0")
		if err != nil {
			panic(err)
		}
		log.Info().Msgf("debug http server on port %d", listener.Addr().(*net.TCPAddr).Port)
		http.Serve(listener, nil)
	}()

	connectionInfo, err := url.Parse(*connectTo)
	if err != nil {
		panic(err)
	}

	host := connectionInfo.Host
	if connectionInfo.User != nil {
		user := connectionInfo.User.Username()
		if user == "" {
			user = "root"
		}
	} else {
		user = "root"
	}

	db, err := conf.DB()
	if err != nil {
		log.Fatal().Msgf("unable to open db: %s", err)
	}
	defer db.Close()

	consumerId := fmt.Sprintf("controller-pid-%d", os.Getpid())
	activityBus := activity.NewAMQPTransport(conf.AmqpConnectionString(), consumerId)
	activitySink := NewBusActivitySink(activityBus)
	activitySink.log = log

	defer activityBus.Close()
	if *operationUuid == "" || host == "" || *entrypoint == "" {
		fmt.Fprint(os.Stderr, "Usage:\n")
		flag.PrintDefaults()
		os.Exit(2)
	}
	log.Info().Msgf("operationuuid=%q host=%q entrypoint=%q\n", *operationUuid, host, *entrypoint)
	deadline := time.After(config.InstanceDeadline)
	go func() {
		<-deadline
		deadlineReached(db, conf, *connectTo, *operationUuid)
	}()

	tx := mustBeginTx(db)
	defer tx.Rollback()

	store := stores.NewDbOperationStore(tx)
	log.Debug().Msg("looking up operation...")
	operation, err := store.FindByUuid(*operationUuid)
	if err != nil {
		log.Fatal().Msgf("operation not found: %s", err)
	}
	log.Debug().Msg("looking up operation... (done)")

	log.Debug().Msg("checking if operation cancelled...")
	if operation.Status() == "canceled" {
		log.Info().Msgf("yes, operation canceled at %s. exiting.", operation.CanceledAt)
		os.Exit(0)
	} else {
		log.Debug().Msg("not cancelled, continuing")
	}

	operation.StartedAt = func() *time.Time { now := time.Now(); return &now }()
	mustCommitTx(tx)

	log.Debug().Msg("broadcasting op started")
	activitySink.EmitActivity(activities.OperationStarted(operation))
	log.Debug().Msg("broadcasting op started (done)")

	log.Debug().Msg("getting ssh config")
	addr := fmt.Sprintf("%s", host)
	sshConf, err := conf.GetSshConfig()
	if err != nil {
		log.Fatal().Msgf("unable to get ssh config: %s", err)
	}
	sshConf.User = user
	log.Debug().Msgf("done, dialing ssh %s %v", addr, sshConf)
	client, err := ssh.Dial("tcp", addr, sshConf)
	if err != nil {
		log.Fatal().Msgf("unable to open ssh connection: %s", err)
	}
	defer client.Close()

	log.Debug().Msg("starting upload user script")
	usu := userScriptUploader{log: log}
	if err := usu.uploadUserScript(client, *containerId); err != nil {
		fatalError := fmt.Errorf("unable to upload user script: %s", err)
		mustMarkFatal(db, *operationUuid, fatalError.Error())
		log.Fatal().Msgf("%s", fatalError)
	}
	log.Debug().Msg("user script uploaded")

	go watchForCancellations(conf, db, activitySink, *operationUuid)

	log.Debug().Msg("running user script")
	err = runUserScript(log, client, activitySink, db, *operationUuid, *entrypoint, conf)
	log.Debug().Msg("done, checking response type")
	switch e := err.(type) {
	case FatalError:
		mustMarkFatal(db, *operationUuid, e.Error())
		log.Fatal().Msgf("Fatal error: %s", e)
	case *ssh.ExitError:
		if n := e.ExitStatus(); n != 0 {
			log.Debug().Msgf("exit status: %d", n)
		}
	}
	log.Debug().Msgf("exiting cleanly")
}

func markFatal(db *sqlx.DB, operationUuid string, fatal string) error {
	tx := mustBeginTx(db)
	defer tx.Rollback()
	store := stores.NewDbOperationStore(tx)
	err := store.MarkAsFailed(operationUuid)
	if err != nil {
		return fmt.Errorf("MarkAsFailed: %s", err)
	}
	if err := store.MarkFatalError(operationUuid, fatal); err != nil {
		return fmt.Errorf("MarkFatalError: %s", err)
	}
	mustCommitTx(tx)

	return nil
}

func mustMarkFatal(db *sqlx.DB, operationUuid string, fatal string) {
	if err := markFatal(db, operationUuid, fatal); err != nil {
		log.Fatal().Msgf("markFatal: %s", err)
	}
}

func mustBeginTx(db *sqlx.DB) *sqlx.Tx {
	tx, err := db.Beginx()
	if err != nil {
		log.Fatal().Msgf("Unable to begin tx: %s", err)
	}
	return tx
}

func mustCommitTx(tx *sqlx.Tx) {
	log.Debug().Msg("entering mustCommitTx")
	if err := tx.Commit(); err != nil {
		log.Fatal().Msgf("Unable to commit tx: %s", err)
	}
	log.Debug().Msg("leaving mustCommitTx")
}

func deadlineReached(db *sqlx.DB, c *config.Config, connect string, operationUuid string) {
	log.Error().Msgf("operation(%s) timed out, aborting", operationUuid)
	tx := mustBeginTx(db)
	store := stores.NewDbOperationStore(tx)
	store.MarkAsTimedOut(operationUuid)
	mustCommitTx(tx)

	activityBus := activity.NewAMQPTransport(c.AmqpConnectionString(), "harrow/fsbuilder")
	defer activityBus.Close()
	activityBus.Publish(activities.OperationTimedOut(operationUuid))

	// deleteContainer(connect, operationUuid)

	// sysexits.h: #define EX_TEMPFAIL	75	/* temp failure; user is invited to retry */
	os.Exit(75)
}

func watchForCancellations(c *config.Config, db *sqlx.DB, activitySink ActivitySink, operationUuid string) {
	consumerId := fmt.Sprintf("controller-%s", operationUuid)
	broadcastBus := broadcast.NewAutoDeletingAMQPTransport(c.AmqpConnectionString(), consumerId)
	broadcastBus.OnlyTable("activities")
	creations, err := broadcastBus.Consume(broadcast.Create)
	if err != nil {
		mustMarkFatal(db, operationUuid, "Listening to activity creations: "+err.Error())
		return
	}

	go func() {
		defer broadcastBus.Close()

		for message := range creations {
			if message.Table() != "activities" {
				message.Acknowledge()
				continue
			}
			id, _ := strconv.Atoi(message.UUID())
			log.Debug().Msgf("received message id=%d table=%s", id, message.Table())
			tx := mustBeginTx(db)
			activityStore := stores.NewDbActivityStore(tx)
			activity, err := activityStore.FindActivityById(id)
			if err != nil {
				log.Warn().Msg("activity not found")
				if err := message.RejectForever(); err != nil {
					log.Warn().Msgf("message.RejectForever(): %s", err)
				}
				tx.Rollback()
				continue
			}

			if err := message.Acknowledge(); err != nil {
				log.Warn().Msgf("message.Acknowledge(): %s", err)
			}

			if activity.Name != "operation.canceled-by-user" {
				tx.Rollback()
				continue
			}

			log.Debug().Msgf("processing %s@%d", activity.Name, activity.Id)

			payload, ok := activity.Payload.(*activities.OperationCanceledByUserPayload)
			if !ok {
				log.Fatal().Msgf("invalid payload for activity: expected %t, got %t", payload, activity.Payload)
			}

			if payload.Uuid != operationUuid {
				tx.Rollback()
				continue
			}

			operationStore := stores.NewDbOperationStore(tx)
			if err := operationStore.MarkAsCanceled(operationUuid); err != nil {
				log.Error().Msgf("failed to mark operation as canceled: %s", err)
			}
			tx.Commit()

			statusLogEntry := cast.NewStatusLogEntry("user.canceled", "Operation canceled by user")
			handleEvent(db, statusLogEntry, activitySink, operationUuid)

			broadcastBus.Close()
			os.Exit(0)
		}
	}()
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Pagoda Box Inc
//
// This Source Code Form is subject to the terms of the Mozilla Public License, v.
// 2.0. If a copy of the MPL was not distributed with this file, You can obtain one
// at http://mozilla.org/MPL/2.0/.
//

package commands

//
import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"

	"github.com/spf13/cobra"

	api "github.com/pagodabox/nanobox-api-client"
	// "github.com/pagodabox/nanobox-cli/auth"
	// "github.com/pagodabox/nanobox-cli/config"
	// "github.com/pagodabox/nanobox-cli/util"
	// "github.com/pagodabox/nanobox-golang-stylish"
)

//
var engineFetchCmd = &cobra.Command{
	Use:   "fetch",
	Short: "Fetches an engine from nanobox.io",
	Long: `
Description:
  Fetches an engine from nanobox.io

  Allowed formats when fetching an engine
  - engine-name
	- engine-name=0.0.1
  - user/engine-name
  - user/engine-name=0.0.1
	`,

	Run: nanoEngineFetch,
}

//
func init() {

	// no default is set here because we define the value later, once we know the
	// name and version of the engine they are fetching
	engineFetchCmd.Flags().StringVarP(&fFile, "ouput-document", "O", "", "specify where to save the engine")
}

// nanoEngineFetch
func nanoEngineFetch(ccmd *cobra.Command, args []string) {

	//
	// api.UserSlug, api.AuthToken = auth.Authenticate()

	if len(args) == 0 {
		// config.Console.Fatal("Please provide the name of an engine you would like to fetch, (run 'nanobox fetch -h' for details)")
		os.Exit(1)
	}

	// fmt.Printf(stylish.Bullet("Attempting to fetch '%v'", args[0]))

	//
	var archive, engine, user, version string // various string values used to store pieces of the engine
	var split []string                        // used in strings.Split()
	var dest io.Writer                        // the destination used in io.Copy()

	// split args on "/" looking for a user:
	// user/engine-name
	// user/engine-name=0.0.1
	split = strings.Split(args[0], "/")

	// switch on the length to determine if the split resulted in a user and a engine
	// or just an engine
	switch len(split) {

	// if len is 1 then only a download was found (no user specified)
	case 1:
		archive = split[0]

		// if len is 2 then a user was found (from which to pull the download)
	case 2:
		user = split[0]
		archive = split[1]

	// any other number or args
	default:
		// fmt.Printf("%v is not a valid format when fetching an engine (see help).\n", args[0])
		os.Exit(1)
	}

	// split on the archive to find the engine and the release
	split = strings.Split(archive, "=")

	// switch on the length to determine if the split resulted in a engine and version
	// or just an engine
	switch len(split) {

	// if len is 1 then just an engine was found (no version specified)
	case 1:
		engine = split[0]

		// if len is 2 then an engine and version were found
	case 2:
		engine = split[0]
		version = split[1]
	}

	//
	e, err := api.GetEngine(user, engine)
	if err != nil {
		// fmt.Printf(stylish.ErrBullet("No official engine, or engine for that user found."))
		os.Exit(1)
	}

	// if no version is provided, fetch the latest release
	if version == "" {
		version = e.ActiveReleaseID
	}

	//
	path := fmt.Sprintf("http://api.nanobox.io/v1/engines/%v/releases/%v/download", engine, version)

	// if a user is found, pull the engine from their engines
	if user != "" {
		path = fmt.Sprintf("http://api.nanobox.io/v1/engines/%v/%v/releases/%v/download", user, engine, version)
	}

	// fmt.Printf(stylish.Bullet("Fetching engine at '%s'", path))

	//
	res, err := http.Get(path)
	if err != nil {
		// util.Fatal("[commands.fetch] http.Get() failed", err)
	}
	defer res.Body.Close()

	//
	switch res.StatusCode / 100 {
	case 2, 3:
		break
	case 4:
		// fmt.Printf(stylish.ErrBullet("No release by that version found for engine '%v'", engine))
		os.Exit(1)
	case 5:
		// fmt.Printf(stylish.ErrBullet("Failed to fetch release (%v).", res.Status))
		os.Exit(1)
	}

	// determine if the file is to be streamed to stdout or to a file
	switch {

	// pipe the ouput to os.Stdout
	default:
		// fmt.Printf(stylish.Bullet("Piping download to stdout"))
		dest = os.Stdout

	// write the download to the local file system
	case fFile != "":
		// fmt.Printf(stylish.Bullet("Saving engine as '%s'", fFile))

		//
		release, err := os.Create(fFile)
		if err != nil {
			// fmt.Printf(stylish.ErrBullet("%v", err))
			os.Exit(1)
		}
		defer release.Close()

		//
		dest = release
	}

	// write the file
	if _, err := io.Copy(dest, res.Body); err != nil {
		// util.Fatal("[commands.fetch] io.Copy() failed", err)
	}
}
<commit_msg>engine fetch output to stderr<commit_after>// Copyright (c) 2015 Pagoda Box Inc
//
// This Source Code Form is subject to the terms of the Mozilla Public License, v.
// 2.0. If a copy of the MPL was not distributed with this file, You can obtain one
// at http://mozilla.org/MPL/2.0/.
//

package commands

//
import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"

	"github.com/spf13/cobra"

	api "github.com/pagodabox/nanobox-api-client"
	// "github.com/pagodabox/nanobox-cli/auth"
	// "github.com/pagodabox/nanobox-cli/config"
	// "github.com/pagodabox/nanobox-cli/util"
	"github.com/pagodabox/nanobox-golang-stylish"
)

//
var engineFetchCmd = &cobra.Command{
	Use:   "fetch",
	Short: "Fetches an engine from nanobox.io",
	Long: `
Description:
  Fetches an engine from nanobox.io

  Allowed formats when fetching an engine
  - engine-name
	- engine-name=0.0.1
  - user/engine-name
  - user/engine-name=0.0.1
	`,

	Run: nanoEngineFetch,
}

//
func init() {

	// no default is set here because we define the value later, once we know the
	// name and version of the engine they are fetching
	engineFetchCmd.Flags().StringVarP(&fFile, "ouput-document", "O", "", "specify where to save the engine")
}

// nanoEngineFetch
func nanoEngineFetch(ccmd *cobra.Command, args []string) {

	//
	// api.UserSlug, api.AuthToken = auth.Authenticate()

	if len(args) == 0 {
		os.Stderr.WriteString("Please provide the name of an engine you would like to fetch, (run 'nanobox engine fetch -h' for details)")
		os.Exit(1)
	}

	os.Stderr.WriteString(stylish.Bullet("Attempting to fetch '%v'", args[0]))

	//
	var archive, engine, user, version string // various string values used to store pieces of the engine
	var split []string                        // used in strings.Split()
	var dest io.Writer                        // the destination used in io.Copy()

	// split args on "/" looking for a user:
	// user/engine-name
	// user/engine-name=0.0.1
	split = strings.Split(args[0], "/")

	// switch on the length to determine if the split resulted in a user and a engine
	// or just an engine
	switch len(split) {

	// if len is 1 then only a download was found (no user specified)
	case 1:
		archive = split[0]

		// if len is 2 then a user was found (from which to pull the download)
	case 2:
		user = split[0]
		archive = split[1]

	// any other number or args
	default:
		// fmt.Printf("%v is not a valid format when fetching an engine (see help).\n", args[0])
		os.Exit(1)
	}

	// split on the archive to find the engine and the release
	split = strings.Split(archive, "=")

	// switch on the length to determine if the split resulted in a engine and version
	// or just an engine
	switch len(split) {

	// if len is 1 then just an engine was found (no version specified)
	case 1:
		engine = split[0]

		// if len is 2 then an engine and version were found
	case 2:
		engine = split[0]
		version = split[1]
	}

	//
	e, err := api.GetEngine(user, engine)
	if err != nil {
		os.Stderr.WriteString(stylish.ErrBullet("No official engine, or engine for that user found."))
		os.Exit(1)
	}

	// if no version is provided, fetch the latest release
	if version == "" {
		version = e.ActiveReleaseID
	}

	//
	path := fmt.Sprintf("http://api.nanobox.io/v1/engines/%v/releases/%v/download", engine, version)

	// if a user is found, pull the engine from their engines
	if user != "" {
		path = fmt.Sprintf("http://api.nanobox.io/v1/engines/%v/%v/releases/%v/download", user, engine, version)
	}

	os.Stderr.WriteString(stylish.Bullet("Fetching engine at '%s'", path))

	//
	res, err := http.Get(path)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	//
	switch res.StatusCode / 100 {
	case 2, 3:
		break
	case 4:
		os.Stderr.WriteString(stylish.ErrBullet("No release by that version found for engine '%v'", engine))
		os.Exit(1)
	case 5:
		os.Stderr.WriteString(stylish.ErrBullet("Failed to fetch release (%v).", res.Status))
		os.Exit(1)
	}

	// determine if the file is to be streamed to stdout or to a file
	switch {

	// pipe the ouput to os.Stdout
	default:
		dest = os.Stdout

	// write the download to the local file system
	case fFile != "":
		os.Stderr.WriteString(stylish.Bullet("Saving engine as '%s'", fFile))

		//
		release, err := os.Create(fFile)
		if err != nil {
			os.Stderr.WriteString(stylish.ErrBullet(err.Error()))
			os.Exit(1)
		}
		defer release.Close()

		//
		dest = release
	}

	// write the file
	if _, err := io.Copy(dest, res.Body); err != nil {
		os.Stderr.WriteString(fmt.Sprintf("[commands.fetch] io.Copy() failed", err.Error()))
	}
}
<|endoftext|>