<commit_before>// Copyright Istio Authors. All Rights Reserved.
//
// 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 branch

import (
	"fmt"

	"istio.io/pkg/log"
	"istio.io/release-builder/pkg/model"
	"istio.io/release-builder/pkg/util"
)

// CreateBranches goes to each repo and creates the branches
func CreateBranches(manifest model.Manifest, release string, dryrun bool) error {
	log.Infof("*** Creating release branches")
	for repo, dep := range manifest.Dependencies.Get() {
		if dep == nil {
			// Missing a dependency is not always a failure; many are optional dependencies just for
			// tagging.
			log.Infof("skipping missing dependency: %v", repo)
			continue
		}
		// Skip particular repos
		if repo == "test-infra" {
			log.Infof("Skipping repo: %v", repo)
			continue
		}
		log.Infof("*** Creating a release branch %s for %s from directory: %s", release, repo, manifest.RepoDir(repo))
		cmd := util.VerboseCommand("git", "checkout", "-b", "release-"+release)
		cmd.Dir = manifest.RepoDir(repo)
		if err := cmd.Run(); err != nil {
			return fmt.Errorf("failed to checkout release: %v", err)
		}
		if !dryrun {
			cmd = util.VerboseCommand("git", "push", "--set-upstream", "origin", "release-"+release)
			cmd.Dir = manifest.RepoDir(repo)
			if err := cmd.Run(); err != nil {
				log.Warnf("failed to push branch to repo: %v. Ignoring as it may already exist.", err)
			}
		}
	}
	log.Infof("*** Release branches created")
	return nil
}
<commit_msg>skip envoy in branch cut step (#622)<commit_after>// Copyright Istio Authors. All Rights Reserved.
//
// 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 branch

import (
	"fmt"

	"istio.io/pkg/log"
	"istio.io/release-builder/pkg/model"
	"istio.io/release-builder/pkg/util"
)

// CreateBranches goes to each repo and creates the branches
func CreateBranches(manifest model.Manifest, release string, dryrun bool) error {
	log.Infof("*** Creating release branches")
	for repo, dep := range manifest.Dependencies.Get() {
		if dep == nil {
			// Missing a dependency is not always a failure; many are optional dependencies just for
			// tagging.
			log.Infof("skipping missing dependency: %v", repo)
			continue
		}
		// test-infra does not use release branches and envoy repo should be manually branched
		// from correct envoy commit
		if repo == "test-infra" || repo == "envoy" {
			log.Infof("Skipping repo: %v", repo)
			continue
		}
		log.Infof("*** Creating a release branch %s for %s from directory: %s", release, repo, manifest.RepoDir(repo))
		cmd := util.VerboseCommand("git", "checkout", "-b", "release-"+release)
		cmd.Dir = manifest.RepoDir(repo)
		if err := cmd.Run(); err != nil {
			return fmt.Errorf("failed to checkout release: %v", err)
		}
		if !dryrun {
			cmd = util.VerboseCommand("git", "push", "--set-upstream", "origin", "release-"+release)
			cmd.Dir = manifest.RepoDir(repo)
			if err := cmd.Run(); err != nil {
				log.Warnf("failed to push branch to repo: %v. Ignoring as it may already exist.", err)
			}
		}
	}
	log.Infof("*** Release branches created")
	return nil
}
<|endoftext|>


<commit_before>package clideployment

import (
	"fmt"
	"io/ioutil"
	"os"
	"strings"

	"github.com/containerum/chkit/pkg/context"
	"github.com/containerum/chkit/pkg/model/container"
	"github.com/containerum/chkit/pkg/model/deployment"
	"github.com/containerum/chkit/pkg/model/deployment/deplactive"
	"github.com/containerum/chkit/pkg/util/activekit"
	"github.com/containerum/chkit/pkg/util/namegen"
	"github.com/containerum/chkit/pkg/util/text"
	"github.com/containerum/kube-client/pkg/model"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
)

func Create(ctx *context.Context) *cobra.Command {
	var file string
	var force bool
	var flagCont container.Container
	var flagDepl deployment.Deployment
	var envs []string
	command := &cobra.Command{
		Use:     "deployment",
		Aliases: aliases,
		Short:   "create new deployment",
		Long: `Creates new deployment.
Has an one-line mode, suitable for integration with other tools, and an interactive wizard mode`,
		Run: func(cmd *cobra.Command, args []string) {
			depl := deplactive.DefaultDeployment()
			if cmd.Flag("file").Changed {
				var err error
				depl, err = deplactive.FromFile(file)
				if err != nil {
					logrus.WithError(err).Errorf("unable to load deployment data from file %s", file)
					fmt.Printf("Unable to load deployment data from file :(\n%v", err)
					os.Exit(1)
				}
			} else if cmd.Flag("force").Changed {
				if cmd.Flag("env").Changed {
					envMap := map[string]string{}
					for _, env := range envs {
						var tokens = strings.SplitN(env, ":", 2)
						if len(tokens) != 2 {
							fmt.Printf("Inavlid env kev-value pair %q", env)
							os.Exit(1)
						}
						var k, v = tokens[0], tokens[1]
						v = strings.TrimPrefix(k, "\"")
						v = strings.TrimSuffix(k, "\"")
						envMap[k] = v
					}
					for k, v := range envMap {
						flagCont.Env = append(flagCont.Env, model.Env{
							Name:  k,
							Value: v,
						})
					}
				}
				if flagCont.Name == "" {
					flagCont.Name = namegen.Aster() + "-" + flagCont.Image
				}
				flagDepl.Containers = []container.Container{flagCont}
				depl = flagDepl
			}
			if cmd.Flag("force").Changed {
				if err := deplactive.ValidateDeployment(depl); err != nil {
					fmt.Println(err)
					os.Exit(1)
				}
				fmt.Println(depl.RenderTable())
				if err := ctx.Client.CreateDeployment(ctx.Namespace, depl); err != nil {
					fmt.Println(err)
					os.Exit(1)
				}
				fmt.Println("OK")
				return
			}
			depl, err := deplactive.Wizard(deplactive.Config{
				Deployment: &depl,
			})
			if err != nil {
				logrus.WithError(err).Errorf("unable to create deployment")
				fmt.Println(err)
				os.Exit(1)
			}

			var firstItem *activekit.MenuItem
			var created = false
			if activekit.YesNo("Are you sure?") {
				if err := ctx.Client.CreateDeployment(ctx.Namespace, depl); err != nil {
					logrus.WithError(err).Errorf("unable to create deployment %q", depl.Name)
					activekit.Attention(err.Error())
					os.Exit(1)
				}
				fmt.Printf("Congratulations! Deployment %q created!\n", depl.Name)
				created = true
				firstItem = &activekit.MenuItem{
					Label: "Push changes to server",
					Action: func() error {
						if activekit.YesNo("Are you sure?") {
							err := ctx.Client.ReplaceDeployment(ctx.Namespace, depl)
							if err != nil {
								logrus.WithError(err).Errorf("unable to update deployment %q", depl.Name)
								fmt.Println(err)
								return nil
							}
							fmt.Printf("Congratulations! Deployment %q updated!\n", depl.Name)
						}
						return nil
					},
				}
			} else {
				firstItem = &activekit.MenuItem{
					Label: "Create deployment on server",
					Action: func() error {
						if activekit.YesNo("Are you sure?") {
							err := ctx.Client.CreateDeployment(ctx.Namespace, depl)
							if err != nil {
								logrus.WithError(err).Errorf("unable to update deployment %q", depl.Name)
								fmt.Println(err)
								return nil
							}
							fmt.Printf("Congratulations! Deployment %q created!\n", depl.Name)
							created = true
						}
						return nil
					},
				}
			}
			for {
				deploymentMenu(ctx, depl, firstItem).Run()
				if created {
					firstItem = &activekit.MenuItem{
						Label: "Push changes to server",
						Action: func() error {
							if activekit.YesNo("Are you sure?") {
								err := ctx.Client.ReplaceDeployment(ctx.Namespace, depl)
								if err != nil {
									logrus.WithError(err).Errorf("unable to update deployment %q", depl.Name)
									fmt.Println(err)
									return nil
								}
								fmt.Printf("Congratulations! Deployment %q updated!\n", depl.Name)
							}
							return nil
						},
					}
				}
			}
		},
	}
	command.PersistentFlags().
		StringVar(&file, "file", "", "create deployment from file")
	command.PersistentFlags().
		BoolVarP(&force, "force", "f", false, "suppress confirmation")

	command.PersistentFlags().
		StringVar(&flagDepl.Name, "deployment-name", namegen.Color()+"-"+namegen.Aster(), "deployment name, optional")
	command.PersistentFlags().
		IntVar(&flagDepl.Replicas, "replicas", 1, "replicas, optional")
	command.PersistentFlags().
		StringVar(&flagCont.Name, "container-name", "", "container name, equal to image name by default")
	command.PersistentFlags().
		StringVar(&flagCont.Image, "image", "", "container image, required")
	command.PersistentFlags().
		UintVar(&flagCont.Limits.Memory, "memory", 256, "container memory limit im Mb, optional")
	command.PersistentFlags().
		UintVar(&flagCont.Limits.CPU, "cpu", 200, "container CPU limit in mCPU, optional")
	command.PersistentFlags().
		StringSliceVar(&flagCont.Commands, "commands", nil, "container commands")
	command.PersistentFlags().
		StringSliceVar(&envs, "env", []string{}, "container env variable in KEY0:VALUE0 KEY1:VALUE1 format")
	return command
}

func deploymentMenu(ctx *context.Context, depl deployment.Deployment, firstItem *activekit.MenuItem) *activekit.Menu {
	return &activekit.Menu{
		Items: []*activekit.MenuItem{
			firstItem,
			{
				Label: "Edit deployment",
				Action: func() error {
					var err error
					depl, err = deplactive.ReplaceWizard(deplactive.Config{
						Deployment: &depl,
					})
					if err != nil {
						logrus.WithError(err).Errorf("unable to create deployment")
						fmt.Println(err)
						os.Exit(1)
					}
					return nil
				},
			},
			{
				Label: "Print to terminal",
				Action: activekit.ActionWithErr(func() error {
					if data, err := depl.RenderYAML(); err != nil {
						return err
					} else {
						upBorders := strings.Repeat("_", text.Width(data))
						downBorders := strings.Repeat("_", text.Width(data))
						fmt.Printf("%s\n\n%s\n%s\n", upBorders, data, downBorders)
					}
					return nil
				}),
			},
			{
				Label: "Save to file",
				Action: func() error {
					filename, _ := activekit.AskLine("Print filename: ")
					data, err := depl.RenderJSON()
					if err != nil {
						return err
					}
					if err := ioutil.WriteFile(filename, []byte(data), os.ModePerm); err != nil {
						logrus.WithError(err).Errorf("unable to save deployment %q to file", depl.Name)
						fmt.Printf("Unable to save deployment to file :(\n%v", err)
						return nil
					}
					fmt.Printf("OK\n")
					return nil
				},
			},
			{
				Label: "Exit",
				Action: func() error {
					if yes, _ := activekit.Yes("Are you sure you want to exit?"); yes {
						os.Exit(0)
					}
					return nil
				},
			},
		},
	}
}
<commit_msg>add value cleaning #87<commit_after>package clideployment

import (
	"fmt"
	"io/ioutil"
	"os"
	"strings"

	"github.com/containerum/chkit/pkg/context"
	"github.com/containerum/chkit/pkg/model/container"
	"github.com/containerum/chkit/pkg/model/deployment"
	"github.com/containerum/chkit/pkg/model/deployment/deplactive"
	"github.com/containerum/chkit/pkg/util/activekit"
	"github.com/containerum/chkit/pkg/util/namegen"
	"github.com/containerum/chkit/pkg/util/text"
	"github.com/containerum/kube-client/pkg/model"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
)

func Create(ctx *context.Context) *cobra.Command {
	var file string
	var force bool
	var flagCont container.Container
	var flagDepl deployment.Deployment
	var envs []string
	command := &cobra.Command{
		Use:     "deployment",
		Aliases: aliases,
		Short:   "create new deployment",
		Long: `Creates new deployment.
Has an one-line mode, suitable for integration with other tools, and an interactive wizard mode`,
		Run: func(cmd *cobra.Command, args []string) {
			depl := deplactive.DefaultDeployment()
			if cmd.Flag("file").Changed {
				var err error
				depl, err = deplactive.FromFile(file)
				if err != nil {
					logrus.WithError(err).Errorf("unable to load deployment data from file %s", file)
					fmt.Printf("Unable to load deployment data from file :(\n%v", err)
					os.Exit(1)
				}
			} else if cmd.Flag("force").Changed {
				if cmd.Flag("env").Changed {
					envMap := map[string]string{}
					for _, env := range envs {
						var tokens = strings.SplitN(env, ":", 2)
						if len(tokens) != 2 {
							fmt.Printf("Inavlid env kev-value pair %q", env)
							os.Exit(1)
						}
						var k, v = tokens[0], tokens[1]
						k = strings.TrimSpace(k)
						v = strings.TrimSpace(v)
						v = strings.TrimPrefix(v, "\"")
						v = strings.TrimSuffix(v, "\"")
						envMap[k] = v
					}
					for k, v := range envMap {
						flagCont.Env = append(flagCont.Env, model.Env{
							Name:  k,
							Value: v,
						})
					}
				}
				if flagCont.Name == "" {
					flagCont.Name = namegen.Aster() + "-" + flagCont.Image
				}
				flagDepl.Containers = []container.Container{flagCont}
				depl = flagDepl
			}
			if cmd.Flag("force").Changed {
				if err := deplactive.ValidateDeployment(depl); err != nil {
					fmt.Println(err)
					os.Exit(1)
				}
				fmt.Println(depl.RenderTable())
				if err := ctx.Client.CreateDeployment(ctx.Namespace, depl); err != nil {
					fmt.Println(err)
					os.Exit(1)
				}
				fmt.Println("OK")
				return
			}
			depl, err := deplactive.Wizard(deplactive.Config{
				Deployment: &depl,
			})
			if err != nil {
				logrus.WithError(err).Errorf("unable to create deployment")
				fmt.Println(err)
				os.Exit(1)
			}

			var firstItem *activekit.MenuItem
			var created = false
			if activekit.YesNo("Are you sure?") {
				if err := ctx.Client.CreateDeployment(ctx.Namespace, depl); err != nil {
					logrus.WithError(err).Errorf("unable to create deployment %q", depl.Name)
					activekit.Attention(err.Error())
					os.Exit(1)
				}
				fmt.Printf("Congratulations! Deployment %q created!\n", depl.Name)
				created = true
				firstItem = &activekit.MenuItem{
					Label: "Push changes to server",
					Action: func() error {
						if activekit.YesNo("Are you sure?") {
							err := ctx.Client.ReplaceDeployment(ctx.Namespace, depl)
							if err != nil {
								logrus.WithError(err).Errorf("unable to update deployment %q", depl.Name)
								fmt.Println(err)
								return nil
							}
							fmt.Printf("Congratulations! Deployment %q updated!\n", depl.Name)
						}
						return nil
					},
				}
			} else {
				firstItem = &activekit.MenuItem{
					Label: "Create deployment on server",
					Action: func() error {
						if activekit.YesNo("Are you sure?") {
							err := ctx.Client.CreateDeployment(ctx.Namespace, depl)
							if err != nil {
								logrus.WithError(err).Errorf("unable to update deployment %q", depl.Name)
								fmt.Println(err)
								return nil
							}
							fmt.Printf("Congratulations! Deployment %q created!\n", depl.Name)
							created = true
						}
						return nil
					},
				}
			}
			for {
				deploymentMenu(ctx, depl, firstItem).Run()
				if created {
					firstItem = &activekit.MenuItem{
						Label: "Push changes to server",
						Action: func() error {
							if activekit.YesNo("Are you sure?") {
								err := ctx.Client.ReplaceDeployment(ctx.Namespace, depl)
								if err != nil {
									logrus.WithError(err).Errorf("unable to update deployment %q", depl.Name)
									fmt.Println(err)
									return nil
								}
								fmt.Printf("Congratulations! Deployment %q updated!\n", depl.Name)
							}
							return nil
						},
					}
				}
			}
		},
	}
	command.PersistentFlags().
		StringVar(&file, "file", "", "create deployment from file")
	command.PersistentFlags().
		BoolVarP(&force, "force", "f", false, "suppress confirmation")

	command.PersistentFlags().
		StringVar(&flagDepl.Name, "deployment-name", namegen.Color()+"-"+namegen.Aster(), "deployment name, optional")
	command.PersistentFlags().
		IntVar(&flagDepl.Replicas, "replicas", 1, "replicas, optional")
	command.PersistentFlags().
		StringVar(&flagCont.Name, "container-name", "", "container name, equal to image name by default")
	command.PersistentFlags().
		StringVar(&flagCont.Image, "image", "", "container image, required")
	command.PersistentFlags().
		UintVar(&flagCont.Limits.Memory, "memory", 256, "container memory limit im Mb, optional")
	command.PersistentFlags().
		UintVar(&flagCont.Limits.CPU, "cpu", 200, "container CPU limit in mCPU, optional")
	command.PersistentFlags().
		StringSliceVar(&flagCont.Commands, "commands", nil, "container commands")
	command.PersistentFlags().
		StringSliceVar(&envs, "env", []string{}, "container env variable in KEY0:VALUE0 KEY1:VALUE1 format")
	return command
}

func deploymentMenu(ctx *context.Context, depl deployment.Deployment, firstItem *activekit.MenuItem) *activekit.Menu {
	return &activekit.Menu{
		Items: []*activekit.MenuItem{
			firstItem,
			{
				Label: "Edit deployment",
				Action: func() error {
					var err error
					depl, err = deplactive.ReplaceWizard(deplactive.Config{
						Deployment: &depl,
					})
					if err != nil {
						logrus.WithError(err).Errorf("unable to create deployment")
						fmt.Println(err)
						os.Exit(1)
					}
					return nil
				},
			},
			{
				Label: "Print to terminal",
				Action: activekit.ActionWithErr(func() error {
					if data, err := depl.RenderYAML(); err != nil {
						return err
					} else {
						upBorders := strings.Repeat("_", text.Width(data))
						downBorders := strings.Repeat("_", text.Width(data))
						fmt.Printf("%s\n\n%s\n%s\n", upBorders, data, downBorders)
					}
					return nil
				}),
			},
			{
				Label: "Save to file",
				Action: func() error {
					filename, _ := activekit.AskLine("Print filename: ")
					data, err := depl.RenderJSON()
					if err != nil {
						return err
					}
					if err := ioutil.WriteFile(filename, []byte(data), os.ModePerm); err != nil {
						logrus.WithError(err).Errorf("unable to save deployment %q to file", depl.Name)
						fmt.Printf("Unable to save deployment to file :(\n%v", err)
						return nil
					}
					fmt.Printf("OK\n")
					return nil
				},
			},
			{
				Label: "Exit",
				Action: func() error {
					if yes, _ := activekit.Yes("Are you sure you want to exit?"); yes {
						os.Exit(0)
					}
					return nil
				},
			},
		},
	}
}
<|endoftext|>


<commit_before>/*
Package types implements the CloudEvents type system.

CloudEvents defines a set of abstract types for event context attributes. Each
type has a corresponding native Go type and a canonical string encoding.  The
native Go types used to represent the CloudEvents types are:

    bool, int32, string, []byte, *url.URL, time.Time

 +----------------+----------------+-----------------------------------+
 |CloudEvents Type|Native Type     |Convertible From                   |
 +================+================+===================================+
 |Bool            |bool            |bool                               |
 +----------------+----------------+-----------------------------------+
 |Integer         |int32           |Any numeric type with value in     |
 |                |                |range of int32                     |
 +----------------+----------------+-----------------------------------+
 |String          |string          |string                             |
 +----------------+----------------+-----------------------------------+
 |Binary          |[]byte          |[]byte                             |
 +----------------+----------------+-----------------------------------+
 |URI-Reference   |*url.URL        |url.URL, types.URIRef, types.URI   |
 +----------------+----------------+-----------------------------------+
 |URI             |*url.URL        |url.URL, types.URIRef, types.URI   |
 |                |                |Must be an absolute URI.           |
 +----------------+----------------+-----------------------------------+
 |Timestamp       |time.Time       |time.Time, types.Timestamp         |
 +----------------+----------------+-----------------------------------+

Extension attributes may be stored as a native type or a canonical string.  The
To<Type> functions will convert to the desired <Type> from any convertible type
or from the canonical string form.

The Parse<Type> and Format<Type> functions convert native types to/from
canonical strings.

Note are no Parse or Format functions for URL or string. For URL use the
standard url.Parse() and url.URL.String(). The canonical string format of a
string is the string itself.

*/
package types
<commit_msg>Minor doc formatting fix<commit_after>/*
Package types implements the CloudEvents type system.

CloudEvents defines a set of abstract types for event context attributes. Each
type has a corresponding native Go type and a canonical string encoding.  The
native Go types used to represent the CloudEvents types are:
bool, int32, string, []byte, *url.URL, time.Time

 +----------------+----------------+-----------------------------------+
 |CloudEvents Type|Native Type     |Convertible From                   |
 +================+================+===================================+
 |Bool            |bool            |bool                               |
 +----------------+----------------+-----------------------------------+
 |Integer         |int32           |Any numeric type with value in     |
 |                |                |range of int32                     |
 +----------------+----------------+-----------------------------------+
 |String          |string          |string                             |
 +----------------+----------------+-----------------------------------+
 |Binary          |[]byte          |[]byte                             |
 +----------------+----------------+-----------------------------------+
 |URI-Reference   |*url.URL        |url.URL, types.URIRef, types.URI   |
 +----------------+----------------+-----------------------------------+
 |URI             |*url.URL        |url.URL, types.URIRef, types.URI   |
 |                |                |Must be an absolute URI.           |
 +----------------+----------------+-----------------------------------+
 |Timestamp       |time.Time       |time.Time, types.Timestamp         |
 +----------------+----------------+-----------------------------------+

Extension attributes may be stored as a native type or a canonical string.  The
To<Type> functions will convert to the desired <Type> from any convertible type
or from the canonical string form.

The Parse<Type> and Format<Type> functions convert native types to/from
canonical strings.

Note are no Parse or Format functions for URL or string. For URL use the
standard url.Parse() and url.URL.String(). The canonical string format of a
string is the string itself.

*/
package types
<|endoftext|>


<commit_before>package ExperimentDriver

import (
	"fmt"

	"github.com/intelsdi-x/swan/pkg/workloads"
)

type ExperimentConfiguration struct {
	SLO             int
	TuningTimeout   int
	LoadDuration    int
	LoadPointsCount int
}

type SensitivitiProfileExperiment struct {
	// Latency Sensitivity workload
	pr workloads.Launcher
	// Workload Generator for Latency Sensitivity workload
	lgForPr workloads.LoadGenerator
	// Aggressors to be but aside to LC workload
	be         []workloads.Launcher
	ec         ExperimentConfiguration
	targetLoad int
	slis       [][]int
}

// Construct new SensitivityProfileExperiment object.
func NewSensitivitiProfileExperiment(c ExperimentConfiguration,
	pr workloads.Launcher,
	lgForPr workloads.LoadGenerator,
	be []workloads.Launcher) *SensitivitiProfileExperiment {

	return &SensitivitiProfileExperiment{pr: pr, lgForPr: lgForPr,
		be: be, ec: c}
}

// Runs single measurement of PR workload with given aggressor.
// Takes aggressor workload and specific loadPoint (rps)
// Return (sli, nil) on success (0, error) otherwise.
func (e *SensitivitiProfileExperiment) runMeasurement(
	aggressor workloads.Launcher,
	qps int) (sli int, err error) {

	prTask, err := e.pr.Launch()
	if err != nil {
		return 0, err
	}
	defer prTask.Stop()

	//Run aggressor
	agrTask, err := aggressor.Launch()
	if err != nil {
		return 0, err
	}
	//Run workload generator - blocking?
	//TBD: output? Raw data?
	sli, err = e.lgForPr.Load(qps, e.ec.LoadDuration)

	agrTask.Stop()
	return sli, err
}

// Executes single phase
func (e *SensitivitiProfileExperiment) runPhase(aggressor workloads.Launcher) (slis []int, err error) {
	slis = make([]int, e.ec.LoadPointsCount)

	loadStep := int(e.targetLoad / e.ec.LoadPointsCount)

	for load := loadStep; load < e.targetLoad; load += loadStep {
		result, err := e.runMeasurement(aggressor, load)
		if err != nil {
			return nil, err
		}
		slis = append(slis, result)
	}
	return slis, err
}

func (e *SensitivitiProfileExperiment) runTunning() error {
	prTask, err := e.pr.Launch()
	if err != nil {
		return err
	}
	defer prTask.Stop()

	e.targetLoad, err = e.lgForPr.Tune(e.ec.SLO, e.ec.TuningTimeout)
	if err != nil {
		e.targetLoad = -1
		return err
	}
	return err
}

// Prints nice output. TBD
func (e *SensitivitiProfileExperiment) PrintSensitivityProfile() error {
	fmt.Print("SensitivityProfile is TBD")
	return nil
}

func (e *SensitivitiProfileExperiment) Run() error {
	var err error

	err = e.runTunning()
	if err != nil {
		//Stop here
		return err
	}

	for _, aggressor := range e.be {
		slis, err := e.runPhase(aggressor)
		if err != nil {
			return err
		}
		e.slis = append(e.slis, slis)
	}

	//That's TBD.
	err = e.PrintSensitivityProfile()
	return err
}
<commit_msg>SCE-155: Refactoring<commit_after>package ExperimentDriver

import (
	"fmt"

	"github.com/intelsdi-x/swan/pkg/workloads"
)

type SensitivityProfileExperimentConfiguration struct {
	SLO             int
	TuningTimeout   int
	LoadDuration    int
	LoadPointsCount int
}

type SensitivityProfileExperiment struct {
	// Latency Sensitivity workload
	pr workloads.Launcher
	// Workload Generator for Latency Sensitivity workload
	lgForPr workloads.LoadGenerator
	// Aggressors to be but aside to LC workload
	be         []workloads.Launcher
	ec         SensitivityProfileExperimentConfiguration
	targetLoad int
	slis       [][]int
}

// Construct new SensitivityProfileExperiment object.
func NewSensitivityProfileExperiment(
	c SensitivityProfileExperimentConfiguration,
	pr workloads.Launcher,
	lgForPr workloads.LoadGenerator,
	be []workloads.Launcher) *SensitivityProfileExperiment {

	return &SensitivityProfileExperiment{
		pr:      pr,
		lgForPr: lgForPr,
		be:      be,
		ec:      c,
	}
}

// Runs single measurement of PR workload with given aggressor.
// Takes aggressor workload and specific loadPoint (rps)
// Return (sli, nil) on success (0, error) otherwise.
func (e *SensitivityProfileExperiment) runMeasurement(
	aggressor workloads.Launcher,
	qps int) (sli int, err error) {

	prTask, err := e.pr.Launch()
	if err != nil {
		return 0, err
	}
	defer prTask.Stop()

	agrTask, err := aggressor.Launch()
	if err != nil {
		return 0, err
	}
	sli, err = e.lgForPr.Load(qps, e.ec.LoadDuration)

	agrTask.Stop()
	return sli, err
}

func (e *SensitivityProfileExperiment) runPhase(
	aggressor workloads.Launcher) (slis []int, err error) {
	slis = make([]int, e.ec.LoadPointsCount)

	loadStep := int(e.targetLoad / e.ec.LoadPointsCount)

	for load := loadStep; load < e.targetLoad; load += loadStep {
		result, err := e.runMeasurement(aggressor, load)
		if err != nil {
			return nil, err
		}
		slis = append(slis, result)
	}
	return slis, err
}

func (e *SensitivityProfileExperiment) runTunning() error {
	prTask, err := e.pr.Launch()
	if err != nil {
		return err
	}
	defer prTask.Stop()

	e.targetLoad, err = e.lgForPr.Tune(e.ec.SLO, e.ec.TuningTimeout)
	if err != nil {
		e.targetLoad = -1
		return err
	}
	return err
}

// Prints nice output. TBD
func (e *SensitivityProfileExperiment) PrintSensitivityProfile() error {
	fmt.Print("SensitivityProfile is TBD")
	return nil
}

func (e *SensitivityProfileExperiment) Run() error {
	var err error

	err = e.runTunning()
	if err != nil {
		//Stop here
		return err
	}

	for _, aggressor := range e.be {
		slis, err := e.runPhase(aggressor)
		if err != nil {
			return err
		}
		e.slis = append(e.slis, slis)
	}

	//That's TBD.
	err = e.PrintSensitivityProfile()
	return err
}
<|endoftext|>


<commit_before>/*
Copyright 2014 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.
*/

// Common logic used by both http and file channels.
package config

import (
	"crypto/md5"
	"encoding/hex"
	"fmt"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/types"
	utilyaml "k8s.io/apimachinery/pkg/util/yaml"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/v1"
	"k8s.io/kubernetes/pkg/api/validation"
	kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
	"k8s.io/kubernetes/pkg/util/hash"

	"github.com/golang/glog"
)

// Generate a pod name that is unique among nodes by appending the nodeName.
func generatePodName(name string, nodeName types.NodeName) string {
	return fmt.Sprintf("%s-%s", name, nodeName)
}

func applyDefaults(pod *api.Pod, source string, isFile bool, nodeName types.NodeName) error {
	if len(pod.UID) == 0 {
		hasher := md5.New()
		if isFile {
			fmt.Fprintf(hasher, "host:%s", nodeName)
			fmt.Fprintf(hasher, "file:%s", source)
		} else {
			fmt.Fprintf(hasher, "url:%s", source)
		}
		hash.DeepHashObject(hasher, pod)
		pod.UID = types.UID(hex.EncodeToString(hasher.Sum(nil)[0:]))
		glog.V(5).Infof("Generated UID %q pod %q from %s", pod.UID, pod.Name, source)
	}

	pod.Name = generatePodName(pod.Name, nodeName)
	glog.V(5).Infof("Generated Name %q for UID %q from URL %s", pod.Name, pod.UID, source)

	if pod.Namespace == "" {
		pod.Namespace = metav1.NamespaceDefault
	}
	glog.V(5).Infof("Using namespace %q for pod %q from %s", pod.Namespace, pod.Name, source)

	// Set the Host field to indicate this pod is scheduled on the current node.
	pod.Spec.NodeName = string(nodeName)

	pod.ObjectMeta.SelfLink = getSelfLink(pod.Name, pod.Namespace)

	if pod.Annotations == nil {
		pod.Annotations = make(map[string]string)
	}
	// The generated UID is the hash of the file.
	pod.Annotations[kubetypes.ConfigHashAnnotationKey] = string(pod.UID)

	// Set the default status to pending.
	pod.Status.Phase = api.PodPending
	return nil
}

func getSelfLink(name, namespace string) string {
	var selfLink string
	if len(namespace) == 0 {
		namespace = metav1.NamespaceDefault
	}
	selfLink = fmt.Sprintf("/api/"+api.Registry.GroupOrDie(api.GroupName).GroupVersion.Version+"/pods/namespaces/%s/%s", name, namespace)
	return selfLink
}

type defaultFunc func(pod *api.Pod) error

func tryDecodeSinglePod(data []byte, defaultFn defaultFunc) (parsed bool, pod *v1.Pod, err error) {
	// JSON is valid YAML, so this should work for everything.
	json, err := utilyaml.ToJSON(data)
	if err != nil {
		return false, nil, err
	}
	obj, err := runtime.Decode(api.Codecs.UniversalDecoder(), json)
	if err != nil {
		return false, pod, err
	}
	// Check whether the object could be converted to single pod.
	if _, ok := obj.(*api.Pod); !ok {
		err = fmt.Errorf("invalid pod: %#v", obj)
		return false, pod, err
	}
	newPod := obj.(*api.Pod)
	// Apply default values and validate the pod.
	if err = defaultFn(newPod); err != nil {
		return true, pod, err
	}
	if errs := validation.ValidatePod(newPod); len(errs) > 0 {
		err = fmt.Errorf("invalid pod: %v", errs)
		return true, pod, err
	}
	v1Pod := &v1.Pod{}
	if err := v1.Convert_api_Pod_To_v1_Pod(newPod, v1Pod, nil); err != nil {
		return true, nil, err
	}
	return true, v1Pod, nil
}

func tryDecodePodList(data []byte, defaultFn defaultFunc) (parsed bool, pods v1.PodList, err error) {
	obj, err := runtime.Decode(api.Codecs.UniversalDecoder(), data)
	if err != nil {
		return false, pods, err
	}
	// Check whether the object could be converted to list of pods.
	if _, ok := obj.(*api.PodList); !ok {
		err = fmt.Errorf("invalid pods list: %#v", obj)
		return false, pods, err
	}
	newPods := obj.(*api.PodList)
	// Apply default values and validate pods.
	for i := range newPods.Items {
		newPod := &newPods.Items[i]
		if err = defaultFn(newPod); err != nil {
			return true, pods, err
		}
		if errs := validation.ValidatePod(newPod); len(errs) > 0 {
			err = fmt.Errorf("invalid pod: %v", errs)
			return true, pods, err
		}
	}
	v1Pods := &v1.PodList{}
	if err := v1.Convert_api_PodList_To_v1_PodList(newPods, v1Pods, nil); err != nil {
		return true, pods, err
	}
	return true, *v1Pods, err
}
<commit_msg>Apply taint tolerations for NoExecute for all static pods.<commit_after>/*
Copyright 2014 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.
*/

// Common logic used by both http and file channels.
package config

import (
	"crypto/md5"
	"encoding/hex"
	"fmt"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/types"
	utilyaml "k8s.io/apimachinery/pkg/util/yaml"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/v1"
	"k8s.io/kubernetes/pkg/api/validation"
	kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
	"k8s.io/kubernetes/pkg/util/hash"

	"github.com/golang/glog"
)

// Generate a pod name that is unique among nodes by appending the nodeName.
func generatePodName(name string, nodeName types.NodeName) string {
	return fmt.Sprintf("%s-%s", name, nodeName)
}

func applyDefaults(pod *api.Pod, source string, isFile bool, nodeName types.NodeName) error {
	if len(pod.UID) == 0 {
		hasher := md5.New()
		if isFile {
			fmt.Fprintf(hasher, "host:%s", nodeName)
			fmt.Fprintf(hasher, "file:%s", source)
		} else {
			fmt.Fprintf(hasher, "url:%s", source)
		}
		hash.DeepHashObject(hasher, pod)
		pod.UID = types.UID(hex.EncodeToString(hasher.Sum(nil)[0:]))
		glog.V(5).Infof("Generated UID %q pod %q from %s", pod.UID, pod.Name, source)
	}

	pod.Name = generatePodName(pod.Name, nodeName)
	glog.V(5).Infof("Generated Name %q for UID %q from URL %s", pod.Name, pod.UID, source)

	if pod.Namespace == "" {
		pod.Namespace = metav1.NamespaceDefault
	}
	glog.V(5).Infof("Using namespace %q for pod %q from %s", pod.Namespace, pod.Name, source)

	// Set the Host field to indicate this pod is scheduled on the current node.
	pod.Spec.NodeName = string(nodeName)

	pod.ObjectMeta.SelfLink = getSelfLink(pod.Name, pod.Namespace)

	if pod.Annotations == nil {
		pod.Annotations = make(map[string]string)
	}
	// The generated UID is the hash of the file.
	pod.Annotations[kubetypes.ConfigHashAnnotationKey] = string(pod.UID)

	if isFile {
		// Applying the default Taint tolerations to static pods,
		// so they are not evicted when there are node problems.
		api.AddOrUpdateTolerationInPod(pod, &api.Toleration{
			Operator: "Exists",
			Effect:   api.TaintEffectNoExecute,
		})
	}

	// Set the default status to pending.
	pod.Status.Phase = api.PodPending
	return nil
}

func getSelfLink(name, namespace string) string {
	var selfLink string
	if len(namespace) == 0 {
		namespace = metav1.NamespaceDefault
	}
	selfLink = fmt.Sprintf("/api/"+api.Registry.GroupOrDie(api.GroupName).GroupVersion.Version+"/pods/namespaces/%s/%s", name, namespace)
	return selfLink
}

type defaultFunc func(pod *api.Pod) error

func tryDecodeSinglePod(data []byte, defaultFn defaultFunc) (parsed bool, pod *v1.Pod, err error) {
	// JSON is valid YAML, so this should work for everything.
	json, err := utilyaml.ToJSON(data)
	if err != nil {
		return false, nil, err
	}
	obj, err := runtime.Decode(api.Codecs.UniversalDecoder(), json)
	if err != nil {
		return false, pod, err
	}
	// Check whether the object could be converted to single pod.
	if _, ok := obj.(*api.Pod); !ok {
		err = fmt.Errorf("invalid pod: %#v", obj)
		return false, pod, err
	}
	newPod := obj.(*api.Pod)
	// Apply default values and validate the pod.
	if err = defaultFn(newPod); err != nil {
		return true, pod, err
	}
	if errs := validation.ValidatePod(newPod); len(errs) > 0 {
		err = fmt.Errorf("invalid pod: %v", errs)
		return true, pod, err
	}
	v1Pod := &v1.Pod{}
	if err := v1.Convert_api_Pod_To_v1_Pod(newPod, v1Pod, nil); err != nil {
		return true, nil, err
	}
	return true, v1Pod, nil
}

func tryDecodePodList(data []byte, defaultFn defaultFunc) (parsed bool, pods v1.PodList, err error) {
	obj, err := runtime.Decode(api.Codecs.UniversalDecoder(), data)
	if err != nil {
		return false, pods, err
	}
	// Check whether the object could be converted to list of pods.
	if _, ok := obj.(*api.PodList); !ok {
		err = fmt.Errorf("invalid pods list: %#v", obj)
		return false, pods, err
	}
	newPods := obj.(*api.PodList)
	// Apply default values and validate pods.
	for i := range newPods.Items {
		newPod := &newPods.Items[i]
		if err = defaultFn(newPod); err != nil {
			return true, pods, err
		}
		if errs := validation.ValidatePod(newPod); len(errs) > 0 {
			err = fmt.Errorf("invalid pod: %v", errs)
			return true, pods, err
		}
	}
	v1Pods := &v1.PodList{}
	if err := v1.Convert_api_PodList_To_v1_PodList(newPods, v1Pods, nil); err != nil {
		return true, pods, err
	}
	return true, *v1Pods, err
}
<|endoftext|>


<commit_before>/*******************************************************************************
*
* Copyright 2017 SAP SE
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You should have received a copy of the License along with this
* program. If not, 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 plugins

import (
	"math"

	"strings"

	"github.com/gophercloud/gophercloud"
	"github.com/gophercloud/gophercloud/openstack"
	"github.com/gophercloud/gophercloud/openstack/compute/v2/flavors"
	"github.com/gophercloud/gophercloud/pagination"
	"github.com/sapcc/limes/pkg/limes"
	"github.com/sapcc/limes/pkg/util"
)

type capacityNovaPlugin struct {
	cfg limes.CapacitorConfiguration
}

type extraSpecs struct {
	ExtraSpecs map[string]string `json:"extra_specs"`
}

func init() {
	limes.RegisterCapacityPlugin(func(c limes.CapacitorConfiguration) limes.CapacityPlugin {
		return &capacityNovaPlugin{c}
	})
}

func (p *capacityNovaPlugin) Client(driver limes.Driver) (*gophercloud.ServiceClient, error) {
	return openstack.NewComputeV2(driver.Client(),
		gophercloud.EndpointOpts{Availability: gophercloud.AvailabilityPublic},
	)
}

func (p *capacityNovaPlugin) ID() string {
	return "nova"
}

//Scrape implements the limes.CapacityPlugin interface.
func (p *capacityNovaPlugin) Scrape(driver limes.Driver) (map[string]map[string]uint64, error) {
	client, err := p.Client(driver)
	if err != nil {
		return nil, err
	}

	var result gophercloud.Result

	//Get absolute limits for a tenant
	url := client.ServiceURL("os-hypervisors", "statistics")
	_, err = client.Get(url, &result.Body, nil)
	if err != nil {
		return nil, err
	}
	var hypervisorData struct {
		HypervisorStatistics struct {
			Vcpus    int `json:"vcpus"`
			MemoryMb int `json:"memory_mb"`
			LocalGb  int `json:"local_gb"`
		} `json:"hypervisor_statistics"`
	}
	err = result.ExtractInto(&hypervisorData)
	if err != nil {
		return nil, err
	}

	//Get availability zones
	url = client.ServiceURL("os-availability-zone")
	_, err = client.Get(url, &result.Body, nil)
	if err != nil {
		return nil, err
	}
	var availabilityZoneData struct {
		AvailabilityZoneInfo []struct {
			ZoneName  string `json:"zoneName"`
			ZoneState struct {
				Available bool `json:"available"`
			} `json:"zoneState"`
		} `json:"availabilityZoneInfo"`
	}
	err = result.ExtractInto(&availabilityZoneData)
	if err != nil {
		return nil, err
	}

	//list all flavors and get max(flavor_size)
	pages, maxFlavorSize := 0, 0.0
	err = flavors.ListDetail(client, nil).EachPage(func(page pagination.Page) (bool, error) {
		pages++
		f, err := flavors.ExtractFlavors(page)
		if err != nil {
			return false, err
		}
		for _, element := range f {
			extras, err := getFlavorExtras(client, element.ID)
			if err != nil {
				util.LogDebug("Failed to get extra specs for flavor: %s.", element.ID)
				return false, err
			}

			//necessary to be able to ignore huge baremetal flavors
			//consider only flavors as defined in extra specs
			var extraSpecs map[string]string
			if p.cfg.Nova.ExtraSpecs != nil {
				extraSpecs = p.cfg.Nova.ExtraSpecs
			}

			for key, value := range extraSpecs {
				if value == strings.Replace(extras.ExtraSpecs[key], "'", "", -1) {
					maxFlavorSize = math.Max(maxFlavorSize, float64(element.Disk))
				}
			}
		}

		return true, nil
	})
	if err != nil {
		return nil, err
	}

	var azCount int

	//count availability zones
	for _, element := range availabilityZoneData.AvailabilityZoneInfo {
		if element.ZoneState.Available == true {
			azCount++
		}
	}

	//get overcommit factor from configuration (hypervisor stats unfortunately is
	//stupid and does not include this factor even though it is in the nova.conf)
	var vcpuOvercommitFactor uint64 = 1
	if p.cfg.Nova.VCPUOvercommitFactor != nil {
		vcpuOvercommitFactor = *p.cfg.Nova.VCPUOvercommitFactor
	}

	//returns something like
	//"volumev2": {
	//	"cores": total_vcpus,
	//	"instances": min(10000 per Availability Zone, local_gb/max(flavor size)),
	//	"ram": total_memory_mb,
	//}
	return map[string]map[string]uint64{
		"compute": {
			"cores":     uint64(hypervisorData.HypervisorStatistics.Vcpus) * vcpuOvercommitFactor,
			"instances": uint64(math.Min(float64(10000*azCount), float64(hypervisorData.HypervisorStatistics.LocalGb)/maxFlavorSize)),
			"ram":       uint64(hypervisorData.HypervisorStatistics.MemoryMb),
		},
	}, nil

}

//get flavor extra-specs
//result contains
//{ "vmware:hv_enabled" : 'True' }
//which identifies a VM flavor
func getFlavorExtras(client *gophercloud.ServiceClient, flavorUUID string) (*extraSpecs, error) {
	var result gophercloud.Result
	var extraSpecsData extraSpecs

	url := client.ServiceURL("flavors", flavorUUID, "os-extra_specs")
	_, err := client.Get(url, &result.Body, nil)
	if err != nil {
		return nil, err
	}

	err = result.ExtractInto(&extraSpecsData)
	if err != nil {
		return nil, err
	}

	return &extraSpecsData, nil
}
<commit_msg>avoid zero division error<commit_after>/*******************************************************************************
*
* Copyright 2017 SAP SE
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You should have received a copy of the License along with this
* program. If not, 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 plugins

import (
	"math"

	"strings"

	"fmt"
	"github.com/gophercloud/gophercloud"
	"github.com/gophercloud/gophercloud/openstack"
	"github.com/gophercloud/gophercloud/openstack/compute/v2/flavors"
	"github.com/gophercloud/gophercloud/pagination"
	"github.com/sapcc/limes/pkg/limes"
	"github.com/sapcc/limes/pkg/util"
)

type capacityNovaPlugin struct {
	cfg limes.CapacitorConfiguration
}

type extraSpecs struct {
	ExtraSpecs map[string]string `json:"extra_specs"`
}

func init() {
	limes.RegisterCapacityPlugin(func(c limes.CapacitorConfiguration) limes.CapacityPlugin {
		return &capacityNovaPlugin{c}
	})
}

func (p *capacityNovaPlugin) Client(driver limes.Driver) (*gophercloud.ServiceClient, error) {
	return openstack.NewComputeV2(driver.Client(),
		gophercloud.EndpointOpts{Availability: gophercloud.AvailabilityPublic},
	)
}

func (p *capacityNovaPlugin) ID() string {
	return "nova"
}

//Scrape implements the limes.CapacityPlugin interface.
func (p *capacityNovaPlugin) Scrape(driver limes.Driver) (map[string]map[string]uint64, error) {
	client, err := p.Client(driver)
	if err != nil {
		return nil, err
	}

	var result gophercloud.Result

	//Get absolute limits for a tenant
	url := client.ServiceURL("os-hypervisors", "statistics")
	_, err = client.Get(url, &result.Body, nil)
	if err != nil {
		return nil, err
	}
	var hypervisorData struct {
		HypervisorStatistics struct {
			Vcpus    int `json:"vcpus"`
			MemoryMb int `json:"memory_mb"`
			LocalGb  int `json:"local_gb"`
		} `json:"hypervisor_statistics"`
	}
	err = result.ExtractInto(&hypervisorData)
	if err != nil {
		return nil, err
	}

	//Get availability zones
	url = client.ServiceURL("os-availability-zone")
	_, err = client.Get(url, &result.Body, nil)
	if err != nil {
		return nil, err
	}
	var availabilityZoneData struct {
		AvailabilityZoneInfo []struct {
			ZoneName  string `json:"zoneName"`
			ZoneState struct {
				Available bool `json:"available"`
			} `json:"zoneState"`
		} `json:"availabilityZoneInfo"`
	}
	err = result.ExtractInto(&availabilityZoneData)
	if err != nil {
		return nil, err
	}

	//list all flavors and get max(flavor_size)
	pages, maxFlavorSize := 0, 0.0
	err = flavors.ListDetail(client, nil).EachPage(func(page pagination.Page) (bool, error) {
		pages++
		f, err := flavors.ExtractFlavors(page)
		if err != nil {
			return false, err
		}
		for _, element := range f {
			extras, err := getFlavorExtras(client, element.ID)
			if err != nil {
				util.LogDebug("Failed to get extra specs for flavor: %s.", element.ID)
				return false, err
			}

			//necessary to be able to ignore huge baremetal flavors
			//consider only flavors as defined in extra specs
			var extraSpecs map[string]string
			if p.cfg.Nova.ExtraSpecs != nil {
				extraSpecs = p.cfg.Nova.ExtraSpecs
			}

			for key, value := range extraSpecs {
				if value == strings.Replace(extras.ExtraSpecs[key], "'", "", -1) {
					maxFlavorSize = math.Max(maxFlavorSize, float64(element.Disk))
				}
			}
		}

		return true, nil
	})
	if err != nil {
		return nil, err
	}

	var azCount int

	//count availability zones
	for _, element := range availabilityZoneData.AvailabilityZoneInfo {
		if element.ZoneState.Available == true {
			azCount++
		}
	}

	//get overcommit factor from configuration (hypervisor stats unfortunately is
	//stupid and does not include this factor even though it is in the nova.conf)
	var vcpuOvercommitFactor uint64 = 1
	if p.cfg.Nova.VCPUOvercommitFactor != nil {
		vcpuOvercommitFactor = *p.cfg.Nova.VCPUOvercommitFactor
	}

	//returns something like
	//"volumev2": {
	//	"cores": total_vcpus,
	//	"instances": min(10000 per Availability Zone, local_gb/max(flavor size)),
	//	"ram": total_memory_mb,
	//}

	capacity := map[string]map[string]uint64{
		"compute": {
			"cores": uint64(hypervisorData.HypervisorStatistics.Vcpus) * vcpuOvercommitFactor,
			"ram":   uint64(hypervisorData.HypervisorStatistics.MemoryMb)},
	}

	if maxFlavorSize != 0 {
		capacity["compute"]["instances"] = uint64(math.Min(float64(10000*azCount), float64(hypervisorData.HypervisorStatistics.LocalGb)/maxFlavorSize))
	} else {
		util.LogError("Nova Capacity: Maximal flavor size is 0. Not reporting instances.")
	}

	return capacity, nil

}

//get flavor extra-specs
//result contains
//{ "vmware:hv_enabled" : 'True' }
//which identifies a VM flavor
func getFlavorExtras(client *gophercloud.ServiceClient, flavorUUID string) (*extraSpecs, error) {
	var result gophercloud.Result
	var extraSpecsData extraSpecs

	url := client.ServiceURL("flavors", flavorUUID, "os-extra_specs")
	_, err := client.Get(url, &result.Body, nil)
	if err != nil {
		return nil, err
	}

	err = result.ExtractInto(&extraSpecsData)
	if err != nil {
		return nil, err
	}

	return &extraSpecsData, nil
}
<|endoftext|>


<commit_before>/* Copyright (c) 2014-2015, Daniel Martí <mvdan@mvdan.cc> */
/* See LICENSE for licensing information */

package jutgelint

import (
	"bufio"
	"fmt"
	"io"
	"os/exec"
	"regexp"
	"strconv"
)

var (
	checkOpts = []string{"/home/mvdan/output.json", "--dead-assign", "--fors", "--local-decl", "--variable-init"}

	lineRegex = regexp.MustCompile(`LINE: ([0-9]+)`)
)

type Result struct {
	Line  int
	Func  string
	Short string
	Long  string
}

func RunChecker(i io.Reader) ([]Result, error) {
	//cmd := exec.Command("printer")
	cmd := exec.Command("check", checkOpts...)
	//stdin, err := cmd.StdinPipe()
	//if err != nil {
	//return nil, err
	//}
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		return nil, err
	}
	if err := cmd.Start(); err != nil {
		return nil, err
	}
	//io.Copy(stdin, i)
	//stdin.Close()
	scanner := bufio.NewScanner(stdout)
	var results []Result
	var cur *Result
	for scanner.Scan() {
		line := scanner.Text()
		fmt.Println(line)
		s := lineRegex.FindStringSubmatch(line)
		if s != nil {
			if cur != nil {
				results = append(results, *cur)
			}
			cur = &Result{}
			i, err := strconv.Atoi(s[1])
			if err != nil {
				return nil, err
			}
			cur.Line = i
		}
	}
	return results, nil
}
<commit_msg>Finish parsing check output<commit_after>/* Copyright (c) 2014-2015, Daniel Martí <mvdan@mvdan.cc> */
/* See LICENSE for licensing information */

package jutgelint

import (
	"bufio"
	"io"
	"os/exec"
	"regexp"
	"strconv"
)

var (
	checkOpts = []string{"/home/mvdan/output.json", "--dead-assign", "--fors", "--local-decl", "--variable-init"}

	lineRegex = regexp.MustCompile(`LINE: ([0-9]+)`)
	funcRegex = regexp.MustCompile(`FUNCTION: (.+)`)
	errDescRegex = regexp.MustCompile(`ERROR: ([^-]+) - (.+)`)
)

type Result struct {
	Line  int
	Func  string
	Short string
	Long  string
}

func RunChecker(i io.Reader) ([]Result, error) {
	//cmd := exec.Command("printer")
	cmd := exec.Command("check", checkOpts...)
	//stdin, err := cmd.StdinPipe()
	//if err != nil {
	//return nil, err
	//}
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		return nil, err
	}
	if err := cmd.Start(); err != nil {
		return nil, err
	}
	//io.Copy(stdin, i)
	//stdin.Close()
	scanner := bufio.NewScanner(stdout)
	var results []Result
	var cur *Result
	for scanner.Scan() {
		line := scanner.Text()
		if s := lineRegex.FindStringSubmatch(line); s != nil {
			if cur != nil {
				results = append(results, *cur)
			}
			cur = &Result{}
			i, err := strconv.Atoi(s[1])
			if err != nil {
				return nil, err
			}
			cur.Line = i
		} else if s := funcRegex.FindStringSubmatch(line); s != nil {
			cur.Func = s[1]
		} else if s := errDescRegex.FindStringSubmatch(line); s != nil {
			cur.Short = s[1]
			cur.Long = s[2]
		}

	}
	return results, nil
}
<|endoftext|>


<commit_before>// 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 newton

import (
	"github.com/szabba/md/src/vect"
)

type Body struct {
	Xs, Vs []vect.Vector
	mass   float64
	currAt int
}

// Constructs a body of specified mass suitable for working with the integrator
func NewBody(algo Integrator, mass float64) *Body {

	b := new(Body)

	b.Xs = make([]vect.Vector, algo.StateLen())
	b.Vs = make([]vect.Vector, algo.StateLen())

	b.mass = mass
	b.currAt = algo.CurrentAt()

	return b
}

// Give a body's mass
func (b *Body) Mass() float64 {

	return b.mass
}

// Put new values of x and v a the beginning of the remembered values
//
// The oldest values get discarded
func (b *Body) Shift(x, v vect.Vector) {

	Shift(b.Xs, x)
	Shift(b.Vs, v)
}

// Current positon and velocity
func (b *Body) Now() (x, v vect.Vector) {

	return b.XNow(), b.VNow()
}

// Current position
func (b *Body) XNow() vect.Vector {

	return b.Xs[b.currAt]
}

// Current velocity
func (b *Body) VNow() vect.Vector {

	return b.Vs[b.currAt]
}

// Set current positon and velocity
func (b *Body) SetNow(x, v vect.Vector) {

	b.SetXNow(x)
	b.SetVNow(v)
}

// Set current positon
func (b *Body) SetXNow(x vect.Vector) {

	b.Xs[b.currAt] = x
}

// Set current velocity
func (b *Body) SetVNow(v vect.Vector) {

	b.Vs[b.currAt] = v
}

// Position and velocity delta steps before now
func (b *Body) Before(delta int) (x, v vect.Vector) {

	return b.XBefore(delta), b.VBefore(delta)
}

// Position delta steps before now
func (b *Body) XBefore(delta int) vect.Vector {

	return b.Xs[b.currAt+delta]
}

// Velocity delta steps before now
func (b *Body) VBefore(delta int) vect.Vector {

	return b.Vs[b.currAt+delta]
}

// Set positon and velocity delta steps in the past
func (b *Body) SetBefore(x, v vect.Vector, delta int) {

	b.SetXBefore(x)
	b.SetVBefore(v)
}

// Set positon delta steps in the past
func (b *Body) SetXBefore(x vect.Vector, delta int) {

	b.Xs[b.currAt+delta] = x
}

// Set velocity delta steps in the past
func (b *Body) SetVBefore(v vect.Vector, delta int) {

	b.Vs[b.currAt+delta] = v
}

// Position and velocity delta steps after now
func (b *Body) After(delta int) (x, v vect.Vector) {

	return b.XAfter(delta), b.VAfter(delta)
}

// Position delta steps after now
func (b *Body) XAfter(delta int) vect.Vector {

	return b.Xs[b.currAt+delta]
}

// Velocity delta steps after now
func (b *Body) VAfter(delta int) vect.Vector {

	return b.Vs[b.currAt+delta]
}

// Set positon and velocity delta steps in the future
func (b *Body) SetAfter(x, v vect.Vector, delta int) {

	b.SetXAfter(x)
	b.SetVAfter(v)
}

// Set positon delta steps in the future
func (b *Body) SetXAfter(x vect.Vector, delta int) {

	b.Xs[b.currAt-delta] = x
}

// Set velocity delta steps in the future
func (b *Body) SetVAfter(v vect.Vector, delta int) {

	b.Vs[b.currAt-delta] = v
}

// Shifts all the values in xs by one and puts x at the beginning.
func Shift(xs []vect.Vector, x vect.Vector) {

	for i := len(xs) - 1; i > 0; i-- {

		xs[i] = xs[i-1]
	}

	xs[0] = x
}
<commit_msg>Fix future/past setters on newton.Body<commit_after>// 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 newton

import (
	"github.com/szabba/md/src/vect"
)

type Body struct {
	Xs, Vs []vect.Vector
	mass   float64
	currAt int
}

// Constructs a body of specified mass suitable for working with the integrator
func NewBody(algo Integrator, mass float64) *Body {

	b := new(Body)

	b.Xs = make([]vect.Vector, algo.StateLen())
	b.Vs = make([]vect.Vector, algo.StateLen())

	b.mass = mass
	b.currAt = algo.CurrentAt()

	return b
}

// Give a body's mass
func (b *Body) Mass() float64 {

	return b.mass
}

// Put new values of x and v a the beginning of the remembered values
//
// The oldest values get discarded
func (b *Body) Shift(x, v vect.Vector) {

	Shift(b.Xs, x)
	Shift(b.Vs, v)
}

// Current positon and velocity
func (b *Body) Now() (x, v vect.Vector) {

	return b.XNow(), b.VNow()
}

// Current position
func (b *Body) XNow() vect.Vector {

	return b.Xs[b.currAt]
}

// Current velocity
func (b *Body) VNow() vect.Vector {

	return b.Vs[b.currAt]
}

// Set current positon and velocity
func (b *Body) SetNow(x, v vect.Vector) {

	b.SetXNow(x)
	b.SetVNow(v)
}

// Set current positon
func (b *Body) SetXNow(x vect.Vector) {

	b.Xs[b.currAt] = x
}

// Set current velocity
func (b *Body) SetVNow(v vect.Vector) {

	b.Vs[b.currAt] = v
}

// Position and velocity delta steps before now
func (b *Body) Before(delta int) (x, v vect.Vector) {

	return b.XBefore(delta), b.VBefore(delta)
}

// Position delta steps before now
func (b *Body) XBefore(delta int) vect.Vector {

	return b.Xs[b.currAt+delta]
}

// Velocity delta steps before now
func (b *Body) VBefore(delta int) vect.Vector {

	return b.Vs[b.currAt+delta]
}

// Set positon and velocity delta steps in the past
func (b *Body) SetBefore(x, v vect.Vector, delta int) {

	b.SetXBefore(x, delta)
	b.SetVBefore(v, delta)
}

// Set positon delta steps in the past
func (b *Body) SetXBefore(x vect.Vector, delta int) {

	b.Xs[b.currAt+delta] = x
}

// Set velocity delta steps in the past
func (b *Body) SetVBefore(v vect.Vector, delta int) {

	b.Vs[b.currAt+delta] = v
}

// Position and velocity delta steps after now
func (b *Body) After(delta int) (x, v vect.Vector) {

	return b.XAfter(delta), b.VAfter(delta)
}

// Position delta steps after now
func (b *Body) XAfter(delta int) vect.Vector {

	return b.Xs[b.currAt+delta]
}

// Velocity delta steps after now
func (b *Body) VAfter(delta int) vect.Vector {

	return b.Vs[b.currAt+delta]
}

// Set positon and velocity delta steps in the future
func (b *Body) SetAfter(x, v vect.Vector, delta int) {

	b.SetXAfter(x, delta)
	b.SetVAfter(v, delta)
}

// Set positon delta steps in the future
func (b *Body) SetXAfter(x vect.Vector, delta int) {

	b.Xs[b.currAt-delta] = x
}

// Set velocity delta steps in the future
func (b *Body) SetVAfter(v vect.Vector, delta int) {

	b.Vs[b.currAt-delta] = v
}

// Shifts all the values in xs by one and puts x at the beginning.
func Shift(xs []vect.Vector, x vect.Vector) {

	for i := len(xs) - 1; i > 0; i-- {

		xs[i] = xs[i-1]
	}

	xs[0] = x
}
<|endoftext|>


<commit_before>// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.

package cli // import "miniflux.app/cli"

import (
	"flag"
	"fmt"

	"miniflux.app/config"
	"miniflux.app/database"
	"miniflux.app/logger"
	"miniflux.app/storage"
	"miniflux.app/version"
)

const (
	flagInfoHelp            = "Show application information"
	flagVersionHelp         = "Show application version"
	flagMigrateHelp         = "Run SQL migrations"
	flagFlsuhSessionsHelp   = "Flush all sessions (disconnect users)"
	flagCreateAdminHelp     = "Create admin user"
	flagResetPasswordHelp   = "Reset user password"
	flagResetFeedErrorsHelp = "Clear all feed errors for all users"
	flagDebugModeHelp       = "Show debug logs"
)

// Parse parses command line arguments.
func Parse() {
	var (
		flagInfo            bool
		flagVersion         bool
		flagMigrate         bool
		flagFlushSessions   bool
		flagCreateAdmin     bool
		flagResetPassword   bool
		flagResetFeedErrors bool
		flagDebugMode       bool
	)

	flag.BoolVar(&flagInfo, "info", false, flagInfoHelp)
	flag.BoolVar(&flagInfo, "i", false, flagInfoHelp)
	flag.BoolVar(&flagVersion, "version", false, flagVersionHelp)
	flag.BoolVar(&flagVersion, "v", false, flagVersionHelp)
	flag.BoolVar(&flagMigrate, "migrate", false, flagMigrateHelp)
	flag.BoolVar(&flagFlushSessions, "flush-sessions", false, flagFlsuhSessionsHelp)
	flag.BoolVar(&flagCreateAdmin, "create-admin", false, flagCreateAdminHelp)
	flag.BoolVar(&flagResetPassword, "reset-password", false, flagResetPasswordHelp)
	flag.BoolVar(&flagResetFeedErrors, "reset-feed-errors", false, flagResetFeedErrorsHelp)
	flag.BoolVar(&flagDebugMode, "debug", false, flagDebugModeHelp)
	flag.Parse()

	cfg := config.NewConfig()

	if flagDebugMode || cfg.HasDebugMode() {
		logger.EnableDebug()
	}

	db, err := database.NewConnectionPool(cfg.DatabaseURL(), cfg.DatabaseMinConns(), cfg.DatabaseMaxConns())
	if err != nil {
		logger.Fatal("Unable to connect to the database: %v", err)
	}
	defer db.Close()

	store := storage.NewStorage(db)

	if flagInfo {
		info()
		return
	}

	if flagVersion {
		fmt.Println(version.Version)
		return
	}

	if flagMigrate {
		database.Migrate(db)
		return
	}

	if flagResetFeedErrors {
		store.ResetFeedErrors()
		return
	}

	if flagFlushSessions {
		flushSessions(store)
		return
	}

	if flagCreateAdmin {
		createAdmin(store)
		return
	}

	if flagResetPassword {
		resetPassword(store)
		return
	}

	// Run migrations and start the deamon.
	if cfg.RunMigrations() {
		database.Migrate(db)
	}

	// Create admin user and start the deamon.
	if cfg.CreateAdmin() {
		createAdmin(store)
	}

	startDaemon(cfg, store)
}
<commit_msg>Do not show $DATABASE_URL warning when showing application info<commit_after>// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.

package cli // import "miniflux.app/cli"

import (
	"flag"
	"fmt"

	"miniflux.app/config"
	"miniflux.app/database"
	"miniflux.app/logger"
	"miniflux.app/storage"
	"miniflux.app/version"
)

const (
	flagInfoHelp            = "Show application information"
	flagVersionHelp         = "Show application version"
	flagMigrateHelp         = "Run SQL migrations"
	flagFlsuhSessionsHelp   = "Flush all sessions (disconnect users)"
	flagCreateAdminHelp     = "Create admin user"
	flagResetPasswordHelp   = "Reset user password"
	flagResetFeedErrorsHelp = "Clear all feed errors for all users"
	flagDebugModeHelp       = "Show debug logs"
)

// Parse parses command line arguments.
func Parse() {
	var (
		flagInfo            bool
		flagVersion         bool
		flagMigrate         bool
		flagFlushSessions   bool
		flagCreateAdmin     bool
		flagResetPassword   bool
		flagResetFeedErrors bool
		flagDebugMode       bool
	)

	flag.BoolVar(&flagInfo, "info", false, flagInfoHelp)
	flag.BoolVar(&flagInfo, "i", false, flagInfoHelp)
	flag.BoolVar(&flagVersion, "version", false, flagVersionHelp)
	flag.BoolVar(&flagVersion, "v", false, flagVersionHelp)
	flag.BoolVar(&flagMigrate, "migrate", false, flagMigrateHelp)
	flag.BoolVar(&flagFlushSessions, "flush-sessions", false, flagFlsuhSessionsHelp)
	flag.BoolVar(&flagCreateAdmin, "create-admin", false, flagCreateAdminHelp)
	flag.BoolVar(&flagResetPassword, "reset-password", false, flagResetPasswordHelp)
	flag.BoolVar(&flagResetFeedErrors, "reset-feed-errors", false, flagResetFeedErrorsHelp)
	flag.BoolVar(&flagDebugMode, "debug", false, flagDebugModeHelp)
	flag.Parse()

	cfg := config.NewConfig()

	if flagDebugMode || cfg.HasDebugMode() {
		logger.EnableDebug()
	}

	if flagInfo {
		info()
		return
	}

	if flagVersion {
		fmt.Println(version.Version)
		return
	}

	db, err := database.NewConnectionPool(cfg.DatabaseURL(), cfg.DatabaseMinConns(), cfg.DatabaseMaxConns())
	if err != nil {
		logger.Fatal("Unable to connect to the database: %v", err)
	}
	defer db.Close()

	if flagMigrate {
		database.Migrate(db)
		return
	}

	store := storage.NewStorage(db)

	if flagResetFeedErrors {
		store.ResetFeedErrors()
		return
	}

	if flagFlushSessions {
		flushSessions(store)
		return
	}

	if flagCreateAdmin {
		createAdmin(store)
		return
	}

	if flagResetPassword {
		resetPassword(store)
		return
	}

	// Run migrations and start the deamon.
	if cfg.RunMigrations() {
		database.Migrate(db)
	}

	// Create admin user and start the deamon.
	if cfg.CreateAdmin() {
		createAdmin(store)
	}

	startDaemon(cfg, store)
}
<|endoftext|>


<commit_before>package cli

import (
	"github.com/mehrdadrad/mylg/banner"
	"gopkg.in/readline.v1"
)

type Readline struct {
	instance *readline.Instance
}

func Init(prompt string) *Readline {
	var (
		r         Readline
		err       error
		completer = readline.NewPrefixCompleter(
			readline.PcItem("ping"),
			readline.PcItem("connect",
				readline.PcItem("telia"),
				readline.PcItem("level3"),
			),
			readline.PcItem("node"),
			readline.PcItem("local"),
			readline.PcItem("help"),
		)
	)
	r.instance, err = readline.NewEx(&readline.Config{
		Prompt:          prompt + "> ",
		HistoryFile:     "/tmp/myping",
		InterruptPrompt: "^C",
		EOFPrompt:       "exit",
		AutoComplete:    completer,
	})
	if err != nil {
		panic(err)
	}
	banner.Println()
	return &r
}

func (r *Readline) SetPrompt(p string) {
	r.instance.SetPrompt(p + "> ")
}

func (r *Readline) Run(cmd chan<- string, next chan struct{}) {
	func() {
		for {
			line, err := r.instance.Readline()
			if err != nil { // io.EOF, readline.ErrInterrupt
				break
			}
			cmd <- line
			<-next
		}
	}()
}
<commit_msg>update completer, remove item<commit_after>package cli

import (
	"github.com/mehrdadrad/mylg/banner"
	"gopkg.in/readline.v1"
	"strings"
)

type Readline struct {
	instance  *readline.Instance
	completer *readline.PrefixCompleter
}

func Init(prompt string) *Readline {
	var (
		r         Readline
		err       error
		completer = readline.NewPrefixCompleter(
			readline.PcItem("ping"),
			readline.PcItem("connect",
				readline.PcItem("telia"),
				readline.PcItem("level3"),
			),
			readline.PcItem("node"),
			readline.PcItem("local"),
			readline.PcItem("help"),
		)
	)
	r.completer = completer
	r.instance, err = readline.NewEx(&readline.Config{
		Prompt:          prompt + "> ",
		HistoryFile:     "/tmp/myping",
		InterruptPrompt: "^C",
		EOFPrompt:       "exit",
		AutoComplete:    completer,
	})
	if err != nil {
		panic(err)
	}
	banner.Println()
	return &r
}

func (r *Readline) RemoveItemCompleter(pcItem string) {
	child := []readline.PrefixCompleterInterface{}
	for _, p := range r.completer.Children {
		if strings.TrimSpace(string(p.GetName())) != pcItem {
			child = append(child, p)
		}
	}

	r.completer.Children = child

}

func (r *Readline) UpdateCompleter(pcItem string, pcSubItems map[string]string) {
	child := []readline.PrefixCompleterInterface{}
	var pc readline.PrefixCompleter
	for _, p := range r.completer.Children {
		if strings.TrimSpace(string(p.GetName())) == pcItem {
			c := []readline.PrefixCompleterInterface{}
			for item, _ := range pcSubItems {
				c = append(c, readline.PcItem(item))
			}
			pc.Name = []rune("node ")
			pc.Children = c
			child = append(child, &pc)
		} else {
			child = append(child, p)
		}
	}

	r.completer.Children = child
}

func (r *Readline) SetPrompt(p string) {
	r.instance.SetPrompt(p + "> ")
}

func (r *Readline) Run(cmd chan<- string, next chan struct{}) {
	func() {
		for {
			line, err := r.instance.Readline()
			if err != nil { // io.EOF, readline.ErrInterrupt
				break
			}
			cmd <- line
			<-next
		}
	}()
}
<|endoftext|>


<commit_before>package tchannel

// Copyright (c) 2015 Uber Technologies, Inc.

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

import (
	"errors"
	"fmt"
	"net"
	"os"
	"path/filepath"
	"sync"
	"time"

	"golang.org/x/net/context"
)

var (
	errAlreadyListening = errors.New("channel already listening")
)

const (
	ephemeralHostPort = "0.0.0.0:0"
)

// ChannelOptions are used to control parameters on a create a TChannel
type ChannelOptions struct {
	// Default Connection options
	DefaultConnectionOptions ConnectionOptions

	// The name of the process, for logging and reporting to peers
	ProcessName string

	// The logger to use for this channel
	Logger Logger
}

// A Channel is a bi-directional connection to the peering and routing network.
// Applications can use a Channel to make service calls to remote peers via
// BeginCall, or to listen for incoming calls from peers.  Applications that
// want to receive requests should call one of Serve or ListenAndServe
// TODO(prashant): Shutdown all subchannels + peers when channel is closed.
type Channel struct {
	log               Logger
	connectionOptions ConnectionOptions
	handlers          *handlerMap
	peers             *PeerList
	subChannels       map[string]*SubChannel

	closed   bool
	mut      sync.RWMutex  // protects the listener and the peer info
	peerInfo LocalPeerInfo // May be ephemeral if this is a client only channel
	l        net.Listener  // May be nil if this is a client only channel
}

// NewChannel creates a new Channel.  The new channel can be used to send outbound requests
// to peers, but will not listen or handling incoming requests until one of ListenAndServe
// or Serve is called. The local service name should be passed to serviceName.
func NewChannel(serviceName string, opts *ChannelOptions) (*Channel, error) {
	if opts == nil {
		opts = &ChannelOptions{}
	}

	logger := opts.Logger
	if logger == nil {
		logger = NullLogger
	}

	processName := opts.ProcessName
	if processName == "" {
		processName = fmt.Sprintf("%s[%d]", filepath.Base(os.Args[0]), os.Getpid())
	}

	ch := &Channel{
		connectionOptions: opts.DefaultConnectionOptions,
		peerInfo: LocalPeerInfo{
			PeerInfo: PeerInfo{
				ProcessName: processName,
				HostPort:    ephemeralHostPort,
			},
			ServiceName: serviceName,
		},
		log:         logger,
		handlers:    &handlerMap{},
		subChannels: make(map[string]*SubChannel),
	}

	ch.peers = newPeerList(ch)
	ch.connectionOptions.ChecksumType = ChecksumTypeCrc32
	return ch, nil
}

// Serve serves incoming requests using the provided listener
func (ch *Channel) Serve(l net.Listener) error {
	ch.mut.Lock()

	if ch.l != nil {
		ch.mut.Unlock()
		return errAlreadyListening
	}

	ch.l = l
	ch.peerInfo.HostPort = ch.l.Addr().String()
	ch.mut.Unlock()

	ch.log.Debugf("%v (%v) listening on %v", ch.peerInfo.ProcessName, ch.peerInfo.ServiceName, ch.peerInfo.HostPort)
	return ch.serve()
}

// ListenAndServe listens on the given address and serves incoming requests.
// The port may be 0, in which case the channel will use an OS assigned port
func (ch *Channel) ListenAndServe(hostPort string) error {
	if err := ch.listen(hostPort); err != nil {
		return err
	}

	return ch.serve()
}

// listen listens on the given address but does not begin serving request.
func (ch *Channel) listen(hostPort string) error {
	ch.mut.Lock()
	defer ch.mut.Unlock()

	if ch.l != nil {
		return errAlreadyListening
	}

	addr, err := net.ResolveTCPAddr("tcp", hostPort)
	if err != nil {
		ch.log.Errorf("Could not resolve network %s: %v", hostPort, err)
		return err
	}

	ch.l, err = net.ListenTCP("tcp", addr)
	if err != nil {
		ch.log.Errorf("Could not listen on %s: %v", hostPort, err)
		return err
	}

	ch.peerInfo.HostPort = ch.l.Addr().String()
	ch.log.Infof("%s listening on %s", ch.peerInfo.ProcessName, ch.peerInfo.HostPort)
	return nil
}

// Register registers a handler for a service+operation pair
func (ch *Channel) Register(h Handler, serviceName, operationName string) {
	ch.handlers.register(h, serviceName, operationName)
}

// PeerInfo returns the current peer info for the channel
func (ch *Channel) PeerInfo() LocalPeerInfo {
	ch.mut.RLock()
	defer ch.mut.RUnlock()

	return ch.peerInfo
}

func (ch *Channel) registerNewSubChannel(serviceName string) *SubChannel {
	ch.mut.Lock()
	defer ch.mut.Unlock()

	// Recheck for the subchannel under the write lock.
	if sc, ok := ch.subChannels[serviceName]; ok {
		return sc
	}

	sc := newSubChannel(serviceName, ch.peers)
	ch.subChannels[serviceName] = sc
	return sc
}

// GetSubChannel returns a SubChannel for the given service name.
func (ch *Channel) GetSubChannel(serviceName string) *SubChannel {
	ch.mut.RLock()

	if sc, ok := ch.subChannels[serviceName]; ok {
		ch.mut.RUnlock()
		return sc
	}

	ch.mut.RUnlock()
	return ch.registerNewSubChannel(serviceName)
}

// BeginCall starts a new call to a remote peer, returning an OutboundCall that can
// be used to write the arguments of the call
func (ch *Channel) BeginCall(ctx context.Context, hostPort, serviceName, operationName string, callOptions *CallOptions) (*OutboundCall, error) {
	// Add this peer if we don't already have it.
	ch.peers.GetOrAdd(hostPort)
	sc := ch.GetSubChannel(serviceName)

	// TODO call this specific peer

	return sc.BeginCall(ctx, operationName, callOptions)
}

// serve runs the listener to accept and manage new incoming connections, blocking
// until the channel is closed.
func (ch *Channel) serve() error {
	acceptBackoff := 0 * time.Millisecond

	for {
		netConn, err := ch.l.Accept()
		if err != nil {
			// Backoff from new accepts if this is a temporary error
			if ne, ok := err.(net.Error); ok && ne.Temporary() {
				if acceptBackoff == 0 {
					acceptBackoff = 5 * time.Millisecond
				} else {
					acceptBackoff *= 2
				}
				if max := 1 * time.Second; acceptBackoff > max {
					acceptBackoff = max
				}
				ch.log.Warnf("accept error: %v; retrying in %v", err, acceptBackoff)
				time.Sleep(acceptBackoff)
				continue
			} else {
				// Only log an error if we are not shutdown.
				if ch.Closed() {
					return nil
				}
				ch.log.Errorf("unrecoverable accept error: %v; closing server", err)
				return err
			}
		}

		acceptBackoff = 0

		// Register the connection in the peer once the channel is set up.
		onActive := func(c *Connection) {
			ch.log.Debugf("Add connection as an active peer for %v", c.remotePeerInfo.HostPort)
			p := ch.peers.GetOrAdd(c.remotePeerInfo.HostPort)
			p.AddConnection(c)
		}
		_, err = newInboundConnection(netConn, ch.handlers, ch.PeerInfo(), ch.log, onActive, &ch.connectionOptions)
		if err != nil {
			// Server is getting overloaded - begin rejecting new connections
			ch.log.Errorf("could not create new TChannelConnection for incoming conn: %v", err)
			netConn.Close()
			continue
		}
	}
}

// Closed returns whether this channel has been closed with .Close()
func (ch *Channel) Closed() bool {
	ch.mut.Lock()
	defer ch.mut.Unlock()
	return ch.closed
}

// Close closes the channel including all connections to any active peers.
func (ch *Channel) Close() {
	ch.mut.Lock()
	defer ch.mut.Unlock()

	ch.closed = true
	ch.peers.Close()
}
<commit_msg>move all mutable members of Channel into a separate struct.<commit_after>package tchannel

// Copyright (c) 2015 Uber Technologies, Inc.

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

import (
	"errors"
	"fmt"
	"net"
	"os"
	"path/filepath"
	"sync"
	"time"

	"golang.org/x/net/context"
)

var (
	errAlreadyListening = errors.New("channel already listening")
)

const (
	ephemeralHostPort = "0.0.0.0:0"
)

// ChannelOptions are used to control parameters on a create a TChannel
type ChannelOptions struct {
	// Default Connection options
	DefaultConnectionOptions ConnectionOptions

	// The name of the process, for logging and reporting to peers
	ProcessName string

	// The logger to use for this channel
	Logger Logger
}

// A Channel is a bi-directional connection to the peering and routing network.
// Applications can use a Channel to make service calls to remote peers via
// BeginCall, or to listen for incoming calls from peers.  Applications that
// want to receive requests should call one of Serve or ListenAndServe
// TODO(prashant): Shutdown all subchannels + peers when channel is closed.
type Channel struct {
	log               Logger
	connectionOptions ConnectionOptions
	handlers          *handlerMap
	peers             *PeerList

	// mutable contains all the members of Channel which are mutable.
	mutable struct {
		mut         sync.RWMutex // protects members of the mutable struct.
		closed      bool
		peerInfo    LocalPeerInfo // May be ephemeral if this is a client only channel
		l           net.Listener  // May be nil if this is a client only channel
		subChannels map[string]*SubChannel
	}
}

// NewChannel creates a new Channel.  The new channel can be used to send outbound requests
// to peers, but will not listen or handling incoming requests until one of ListenAndServe
// or Serve is called. The local service name should be passed to serviceName.
func NewChannel(serviceName string, opts *ChannelOptions) (*Channel, error) {
	if opts == nil {
		opts = &ChannelOptions{}
	}

	logger := opts.Logger
	if logger == nil {
		logger = NullLogger
	}

	processName := opts.ProcessName
	if processName == "" {
		processName = fmt.Sprintf("%s[%d]", filepath.Base(os.Args[0]), os.Getpid())
	}

	ch := &Channel{
		connectionOptions: opts.DefaultConnectionOptions,
		log:               logger,
		handlers:          &handlerMap{},
	}
	ch.mutable.peerInfo = LocalPeerInfo{
		PeerInfo: PeerInfo{
			ProcessName: processName,
			HostPort:    ephemeralHostPort,
		},
		ServiceName: serviceName,
	}
	ch.mutable.subChannels = make(map[string]*SubChannel)
	ch.peers = newPeerList(ch)
	ch.connectionOptions.ChecksumType = ChecksumTypeCrc32
	return ch, nil
}

// Serve serves incoming requests using the provided listener
func (ch *Channel) Serve(l net.Listener) error {
	mutable := &ch.mutable
	mutable.mut.Lock()

	if mutable.l != nil {
		mutable.mut.Unlock()
		return errAlreadyListening
	}

	mutable.l = l
	mutable.peerInfo.HostPort = l.Addr().String()
	mutable.mut.Unlock()

	peerInfo := mutable.peerInfo
	ch.log.Debugf("%v (%v) listening on %v", peerInfo.ProcessName, peerInfo.ServiceName, peerInfo.HostPort)
	return ch.serve()
}

// ListenAndServe listens on the given address and serves incoming requests.
// The port may be 0, in which case the channel will use an OS assigned port
func (ch *Channel) ListenAndServe(hostPort string) error {
	if err := ch.listen(hostPort); err != nil {
		return err
	}

	return ch.serve()
}

// listen listens on the given address but does not begin serving request.
func (ch *Channel) listen(hostPort string) error {
	mutable := &ch.mutable
	mutable.mut.Lock()
	defer mutable.mut.Unlock()

	if mutable.l != nil {
		return errAlreadyListening
	}

	addr, err := net.ResolveTCPAddr("tcp", hostPort)
	if err != nil {
		ch.log.Errorf("Could not resolve network %s: %v", hostPort, err)
		return err
	}

	mutable.l, err = net.ListenTCP("tcp", addr)
	if err != nil {
		ch.log.Errorf("Could not listen on %s: %v", hostPort, err)
		return err
	}

	mutable.peerInfo.HostPort = mutable.l.Addr().String()
	peerInfo := mutable.peerInfo
	ch.log.Infof("%s listening on %s", peerInfo.ProcessName, peerInfo.HostPort)
	return nil
}

// Register registers a handler for a service+operation pair
func (ch *Channel) Register(h Handler, serviceName, operationName string) {
	ch.handlers.register(h, serviceName, operationName)
}

// PeerInfo returns the current peer info for the channel
func (ch *Channel) PeerInfo() LocalPeerInfo {
	ch.mutable.mut.RLock()
	defer ch.mutable.mut.RUnlock()

	return ch.mutable.peerInfo
}

func (ch *Channel) registerNewSubChannel(serviceName string) *SubChannel {
	mutable := &ch.mutable
	mutable.mut.Lock()
	defer mutable.mut.Unlock()

	// Recheck for the subchannel under the write lock.
	if sc, ok := mutable.subChannels[serviceName]; ok {
		return sc
	}

	sc := newSubChannel(serviceName, ch.peers)
	mutable.subChannels[serviceName] = sc
	return sc
}

// GetSubChannel returns a SubChannel for the given service name.
func (ch *Channel) GetSubChannel(serviceName string) *SubChannel {
	mutable := &ch.mutable
	mutable.mut.RLock()

	if sc, ok := mutable.subChannels[serviceName]; ok {
		mutable.mut.RUnlock()
		return sc
	}

	mutable.mut.RUnlock()
	return ch.registerNewSubChannel(serviceName)
}

// BeginCall starts a new call to a remote peer, returning an OutboundCall that can
// be used to write the arguments of the call
func (ch *Channel) BeginCall(ctx context.Context, hostPort, serviceName, operationName string, callOptions *CallOptions) (*OutboundCall, error) {
	// Add this peer if we don't already have it.
	ch.peers.GetOrAdd(hostPort)
	sc := ch.GetSubChannel(serviceName)

	// TODO call this specific peer

	return sc.BeginCall(ctx, operationName, callOptions)
}

// serve runs the listener to accept and manage new incoming connections, blocking
// until the channel is closed.
func (ch *Channel) serve() error {
	acceptBackoff := 0 * time.Millisecond

	for {
		netConn, err := ch.mutable.l.Accept()
		if err != nil {
			// Backoff from new accepts if this is a temporary error
			if ne, ok := err.(net.Error); ok && ne.Temporary() {
				if acceptBackoff == 0 {
					acceptBackoff = 5 * time.Millisecond
				} else {
					acceptBackoff *= 2
				}
				if max := 1 * time.Second; acceptBackoff > max {
					acceptBackoff = max
				}
				ch.log.Warnf("accept error: %v; retrying in %v", err, acceptBackoff)
				time.Sleep(acceptBackoff)
				continue
			} else {
				// Only log an error if we are not shutdown.
				if ch.Closed() {
					return nil
				}
				ch.log.Errorf("unrecoverable accept error: %v; closing server", err)
				return err
			}
		}

		acceptBackoff = 0

		// Register the connection in the peer once the channel is set up.
		onActive := func(c *Connection) {
			ch.log.Debugf("Add connection as an active peer for %v", c.remotePeerInfo.HostPort)
			p := ch.peers.GetOrAdd(c.remotePeerInfo.HostPort)
			p.AddConnection(c)
		}
		_, err = newInboundConnection(netConn, ch.handlers, ch.PeerInfo(), ch.log, onActive, &ch.connectionOptions)
		if err != nil {
			// Server is getting overloaded - begin rejecting new connections
			ch.log.Errorf("could not create new TChannelConnection for incoming conn: %v", err)
			netConn.Close()
			continue
		}
	}
}

// Closed returns whether this channel has been closed with .Close()
func (ch *Channel) Closed() bool {
	ch.mutable.mut.Lock()
	defer ch.mutable.mut.Unlock()
	return ch.mutable.closed
}

// Close closes the channel including all connections to any active peers.
func (ch *Channel) Close() {
	ch.mutable.mut.Lock()
	defer ch.mutable.mut.Unlock()

	ch.mutable.closed = true
	ch.peers.Close()
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"io"
	"log"
	"os"
	"os/signal"
	"strconv"
	"syscall"
	"time"

	"github.com/flynn/flynn/Godeps/_workspace/src/github.com/flynn/go-docopt"
	"github.com/flynn/flynn/Godeps/_workspace/src/github.com/heroku/hk/term"
	"github.com/flynn/flynn/controller/client"
	ct "github.com/flynn/flynn/controller/types"
	"github.com/flynn/flynn/pkg/cluster"
)

func init() {
	cmd := register("run", runRun, `
usage: flynn run [-d] [-r <release>] [-e <entrypoint>] <command> [<argument>...]

Run a job.

Options:
   -d, --detached  run job without connecting io streams
   -r <release>    id of release to run (defaults to current app release)
   -e <entrypoint> overwrite the default entrypoint of the release's image
`)
	cmd.optsFirst = true
}

// Declared here for Windows portability
const SIGWINCH syscall.Signal = 28

func runRun(args *docopt.Args, client *controller.Client) error {
	runDetached := args.Bool["--detached"]
	runRelease := args.String["-r"]

	if runRelease == "" {
		release, err := client.GetAppRelease(mustApp())
		if err == controller.ErrNotFound {
			return errors.New("No app release, specify a release with -release")
		}
		if err != nil {
			return err
		}
		runRelease = release.ID
	}
	req := &ct.NewJob{
		Cmd:       append([]string{args.String["<command>"]}, args.All["<argument>"].([]string)...),
		TTY:       term.IsTerminal(os.Stdin) && term.IsTerminal(os.Stdout) && !runDetached,
		ReleaseID: runRelease,
	}
	if args.String["-e"] != "" {
		req.Entrypoint = []string{args.String["-e"]}
	}
	if req.TTY {
		cols, err := term.Cols()
		if err != nil {
			return err
		}
		lines, err := term.Lines()
		if err != nil {
			return err
		}
		req.Columns = cols
		req.Lines = lines
		req.Env = map[string]string{
			"COLUMNS": strconv.Itoa(cols),
			"LINES":   strconv.Itoa(lines),
			"TERM":    os.Getenv("TERM"),
		}
	}

	if runDetached {
		job, err := client.RunJobDetached(mustApp(), req)
		if err != nil {
			return err
		}
		log.Println(job.ID)
		return nil
	}

	rwc, err := client.RunJobAttached(mustApp(), req)
	if err != nil {
		return err
	}
	defer rwc.Close()
	attachClient := cluster.NewAttachClient(rwc)

	if req.TTY {
		if err := term.MakeRaw(os.Stdin); err != nil {
			return err
		}
		defer term.Restore(os.Stdin)
		go func() {
			ch := make(chan os.Signal)
			signal.Notify(ch, SIGWINCH)
			<-ch
			height, err := term.Lines()
			if err != nil {
				return
			}
			width, err := term.Cols()
			if err != nil {
				return
			}
			attachClient.ResizeTTY(uint16(height), uint16(width))
			attachClient.Signal(int(SIGWINCH))
		}()
	}

	go func() {
		ch := make(chan os.Signal)
		signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
		sig := <-ch
		attachClient.Signal(int(sig.(syscall.Signal)))
		time.Sleep(10 * time.Second)
		attachClient.Signal(int(syscall.SIGKILL))
	}()
	go func() {
		io.Copy(attachClient, os.Stdin)
		attachClient.CloseWrite()
	}()
	exitStatus, err := attachClient.Receive(os.Stdout, os.Stderr)
	if err != nil {
		return err
	}
	if req.TTY {
		term.Restore(os.Stdin)
	}
	os.Exit(exitStatus)

	panic("unreached")
}
<commit_msg>cli: Docopt expects at least two spaces between flag and desc.<commit_after>package main

import (
	"errors"
	"io"
	"log"
	"os"
	"os/signal"
	"strconv"
	"syscall"
	"time"

	"github.com/flynn/flynn/Godeps/_workspace/src/github.com/flynn/go-docopt"
	"github.com/flynn/flynn/Godeps/_workspace/src/github.com/heroku/hk/term"
	"github.com/flynn/flynn/controller/client"
	ct "github.com/flynn/flynn/controller/types"
	"github.com/flynn/flynn/pkg/cluster"
)

func init() {
	cmd := register("run", runRun, `
usage: flynn run [-d] [-r <release>] [-e <entrypoint>] <command> [<argument>...]

Run a job.

Options:
   -d, --detached   run job without connecting io streams
   -r <release>     id of release to run (defaults to current app release)
   -e <entrypoint>  overwrite the default entrypoint of the release's image
`)
	cmd.optsFirst = true
}

// Declared here for Windows portability
const SIGWINCH syscall.Signal = 28

func runRun(args *docopt.Args, client *controller.Client) error {
	runDetached := args.Bool["--detached"]
	runRelease := args.String["-r"]

	if runRelease == "" {
		release, err := client.GetAppRelease(mustApp())
		if err == controller.ErrNotFound {
			return errors.New("No app release, specify a release with -release")
		}
		if err != nil {
			return err
		}
		runRelease = release.ID
	}
	req := &ct.NewJob{
		Cmd:       append([]string{args.String["<command>"]}, args.All["<argument>"].([]string)...),
		TTY:       term.IsTerminal(os.Stdin) && term.IsTerminal(os.Stdout) && !runDetached,
		ReleaseID: runRelease,
	}
	if args.String["-e"] != "" {
		req.Entrypoint = []string{args.String["-e"]}
	}
	if req.TTY {
		cols, err := term.Cols()
		if err != nil {
			return err
		}
		lines, err := term.Lines()
		if err != nil {
			return err
		}
		req.Columns = cols
		req.Lines = lines
		req.Env = map[string]string{
			"COLUMNS": strconv.Itoa(cols),
			"LINES":   strconv.Itoa(lines),
			"TERM":    os.Getenv("TERM"),
		}
	}

	if runDetached {
		job, err := client.RunJobDetached(mustApp(), req)
		if err != nil {
			return err
		}
		log.Println(job.ID)
		return nil
	}

	rwc, err := client.RunJobAttached(mustApp(), req)
	if err != nil {
		return err
	}
	defer rwc.Close()
	attachClient := cluster.NewAttachClient(rwc)

	if req.TTY {
		if err := term.MakeRaw(os.Stdin); err != nil {
			return err
		}
		defer term.Restore(os.Stdin)
		go func() {
			ch := make(chan os.Signal)
			signal.Notify(ch, SIGWINCH)
			<-ch
			height, err := term.Lines()
			if err != nil {
				return
			}
			width, err := term.Cols()
			if err != nil {
				return
			}
			attachClient.ResizeTTY(uint16(height), uint16(width))
			attachClient.Signal(int(SIGWINCH))
		}()
	}

	go func() {
		ch := make(chan os.Signal)
		signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
		sig := <-ch
		attachClient.Signal(int(sig.(syscall.Signal)))
		time.Sleep(10 * time.Second)
		attachClient.Signal(int(syscall.SIGKILL))
	}()
	go func() {
		io.Copy(attachClient, os.Stdin)
		attachClient.CloseWrite()
	}()
	exitStatus, err := attachClient.Receive(os.Stdout, os.Stderr)
	if err != nil {
		return err
	}
	if req.TTY {
		term.Restore(os.Stdin)
	}
	os.Exit(exitStatus)

	panic("unreached")
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2014 by Michael Dvorkin. All Rights Reserved.
// Use of this source code is governed by a MIT-style license that can
// be found in the LICENSE file.

package cli

import(
	`github.com/michaeldv/donna`
	`bufio`
	`fmt`
	`os`
	`strings`
)

// Brain-damaged universal chess interface (UCI) protocol as described at
// http://wbec-ridderkerk.nl/html/UCIProtocol.html
func Uci() {
	var game *donna.Game
	var position *donna.Position

	// "uci" command handler.
	doUci := func(args []string) {
		fmt.Println(`Donna v1.0.0 Copyright (c) 2014 by Michael Dvorkin. All Rights Reserved.`)
		fmt.Println(`id author Michael Dvorkin`)
		fmt.Println(`uciok`)
	}

	// "ucinewgame" command handler.
	doUciNewGame := func(args []string) {
		game, position = nil, nil
	}

	// "isready" command handler.
	doIsReady := func(args []string) {
		fmt.Println(`readyok`)
	}

	// "position [startpos | fen ] [ moves ... ]" command handler.
	doPosition := func(args []string) {
		fmt.Printf("%q\n", args)

		// Make sure we've started the game since "ucinewgame" is optional.
		if game == nil || position == nil {
			game = donna.NewGame().Set(`cache`, 64, `movetime`, 5000) // 5s per move.
			position = game.Start()
		}

		switch args[0] {
		case `startpos`:
			args = args[1:]
			position = donna.NewInitialPosition(game)
		case `fen`:
			fen := []string{}
			for _, token := range args[1:] {
				args = args[1:] // Shift the token.
				if token == `moves` {
					break
				}
				fen = append(fen, token)
			}
			fmt.Printf("fen: %s\n", strings.Join(fen, ` `))
			position = donna.NewPositionFromFEN(game, strings.Join(fen, ` `))
		default: return
		}

		fmt.Printf("args: %q\n%s\n", args, position)
		if position != nil && len(args) > 0 && args[0] == `moves` {
			for _, move := range args[1:] {
				args = args[1:] // Shift the move.
				position = position.MakeMove(donna.NewMoveFromNotation(position, move))
			}
		}
		fmt.Printf("%s\n", position)
	}

	var commands = map[string]func([]string){
		`isready`: doIsReady,
		`uci`: doUci,
		`ucinewgame`: doUciNewGame,
		`position`: doPosition,
	}

 	bio := bufio.NewReader(os.Stdin)
	for {
		command, _ := bio.ReadString('\n')
		args := strings.Split(command[:len(command)-1], ` `)
		if args[0] == `quit` {
			break
		}
		if handler, found := commands[args[0]]; found {
			handler(args[1:])
		}
	}
}
<commit_msg>Added go/stop/quit command stubs<commit_after>// Copyright (c) 2013-2014 by Michael Dvorkin. All Rights Reserved.
// Use of this source code is governed by a MIT-style license that can
// be found in the LICENSE file.

package cli

import(
	`github.com/michaeldv/donna`
	`bufio`
	`fmt`
	`os`
	`strings`
)

// Brain-damaged universal chess interface (UCI) protocol as described at
// http://wbec-ridderkerk.nl/html/UCIProtocol.html
func Uci() {
	var game *donna.Game
	var position *donna.Position

	// "uci" command handler.
	doUci := func(args []string) {
		fmt.Println(`Donna v1.0.0 Copyright (c) 2014 by Michael Dvorkin. All Rights Reserved.`)
		fmt.Println(`id author Michael Dvorkin`)
		fmt.Println(`uciok`)
	}

	// "ucinewgame" command handler.
	doUciNewGame := func(args []string) {
		game, position = nil, nil
	}

	// "isready" command handler.
	doIsReady := func(args []string) {
		fmt.Println(`readyok`)
	}

	// "position [startpos | fen ] [ moves ... ]" command handler.
	doPosition := func(args []string) {
		fmt.Printf("%q\n", args)

		// Make sure we've started the game since "ucinewgame" is optional.
		if game == nil || position == nil {
			game = donna.NewGame().Set(`cache`, 64, `movetime`, 5000) // 5s per move.
			position = game.Start()
		}

		switch args[0] {
		case `startpos`:
			args = args[1:]
			position = donna.NewInitialPosition(game)
		case `fen`:
			fen := []string{}
			for _, token := range args[1:] {
				args = args[1:] // Shift the token.
				if token == `moves` {
					break
				}
				fen = append(fen, token)
			}
			fmt.Printf("fen: %s\n", strings.Join(fen, ` `))
			position = donna.NewPositionFromFEN(game, strings.Join(fen, ` `))
		default: return
		}

		fmt.Printf("args: %q\n%s\n", args, position)
		if position != nil && len(args) > 0 && args[0] == `moves` {
			for _, move := range args[1:] {
				args = args[1:] // Shift the move.
				position = position.MakeMove(donna.NewMoveFromNotation(position, move))
			}
		}
		fmt.Printf("%s\n", position)
	}

	// "go [[wtime winc | btime binc ] movestogo] | depth | movetime"
	doGo := func(args []string) {
		fmt.Printf("%q\n", args)
	}

	// Stop calculating as soon as possible.
	doStop := func(args []string) {
	}

	// Quit the program as soon as possible.
	doQuit := func(args []string) {
		fmt.Printf("%q\n", args)
	}
	var commands = map[string]func([]string){
		`isready`: doIsReady,
		`uci`: doUci,
		`ucinewgame`: doUciNewGame,
		`position`: doPosition,
		`go`: doGo,
		`stop`: doStop,
		`quict`: doQuit,
	}

 	bio := bufio.NewReader(os.Stdin)
	for {
		command, _ := bio.ReadString('\n')
		args := strings.Split(command[:len(command)-1], ` `)
		if args[0] == `quit` {
			break
		}
		if handler, found := commands[args[0]]; found {
			handler(args[1:])
		}
	}
}
<|endoftext|>