<commit_before>// Copyright © 2017 Matt Tyler <me@matthewtyler.io>
// 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 gke

import (
	"context"
	"encoding/base64"
	"golang.org/x/oauth2/google"
	"google.golang.org/api/container/v1"
	k8s "k8s.io/client-go/kubernetes"
	rest "k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"
	clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
	"net/http"
	"time"
)

type GkeClient struct {
	Project string
	Zone    string
	client  *http.Client
}

func NewGkeClient(gkeClient *GkeClient, ctx context.Context, project, zone string) error {
	client, err := google.DefaultClient(ctx, container.CloudPlatformScope)
	if err != nil {
		return err
	}
	*gkeClient = GkeClient{project, zone, client}
	return nil
}

func (c *GkeClient) DeleteCluster(clusterId string) (string, error) {
	service, err := container.New(c.client)
	if err != nil {
		return "", err
	}

	projectsZonesClustersService := container.NewProjectsZonesClustersService(service)
	projectZonesClustersDeleteCall := projectsZonesClustersService.Delete(c.Project, c.Zone, clusterId)

	op, err := projectZonesClustersDeleteCall.Do()
	if err != nil {
		return "", err
	}

	return op.Name, nil
}

func (c *Cluster) Client() (*k8s.Clientset, error) {
	config, err := clientcmd.BuildConfigFromFlags(c.Endpoint, "")
	if err != nil {
		return nil, err
	}

	config.AuthProvider = &clientcmdapi.AuthProviderConfig{
		Name: "gcp",
	}

	cacert, _ := base64.StdEncoding.DecodeString(c.Auth.ClusterCaCertificate)

	config.TLSClientConfig = rest.TLSClientConfig{
		CAData: cacert,
	}

	return k8s.NewForConfig(config)
}

type Cluster struct {
	Auth     *container.MasterAuth
	Status   string
	Endpoint string
}

func (c *GkeClient) GetCluster(clusterId string) (*Cluster, error) {
	service, err := container.New(c.client)
	if err != nil {
		return nil, err
	}

	projectsZonesClustersService := container.NewProjectsZonesClustersService(service)
	projectZonesClustersGetCall := projectsZonesClustersService.Get(c.Project, c.Zone, clusterId)
	projectZonesClustersGetCall.Fields("status,endpoint,masterAuth")

	cluster, err := projectZonesClustersGetCall.Do()
	if err != nil {
		return nil, err
	}

	return &Cluster{cluster.MasterAuth, cluster.Status, cluster.Endpoint}, nil
}

func (c *GkeClient) CreateCluster(clusterId string) (string, error) {
	service, err := container.New(c.client)
	if err != nil {
		return "", err
	}

	projectsZonesClustersService := container.NewProjectsZonesClustersService(service)

	createClusterRequest := &container.CreateClusterRequest{
		Cluster: &container.Cluster{
			Name:                  clusterId,
			Description:           "A cluster for e2e testing of elasticsearch-operator",
			InitialClusterVersion: "1.6.4",
			InitialNodeCount:      3,
			NodeConfig: &container.NodeConfig{
				DiskSizeGb:  40,
				ImageType:   "COS",
				MachineType: "f1-micro",
				OauthScopes: []string{
					"https://www.googleapis.com/auth/compute",
					"https://www.googleapis.com/auth/devstorage.read_only",
					"https://www.googleapis.com/auth/logging.write",
					"https://www.googleapis.com/auth/monitoring.write",
					"https://www.googleapis.com/auth/servicecontrol",
					"https://www.googleapis.com/auth/service.management.readonly",
					"https://www.googleapis.com/auth/trace.append",
				},
			},
		},
	}

	createCall := projectsZonesClustersService.Create(c.Project, c.Zone, createClusterRequest)
	op, err := createCall.Do()
	if err != nil {
		return "", err
	}

	return op.Name, nil
}

func (c *GkeClient) Done(operationId string) error {
	service, err := container.New(c.client)
	if err != nil {
		return err
	}

	projectsZonesOperationsService := container.NewProjectsZonesOperationsService(service)
	projectsZonesOperationsGetCall := projectsZonesOperationsService.Get(c.Project, c.Zone, operationId)
	projectsZonesOperationsGetCall.Fields("status")

	DoGetCall := func() (*container.Operation, error) {
		return projectsZonesOperationsGetCall.Do()
	}

	for op, err := DoGetCall(); op.Status != "DONE"; op, err = DoGetCall() {
		if err != nil {
			return err
		}

		time.Sleep(10 * time.Second)
	}

	return nil
}
<commit_msg>e2e: Update to 1.7.2 cluster<commit_after>// Copyright © 2017 Matt Tyler <me@matthewtyler.io>
// 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 gke

import (
	"context"
	"encoding/base64"
	"golang.org/x/oauth2/google"
	"google.golang.org/api/container/v1"
	k8s "k8s.io/client-go/kubernetes"
	rest "k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"
	clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
	"net/http"
	"time"
)

type GkeClient struct {
	Project string
	Zone    string
	client  *http.Client
}

func NewGkeClient(gkeClient *GkeClient, ctx context.Context, project, zone string) error {
	client, err := google.DefaultClient(ctx, container.CloudPlatformScope)
	if err != nil {
		return err
	}
	*gkeClient = GkeClient{project, zone, client}
	return nil
}

func (c *GkeClient) DeleteCluster(clusterId string) (string, error) {
	service, err := container.New(c.client)
	if err != nil {
		return "", err
	}

	projectsZonesClustersService := container.NewProjectsZonesClustersService(service)
	projectZonesClustersDeleteCall := projectsZonesClustersService.Delete(c.Project, c.Zone, clusterId)

	op, err := projectZonesClustersDeleteCall.Do()
	if err != nil {
		return "", err
	}

	return op.Name, nil
}

func (c *Cluster) Client() (*k8s.Clientset, error) {
	config, err := clientcmd.BuildConfigFromFlags(c.Endpoint, "")
	if err != nil {
		return nil, err
	}

	config.AuthProvider = &clientcmdapi.AuthProviderConfig{
		Name: "gcp",
	}

	cacert, _ := base64.StdEncoding.DecodeString(c.Auth.ClusterCaCertificate)

	config.TLSClientConfig = rest.TLSClientConfig{
		CAData: cacert,
	}

	return k8s.NewForConfig(config)
}

type Cluster struct {
	Auth     *container.MasterAuth
	Status   string
	Endpoint string
}

func (c *GkeClient) GetCluster(clusterId string) (*Cluster, error) {
	service, err := container.New(c.client)
	if err != nil {
		return nil, err
	}

	projectsZonesClustersService := container.NewProjectsZonesClustersService(service)
	projectZonesClustersGetCall := projectsZonesClustersService.Get(c.Project, c.Zone, clusterId)
	projectZonesClustersGetCall.Fields("status,endpoint,masterAuth")

	cluster, err := projectZonesClustersGetCall.Do()
	if err != nil {
		return nil, err
	}

	return &Cluster{cluster.MasterAuth, cluster.Status, cluster.Endpoint}, nil
}

func (c *GkeClient) CreateCluster(clusterId string) (string, error) {
	service, err := container.New(c.client)
	if err != nil {
		return "", err
	}

	projectsZonesClustersService := container.NewProjectsZonesClustersService(service)

	createClusterRequest := &container.CreateClusterRequest{
		Cluster: &container.Cluster{
			Name:                  clusterId,
			Description:           "A cluster for e2e testing of elasticsearch-operator",
			InitialClusterVersion: "1.7.2",
			InitialNodeCount:      3,
			EnableKubernetesAlpha: true,
			NodeConfig: &container.NodeConfig{
				DiskSizeGb:  40,
				ImageType:   "COS",
				MachineType: "f1-micro",
				OauthScopes: []string{
					"https://www.googleapis.com/auth/compute",
					"https://www.googleapis.com/auth/devstorage.read_only",
					"https://www.googleapis.com/auth/logging.write",
					"https://www.googleapis.com/auth/monitoring.write",
					"https://www.googleapis.com/auth/servicecontrol",
					"https://www.googleapis.com/auth/service.management.readonly",
					"https://www.googleapis.com/auth/trace.append",
				},
			},
		},
	}

	createCall := projectsZonesClustersService.Create(c.Project, c.Zone, createClusterRequest)
	op, err := createCall.Do()
	if err != nil {
		return "", err
	}

	return op.Name, nil
}

func (c *GkeClient) Done(operationId string) error {
	service, err := container.New(c.client)
	if err != nil {
		return err
	}

	projectsZonesOperationsService := container.NewProjectsZonesOperationsService(service)
	projectsZonesOperationsGetCall := projectsZonesOperationsService.Get(c.Project, c.Zone, operationId)
	projectsZonesOperationsGetCall.Fields("status")

	DoGetCall := func() (*container.Operation, error) {
		return projectsZonesOperationsGetCall.Do()
	}

	for op, err := DoGetCall(); op.Status != "DONE"; op, err = DoGetCall() {
		if err != nil {
			return err
		}

		time.Sleep(10 * time.Second)
	}

	return nil
}
<|endoftext|>


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

// Package ssa defines a representation of the elements of Go programs
// (packages, types, functions, variables and constants) using a
// static single-assignment (SSA) form intermediate representation
// (IR) for the bodies of functions.
//
// THIS INTERFACE IS EXPERIMENTAL AND IS LIKELY TO CHANGE.
//
// For an introduction to SSA form, see
// http://en.wikipedia.org/wiki/Static_single_assignment_form.
// This page provides a broader reading list:
// http://www.dcs.gla.ac.uk/~jsinger/ssa.html.
//
// The level of abstraction of the SSA form is intentionally close to
// the source language to facilitate construction of source analysis
// tools.  It is not intended for machine code generation.
//
// All looping, branching and switching constructs are replaced with
// unstructured control flow.  We may add higher-level control flow
// primitives in the future to facilitate constant-time dispatch of
// switch statements, for example.
//
// Builder encapsulates the tasks of type-checking (using go/types)
// abstract syntax trees (as defined by go/ast) for the source files
// comprising a Go program, and the conversion of each function from
// Go ASTs to the SSA representation.
//
// By supplying an instance of the SourceLocator function prototype,
// clients may control how the builder locates, loads and parses Go
// sources files for imported packages.  This package provides
// MakeGoBuildLoader, which creates a loader that uses go/build to
// locate packages in the Go source distribution, and go/parser to
// parse them.
//
// The builder initially builds a naive SSA form in which all local
// variables are addresses of stack locations with explicit loads and
// stores.  Registerisation of eligible locals and φ-node insertion
// using dominance and dataflow are then performed as a second pass
// called "lifting" to improve the accuracy and performance of
// subsequent analyses; this pass can be skipped by setting the
// NaiveForm builder flag.
//
// The primary interfaces of this package are:
//
//    - Member: a named member of a Go package.
//    - Value: an expression that yields a value.
//    - Instruction: a statement that consumes values and performs computation.
//
// A computation that yields a result implements both the Value and
// Instruction interfaces.  The following table shows for each
// concrete type which of these interfaces it implements.
//
//                      Value?          Instruction?    Member?
//   *Alloc             ✔               ✔
//   *BinOp             ✔               ✔
//   *Builtin           ✔               ✔
//   *Call              ✔               ✔
//   *Capture           ✔
//   *ChangeInterface   ✔               ✔
//   *ChangeType        ✔               ✔
//   *Const             ✔
//   *Convert           ✔               ✔
//   *DebugRef                          ✔
//   *Defer                             ✔
//   *Extract           ✔               ✔
//   *Field             ✔               ✔
//   *FieldAddr         ✔               ✔
//   *Function          ✔                               ✔ (func)
//   *Global            ✔                               ✔ (var)
//   *Go                                ✔
//   *If                                ✔
//   *Index             ✔               ✔
//   *IndexAddr         ✔               ✔
//   *Jump                              ✔
//   *Lookup            ✔               ✔
//   *MakeChan          ✔               ✔
//   *MakeClosure       ✔               ✔
//   *MakeInterface     ✔               ✔
//   *MakeMap           ✔               ✔
//   *MakeSlice         ✔               ✔
//   *MapUpdate                         ✔
//   *NamedConst                                        ✔ (const)
//   *Next              ✔               ✔
//   *Panic                             ✔
//   *Parameter         ✔
//   *Phi               ✔               ✔
//   *Range             ✔               ✔
//   *Return                            ✔
//   *RunDefers                         ✔
//   *Select            ✔               ✔
//   *Send                              ✔
//   *Slice             ✔               ✔
//   *Store                             ✔
//   *Type                                              ✔ (type)
//   *TypeAssert        ✔               ✔
//   *UnOp              ✔               ✔
//
// Other key types in this package include: Program, Package, Function
// and BasicBlock.
//
// The program representation constructed by this package is fully
// resolved internally, i.e. it does not rely on the names of Values,
// Packages, Functions, Types or BasicBlocks for the correct
// interpretation of the program.  Only the identities of objects and
// the topology of the SSA and type graphs are semantically
// significant.  (There is one exception: Ids, used to identify field
// and method names, contain strings.)  Avoidance of name-based
// operations simplifies the implementation of subsequent passes and
// can make them very efficient.  Many objects are nonetheless named
// to aid in debugging, but it is not essential that the names be
// either accurate or unambiguous.  The public API exposes a number of
// name-based maps for client convenience.
//
// The ssa/ssautil package provides various utilities that depend only
// on the public API of this package.
//
// TODO(adonovan): Consider the exceptional control-flow implications
// of defer and recover().
//
// TODO(adonovan): write a how-to document for all the various cases
// of trying to determine corresponding elements across the four
// domains of source locations, ast.Nodes, types.Objects,
// ssa.Values/Instructions.
//
package ssa
<commit_msg>go.tools/ssa: doc: Builtin is not an Instruction.<commit_after>// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package ssa defines a representation of the elements of Go programs
// (packages, types, functions, variables and constants) using a
// static single-assignment (SSA) form intermediate representation
// (IR) for the bodies of functions.
//
// THIS INTERFACE IS EXPERIMENTAL AND IS LIKELY TO CHANGE.
//
// For an introduction to SSA form, see
// http://en.wikipedia.org/wiki/Static_single_assignment_form.
// This page provides a broader reading list:
// http://www.dcs.gla.ac.uk/~jsinger/ssa.html.
//
// The level of abstraction of the SSA form is intentionally close to
// the source language to facilitate construction of source analysis
// tools.  It is not intended for machine code generation.
//
// All looping, branching and switching constructs are replaced with
// unstructured control flow.  We may add higher-level control flow
// primitives in the future to facilitate constant-time dispatch of
// switch statements, for example.
//
// Builder encapsulates the tasks of type-checking (using go/types)
// abstract syntax trees (as defined by go/ast) for the source files
// comprising a Go program, and the conversion of each function from
// Go ASTs to the SSA representation.
//
// By supplying an instance of the SourceLocator function prototype,
// clients may control how the builder locates, loads and parses Go
// sources files for imported packages.  This package provides
// MakeGoBuildLoader, which creates a loader that uses go/build to
// locate packages in the Go source distribution, and go/parser to
// parse them.
//
// The builder initially builds a naive SSA form in which all local
// variables are addresses of stack locations with explicit loads and
// stores.  Registerisation of eligible locals and φ-node insertion
// using dominance and dataflow are then performed as a second pass
// called "lifting" to improve the accuracy and performance of
// subsequent analyses; this pass can be skipped by setting the
// NaiveForm builder flag.
//
// The primary interfaces of this package are:
//
//    - Member: a named member of a Go package.
//    - Value: an expression that yields a value.
//    - Instruction: a statement that consumes values and performs computation.
//
// A computation that yields a result implements both the Value and
// Instruction interfaces.  The following table shows for each
// concrete type which of these interfaces it implements.
//
//                      Value?          Instruction?    Member?
//   *Alloc             ✔               ✔
//   *BinOp             ✔               ✔
//   *Builtin           ✔
//   *Call              ✔               ✔
//   *Capture           ✔
//   *ChangeInterface   ✔               ✔
//   *ChangeType        ✔               ✔
//   *Const             ✔
//   *Convert           ✔               ✔
//   *DebugRef                          ✔
//   *Defer                             ✔
//   *Extract           ✔               ✔
//   *Field             ✔               ✔
//   *FieldAddr         ✔               ✔
//   *Function          ✔                               ✔ (func)
//   *Global            ✔                               ✔ (var)
//   *Go                                ✔
//   *If                                ✔
//   *Index             ✔               ✔
//   *IndexAddr         ✔               ✔
//   *Jump                              ✔
//   *Lookup            ✔               ✔
//   *MakeChan          ✔               ✔
//   *MakeClosure       ✔               ✔
//   *MakeInterface     ✔               ✔
//   *MakeMap           ✔               ✔
//   *MakeSlice         ✔               ✔
//   *MapUpdate                         ✔
//   *NamedConst                                        ✔ (const)
//   *Next              ✔               ✔
//   *Panic                             ✔
//   *Parameter         ✔
//   *Phi               ✔               ✔
//   *Range             ✔               ✔
//   *Return                            ✔
//   *RunDefers                         ✔
//   *Select            ✔               ✔
//   *Send                              ✔
//   *Slice             ✔               ✔
//   *Store                             ✔
//   *Type                                              ✔ (type)
//   *TypeAssert        ✔               ✔
//   *UnOp              ✔               ✔
//
// Other key types in this package include: Program, Package, Function
// and BasicBlock.
//
// The program representation constructed by this package is fully
// resolved internally, i.e. it does not rely on the names of Values,
// Packages, Functions, Types or BasicBlocks for the correct
// interpretation of the program.  Only the identities of objects and
// the topology of the SSA and type graphs are semantically
// significant.  (There is one exception: Ids, used to identify field
// and method names, contain strings.)  Avoidance of name-based
// operations simplifies the implementation of subsequent passes and
// can make them very efficient.  Many objects are nonetheless named
// to aid in debugging, but it is not essential that the names be
// either accurate or unambiguous.  The public API exposes a number of
// name-based maps for client convenience.
//
// The ssa/ssautil package provides various utilities that depend only
// on the public API of this package.
//
// TODO(adonovan): Consider the exceptional control-flow implications
// of defer and recover().
//
// TODO(adonovan): write a how-to document for all the various cases
// of trying to determine corresponding elements across the four
// domains of source locations, ast.Nodes, types.Objects,
// ssa.Values/Instructions.
//
package ssa
<|endoftext|>


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

// Package ssh contains utilities for dealing with SSH connections,
// key management, and so on. All SSH-based command executions in
// Juju should use the Command/ScpCommand functions in this package.
//
package ssh

import (
	"bytes"
	"errors"
	"io"
	"os/exec"
	"syscall"

	"launchpad.net/juju-core/cmd"
)

// Options is a client-implementation independent SSH options set.
type Options struct {
	// ssh server port; zero means use the default (22)
	port int
	// no PTY forced by default
	allocatePTY bool
	// password authentication is disallowed by default
	passwordAuthAllowed bool
	// identities is a sequence of paths to private key/identity files
	// to use when attempting to login. A client implementaton may attempt
	// with additional identities, but must give preference to these
	identities []string
}

// SetPort sets the SSH server port to connect to.
func (o *Options) SetPort(port int) {
	o.port = port
}

// EnablePTY forces the allocation of a pseudo-TTY.
//
// Forcing a pseudo-TTY is required, for example, for sudo
// prompts on the target host.
func (o *Options) EnablePTY() {
	o.allocatePTY = true
}

// AllowPasswordAuthentication allows the SSH
// client to prompt the user for a password.
//
// Password authentication is disallowed by default.
func (o *Options) AllowPasswordAuthentication() {
	o.passwordAuthAllowed = true
}

// SetIdentities sets a sequence of paths to private key/identity files
// to use when attempting login. Client implementations may attempt to
// use additional identities, but must give preference to the ones
// specified here.
func (o *Options) SetIdentities(identityFiles ...string) {
	o.identities = append([]string{}, identityFiles...)
}

// Client is an interface for SSH clients to implement
type Client interface {
	// Command returns a Command for executing a command
	// on the specified host. Each Command is executed
	// within its own SSH session.
	//
	// Host is specified in the format [user@]host.
	Command(host string, command []string, options *Options) *Cmd

	// Copy copies file(s) between local and remote host(s).
	// Paths are specified in the scp format, [[user@]host:]path. If
	// any extra arguments are specified in extraArgs, they are passed
	// verbatim.
	Copy(targets, extraArgs []string, options *Options) error
}

// Cmd represents a command to be (or being) executed
// on a remote host.
type Cmd struct {
	Stdin  io.Reader
	Stdout io.Writer
	Stderr io.Writer
	impl   command
}

// CombinedOutput runs the command, and returns the
// combined stdout/stderr output and result of
// executing the command.
func (c *Cmd) CombinedOutput() ([]byte, error) {
	if c.Stdout != nil {
		return nil, errors.New("ssh: Stdout already set")
	}
	if c.Stderr != nil {
		return nil, errors.New("ssh: Stderr already set")
	}
	var b bytes.Buffer
	c.Stdout = &b
	c.Stderr = &b
	err := c.Run()
	return b.Bytes(), err
}

// Output runs the command, and returns the stdout
// output and result of executing the command.
func (c *Cmd) Output() ([]byte, error) {
	if c.Stdout != nil {
		return nil, errors.New("ssh: Stdout already set")
	}
	var b bytes.Buffer
	c.Stdout = &b
	err := c.Run()
	return b.Bytes(), err
}

// Run runs the command, and returns the result as an error.
func (c *Cmd) Run() error {
	if err := c.Start(); err != nil {
		return err
	}
	err := c.Wait()
	if exitError, ok := err.(*exec.ExitError); ok && exitError != nil {
		status := exitError.ProcessState.Sys().(syscall.WaitStatus)
		if status.Exited() {
			return cmd.NewRcPassthroughError(status.ExitStatus())
		}
	}
	return err
}

// Start starts the command running, but does not wait for
// it to complete. If the command could not be started, an
// error is returned.
func (c *Cmd) Start() error {
	c.impl.SetStdio(c.Stdin, c.Stdout, c.Stderr)
	return c.impl.Start()
}

// Wait waits for the started command to complete,
// and returns the result as an error.
func (c *Cmd) Wait() error {
	return c.impl.Wait()
}

// Kill kills the started command.
func (c *Cmd) Kill() error {
	return c.impl.Kill()
}

// StdinPipe creates a pipe and connects it to
// the command's stdin. The read end of the pipe
// is assigned to c.Stdin.
func (c *Cmd) StdinPipe() (io.WriteCloser, error) {
	wc, r, err := c.impl.StdinPipe()
	if err != nil {
		return nil, err
	}
	c.Stdin = r
	return wc, nil
}

// StdoutPipe creates a pipe and connects it to
// the command's stdout. The write end of the pipe
// is assigned to c.Stdout.
func (c *Cmd) StdoutPipe() (io.ReadCloser, error) {
	rc, w, err := c.impl.StdoutPipe()
	if err != nil {
		return nil, err
	}
	c.Stdout = w
	return rc, nil
}

// StderrPipe creates a pipe and connects it to
// the command's stderr. The write end of the pipe
// is assigned to c.Stderr.
func (c *Cmd) StderrPipe() (io.ReadCloser, error) {
	rc, w, err := c.impl.StderrPipe()
	if err != nil {
		return nil, err
	}
	c.Stderr = w
	return rc, nil
}

// command is an implementation-specific representation of a
// command prepared to execute against a specific host.
type command interface {
	Start() error
	Wait() error
	Kill() error
	SetStdio(stdin io.Reader, stdout, stderr io.Writer)
	StdinPipe() (io.WriteCloser, io.Reader, error)
	StdoutPipe() (io.ReadCloser, io.Writer, error)
	StderrPipe() (io.ReadCloser, io.Writer, error)
}

// DefaultClient is the default SSH client for the process.
//
// If the OpenSSH client is found in $PATH, then it will be
// used for DefaultClient; otherwise, DefaultClient will use
// an embedded client based on go.crypto/ssh.
var DefaultClient Client

// chosenClient holds the type of SSH client created for
// DefaultClient, so that we can log it in Command or Copy.
var chosenClient string

func init() {
	initDefaultClient()
}

func initDefaultClient() {
	if client, err := NewOpenSSHClient(); err == nil {
		DefaultClient = client
		chosenClient = "OpenSSH"
	} else if client, err := NewGoCryptoClient(); err == nil {
		DefaultClient = client
		chosenClient = "go.crypto (embedded)"
	}
}

// Command is a short-cut for DefaultClient.Command.
func Command(host string, command []string, options *Options) *Cmd {
	logger.Debugf("using %s ssh client", chosenClient)
	return DefaultClient.Command(host, command, options)
}

// Copy is a short-cut for DefaultClient.Copy.
func Copy(targets, extraArgs []string, options *Options) error {
	logger.Debugf("using %s ssh client", chosenClient)
	return DefaultClient.Copy(targets, extraArgs, options)
}
<commit_msg>added init call to environment command, fixed import cycle<commit_after>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

// Package ssh contains utilities for dealing with SSH connections,
// key management, and so on. All SSH-based command executions in
// Juju should use the Command/ScpCommand functions in this package.
//
package ssh

import (
	"bytes"
	"errors"
	"io"
	"os/exec"
	"syscall"

	jujuerrors "launchpad.net/juju-core/errors"
)

// Options is a client-implementation independent SSH options set.
type Options struct {
	// ssh server port; zero means use the default (22)
	port int
	// no PTY forced by default
	allocatePTY bool
	// password authentication is disallowed by default
	passwordAuthAllowed bool
	// identities is a sequence of paths to private key/identity files
	// to use when attempting to login. A client implementaton may attempt
	// with additional identities, but must give preference to these
	identities []string
}

// SetPort sets the SSH server port to connect to.
func (o *Options) SetPort(port int) {
	o.port = port
}

// EnablePTY forces the allocation of a pseudo-TTY.
//
// Forcing a pseudo-TTY is required, for example, for sudo
// prompts on the target host.
func (o *Options) EnablePTY() {
	o.allocatePTY = true
}

// AllowPasswordAuthentication allows the SSH
// client to prompt the user for a password.
//
// Password authentication is disallowed by default.
func (o *Options) AllowPasswordAuthentication() {
	o.passwordAuthAllowed = true
}

// SetIdentities sets a sequence of paths to private key/identity files
// to use when attempting login. Client implementations may attempt to
// use additional identities, but must give preference to the ones
// specified here.
func (o *Options) SetIdentities(identityFiles ...string) {
	o.identities = append([]string{}, identityFiles...)
}

// Client is an interface for SSH clients to implement
type Client interface {
	// Command returns a Command for executing a command
	// on the specified host. Each Command is executed
	// within its own SSH session.
	//
	// Host is specified in the format [user@]host.
	Command(host string, command []string, options *Options) *Cmd

	// Copy copies file(s) between local and remote host(s).
	// Paths are specified in the scp format, [[user@]host:]path. If
	// any extra arguments are specified in extraArgs, they are passed
	// verbatim.
	Copy(targets, extraArgs []string, options *Options) error
}

// Cmd represents a command to be (or being) executed
// on a remote host.
type Cmd struct {
	Stdin  io.Reader
	Stdout io.Writer
	Stderr io.Writer
	impl   command
}

// CombinedOutput runs the command, and returns the
// combined stdout/stderr output and result of
// executing the command.
func (c *Cmd) CombinedOutput() ([]byte, error) {
	if c.Stdout != nil {
		return nil, errors.New("ssh: Stdout already set")
	}
	if c.Stderr != nil {
		return nil, errors.New("ssh: Stderr already set")
	}
	var b bytes.Buffer
	c.Stdout = &b
	c.Stderr = &b
	err := c.Run()
	return b.Bytes(), err
}

// Output runs the command, and returns the stdout
// output and result of executing the command.
func (c *Cmd) Output() ([]byte, error) {
	if c.Stdout != nil {
		return nil, errors.New("ssh: Stdout already set")
	}
	var b bytes.Buffer
	c.Stdout = &b
	err := c.Run()
	return b.Bytes(), err
}

// Run runs the command, and returns the result as an error.
func (c *Cmd) Run() error {
	if err := c.Start(); err != nil {
		return err
	}
	err := c.Wait()
	if exitError, ok := err.(*exec.ExitError); ok && exitError != nil {
		status := exitError.ProcessState.Sys().(syscall.WaitStatus)
		if status.Exited() {
			return jujuerrors.NewRcPassthroughError(status.ExitStatus())
		}
	}
	return err
}

// Start starts the command running, but does not wait for
// it to complete. If the command could not be started, an
// error is returned.
func (c *Cmd) Start() error {
	c.impl.SetStdio(c.Stdin, c.Stdout, c.Stderr)
	return c.impl.Start()
}

// Wait waits for the started command to complete,
// and returns the result as an error.
func (c *Cmd) Wait() error {
	return c.impl.Wait()
}

// Kill kills the started command.
func (c *Cmd) Kill() error {
	return c.impl.Kill()
}

// StdinPipe creates a pipe and connects it to
// the command's stdin. The read end of the pipe
// is assigned to c.Stdin.
func (c *Cmd) StdinPipe() (io.WriteCloser, error) {
	wc, r, err := c.impl.StdinPipe()
	if err != nil {
		return nil, err
	}
	c.Stdin = r
	return wc, nil
}

// StdoutPipe creates a pipe and connects it to
// the command's stdout. The write end of the pipe
// is assigned to c.Stdout.
func (c *Cmd) StdoutPipe() (io.ReadCloser, error) {
	rc, w, err := c.impl.StdoutPipe()
	if err != nil {
		return nil, err
	}
	c.Stdout = w
	return rc, nil
}

// StderrPipe creates a pipe and connects it to
// the command's stderr. The write end of the pipe
// is assigned to c.Stderr.
func (c *Cmd) StderrPipe() (io.ReadCloser, error) {
	rc, w, err := c.impl.StderrPipe()
	if err != nil {
		return nil, err
	}
	c.Stderr = w
	return rc, nil
}

// command is an implementation-specific representation of a
// command prepared to execute against a specific host.
type command interface {
	Start() error
	Wait() error
	Kill() error
	SetStdio(stdin io.Reader, stdout, stderr io.Writer)
	StdinPipe() (io.WriteCloser, io.Reader, error)
	StdoutPipe() (io.ReadCloser, io.Writer, error)
	StderrPipe() (io.ReadCloser, io.Writer, error)
}

// DefaultClient is the default SSH client for the process.
//
// If the OpenSSH client is found in $PATH, then it will be
// used for DefaultClient; otherwise, DefaultClient will use
// an embedded client based on go.crypto/ssh.
var DefaultClient Client

// chosenClient holds the type of SSH client created for
// DefaultClient, so that we can log it in Command or Copy.
var chosenClient string

func init() {
	initDefaultClient()
}

func initDefaultClient() {
	if client, err := NewOpenSSHClient(); err == nil {
		DefaultClient = client
		chosenClient = "OpenSSH"
	} else if client, err := NewGoCryptoClient(); err == nil {
		DefaultClient = client
		chosenClient = "go.crypto (embedded)"
	}
}

// Command is a short-cut for DefaultClient.Command.
func Command(host string, command []string, options *Options) *Cmd {
	logger.Debugf("using %s ssh client", chosenClient)
	return DefaultClient.Command(host, command, options)
}

// Copy is a short-cut for DefaultClient.Copy.
func Copy(targets, extraArgs []string, options *Options) error {
	logger.Debugf("using %s ssh client", chosenClient)
	return DefaultClient.Copy(targets, extraArgs, options)
}
<|endoftext|>


<commit_before>package model

import "regexp"

type Sound struct {
	Type      string
	Sharer    *User
	Source    SoundSource
	Timestamp int
}

type Vendor interface {
	GetHash(string) string
}

type SoundSource struct {
	Vendor Vendor
	Url    string
	Hash   string
}

type SoundCloud struct {
	Name string
}

func (sc SoundCloud) GetHash(url string) string {
	// サンクラの場合はこのままハッシュとして使う
	return url
}

type YouTube struct {
	Name string
}

func (yt YouTube) GetHash(url string) string {
	exp, _ := regexp.Compile("(.+)/watch\\?v=([a-zA-Z0-9_-]+)")
	matched := exp.FindAllStringSubmatch(url, 3)
	return matched[0][2]
}

type UnknownVendor struct {
	Name string
}

func (uk UnknownVendor) GetHash(url string) string {
	return ""
}
<commit_msg>Avoid panic<commit_after>package model

import "regexp"

type Sound struct {
	Type      string
	Sharer    *User
	Source    SoundSource
	Timestamp int
}

type Vendor interface {
	GetHash(string) string
}

type SoundSource struct {
	Vendor Vendor
	Url    string
	Hash   string
}

type SoundCloud struct {
	Name string
}

func (sc SoundCloud) GetHash(url string) string {
	// サンクラの場合はこのままハッシュとして使う
	return url
}

type YouTube struct {
	Name string
}

func (yt YouTube) GetHash(url string) string {
	exp, _ := regexp.Compile("(.+)/watch\\?.*v=([a-zA-Z0-9_-]+)")
	matched := exp.FindAllStringSubmatch(url, 3)
	return matched[0][2]
}

type UnknownVendor struct {
	Name string
}

func (uk UnknownVendor) GetHash(url string) string {
	return ""
}
<|endoftext|>


<commit_before>package main

import (
    "fmt"
    "io/ioutil"
	"log"
    "os"
    "os/user"
    "strconv"
	"syscall"

    "github.com/tsuru/config"
    "github.com/dchest/uniuri"
	"github.com/gin-gonic/gin"
	"github.com/jinzhu/gorm"
	_ "github.com/mattn/go-sqlite3"
    _ "github.com/go-sql-driver/mysql"
    _ "github.com/lib/pq"
)

type LMVFile struct {
	Id        int64      `json:"-"`
	Size      int64      `bson:"size"         json:"size"         binding:"required"`
	Name      string     `bson:"name"         json:"name"         binding:"required"`
	Algorithm string     `bson:"algorithm"    json:"algorithm"    binding:"required"`
	Chunks    []LMVChunk `bson:"chunks"       json:"chunks"       binding:"required"`
	Tar       bool       `bson:"tar"          json:"tar"`
	Token     string     `bson:"token"        json:"token"`
}

type LMVChunk struct {
	Id        int64  `json:"-"`
	LMVFileId int64  `json:"-"`
	Hash      string `bson:"hash"         json:"hash"         binding:"required"`
	Size      int64  `bson:"size"         json:"size"         binding:"required"`
	Index     int    `bson:"index"        json:"index"        binding:"required"`
}

type Configuration struct {
    Web     struct {
        Address     string
    }
    System  struct {
        Pid         bool
    }
    Tokens  struct {
    	Pool        []byte
    	Length      int
    }
    Database struct {
        Type        string
        Source      string
    }
}

func GenerateToken(conf Configuration) string {

    return uniuri.NewLenChars(conf.Tokens.Length, conf.Tokens.Pool)

}

func processConfig() Configuration {

    conf := Configuration{}

    if _, err := os.Stat("lmv-tracker.yml"); err == nil {
        config.ReadConfigFile("lmv-tracker.yml")
    } else {
        usr, err := user.Current()

        if err != nil {
            log.Fatal(err)
        }

        if _, err := os.Stat(usr.HomeDir+"/lmv-tracker.yml"); err == nil {
            config.ReadConfigFile(usr.HomeDir+"/lmv-tracker.yml")
        } else {
            if _, err := os.Stat("/etc/lmv-tracker.yml"); err == nil {
        		config.ReadConfigFile("/etc/lmv-tracker.yml")
    	    }
    	}
    }

    address, _ := config.GetString("web:address")
    conf.Web.Address = address

    pid, _ := config.GetBool("system:pid")
    conf.System.Pid = pid

    token_pool, _ := config.GetString("tokens:pool")
    conf.Tokens.Pool = []byte(token_pool)

    fmt.Println(conf.Tokens.Pool)

    token_length, _ := config.GetInt("tokens:length")
    conf.Tokens.Length = token_length

    database_type, _ := config.GetString("database:type")
    conf.Database.Type = database_type

    database_source, _ := config.GetString("database:source")
    conf.Database.Source = database_source

    return conf
}

func main() {

    conf := processConfig()

	if conf.System.Pid {
		ioutil.WriteFile("lmv-tracker.pid", []byte(strconv.Itoa(syscall.Getpid())), 0644)
	}

	db, err := gorm.Open(conf.Database.Type, conf.Database.Source)

	if err != nil {
		log.Fatal(err)
	}

	db.DB()
	db.DB().Ping()

	db.CreateTable(LMVFile{})
	db.CreateTable(LMVChunk{})

	r := gin.Default()

	r.GET("/files/", func(gc *gin.Context) {
		var lmvfiles []LMVFile
		var response []LMVFile

		db.Find(&lmvfiles)

		for _, file := range lmvfiles {

			var chunks []LMVChunk

			db.Where(&LMVChunk{LMVFileId: file.Id}).Find(&chunks)

			file.Chunks = chunks

			response = append(response, file)
		}

		gc.JSON(200, response)
	})

	r.GET("/files/:token/", func(gc *gin.Context) {

		token := gc.Params.ByName("token")
		var lmv_file LMVFile
		var response LMVFile

		db.Where(&LMVFile{Token: token}).First(&lmv_file)

		if lmv_file.Name != "" {

			var chunks []LMVChunk

			db.Where(&LMVChunk{LMVFileId: lmv_file.Id}).Find(&chunks)

			response = lmv_file
			response.Chunks = chunks

			gc.JSON(200, response)

		} else {

			gc.JSON(404, nil)

		}

	})

	r.POST("/files/", func(gc *gin.Context) {

		token := GenerateToken(conf)
		var lmv_file LMVFile

		gc.Bind(&lmv_file)

		for {

			var testFile = LMVFile{}
			db.Where(&LMVFile{Token: token}).First(&testFile)

			if testFile.Name != "" {

				token = GenerateToken(conf)

			} else {

				break

			}

		}

		lmv_file.Token = token

		db.Create(&lmv_file)

		gc.JSON(200, map[string]interface{}{"token": token})

	})

	r.GET("/ping/", func(c *gin.Context) {
		c.String(200, "pong")
	})

	r.Run(conf.Web.Address)

}
<commit_msg>Provide defaults is a config isn't found<commit_after>package main

import (
    "fmt"
    "io/ioutil"
	"log"
    "os"
    "os/user"
    "strconv"
	"syscall"

    "github.com/tsuru/config"
    "github.com/dchest/uniuri"
	"github.com/gin-gonic/gin"
	"github.com/jinzhu/gorm"
	_ "github.com/mattn/go-sqlite3"
    _ "github.com/go-sql-driver/mysql"
    _ "github.com/lib/pq"
)

type LMVFile struct {
	Id        int64      `json:"-"`
	Size      int64      `bson:"size"         json:"size"         binding:"required"`
	Name      string     `bson:"name"         json:"name"         binding:"required"`
	Algorithm string     `bson:"algorithm"    json:"algorithm"    binding:"required"`
	Chunks    []LMVChunk `bson:"chunks"       json:"chunks"       binding:"required"`
	Tar       bool       `bson:"tar"          json:"tar"`
	Token     string     `bson:"token"        json:"token"`
}

type LMVChunk struct {
	Id        int64  `json:"-"`
	LMVFileId int64  `json:"-"`
	Hash      string `bson:"hash"         json:"hash"         binding:"required"`
	Size      int64  `bson:"size"         json:"size"         binding:"required"`
	Index     int    `bson:"index"        json:"index"        binding:"required"`
}

type Configuration struct {
    Web     struct {
        Address     string
    }
    System  struct {
        Pid         bool
    }
    Tokens  struct {
    	Pool        []byte
    	Length      int
    }
    Database struct {
        Type        string
        Source      string
    }
}

func GenerateToken(conf Configuration) string {

    return uniuri.NewLenChars(conf.Tokens.Length, conf.Tokens.Pool)

}

func processConfig() Configuration {

    conf := Configuration{}

    foundConf := true

    if _, err := os.Stat("lmv-tracker.yml"); err == nil {
        config.ReadConfigFile("lmv-tracker.yml")
    } else {
        usr, err := user.Current()

        if err != nil {
            log.Fatal(err)
        }

        if _, err := os.Stat(usr.HomeDir+"/lmv-tracker.yml"); err == nil {
            config.ReadConfigFile(usr.HomeDir+"/lmv-tracker.yml")
        } else {
            if _, err := os.Stat("/etc/lmv-tracker.yml"); err == nil {
        		config.ReadConfigFile("/etc/lmv-tracker.yml")
    	    } else {
                foundConf = false
            }
    	}
    }

    if foundConf {
        address, _ := config.GetString("web:address")
        conf.Web.Address = address

        pid, _ := config.GetBool("system:pid")
        conf.System.Pid = pid

        token_pool, _ := config.GetString("tokens:pool")
        conf.Tokens.Pool = []byte(token_pool)

        fmt.Println(conf.Tokens.Pool)

        token_length, _ := config.GetInt("tokens:length")
        conf.Tokens.Length = token_length

        database_type, _ := config.GetString("database:type")
        conf.Database.Type = database_type

        database_source, _ := config.GetString("database:source")
        conf.Database.Source = database_source
    } else {
        conf.Web.Address = ":8080"
        conf.System.Pid = false
        conf.Tokens.Pool = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
        conf.Tokens.Length = 10
        conf.Database.Type = "sqlite3"
        conf.Database.Source = "lmv-tracker.db"
    }

    return conf

}

func main() {

    conf := processConfig()

	if conf.System.Pid {
		ioutil.WriteFile("lmv-tracker.pid", []byte(strconv.Itoa(syscall.Getpid())), 0644)
	}

	db, err := gorm.Open(conf.Database.Type, conf.Database.Source)

	if err != nil {
		log.Fatal(err)
	}

	db.DB()
	db.DB().Ping()

	db.CreateTable(LMVFile{})
	db.CreateTable(LMVChunk{})

	r := gin.Default()

	r.GET("/files/", func(gc *gin.Context) {
		var lmvfiles []LMVFile
		var response []LMVFile

		db.Find(&lmvfiles)

		for _, file := range lmvfiles {

			var chunks []LMVChunk

			db.Where(&LMVChunk{LMVFileId: file.Id}).Find(&chunks)

			file.Chunks = chunks

			response = append(response, file)
		}

		gc.JSON(200, response)
	})

	r.GET("/files/:token/", func(gc *gin.Context) {

		token := gc.Params.ByName("token")
		var lmv_file LMVFile
		var response LMVFile

		db.Where(&LMVFile{Token: token}).First(&lmv_file)

		if lmv_file.Name != "" {

			var chunks []LMVChunk

			db.Where(&LMVChunk{LMVFileId: lmv_file.Id}).Find(&chunks)

			response = lmv_file
			response.Chunks = chunks

			gc.JSON(200, response)

		} else {

			gc.JSON(404, nil)

		}

	})

	r.POST("/files/", func(gc *gin.Context) {

		token := GenerateToken(conf)
		var lmv_file LMVFile

		gc.Bind(&lmv_file)

		for {

			var testFile = LMVFile{}
			db.Where(&LMVFile{Token: token}).First(&testFile)

			if testFile.Name != "" {

				token = GenerateToken(conf)

			} else {

				break

			}

		}

		lmv_file.Token = token

		db.Create(&lmv_file)

		gc.JSON(200, map[string]interface{}{"token": token})

	})

	r.GET("/ping/", func(c *gin.Context) {
		c.String(200, "pong")
	})

	r.Run(conf.Web.Address)

}
<|endoftext|>


<commit_before>package rabric

import (
	"fmt"
	"net/http"

	"github.com/gorilla/websocket"
)

const (
	jsonWebsocketProtocol    = "wamp.2.json"
	msgpackWebsocketProtocol = "wamp.2.msgpack"
)

type invalidPayload byte

func (e invalidPayload) Error() string {
	return fmt.Sprintf("Invalid payloadType: %d", e)
}

type protocolExists string

func (e protocolExists) Error() string {
	return "This protocol has already been registered: " + string(e)
}

type protocol struct {
	payloadType int
	serializer  Serializer
}

// WebsocketServer handles websocket connections.
type WebsocketServer struct {
	Node
	Upgrader *websocket.Upgrader

	protocols map[string]protocol

	// The serializer to use for text frames. Defaults to JSONSerializer.
	TextSerializer Serializer

	// The serializer to use for binary frames. Defaults to JSONSerializer.
	BinarySerializer Serializer
}

// Creates a new WebsocketServer from a map of realms
func NewWebsocketServer(pdid string) (*WebsocketServer, error) {
	//out.Debug("NewWebsocketServer")

	r := NewNode(pdid)
	s := newWebsocketServer(r)
	return s, nil
}

// Creates a new WebsocketServer with a single basic realm
func NewBasicWebsocketServer(pdid string) *WebsocketServer {
	s, _ := NewWebsocketServer(pdid)
	return s
}

func newWebsocketServer(r Node) *WebsocketServer {
	s := &WebsocketServer{
		Node:      r,
		protocols: make(map[string]protocol),
	}

	s.Upgrader = &websocket.Upgrader{
		CheckOrigin: func(r *http.Request) bool { return true },
	}
	s.RegisterProtocol(jsonWebsocketProtocol, websocket.TextMessage, new(JSONSerializer))
	s.RegisterProtocol(msgpackWebsocketProtocol, websocket.BinaryMessage, new(MessagePackSerializer))

	return s
}

// RegisterProtocol registers a serializer that should be used for a given protocol string and payload type.
func (s *WebsocketServer) RegisterProtocol(proto string, payloadType int, serializer Serializer) error {
	//out.Debug("RegisterProtocol:", proto)

	if payloadType != websocket.TextMessage && payloadType != websocket.BinaryMessage {
		return invalidPayload(payloadType)
	}

	if _, ok := s.protocols[proto]; ok {
		return protocolExists(proto)
	}

	s.protocols[proto] = protocol{payloadType, serializer}
	s.Upgrader.Subprotocols = append(s.Upgrader.Subprotocols, proto)
	return nil
}

// GetLocalClient returns a client connected to the specified realm
func (s *WebsocketServer) GetLocalClient(realm string, details map[string]interface{}) (*Client, error) {
	//out.Debug("Request for local client for realm: %s", realm)
	if peer, err := s.Node.GetLocalPeer(URI(realm), details); err != nil {
		return nil, err
	} else {
		c := NewClient(peer)
		go c.Receive()
		return c, nil
	}
}

// ServeHTTP handles a new HTTP connection.
func (s *WebsocketServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	//out.Debug("WebsocketServer.ServeHTTP", r.Method, r.RequestURI)

	// TODO: subprotocol?
	conn, err := s.Upgrader.Upgrade(w, r, nil)

	if err != nil {
		out.Critical("Error upgrading to websocket connection:", err)
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	s.handleWebsocket(conn)
}

func (s *WebsocketServer) handleWebsocket(conn *websocket.Conn) {
	//out.Debug("New WS connection: %s", conn)
	var serializer Serializer
	var payloadType int
	if proto, ok := s.protocols[conn.Subprotocol()]; ok {
		serializer = proto.serializer
		payloadType = proto.payloadType
	} else {
		// TODO: this will not currently ever be hit because
		//       gorilla/websocket will reject the conncetion
		//       if the subprotocol isn't registered
		switch conn.Subprotocol() {
		case jsonWebsocketProtocol:
			serializer = new(JSONSerializer)
			payloadType = websocket.TextMessage
		case msgpackWebsocketProtocol:
			serializer = new(MessagePackSerializer)
			payloadType = websocket.BinaryMessage
		default:
			conn.Close()
			return
		}
	}

	peer := websocketPeer{
		conn:        conn,
		serializer:  serializer,
		messages:    make(chan Message, 10),
		payloadType: payloadType,
	}
	go peer.run()

	logErr(s.Node.Accept(&peer))
}
<commit_msg>added a top level pdid<commit_after>package rabric

import (
	"fmt"
	"net/http"

	"github.com/gorilla/websocket"
)

const (
	jsonWebsocketProtocol    = "wamp.2.json"
	msgpackWebsocketProtocol = "wamp.2.msgpack"
)

type invalidPayload byte

func (e invalidPayload) Error() string {
	return fmt.Sprintf("Invalid payloadType: %d", e)
}

type protocolExists string

func (e protocolExists) Error() string {
	return "This protocol has already been registered: " + string(e)
}

type protocol struct {
	payloadType int
	serializer  Serializer
}

// WebsocketServer handles websocket connections.
type WebsocketServer struct {
	Node
	Upgrader *websocket.Upgrader

	protocols map[string]protocol

	// The serializer to use for text frames. Defaults to JSONSerializer.
	TextSerializer Serializer

	// The serializer to use for binary frames. Defaults to JSONSerializer.
	BinarySerializer Serializer
}

func CreateNode(pdid string) *WebsocketServer {
	s, _ := NewWebsocketServer(pdid)
	return s
}

// Creates a new WebsocketServer from a map of realms
func NewWebsocketServer(pdid string) (*WebsocketServer, error) {
	r := NewNode(pdid)
	s := newWebsocketServer(r)
	return s, nil
}

// Creates a new WebsocketServer with a single basic realm
func NewBasicWebsocketServer(pdid string) *WebsocketServer {
	s, _ := NewWebsocketServer(pdid)
	return s
}

func newWebsocketServer(r Node) *WebsocketServer {
	s := &WebsocketServer{
		Node:      r,
		protocols: make(map[string]protocol),
	}

	s.Upgrader = &websocket.Upgrader{
		CheckOrigin: func(r *http.Request) bool { return true },
	}
	s.RegisterProtocol(jsonWebsocketProtocol, websocket.TextMessage, new(JSONSerializer))
	s.RegisterProtocol(msgpackWebsocketProtocol, websocket.BinaryMessage, new(MessagePackSerializer))

	return s
}

// RegisterProtocol registers a serializer that should be used for a given protocol string and payload type.
func (s *WebsocketServer) RegisterProtocol(proto string, payloadType int, serializer Serializer) error {
	//out.Debug("RegisterProtocol:", proto)

	if payloadType != websocket.TextMessage && payloadType != websocket.BinaryMessage {
		return invalidPayload(payloadType)
	}

	if _, ok := s.protocols[proto]; ok {
		return protocolExists(proto)
	}

	s.protocols[proto] = protocol{payloadType, serializer}
	s.Upgrader.Subprotocols = append(s.Upgrader.Subprotocols, proto)
	return nil
}

// GetLocalClient returns a client connected to the specified realm
func (s *WebsocketServer) GetLocalClient(realm string, details map[string]interface{}) (*Client, error) {
	//out.Debug("Request for local client for realm: %s", realm)
	if peer, err := s.Node.GetLocalPeer(URI(realm), details); err != nil {
		return nil, err
	} else {
		c := NewClient(peer)
		go c.Receive()
		return c, nil
	}
}

// ServeHTTP handles a new HTTP connection.
func (s *WebsocketServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	//out.Debug("WebsocketServer.ServeHTTP", r.Method, r.RequestURI)

	// TODO: subprotocol?
	conn, err := s.Upgrader.Upgrade(w, r, nil)

	if err != nil {
		out.Critical("Error upgrading to websocket connection:", err)
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	s.handleWebsocket(conn)
}

func (s *WebsocketServer) handleWebsocket(conn *websocket.Conn) {
	//out.Debug("New WS connection: %s", conn)
	var serializer Serializer
	var payloadType int
	if proto, ok := s.protocols[conn.Subprotocol()]; ok {
		serializer = proto.serializer
		payloadType = proto.payloadType
	} else {
		// TODO: this will not currently ever be hit because
		//       gorilla/websocket will reject the conncetion
		//       if the subprotocol isn't registered
		switch conn.Subprotocol() {
		case jsonWebsocketProtocol:
			serializer = new(JSONSerializer)
			payloadType = websocket.TextMessage
		case msgpackWebsocketProtocol:
			serializer = new(MessagePackSerializer)
			payloadType = websocket.BinaryMessage
		default:
			conn.Close()
			return
		}
	}

	peer := websocketPeer{
		conn:        conn,
		serializer:  serializer,
		messages:    make(chan Message, 10),
		payloadType: payloadType,
	}
	go peer.run()

	logErr(s.Node.Accept(&peer))
}
<|endoftext|>


<commit_before>/*
 * This file is part of the KubeVirt project
 *
 * 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.
 *
 * Copyright 2018 Red Hat, Inc.
 *
 */

//go:generate mockgen -source $GOFILE -package=$GOPACKAGE -destination=generated_mock_$GOFILE

package network

import (
	"fmt"
	"net"

	"github.com/vishvananda/netlink"

	"kubevirt.io/kubevirt/pkg/api/v1"
	"kubevirt.io/kubevirt/pkg/log"
	"kubevirt.io/kubevirt/pkg/precond"
	"kubevirt.io/kubevirt/pkg/virt-launcher/virtwrap/api"
)

var bridgeFakeIP = "169.254.75.1%d/32"

type BindMechanism interface {
	discoverPodNetworkInterface() error
	preparePodNetworkInterfaces() error
	decorateConfig() error
	loadCachedInterface(name string) (bool, error)
	setCachedInterface(name string) error
}

type PodInterface struct{}

func (l *PodInterface) Unplug() {}

func findInterfaceByName(ifaces []api.Interface, name string) (int, error) {
	for i, iface := range ifaces {
		if iface.Alias.Name == name {
			return i, nil
		}
	}
	return 0, fmt.Errorf("failed to find interface with alias set to %s", name)
}

// Plug connect a Pod network device to the virtual machine
func (l *PodInterface) Plug(iface *v1.Interface, network *v1.Network, domain *api.Domain, podInterfaceName string) error {
	precond.MustNotBeNil(domain)
	initHandler()

	// There is nothing to plug for SR-IOV devices
	if iface.SRIOV != nil {
		return nil
	}

	driver, err := getBinding(iface, domain, podInterfaceName)
	if err != nil {
		return err
	}

	isExist, err := driver.loadCachedInterface(iface.Name)
	if err != nil {
		return err
	}

	if !isExist {
		err := driver.discoverPodNetworkInterface()
		if err != nil {
			return err
		}

		if err := driver.preparePodNetworkInterfaces(); err != nil {
			log.Log.Reason(err).Critical("failed to prepared pod networking")
			panic(err)
		}

		// After the network is configured, cache the result
		// in case this function is called again.
		err = driver.decorateConfig()
		if err != nil {
			log.Log.Reason(err).Critical("failed to create libvirt configuration")
			panic(err)
		}

		err = driver.setCachedInterface(iface.Name)
		if err != nil {
			log.Log.Reason(err).Critical("failed to save interface configuration")
			panic(err)
		}
	}

	return nil
}

func getBinding(iface *v1.Interface, domain *api.Domain, podInterfaceName string) (BindMechanism, error) {
	podInterfaceNum, err := findInterfaceByName(domain.Spec.Devices.Interfaces, iface.Name)
	if err != nil {
		return nil, err
	}

	populateMacAddress := func(vif *VIF, iface *v1.Interface) error {
		if iface.MacAddress != "" {
			macAddress, err := net.ParseMAC(iface.MacAddress)
			if err != nil {
				return err
			}
			vif.MAC = macAddress
		}
		return nil
	}

	if iface.Bridge != nil {
		vif := &VIF{Name: podInterfaceName}
		populateMacAddress(vif, iface)
		return &BridgePodInterface{iface: iface,
			vif:                 vif,
			domain:              domain,
			podInterfaceNum:     podInterfaceNum,
			podInterfaceName:    podInterfaceName,
			bridgeInterfaceName: fmt.Sprintf("k6t-%s", podInterfaceName)}, nil
	}
	if iface.Slirp != nil {
		return &SlirpPodInterface{iface: iface, domain: domain, podInterfaceNum: podInterfaceNum}, nil
	}
	return nil, fmt.Errorf("Not implemented")
}

type BridgePodInterface struct {
	vif                 *VIF
	iface               *v1.Interface
	podNicLink          netlink.Link
	domain              *api.Domain
	isLayer2            bool
	podInterfaceNum     int
	podInterfaceName    string
	bridgeInterfaceName string
}

func (b *BridgePodInterface) discoverPodNetworkInterface() error {
	link, err := Handler.LinkByName(b.podInterfaceName)
	if err != nil {
		log.Log.Reason(err).Errorf("failed to get a link for interface: %s", b.podInterfaceName)
		return err
	}
	b.podNicLink = link

	// get IP address
	addrList, err := Handler.AddrList(b.podNicLink, netlink.FAMILY_V4)
	if err != nil {
		log.Log.Reason(err).Errorf("failed to get an ip address for %s", b.podInterfaceName)
		return err
	}
	if len(addrList) == 0 {
		b.isLayer2 = true
	} else {
		b.vif.IP = addrList[0]
		b.isLayer2 = false
	}

	if len(b.vif.MAC) == 0 {
		// Get interface MAC address
		mac, err := Handler.GetMacDetails(b.podInterfaceName)
		if err != nil {
			log.Log.Reason(err).Errorf("failed to get MAC for %s", b.podInterfaceName)
			return err
		}
		b.vif.MAC = mac
	}

	// Get interface MTU
	b.vif.Mtu = uint16(b.podNicLink.Attrs().MTU)

	if !b.isLayer2 {
		// Handle interface routes
		if err := b.setInterfaceRoutes(); err != nil {
			return err
		}
	}
	return nil
}

func (b *BridgePodInterface) preparePodNetworkInterfaces() error {
	// Set interface link to down to change its MAC address
	if err := Handler.LinkSetDown(b.podNicLink); err != nil {
		log.Log.Reason(err).Errorf("failed to bring link down for interface: %s", b.podInterfaceName)
		return err
	}

	if _, err := Handler.SetRandomMac(b.podInterfaceName); err != nil {
		return err
	}

	if err := Handler.LinkSetUp(b.podNicLink); err != nil {
		log.Log.Reason(err).Errorf("failed to bring link up for interface: %s", b.podInterfaceName)
		return err
	}

	if err := b.createBridge(); err != nil {
		return err
	}

	if !b.isLayer2 {
		// Remove IP from POD interface
		err := Handler.AddrDel(b.podNicLink, &b.vif.IP)

		if err != nil {
			log.Log.Reason(err).Errorf("failed to delete address for interface: %s", b.podInterfaceName)
			return err
		}

		b.startDHCPServer()
	}

	if err := Handler.LinkSetLearningOff(b.podNicLink); err != nil {
		log.Log.Reason(err).Errorf("failed to disable mac learning for interface: %s", b.podInterfaceName)
		return err
	}

	// turn TX offload checksum because it causes dhcp failures
	if err := EthtoolTXOff("k6t-eth0"); err != nil {
		log.Log.Reason(err).Errorf("Failed to set tx offload for interface %s off", "k6t-eth0")
		return err
	}

	if err := EthtoolTXOff("vnet0"); err != nil {
		log.Log.Reason(err).Errorf("Failed to set tx offload for interface %s off", "vnet0")
		return err
	}

	return nil
}

func (b *BridgePodInterface) startDHCPServer() {
	// Start DHCP Server
	fakeServerAddr, _ := netlink.ParseAddr(fmt.Sprintf(bridgeFakeIP, b.podInterfaceNum))
	Handler.StartDHCP(b.vif, fakeServerAddr, b.bridgeInterfaceName, b.iface.DHCPOptions)
}

func (b *BridgePodInterface) decorateConfig() error {
	b.domain.Spec.Devices.Interfaces[b.podInterfaceNum].MAC = &api.MAC{MAC: b.vif.MAC.String()}

	return nil
}

func (b *BridgePodInterface) loadCachedInterface(name string) (bool, error) {
	var ifaceConfig api.Interface

	isExist, err := readFromCachedFile(name, interfaceCacheFile, &ifaceConfig)
	if err != nil {
		return false, err
	}

	if isExist {
		b.domain.Spec.Devices.Interfaces[b.podInterfaceNum] = ifaceConfig
		return true, nil
	}

	return false, nil
}

func (b *BridgePodInterface) setCachedInterface(name string) error {
	err := writeToCachedFile(&b.domain.Spec.Devices.Interfaces[b.podInterfaceNum], interfaceCacheFile, name)
	return err
}

func (b *BridgePodInterface) setInterfaceRoutes() error {
	routes, err := Handler.RouteList(b.podNicLink, netlink.FAMILY_V4)
	if err != nil {
		log.Log.Reason(err).Errorf("failed to get routes for %s", b.podInterfaceName)
		return err
	}
	if len(routes) == 0 {
		return fmt.Errorf("No gateway address found in routes for %s", b.podInterfaceName)
	}
	b.vif.Gateway = routes[0].Gw
	if len(routes) > 1 {
		dhcpRoutes := filterPodNetworkRoutes(routes, b.vif)
		b.vif.Routes = &dhcpRoutes
	}
	return nil
}

func (b *BridgePodInterface) createBridge() error {
	// Create a bridge
	bridge := &netlink.Bridge{
		LinkAttrs: netlink.LinkAttrs{
			Name: b.bridgeInterfaceName,
		},
	}
	err := Handler.LinkAdd(bridge)
	if err != nil {
		log.Log.Reason(err).Errorf("failed to create a bridge")
		return err
	}
	netlink.LinkSetMaster(b.podNicLink, bridge)

	err = Handler.LinkSetUp(bridge)
	if err != nil {
		log.Log.Reason(err).Errorf("failed to bring link up for interface: %s", b.bridgeInterfaceName)
		return err
	}

	// set fake ip on a bridge
	fakeaddr, err := Handler.ParseAddr(fmt.Sprintf(bridgeFakeIP, b.podInterfaceNum))
	if err != nil {
		log.Log.Reason(err).Errorf("failed to bring link up for interface: %s", b.bridgeInterfaceName)
		return err
	}

	if err := Handler.AddrAdd(bridge, fakeaddr); err != nil {
		log.Log.Reason(err).Errorf("failed to set bridge IP")
		return err
	}

	return nil
}

type SlirpPodInterface struct {
	iface           *v1.Interface
	domain          *api.Domain
	podInterfaceNum int
}

func (s *SlirpPodInterface) discoverPodNetworkInterface() error {
	s.domain.Spec.QEMUCmd.QEMUArg = append(s.domain.Spec.QEMUCmd.QEMUArg, api.Arg{Value: "-device"})
	return nil
}

func (s *SlirpPodInterface) preparePodNetworkInterfaces() error {
	interfaces := s.domain.Spec.Devices.Interfaces
	domainInterface := interfaces[s.podInterfaceNum]
	s.domain.Spec.QEMUCmd.QEMUArg = append(s.domain.Spec.QEMUCmd.QEMUArg, api.Arg{Value: fmt.Sprintf("%s,netdev=%s", domainInterface.Model.Type, s.iface.Name)})

	s.domain.Spec.Devices.Interfaces = append(interfaces[:s.podInterfaceNum], interfaces[s.podInterfaceNum+1:]...)
	s.podInterfaceNum = len(s.domain.Spec.QEMUCmd.QEMUArg) - 1

	return nil
}

func (s *SlirpPodInterface) decorateConfig() error {
	s.domain.Spec.QEMUCmd.QEMUArg[s.podInterfaceNum].Value += fmt.Sprintf(",id=%s", s.iface.Name)
	if s.iface.MacAddress != "" {
		// We assume address was already validated in API layer so just pass it to libvirt as-is.
		s.domain.Spec.QEMUCmd.QEMUArg[s.podInterfaceNum].Value += fmt.Sprintf(",mac=%s", s.iface.MacAddress)
	}
	return nil
}

func (s *SlirpPodInterface) loadCachedInterface(name string) (bool, error) {
	var qemuArg api.Arg
	interfaces := s.domain.Spec.Devices.Interfaces

	isExist, err := readFromCachedFile(name, qemuArgCacheFile, &qemuArg)
	if err != nil {
		return false, err
	}

	if isExist {
		// remove slirp interface from domain spec devices interfaces
		interfaces = append(interfaces[:s.podInterfaceNum], interfaces[s.podInterfaceNum+1:]...)

		// Add interface configuration to qemuArgs
		s.domain.Spec.QEMUCmd.QEMUArg = append(s.domain.Spec.QEMUCmd.QEMUArg, qemuArg)
		return true, nil
	}

	return false, nil
}

func (s *SlirpPodInterface) setCachedInterface(name string) error {
	err := writeToCachedFile(&s.domain.Spec.QEMUCmd.QEMUArg[s.podInterfaceNum], qemuArgCacheFile, name)
	return err
}
<commit_msg>Changed k6t-eth0 to b.podInterfaceName.<commit_after>/*
 * This file is part of the KubeVirt project
 *
 * 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.
 *
 * Copyright 2018 Red Hat, Inc.
 *
 */

//go:generate mockgen -source $GOFILE -package=$GOPACKAGE -destination=generated_mock_$GOFILE

package network

import (
	"fmt"
	"net"

	"github.com/vishvananda/netlink"

	"kubevirt.io/kubevirt/pkg/api/v1"
	"kubevirt.io/kubevirt/pkg/log"
	"kubevirt.io/kubevirt/pkg/precond"
	"kubevirt.io/kubevirt/pkg/virt-launcher/virtwrap/api"
)

var bridgeFakeIP = "169.254.75.1%d/32"

type BindMechanism interface {
	discoverPodNetworkInterface() error
	preparePodNetworkInterfaces() error
	decorateConfig() error
	loadCachedInterface(name string) (bool, error)
	setCachedInterface(name string) error
}

type PodInterface struct{}

func (l *PodInterface) Unplug() {}

func findInterfaceByName(ifaces []api.Interface, name string) (int, error) {
	for i, iface := range ifaces {
		if iface.Alias.Name == name {
			return i, nil
		}
	}
	return 0, fmt.Errorf("failed to find interface with alias set to %s", name)
}

// Plug connect a Pod network device to the virtual machine
func (l *PodInterface) Plug(iface *v1.Interface, network *v1.Network, domain *api.Domain, podInterfaceName string) error {
	precond.MustNotBeNil(domain)
	initHandler()

	// There is nothing to plug for SR-IOV devices
	if iface.SRIOV != nil {
		return nil
	}

	driver, err := getBinding(iface, domain, podInterfaceName)
	if err != nil {
		return err
	}

	isExist, err := driver.loadCachedInterface(iface.Name)
	if err != nil {
		return err
	}

	if !isExist {
		err := driver.discoverPodNetworkInterface()
		if err != nil {
			return err
		}

		if err := driver.preparePodNetworkInterfaces(); err != nil {
			log.Log.Reason(err).Critical("failed to prepared pod networking")
			panic(err)
		}

		// After the network is configured, cache the result
		// in case this function is called again.
		err = driver.decorateConfig()
		if err != nil {
			log.Log.Reason(err).Critical("failed to create libvirt configuration")
			panic(err)
		}

		err = driver.setCachedInterface(iface.Name)
		if err != nil {
			log.Log.Reason(err).Critical("failed to save interface configuration")
			panic(err)
		}
	}

	return nil
}

func getBinding(iface *v1.Interface, domain *api.Domain, podInterfaceName string) (BindMechanism, error) {
	podInterfaceNum, err := findInterfaceByName(domain.Spec.Devices.Interfaces, iface.Name)
	if err != nil {
		return nil, err
	}

	populateMacAddress := func(vif *VIF, iface *v1.Interface) error {
		if iface.MacAddress != "" {
			macAddress, err := net.ParseMAC(iface.MacAddress)
			if err != nil {
				return err
			}
			vif.MAC = macAddress
		}
		return nil
	}

	if iface.Bridge != nil {
		vif := &VIF{Name: podInterfaceName}
		populateMacAddress(vif, iface)
		return &BridgePodInterface{iface: iface,
			vif:                 vif,
			domain:              domain,
			podInterfaceNum:     podInterfaceNum,
			podInterfaceName:    podInterfaceName,
			bridgeInterfaceName: fmt.Sprintf("k6t-%s", podInterfaceName)}, nil
	}
	if iface.Slirp != nil {
		return &SlirpPodInterface{iface: iface, domain: domain, podInterfaceNum: podInterfaceNum}, nil
	}
	return nil, fmt.Errorf("Not implemented")
}

type BridgePodInterface struct {
	vif                 *VIF
	iface               *v1.Interface
	podNicLink          netlink.Link
	domain              *api.Domain
	isLayer2            bool
	podInterfaceNum     int
	podInterfaceName    string
	bridgeInterfaceName string
}

func (b *BridgePodInterface) discoverPodNetworkInterface() error {
	link, err := Handler.LinkByName(b.podInterfaceName)
	if err != nil {
		log.Log.Reason(err).Errorf("failed to get a link for interface: %s", b.podInterfaceName)
		return err
	}
	b.podNicLink = link

	// get IP address
	addrList, err := Handler.AddrList(b.podNicLink, netlink.FAMILY_V4)
	if err != nil {
		log.Log.Reason(err).Errorf("failed to get an ip address for %s", b.podInterfaceName)
		return err
	}
	if len(addrList) == 0 {
		b.isLayer2 = true
	} else {
		b.vif.IP = addrList[0]
		b.isLayer2 = false
	}

	if len(b.vif.MAC) == 0 {
		// Get interface MAC address
		mac, err := Handler.GetMacDetails(b.podInterfaceName)
		if err != nil {
			log.Log.Reason(err).Errorf("failed to get MAC for %s", b.podInterfaceName)
			return err
		}
		b.vif.MAC = mac
	}

	// Get interface MTU
	b.vif.Mtu = uint16(b.podNicLink.Attrs().MTU)

	if !b.isLayer2 {
		// Handle interface routes
		if err := b.setInterfaceRoutes(); err != nil {
			return err
		}
	}
	return nil
}

func (b *BridgePodInterface) preparePodNetworkInterfaces() error {
	// Set interface link to down to change its MAC address
	if err := Handler.LinkSetDown(b.podNicLink); err != nil {
		log.Log.Reason(err).Errorf("failed to bring link down for interface: %s", b.podInterfaceName)
		return err
	}

	if _, err := Handler.SetRandomMac(b.podInterfaceName); err != nil {
		return err
	}

	if err := Handler.LinkSetUp(b.podNicLink); err != nil {
		log.Log.Reason(err).Errorf("failed to bring link up for interface: %s", b.podInterfaceName)
		return err
	}

	if err := b.createBridge(); err != nil {
		return err
	}

	if !b.isLayer2 {
		// Remove IP from POD interface
		err := Handler.AddrDel(b.podNicLink, &b.vif.IP)

		if err != nil {
			log.Log.Reason(err).Errorf("failed to delete address for interface: %s", b.podInterfaceName)
			return err
		}

		b.startDHCPServer()
	}

	if err := Handler.LinkSetLearningOff(b.podNicLink); err != nil {
		log.Log.Reason(err).Errorf("failed to disable mac learning for interface: %s", b.podInterfaceName)
		return err
	}

	// turn TX offload checksum because it causes dhcp failures
	if err := EthtoolTXOff(b.podInterfaceName); err != nil {
		log.Log.Reason(err).Errorf("Failed to set tx offload for interface %s off", b.podInterfaceName)
		return err
	}

	if err := EthtoolTXOff("vnet0"); err != nil {
		log.Log.Reason(err).Errorf("Failed to set tx offload for interface %s off", "vnet0")
		return err
	}

	return nil
}

func (b *BridgePodInterface) startDHCPServer() {
	// Start DHCP Server
	fakeServerAddr, _ := netlink.ParseAddr(fmt.Sprintf(bridgeFakeIP, b.podInterfaceNum))
	Handler.StartDHCP(b.vif, fakeServerAddr, b.bridgeInterfaceName, b.iface.DHCPOptions)
}

func (b *BridgePodInterface) decorateConfig() error {
	b.domain.Spec.Devices.Interfaces[b.podInterfaceNum].MAC = &api.MAC{MAC: b.vif.MAC.String()}

	return nil
}

func (b *BridgePodInterface) loadCachedInterface(name string) (bool, error) {
	var ifaceConfig api.Interface

	isExist, err := readFromCachedFile(name, interfaceCacheFile, &ifaceConfig)
	if err != nil {
		return false, err
	}

	if isExist {
		b.domain.Spec.Devices.Interfaces[b.podInterfaceNum] = ifaceConfig
		return true, nil
	}

	return false, nil
}

func (b *BridgePodInterface) setCachedInterface(name string) error {
	err := writeToCachedFile(&b.domain.Spec.Devices.Interfaces[b.podInterfaceNum], interfaceCacheFile, name)
	return err
}

func (b *BridgePodInterface) setInterfaceRoutes() error {
	routes, err := Handler.RouteList(b.podNicLink, netlink.FAMILY_V4)
	if err != nil {
		log.Log.Reason(err).Errorf("failed to get routes for %s", b.podInterfaceName)
		return err
	}
	if len(routes) == 0 {
		return fmt.Errorf("No gateway address found in routes for %s", b.podInterfaceName)
	}
	b.vif.Gateway = routes[0].Gw
	if len(routes) > 1 {
		dhcpRoutes := filterPodNetworkRoutes(routes, b.vif)
		b.vif.Routes = &dhcpRoutes
	}
	return nil
}

func (b *BridgePodInterface) createBridge() error {
	// Create a bridge
	bridge := &netlink.Bridge{
		LinkAttrs: netlink.LinkAttrs{
			Name: b.bridgeInterfaceName,
		},
	}
	err := Handler.LinkAdd(bridge)
	if err != nil {
		log.Log.Reason(err).Errorf("failed to create a bridge")
		return err
	}
	netlink.LinkSetMaster(b.podNicLink, bridge)

	err = Handler.LinkSetUp(bridge)
	if err != nil {
		log.Log.Reason(err).Errorf("failed to bring link up for interface: %s", b.bridgeInterfaceName)
		return err
	}

	// set fake ip on a bridge
	fakeaddr, err := Handler.ParseAddr(fmt.Sprintf(bridgeFakeIP, b.podInterfaceNum))
	if err != nil {
		log.Log.Reason(err).Errorf("failed to bring link up for interface: %s", b.bridgeInterfaceName)
		return err
	}

	if err := Handler.AddrAdd(bridge, fakeaddr); err != nil {
		log.Log.Reason(err).Errorf("failed to set bridge IP")
		return err
	}

	return nil
}

type SlirpPodInterface struct {
	iface           *v1.Interface
	domain          *api.Domain
	podInterfaceNum int
}

func (s *SlirpPodInterface) discoverPodNetworkInterface() error {
	s.domain.Spec.QEMUCmd.QEMUArg = append(s.domain.Spec.QEMUCmd.QEMUArg, api.Arg{Value: "-device"})
	return nil
}

func (s *SlirpPodInterface) preparePodNetworkInterfaces() error {
	interfaces := s.domain.Spec.Devices.Interfaces
	domainInterface := interfaces[s.podInterfaceNum]
	s.domain.Spec.QEMUCmd.QEMUArg = append(s.domain.Spec.QEMUCmd.QEMUArg, api.Arg{Value: fmt.Sprintf("%s,netdev=%s", domainInterface.Model.Type, s.iface.Name)})

	s.domain.Spec.Devices.Interfaces = append(interfaces[:s.podInterfaceNum], interfaces[s.podInterfaceNum+1:]...)
	s.podInterfaceNum = len(s.domain.Spec.QEMUCmd.QEMUArg) - 1

	return nil
}

func (s *SlirpPodInterface) decorateConfig() error {
	s.domain.Spec.QEMUCmd.QEMUArg[s.podInterfaceNum].Value += fmt.Sprintf(",id=%s", s.iface.Name)
	if s.iface.MacAddress != "" {
		// We assume address was already validated in API layer so just pass it to libvirt as-is.
		s.domain.Spec.QEMUCmd.QEMUArg[s.podInterfaceNum].Value += fmt.Sprintf(",mac=%s", s.iface.MacAddress)
	}
	return nil
}

func (s *SlirpPodInterface) loadCachedInterface(name string) (bool, error) {
	var qemuArg api.Arg
	interfaces := s.domain.Spec.Devices.Interfaces

	isExist, err := readFromCachedFile(name, qemuArgCacheFile, &qemuArg)
	if err != nil {
		return false, err
	}

	if isExist {
		// remove slirp interface from domain spec devices interfaces
		interfaces = append(interfaces[:s.podInterfaceNum], interfaces[s.podInterfaceNum+1:]...)

		// Add interface configuration to qemuArgs
		s.domain.Spec.QEMUCmd.QEMUArg = append(s.domain.Spec.QEMUCmd.QEMUArg, qemuArg)
		return true, nil
	}

	return false, nil
}

func (s *SlirpPodInterface) setCachedInterface(name string) error {
	err := writeToCachedFile(&s.domain.Spec.QEMUCmd.QEMUArg[s.podInterfaceNum], qemuArgCacheFile, name)
	return err
}
<|endoftext|>


<commit_before>/*
   Copyright 2012 the go.wde authors

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

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

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

package win

import (
	"fmt"
	"github.com/AllenDang/w32"
	"github.com/skelterjohn/go.wde"
)

/*
TODO:
 F10 loses focus
 left alt loses focus
<	(left from z), code 226. Coded as ',' in xgb for some reason.
		// Some that are not found in wde constants
		// Hardcoded to be compatible with xgb
		19:	"Pause",
		93:	"Menu",
		145:	"Scroll_Lock",
		186:	"dead_diaeresis",	// ¨
		192:	"odiaresis",			// ö
		220:	"section",				// §
		221:	"aring",					// å
		222:	"adiaresis",			// ä
*/

func keyFromVirtualKeyCode(vk uintptr) string {
	switch vk {
	case w32.VK_LBUTTON:
	case w32.VK_RBUTTON:
	case w32.VK_CANCEL:
	case w32.VK_MBUTTON:
	case w32.VK_XBUTTON1:
	case w32.VK_XBUTTON2:
	case w32.VK_BACK:
		return wde.KeyBackspace
	case w32.VK_TAB:
		return wde.KeyTab
	case w32.VK_CLEAR:
	case w32.VK_RETURN:
		return wde.KeyReturn
	case w32.VK_SHIFT:
		return wde.KeyLeftShift
	case w32.VK_CONTROL:
		return wde.KeyLeftControl
	case w32.VK_MENU:
		return wde.KeyLeftAlt
	case w32.VK_PAUSE:
	case w32.VK_CAPITAL:
		return wde.KeyCapsLock
	case w32.VK_HANGUL:
	case w32.VK_JUNJA:
	case w32.VK_FINAL:
	case w32.VK_KANJI:
	case w32.VK_ESCAPE:
		return wde.KeyEscape
	case w32.VK_CONVERT:
	case w32.VK_NONCONVERT:
	case w32.VK_ACCEPT:
	case w32.VK_MODECHANGE:
	case w32.VK_SPACE:
		return wde.KeySpace
	case w32.VK_PRIOR:
		return wde.KeyPrior
	case w32.VK_NEXT:
		return wde.KeyNext
	case w32.VK_END:
		return wde.KeyEnd
	case w32.VK_HOME:
		return wde.KeyHome
	case w32.VK_LEFT:
		return wde.KeyLeftArrow
	case w32.VK_UP:
		return wde.KeyUpArrow
	case w32.VK_RIGHT:
		return wde.KeyRightArrow
	case w32.VK_DOWN:
		return wde.KeyDownArrow
	case w32.VK_SELECT:
	case w32.VK_PRINT:
	case w32.VK_EXECUTE:
	case w32.VK_SNAPSHOT:
	case w32.VK_INSERT:
		return wde.KeyInsert
	case w32.VK_DELETE:
		return wde.KeyDelete
	case w32.VK_HELP:
	case w32.VK_LWIN:
	case w32.VK_RWIN:
	case w32.VK_APPS:
	case w32.VK_SLEEP:
	case w32.VK_NUMPAD0:
		return wde.Key0
	case w32.VK_NUMPAD1:
		return wde.Key1
	case w32.VK_NUMPAD2:
		return wde.Key2
	case w32.VK_NUMPAD3:
		return wde.Key3
	case w32.VK_NUMPAD4:
		return wde.Key4
	case w32.VK_NUMPAD5:
		return wde.Key5
	case w32.VK_NUMPAD6:
		return wde.Key6
	case w32.VK_NUMPAD7:
		return wde.Key7
	case w32.VK_NUMPAD8:
		return wde.Key8
	case w32.VK_NUMPAD9:
		return wde.Key9
	case w32.VK_MULTIPLY:
		return wde.KeyPadStar
	case w32.VK_ADD:
		return wde.KeyPadPlus
	case w32.VK_SEPARATOR:
	case w32.VK_SUBTRACT:
		return wde.KeyPadMinus
	case w32.VK_DECIMAL:
		return wde.KeyPadDot
	case w32.VK_DIVIDE:
		return wde.KeyPadSlash
	case w32.VK_F1:
		return wde.KeyF1
	case w32.VK_F2:
		return wde.KeyF2
	case w32.VK_F3:
		return wde.KeyF3
	case w32.VK_F4:
		return wde.KeyF4
	case w32.VK_F5:
		return wde.KeyF5
	case w32.VK_F6:
		return wde.KeyF5
	case w32.VK_F7:
		return wde.KeyF7
	case w32.VK_F8:
		return wde.KeyF8
	case w32.VK_F9:
		return wde.KeyF9
	case w32.VK_F10:
		return wde.KeyF10
	case w32.VK_F11:
		return wde.KeyF11
	case w32.VK_F12:
		return wde.KeyF12
	case w32.VK_F13:
		return wde.KeyF13
	case w32.VK_F14:
		return wde.KeyF14
	case w32.VK_F15:
		return wde.KeyF15
	case w32.VK_F16:
		return wde.KeyF16
	case w32.VK_F17:
	case w32.VK_F18:
	case w32.VK_F19:
	case w32.VK_F20:
	case w32.VK_F21:
	case w32.VK_F22:
	case w32.VK_F23:
	case w32.VK_F24:
	case w32.VK_NUMLOCK:
		return wde.KeyNumlock
	case w32.VK_SCROLL:
	case w32.VK_LSHIFT:
		return wde.KeyLeftShift
	case w32.VK_RSHIFT:
		return wde.KeyRightShift
	case w32.VK_LCONTROL:
		return wde.KeyLeftShift
	case w32.VK_RCONTROL:
		return wde.KeyRightShift
	case w32.VK_LMENU:
		return wde.KeyLeftAlt
	case w32.VK_RMENU:
		return wde.KeyRightAlt
	case w32.VK_BROWSER_BACK:
	case w32.VK_BROWSER_FORWARD:
	case w32.VK_BROWSER_REFRESH:
	case w32.VK_BROWSER_STOP:
	case w32.VK_BROWSER_SEARCH:
	case w32.VK_BROWSER_FAVORITES:
	case w32.VK_BROWSER_HOME:
	case w32.VK_VOLUME_MUTE:
	case w32.VK_VOLUME_DOWN:
	case w32.VK_VOLUME_UP:
	case w32.VK_MEDIA_NEXT_TRACK:
	case w32.VK_MEDIA_PREV_TRACK:
	case w32.VK_MEDIA_STOP:
	case w32.VK_MEDIA_PLAY_PAUSE:
	case w32.VK_LAUNCH_MAIL:
	case w32.VK_LAUNCH_MEDIA_SELECT:
	case w32.VK_LAUNCH_APP1:
	case w32.VK_LAUNCH_APP2:
	case w32.VK_OEM_1:
	case w32.VK_OEM_PLUS:
	case w32.VK_OEM_COMMA:
	case w32.VK_OEM_MINUS:
	case w32.VK_OEM_PERIOD:
	case w32.VK_OEM_2:
	case w32.VK_OEM_3:
	case w32.VK_OEM_4:
	case w32.VK_OEM_5:
	case w32.VK_OEM_6:
	case w32.VK_OEM_7:
	case w32.VK_OEM_8:
	case w32.VK_OEM_AX:
	case w32.VK_OEM_102:
	case w32.VK_ICO_HELP:
	case w32.VK_ICO_00:
	case w32.VK_PROCESSKEY:
	case w32.VK_ICO_CLEAR:
	case w32.VK_OEM_RESET:
	case w32.VK_OEM_JUMP:
	case w32.VK_OEM_PA1:
	case w32.VK_OEM_PA2:
	case w32.VK_OEM_PA3:
	case w32.VK_OEM_WSCTRL:
	case w32.VK_OEM_CUSEL:
	case w32.VK_OEM_ATTN:
	case w32.VK_OEM_FINISH:
	case w32.VK_OEM_COPY:
	case w32.VK_OEM_AUTO:
	case w32.VK_OEM_ENLW:
	case w32.VK_OEM_BACKTAB:
	case w32.VK_ATTN:
	case w32.VK_CRSEL:
	case w32.VK_EXSEL:
	case w32.VK_EREOF:
	case w32.VK_PLAY:
	case w32.VK_ZOOM:
	case w32.VK_NONAME:
	case w32.VK_PA1:
	case w32.VK_OEM_CLEAR:

	}
	return fmt.Sprintf("%c", vk)
}
<commit_msg>win: add missing keycodes (assuming US keyboard)<commit_after>/*
   Copyright 2012 the go.wde authors

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

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

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

package win

import (
	"fmt"
	"github.com/AllenDang/w32"
	"github.com/skelterjohn/go.wde"
)

/*
TODO:
 F10 loses focus
 left alt loses focus
<	(left from z), code 226. Coded as ',' in xgb for some reason.
		// Some that are not found in wde constants
		// Hardcoded to be compatible with xgb
		19:	"Pause",
		93:	"Menu",
		145:	"Scroll_Lock",
		186:	"dead_diaeresis",	// ¨
		192:	"odiaresis",			// ö
		220:	"section",				// §
		221:	"aring",					// å
		222:	"adiaresis",			// ä
*/

func keyFromVirtualKeyCode(vk uintptr) string {
	switch vk {
	case w32.VK_LBUTTON:
	case w32.VK_RBUTTON:
	case w32.VK_CANCEL:
	case w32.VK_MBUTTON:
	case w32.VK_XBUTTON1:
	case w32.VK_XBUTTON2:
	case w32.VK_BACK:
		return wde.KeyBackspace
	case w32.VK_TAB:
		return wde.KeyTab
	case w32.VK_CLEAR:
	case w32.VK_RETURN:
		return wde.KeyReturn
	case w32.VK_SHIFT:
		return wde.KeyLeftShift
	case w32.VK_CONTROL:
		return wde.KeyLeftControl
	case w32.VK_MENU:
		return wde.KeyLeftAlt
	case w32.VK_PAUSE:
	case w32.VK_CAPITAL:
		return wde.KeyCapsLock
	case w32.VK_HANGUL:
	case w32.VK_JUNJA:
	case w32.VK_FINAL:
	case w32.VK_KANJI:
	case w32.VK_ESCAPE:
		return wde.KeyEscape
	case w32.VK_CONVERT:
	case w32.VK_NONCONVERT:
	case w32.VK_ACCEPT:
	case w32.VK_MODECHANGE:
	case w32.VK_SPACE:
		return wde.KeySpace
	case w32.VK_PRIOR:
		return wde.KeyPrior
	case w32.VK_NEXT:
		return wde.KeyNext
	case w32.VK_END:
		return wde.KeyEnd
	case w32.VK_HOME:
		return wde.KeyHome
	case w32.VK_LEFT:
		return wde.KeyLeftArrow
	case w32.VK_UP:
		return wde.KeyUpArrow
	case w32.VK_RIGHT:
		return wde.KeyRightArrow
	case w32.VK_DOWN:
		return wde.KeyDownArrow
	case w32.VK_SELECT:
	case w32.VK_PRINT:
	case w32.VK_EXECUTE:
	case w32.VK_SNAPSHOT:
	case w32.VK_INSERT:
		return wde.KeyInsert
	case w32.VK_DELETE:
		return wde.KeyDelete
	case w32.VK_HELP:
	case w32.VK_LWIN:
		return wde.KeyLeftSuper
	case w32.VK_RWIN:
		return wde.KeyRightSuper
	case w32.VK_APPS:
	case w32.VK_SLEEP:
	case w32.VK_NUMPAD0:
		return wde.Key0
	case w32.VK_NUMPAD1:
		return wde.Key1
	case w32.VK_NUMPAD2:
		return wde.Key2
	case w32.VK_NUMPAD3:
		return wde.Key3
	case w32.VK_NUMPAD4:
		return wde.Key4
	case w32.VK_NUMPAD5:
		return wde.Key5
	case w32.VK_NUMPAD6:
		return wde.Key6
	case w32.VK_NUMPAD7:
		return wde.Key7
	case w32.VK_NUMPAD8:
		return wde.Key8
	case w32.VK_NUMPAD9:
		return wde.Key9
	case w32.VK_MULTIPLY:
		return wde.KeyPadStar
	case w32.VK_ADD:
		return wde.KeyPadPlus
	case w32.VK_SEPARATOR:
	case w32.VK_SUBTRACT:
		return wde.KeyPadMinus
	case w32.VK_DECIMAL:
		return wde.KeyPadDot
	case w32.VK_DIVIDE:
		return wde.KeyPadSlash
	case w32.VK_F1:
		return wde.KeyF1
	case w32.VK_F2:
		return wde.KeyF2
	case w32.VK_F3:
		return wde.KeyF3
	case w32.VK_F4:
		return wde.KeyF4
	case w32.VK_F5:
		return wde.KeyF5
	case w32.VK_F6:
		return wde.KeyF5
	case w32.VK_F7:
		return wde.KeyF7
	case w32.VK_F8:
		return wde.KeyF8
	case w32.VK_F9:
		return wde.KeyF9
	case w32.VK_F10:
		return wde.KeyF10
	case w32.VK_F11:
		return wde.KeyF11
	case w32.VK_F12:
		return wde.KeyF12
	case w32.VK_F13:
		return wde.KeyF13
	case w32.VK_F14:
		return wde.KeyF14
	case w32.VK_F15:
		return wde.KeyF15
	case w32.VK_F16:
		return wde.KeyF16
	case w32.VK_F17:
	case w32.VK_F18:
	case w32.VK_F19:
	case w32.VK_F20:
	case w32.VK_F21:
	case w32.VK_F22:
	case w32.VK_F23:
	case w32.VK_F24:
	case w32.VK_NUMLOCK:
		return wde.KeyNumlock
	case w32.VK_SCROLL:
	case w32.VK_LSHIFT:
		return wde.KeyLeftShift
	case w32.VK_RSHIFT:
		return wde.KeyRightShift
	case w32.VK_LCONTROL:
		return wde.KeyLeftShift
	case w32.VK_RCONTROL:
		return wde.KeyRightShift
	case w32.VK_LMENU:
		return wde.KeyLeftAlt
	case w32.VK_RMENU:
		return wde.KeyRightAlt
	case w32.VK_BROWSER_BACK:
	case w32.VK_BROWSER_FORWARD:
	case w32.VK_BROWSER_REFRESH:
	case w32.VK_BROWSER_STOP:
	case w32.VK_BROWSER_SEARCH:
	case w32.VK_BROWSER_FAVORITES:
	case w32.VK_BROWSER_HOME:
	case w32.VK_VOLUME_MUTE:
	case w32.VK_VOLUME_DOWN:
	case w32.VK_VOLUME_UP:
	case w32.VK_MEDIA_NEXT_TRACK:
	case w32.VK_MEDIA_PREV_TRACK:
	case w32.VK_MEDIA_STOP:
	case w32.VK_MEDIA_PLAY_PAUSE:
	case w32.VK_LAUNCH_MAIL:
	case w32.VK_LAUNCH_MEDIA_SELECT:
	case w32.VK_LAUNCH_APP1:
	case w32.VK_LAUNCH_APP2:
	case w32.VK_OEM_1:
		return wde.KeySemicolon
	case w32.VK_OEM_PLUS:
		return wde.KeyEqual
	case w32.VK_OEM_COMMA:
		return wde.KeyComma
	case w32.VK_OEM_MINUS:
		return wde.KeyMinus
	case w32.VK_OEM_PERIOD:
		return wde.KeyPeriod
	case w32.VK_OEM_2:
		return wde.KeySlash
	case w32.VK_OEM_3:
		return wde.KeyBackTick
	case w32.VK_OEM_4:
		return wde.KeyLeftBracket
	case w32.VK_OEM_5:
		return wde.KeyBackslash
	case w32.VK_OEM_6:
		return wde.KeyRightBracket
	case w32.VK_OEM_7:
		return wde.KeyQuote
	case w32.VK_OEM_8:
	case w32.VK_OEM_AX:
	case w32.VK_OEM_102:
	case w32.VK_ICO_HELP:
	case w32.VK_ICO_00:
	case w32.VK_PROCESSKEY:
	case w32.VK_ICO_CLEAR:
	case w32.VK_OEM_RESET:
	case w32.VK_OEM_JUMP:
	case w32.VK_OEM_PA1:
	case w32.VK_OEM_PA2:
	case w32.VK_OEM_PA3:
	case w32.VK_OEM_WSCTRL:
	case w32.VK_OEM_CUSEL:
	case w32.VK_OEM_ATTN:
	case w32.VK_OEM_FINISH:
	case w32.VK_OEM_COPY:
	case w32.VK_OEM_AUTO:
	case w32.VK_OEM_ENLW:
	case w32.VK_OEM_BACKTAB:
	case w32.VK_ATTN:
	case w32.VK_CRSEL:
	case w32.VK_EXSEL:
	case w32.VK_EREOF:
	case w32.VK_PLAY:
	case w32.VK_ZOOM:
	case w32.VK_NONAME:
	case w32.VK_PA1:
	case w32.VK_OEM_CLEAR:

	}
	return fmt.Sprintf("%c", vk)
}
<|endoftext|>


<commit_before>/* https://leetcode.com/problems/3sum-closest/#/description
Given an array S of n integers, find three integers in S such that the sum is closest to a given number, target.
Return the sum of the three integers. You may assume that each input would have exactly one solution.

    For example, given array S = {-1 2 1 -4}, and target = 1.

    The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).
*/

package leetcode

func threeSumClosest(nums []int, target int) int {
	return -1
}
<commit_msg>add threeSumClosest<commit_after>/* https://leetcode.com/problems/3sum-closest/#/description
Given an array S of n integers, find three integers in S such that the sum is closest to a given number, target.
Return the sum of the three integers. You may assume that each input would have exactly one solution.

    For example, given array S = {-1 2 1 -4}, and target = 1.

    The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).
*/

package leetcode

import "sort"

func threeSumClosest(nums []int, target int) int {
	sort.Ints(nums)

	abs := func(a int) int {
		if a < 0 {
			return -a
		}
		return a
	}

	sum := nums[0] + nums[1] + nums[2]
	for i := 0; i+2 < len(nums); i++ {
		if i > 0 && nums[i] == nums[i-1] { // skip same result
			continue
		}

		for j, k := i+1, len(nums)-1; j < k; {
			temp := nums[j] + nums[k] + nums[i]
			if temp == target {
				return target
			} else if temp > target {
				k--
			} else {
				j++
			}
			if abs(temp-target) < abs(sum-target) {
				sum = temp
			}
		}
	}

	return sum
}
<|endoftext|>


<commit_before>package lemon

import (
	"context"
	"os"
	"sync"
	"time"
)

// Engine is a components that handle your application lifecycle.
//
// Start
//
// It will start every registered hook (or daemon, service, etc...) and block until it
// receives a SIGINT, SIGTERM or SIGQUIT signal.
//
// For example:
//
//   if e, err := New(); err == nil {
//       e.Register(&MyService{})
//       e.Register(&MyWorker{})
//       e.Start()
//       // Wait until Ctrl-C
//   }
//
// Stop
//
// When your application has to stop, the engine will notify every hook to shutdown gracefully.
// However, if a hook fails to stop before timeout, the underlying goroutine will be destroyed...
//
type Engine struct {
	interrupt      chan os.Signal
	timeout        time.Duration
	hooks          []Hook
	wait           sync.WaitGroup
	parent         context.Context
	ctx            context.Context
	cancel         context.CancelFunc
	signals        []os.Signal
	beforeShutdown func()
	afterShutdown  func()
	logger         func(error)
}

// New creates a new engine with given options.
//
// Options can change the timeout, register a signal, execute a pre-hook callback and many other behaviors.
func New(options ...Option) (*Engine, error) {
	return NewWithContext(context.Background(), options...)
}

// NewWithContext creates a new engine with given context and options.
//
// Options can change the timeout, register a signal, execute a pre-hook callback and many other behaviors.
func NewWithContext(parent context.Context, options ...Option) (*Engine, error) {

	ctx, cancel := context.WithCancel(context.Background())

	e := &Engine{}

	e.wait = sync.WaitGroup{}
	e.parent = parent
	e.ctx = ctx
	e.cancel = cancel
	e.timeout = DefaultTimeout
	e.signals = Signals

	for _, o := range options {
		if err := o.apply(e); err != nil {
			return nil, err
		}
	}

	return e, nil
}

func (e *Engine) launch(h Hook) {

	e.wait.Add(1)

	go func() {

		defer e.wait.Done()

		runtime := &HookRuntime{}

		// Wait for an event to notify this goroutine that a shutdown is required.
		// It could either be from engine's context or during Hook startup if an error has occurred.
		// NOTE: If HookRuntime returns an error, we have to shutdown every Hook...
		if err := runtime.WaitForEvent(e.ctx, h); err != nil {
			e.log(err)
			e.cancel()
		}

		// Wait for hook to gracefully shutdown, or kill it after timeout.
		// This is handled by HookRuntime.
		for _, err := range runtime.Shutdown(e.timeout) {
			e.log(err)
		}

	}()
}

func (e *Engine) onContextNotification() {

	<-e.parent.Done()

	e.interrupted = true

	if e.beforeShutdown != nil {
		e.beforeShutdown()
	}

	e.cancel()

}

// Start will launch the engine and start registered hooks.
// It will block until every hooks has shutdown, gracefully or with force...
func (e *Engine) Start() {

	go e.waitShutdownNotification()

	for _, h := range e.hooks {
		e.launch(h)
	}

	e.wait.Wait()

	if e.afterShutdown != nil {
		e.afterShutdown()
	}

}
<commit_msg>refactor(init): Force assignment of engine's struct field<commit_after>package lemon

import (
	"context"
	"os"
	"sync"
	"time"
)

// Engine is a components that handle your application lifecycle.
//
// Start
//
// It will start every registered hook (or daemon, service, etc...) and block until it
// receives a SIGINT, SIGTERM or SIGQUIT signal.
//
// For example:
//
//   if e, err := New(); err == nil {
//       e.Register(&MyService{})
//       e.Register(&MyWorker{})
//       e.Start()
//       // Wait until Ctrl-C
//   }
//
// Stop
//
// When your application has to stop, the engine will notify every hook to shutdown gracefully.
// However, if a hook fails to stop before timeout, the underlying goroutine will be destroyed...
//
type Engine struct {
	interrupt      chan os.Signal
	timeout        time.Duration
	hooks          []Hook
	wait           sync.WaitGroup
	parent         context.Context
	ctx            context.Context
	cancel         context.CancelFunc
	signals        []os.Signal
	beforeShutdown func()
	afterShutdown  func()
	logger         func(error)
}

// New creates a new engine with given options.
//
// Options can change the timeout, register a signal, execute a pre-hook callback and many other behaviors.
func New(options ...Option) (*Engine, error) {
	return NewWithContext(context.Background(), options...)
}

// NewWithContext creates a new engine with given context and options.
//
// Options can change the timeout, register a signal, execute a pre-hook callback and many other behaviors.
func NewWithContext(parent context.Context, options ...Option) (*Engine, error) {

	e := &Engine{}
	e.parent = parent
	e.init()

	for _, o := range options {
		if err := o.apply(e); err != nil {
			return nil, err
		}
	}

	return e, nil
}

func (e *Engine) launch(h Hook) {

	e.wait.Add(1)

	go func() {

		defer e.wait.Done()

		runtime := &HookRuntime{}

		// Wait for an event to notify this goroutine that a shutdown is required.
		// It could either be from engine's context or during Hook startup if an error has occurred.
		// NOTE: If HookRuntime returns an error, we have to shutdown every Hook...
		if err := runtime.WaitForEvent(e.ctx, h); err != nil {
			e.log(err)
			e.cancel()
		}

		// Wait for hook to gracefully shutdown, or kill it after timeout.
		// This is handled by HookRuntime.
		for _, err := range runtime.Shutdown(e.timeout) {
			e.log(err)
		}

	}()
}

// init configures default parameters for engine.
func (e *Engine) init() {

	if e.parent == nil {
		e.parent = context.Background()
	}

	if e.ctx == nil || e.cancel == nil {
		e.ctx, e.cancel = context.WithCancel(context.Background())
	}

	if e.timeout == 0 {
		e.timeout = DefaultTimeout
	}

	if len(e.signals) == 0 {
		e.signals = Signals
	}

	if e.interrupt == nil {
		e.interrupt = make(chan os.Signal, 1)
	}

}

// Start will launch the engine and start registered hooks.
// It will block until every hooks has shutdown, gracefully or with force...
func (e *Engine) Start() {

	e.init()

	go e.waitShutdownNotification()

	for _, h := range e.hooks {
		e.launch(h)
	}

	e.wait.Wait()

	if e.afterShutdown != nil {
		e.afterShutdown()
	}

}
<|endoftext|>


<commit_before>package stringsutil

import (
	"regexp"
	"strings"
	"time"
)

type MatchType int

const (
	Exact MatchType = iota
	TrimSpace
	TrimSpaceLower
	Regexp
	TimeGT
	TimeGTE
	TimeLT
	TimeLTE
)

type MatchInfo struct {
	MatchType  MatchType
	String     string
	Regexp     *regexp.Regexp
	TimeLayout string
	TimeMin    time.Time
	TimeMax    time.Time
}

// Match provides an canonical way to match strings using multiple
// approaches
func Match(s string, matchInfo MatchInfo) (bool, error) {
	switch matchInfo.MatchType {
	case Exact:
		if s == matchInfo.String {
			return true, nil
		}
		return false, nil
	case TrimSpace:
		m := strings.TrimSpace(s)
		if m == strings.TrimSpace(matchInfo.String) {
			return true, nil
		}
		return false, nil
	case TrimSpaceLower:
		m := strings.ToLower(strings.TrimSpace(s))
		if m == strings.ToLower(strings.TrimSpace(matchInfo.String)) {
			return true, nil
		}
		return false, nil
	case Regexp:
		if matchInfo.Regexp == nil {
			return false, nil
		}
		return matchInfo.Regexp.MatchString(s), nil
	case TimeGT:
		t, err := time.Parse(matchInfo.TimeLayout, s)
		if err != nil {
			return false, err
		}
		if t.After(matchInfo.TimeMin) {
			return true, nil
		} else {
			return false, nil
		}
	case TimeGTE:
		t, err := time.Parse(matchInfo.TimeLayout, s)
		if err != nil {
			return false, err
		}
		if t.After(matchInfo.TimeMin) || t.Equal(matchInfo.TimeMin) {
			return true, nil
		} else {
			return false, nil
		}
	case TimeLT:
		t, err := time.Parse(matchInfo.TimeLayout, s)
		if err != nil {
			return false, err
		}
		if t.Before(matchInfo.TimeMin) {
			return true, nil
		} else {
			return false, nil
		}
	case TimeLTE:
		t, err := time.Parse(matchInfo.TimeLayout, s)
		if err != nil {
			return false, err
		}
		if t.Before(matchInfo.TimeMin) || t.Equal(matchInfo.TimeMin) {
			return true, nil
		} else {
			return false, nil
		}
	default:
		return false, nil
	}
}
<commit_msg>bugfix<commit_after>package stringsutil

import (
	"regexp"
	"strings"
	"time"
)

type MatchType int

const (
	Exact MatchType = iota
	TrimSpace
	TrimSpaceLower
	Regexp
	TimeGT
	TimeGTE
	TimeLT
	TimeLTE
)

type MatchInfo struct {
	MatchType  MatchType
	String     string
	Regexp     *regexp.Regexp
	TimeLayout string
	TimeMin    time.Time
	TimeMax    time.Time
}

// Match provides an canonical way to match strings using multiple
// approaches
func Match(s string, matchInfo MatchInfo) (bool, error) {
	switch matchInfo.MatchType {
	case Exact:
		if s == matchInfo.String {
			return true, nil
		}
		return false, nil
	case TrimSpace:
		m := strings.TrimSpace(s)
		if m == strings.TrimSpace(matchInfo.String) {
			return true, nil
		}
		return false, nil
	case TrimSpaceLower:
		m := strings.ToLower(strings.TrimSpace(s))
		if m == strings.ToLower(strings.TrimSpace(matchInfo.String)) {
			return true, nil
		}
		return false, nil
	case Regexp:
		if matchInfo.Regexp == nil {
			return false, nil
		}
		return matchInfo.Regexp.MatchString(s), nil
	case TimeGT:
		t, err := time.Parse(matchInfo.TimeLayout, s)
		if err != nil {
			return false, err
		}
		if t.After(matchInfo.TimeMin) {
			return true, nil
		} else {
			return false, nil
		}
	case TimeGTE:
		t, err := time.Parse(matchInfo.TimeLayout, s)
		if err != nil {
			return false, err
		}
		if t.After(matchInfo.TimeMin) || t.Equal(matchInfo.TimeMin) {
			return true, nil
		} else {
			return false, nil
		}
	case TimeLT:
		t, err := time.Parse(matchInfo.TimeLayout, s)
		if err != nil {
			return false, err
		}
		if t.Before(matchInfo.TimeMax) {
			return true, nil
		} else {
			return false, nil
		}
	case TimeLTE:
		t, err := time.Parse(matchInfo.TimeLayout, s)
		if err != nil {
			return false, err
		}
		if t.Before(matchInfo.TimeMax) || t.Equal(matchInfo.TimeMax) {
			return true, nil
		} else {
			return false, nil
		}
	default:
		return false, nil
	}
}
<|endoftext|>