<commit_before>// Copyright 2016 go-dockerclient 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 docker

import (
	"context"
	"net"
	"net/http"
	"time"

	winio "github.com/Microsoft/go-winio"
)

const (
	defaultHost             = "npipe:////./pipe/docker_engine"
	namedPipeConnectTimeout = 2 * time.Second
)

type pipeDialer struct {
	dialFunc func(network, addr string) (net.Conn, error)
}

func (p pipeDialer) Dial(network, address string) (net.Conn, error) {
	return p.dialFunc(network, address)
}

// initializeNativeClient initializes the native Named Pipe client for Windows
func (c *Client) initializeNativeClient(trFunc func() *http.Transport) {
	if c.endpointURL.Scheme != namedPipeProtocol {
		return
	}
	namedPipePath := c.endpointURL.Path
	dialFunc := func(network, addr string) (net.Conn, error) {
		timeout := namedPipeConnectTimeout
		return winio.DialPipe(namedPipePath, &timeout)
	}
	tr := trFunc()
	tr.Proxy = nil
	tr.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
		return dialFunc(network, addr)
	}
	c.Dialer = &pipeDialer{dialFunc}
	c.HTTPClient.Transport = tr
}
<commit_msg>client_windows: disable unparam for a specific check<commit_after>// Copyright 2016 go-dockerclient 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 docker

import (
	"context"
	"net"
	"net/http"
	"time"

	winio "github.com/Microsoft/go-winio"
)

const (
	defaultHost             = "npipe:////./pipe/docker_engine"
	namedPipeConnectTimeout = 2 * time.Second
)

type pipeDialer struct {
	dialFunc func(network, addr string) (net.Conn, error)
}

func (p pipeDialer) Dial(network, address string) (net.Conn, error) {
	return p.dialFunc(network, address)
}

// initializeNativeClient initializes the native Named Pipe client for Windows
func (c *Client) initializeNativeClient(trFunc func() *http.Transport) {
	if c.endpointURL.Scheme != namedPipeProtocol {
		return
	}
	namedPipePath := c.endpointURL.Path
	//nolint:unparam
	dialFunc := func(_, addr string) (net.Conn, error) {
		timeout := namedPipeConnectTimeout
		return winio.DialPipe(namedPipePath, &timeout)
	}
	tr := trFunc()
	tr.Proxy = nil
	tr.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
		return dialFunc(network, addr)
	}
	c.Dialer = &pipeDialer{dialFunc}
	c.HTTPClient.Transport = tr
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"context"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"sync"
	"sync/atomic"
	"time"

	"github.com/buger/jsonparser"
	"github.com/gorilla/websocket"
	"github.com/joho/godotenv"
	log "github.com/sirupsen/logrus"
	"github.com/syhlion/requestwork.v2"
	"github.com/urfave/cli"
)

var (
	name     string
	version  string
	cmdStart = cli.Command{
		Name:    "run",
		Aliases: []string{"r"},
		Usage:   "test connect to websocket ",
		Action:  start,
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "env-file,e",
				Usage: "import env file",
			},
			cli.BoolFlag{
				Name:  "debug,d",
				Usage: "open debug mode",
			},
		},
	}
	wg        sync.WaitGroup
	listen_wg sync.WaitGroup
)

func start(c *cli.Context) {
	if c.String("env-file") != "" {
		envfile := c.String("env-file")
		//flag.Parse()
		err := godotenv.Load(envfile)
		if err != nil {
			log.Fatal(err)
		}
	}
	ws_api := os.Getenv("GUSHER-CONN-TEST_WS_API")
	if ws_api == "" {
		log.Fatal("empty env GUSHER-CONN-TEST_WS_API")
	}
	ws_auth_api := os.Getenv("GUSHER-CONN-TEST_WS_AUTH_API")
	if ws_auth_api == "" {
		log.Fatal("empty env GUSHER-CONN-TEST_WS_AUTH_API")
	}
	push_api := os.Getenv("GUSHER-CONN-TEST_PUSH_API")
	if push_api == "" {
		log.Fatal("empty env GUSHER-CONN-TEST_PUSH_API")
	}
	jwt := os.Getenv("GUSHER-CONN-TEST_JWT")
	if jwt == "" {
		log.Fatal("empty env GUSHER-CONN-TEST_JWT")
	}
	sub_msg := os.Getenv("GUSHER-CONN-TEST_SUBSCRIBE_MESSAGE")
	if sub_msg == "" {
		log.Fatal("empty env GUSHER-CONN-TEST_SUBSCRIBE_MESSAGE")
	}
	sub_resp := os.Getenv("GUSHER-CONN-TEST_SUBSCRIBE_RESPONSE")
	if sub_resp == "" {
		log.Fatal("empty env GUSHER-CONN-TEST_SUBSCRIBE_RESPONSE")
	}
	push_msg := os.Getenv("GUSHER-CONN-TEST_PUSH_MESSAGE")
	if push_msg == "" {
		log.Fatal("empty env GUSHER-CONN-TEST_PUSH_MESSAGE")
	}
	connections := os.Getenv("GUSHER-CONN-TEST_CONNECTIONS")
	if connections == "" {
		log.Fatal("empty env GUSHER-CONN-TEST_CONNECTIONS")
	}
	conn_total, err := strconv.Atoi(connections)
	if err != nil {
		log.Fatal(err)
	}
	/*auth*/

	wsAuthurl, err := url.Parse(ws_auth_api)
	if err != nil {
		log.Fatal(err)
	}
	work := requestwork.New(5)
	loginUrl := url.Values{}

	loginUrl.Add("jwt", jwt)
	tokenChan := make(chan string, conn_total)
	tokenGroup := sync.WaitGroup{}
	for i := 0; i < conn_total; i++ {
		tokenGroup.Add(1)
		go func() {
			req, err := http.NewRequest("POST", wsAuthurl.String(), bytes.NewBufferString(loginUrl.Encode()))
			if err != nil {
				log.Fatal(err)
			}
			req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
			req.Header.Add("Content-Length", strconv.Itoa(len(loginUrl.Encode())))
			ctx, _ := context.WithTimeout(context.Background(), 30*time.Second)
			err = work.Execute(ctx, req, func(resp *http.Response, e error) (err error) {
				defer tokenGroup.Done()
				if e != nil {
					return e
				}
				defer resp.Body.Close()
				b, err := ioutil.ReadAll(resp.Body)
				if err != nil {
					return err
				}
				v, err := jsonparser.GetString(b, "token")
				if err != nil {
					return err
				}
				tokenChan <- v
				return
			})
		}()

	}
	tokenGroup.Wait()
	close(tokenChan)
	/**/
	wsurlChan := make(chan *url.URL, conn_total)
	wsurlGroup := sync.WaitGroup{}
	for v := range tokenChan {
		wsurlGroup.Add(1)
		go func(v string) {
			defer wsurlGroup.Done()
			wsurl, err := url.Parse(ws_api + "?token=" + v)
			if err != nil {
				return
			}
			wsurlChan <- wsurl

		}(v)
	}
	wsurlGroup.Wait()
	close(wsurlChan)
	pushurl, err := url.Parse(push_api)
	if err != nil {
		log.Fatal(err)
	}
	wsHeaders := http.Header{
		"Origin":                   {"*"},
		"Sec-WebSocket-Extensions": {"permessage-deflate; client_max_window_bits, x-webkit-deflate-frame"},
	}
	connChan := make(chan *websocket.Conn, conn_total)

	connGroup := sync.WaitGroup{}
	log.Infof("%v connect start!", conn_total)
	for wsurl := range wsurlChan {
		connGroup.Add(1)
		go func(wsurl *url.URL) {
			defer connGroup.Done()
			rawConn, err := net.Dial("tcp", wsurl.Host)
			if err != nil {
				return
			}

			//conn, _, err := websocket.NewClient(rawConn, wsurl, wsHeaders, 8192, 8192)
			dialer := websocket.Dialer{
				ReadBufferSize:  8192,
				WriteBufferSize: 8192,
				NetDial: func(net, addr string) (net.Conn, error) {
					return rawConn, nil
				},
				//EnableCompression: true,
			}
			conn, _, err := dialer.Dial(wsurl.String(), wsHeaders)
			if err != nil {
				rawConn.Close()
				return
			}
			connChan <- conn
			return
		}(wsurl)
	}
	connGroup.Wait()
	close(connChan)
	connTotal := len(connChan)
	var counter uint64
	for conn := range connChan {
		wg.Add(1)
		listen_wg.Add(1)
		go func(conn *websocket.Conn) {
			defer func() {
				conn.Close()
			}()
			subStatus := false
			for {
				_, d, err := conn.ReadMessage()

				if err != nil {
					if c.Bool("debug") {
						log.Error("test", err)
					}
					if !subStatus {
						listen_wg.Done()
					}
					wg.Done()
					atomic.AddUint64(&counter, 1)
					return
				}
				if string(d) == sub_resp {
					subStatus = true
					listen_wg.Done()
				}
				if c.Bool("debug") {
					log.Println("slave repsonse message", string(d))
				}
				data, _, _, err := jsonparser.Get(d, "data")
				if len(data) == len([]byte(push_msg)) {
					wg.Done()
					return
				}
			}
		}(conn)
		err = conn.WriteMessage(websocket.TextMessage, []byte(sub_msg))
		if err != nil {
			conn.Close()
			continue
		}
	}

	listen_wg.Wait()
	log.Infof("%v connect finish", connTotal)
	//push start
	v := url.Values{}

	v.Add("data", push_msg)
	req, err := http.NewRequest("POST", pushurl.String(), bytes.NewBufferString(v.Encode()))
	if err != nil {
		log.Fatal(err)
	}
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Add("Content-Length", strconv.Itoa(len(v.Encode())))

	if err != nil {
		log.Fatal(err)
	}
	var pushStart time.Time
	ctx, _ := context.WithTimeout(context.Background(), 30*time.Second)
	err = work.Execute(ctx, req, func(resp *http.Response, e error) (err error) {
		if e != nil {
			return
		}
		defer resp.Body.Close()
		b, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return err
		}
		if c.Bool("debug") {
			log.Println("master response", string(b))
		}
		pushStart = time.Now()
		return
	})
	log.Println("Waiting...")
	wg.Wait()
	t := time.Now().Sub(pushStart)
	if connTotal == 0 {
		log.Error("0 client connect, please check slave server!")
	} else if connTotal == int(counter) {
		log.Error("no client read message, please check master server!")
	} else {

		log.Infof("%v client connect, %v error read , receive msg time:%s", connTotal, counter, t)
	}

	return
}

func main() {
	cli.AppHelpTemplate += "\nWEBSITE:\n\t\thttps://github.com/syhlion/gusher.cluster/tree/master/test/conn-test\n\n"
	gusher := cli.NewApp()
	gusher.Usage = "simple connection test for gusher.cluster"
	gusher.Name = name
	gusher.Author = "Scott (syhlion)"
	gusher.Version = version
	gusher.Compiled = time.Now()
	gusher.Commands = []cli.Command{
		cmdStart,
	}
	gusher.Run(os.Args)
}
<commit_msg>fix conn-test<commit_after>package main

import (
	"bytes"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"sync"
	"sync/atomic"
	"time"

	"github.com/buger/jsonparser"
	"github.com/gorilla/websocket"
	"github.com/joho/godotenv"
	log "github.com/sirupsen/logrus"
	"github.com/syhlion/requestwork.v2"
	"github.com/urfave/cli"
)

var (
	name     string
	version  string
	cmdStart = cli.Command{
		Name:    "run",
		Aliases: []string{"r"},
		Usage:   "test connect to websocket ",
		Action:  start,
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "env-file,e",
				Usage: "import env file",
			},
			cli.BoolFlag{
				Name:  "debug,d",
				Usage: "open debug mode",
			},
		},
	}
	wg        sync.WaitGroup
	listen_wg sync.WaitGroup
)

func start(c *cli.Context) {
	if c.String("env-file") != "" {
		envfile := c.String("env-file")
		//flag.Parse()
		err := godotenv.Load(envfile)
		if err != nil {
			log.Fatal(err)
		}
	}
	ws_api := os.Getenv("GUSHER-CONN-TEST_WS_API")
	if ws_api == "" {
		log.Fatal("empty env GUSHER-CONN-TEST_WS_API")
	}
	ws_auth_api := os.Getenv("GUSHER-CONN-TEST_WS_AUTH_API")
	if ws_auth_api == "" {
		log.Fatal("empty env GUSHER-CONN-TEST_WS_AUTH_API")
	}
	push_api := os.Getenv("GUSHER-CONN-TEST_PUSH_API")
	if push_api == "" {
		log.Fatal("empty env GUSHER-CONN-TEST_PUSH_API")
	}
	jwt := os.Getenv("GUSHER-CONN-TEST_JWT")
	if jwt == "" {
		log.Fatal("empty env GUSHER-CONN-TEST_JWT")
	}
	sub_msg := os.Getenv("GUSHER-CONN-TEST_SUBSCRIBE_MESSAGE")
	if sub_msg == "" {
		log.Fatal("empty env GUSHER-CONN-TEST_SUBSCRIBE_MESSAGE")
	}
	sub_resp := os.Getenv("GUSHER-CONN-TEST_SUBSCRIBE_RESPONSE")
	if sub_resp == "" {
		log.Fatal("empty env GUSHER-CONN-TEST_SUBSCRIBE_RESPONSE")
	}
	push_msg := os.Getenv("GUSHER-CONN-TEST_PUSH_MESSAGE")
	if push_msg == "" {
		log.Fatal("empty env GUSHER-CONN-TEST_PUSH_MESSAGE")
	}
	connections := os.Getenv("GUSHER-CONN-TEST_CONNECTIONS")
	if connections == "" {
		log.Fatal("empty env GUSHER-CONN-TEST_CONNECTIONS")
	}
	conn_total, err := strconv.Atoi(connections)
	if err != nil {
		log.Fatal(err)
	}
	/*auth*/

	wsAuthurl, err := url.Parse(ws_auth_api)
	if err != nil {
		log.Fatal(err)
	}
	work := requestwork.New(5)
	loginUrl := url.Values{}

	loginUrl.Add("jwt", jwt)
	tokenChan := make(chan string, conn_total)
	tokenGroup := sync.WaitGroup{}
	for i := 0; i < conn_total; i++ {
		tokenGroup.Add(1)
		go func() {
			req, err := http.NewRequest("POST", wsAuthurl.String(), bytes.NewBufferString(loginUrl.Encode()))
			if err != nil {
				log.Fatal(err)
			}
			req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
			req.Header.Add("Content-Length", strconv.Itoa(len(loginUrl.Encode())))
			//ctx, _ := context.WithTimeout(context.Background(), 30*time.Second)
			err = work.Execute(req, func(resp *http.Response, e error) (err error) {
				defer tokenGroup.Done()
				if e != nil {
					return e
				}
				defer resp.Body.Close()
				b, err := ioutil.ReadAll(resp.Body)
				if err != nil {
					return err
				}
				v, err := jsonparser.GetString(b, "token")
				if err != nil {
					return err
				}
				tokenChan <- v
				return
			})
		}()

	}
	tokenGroup.Wait()
	close(tokenChan)
	/**/
	wsurlChan := make(chan *url.URL, conn_total)
	wsurlGroup := sync.WaitGroup{}
	for v := range tokenChan {
		wsurlGroup.Add(1)
		go func(v string) {
			defer wsurlGroup.Done()
			wsurl, err := url.Parse(ws_api + "?token=" + v)
			if err != nil {
				return
			}
			wsurlChan <- wsurl

		}(v)
	}
	wsurlGroup.Wait()
	close(wsurlChan)
	pushurl, err := url.Parse(push_api)
	if err != nil {
		log.Fatal(err)
	}
	wsHeaders := http.Header{
		"Origin":                   {"*"},
		"Sec-WebSocket-Extensions": {"permessage-deflate; client_max_window_bits, x-webkit-deflate-frame"},
	}
	connChan := make(chan *websocket.Conn, conn_total)

	connGroup := sync.WaitGroup{}
	log.Infof("%v connect start!", conn_total)
	for wsurl := range wsurlChan {
		connGroup.Add(1)
		go func(wsurl *url.URL) {
			defer connGroup.Done()
			rawConn, err := net.Dial("tcp", wsurl.Host)
			if err != nil {
				return
			}

			//conn, _, err := websocket.NewClient(rawConn, wsurl, wsHeaders, 8192, 8192)
			dialer := websocket.Dialer{
				ReadBufferSize:  8192,
				WriteBufferSize: 8192,
				NetDial: func(net, addr string) (net.Conn, error) {
					return rawConn, nil
				},
				//EnableCompression: true,
			}
			conn, _, err := dialer.Dial(wsurl.String(), wsHeaders)
			if err != nil {
				rawConn.Close()
				return
			}
			connChan <- conn
			return
		}(wsurl)
	}
	connGroup.Wait()
	close(connChan)
	connTotal := len(connChan)
	var counter uint64
	for conn := range connChan {
		wg.Add(1)
		listen_wg.Add(1)
		go func(conn *websocket.Conn) {
			defer func() {
				conn.Close()
			}()
			subStatus := false
			for {
				_, d, err := conn.ReadMessage()

				if err != nil {
					if c.Bool("debug") {
						log.Error("test", err)
					}
					if !subStatus {
						listen_wg.Done()
					}
					wg.Done()
					atomic.AddUint64(&counter, 1)
					return
				}
				if string(d) == sub_resp {
					subStatus = true
					listen_wg.Done()
				}
				if c.Bool("debug") {
					log.Println("slave repsonse message", string(d))
				}
				data, _, _, err := jsonparser.Get(d, "data")
				if len(data) == len([]byte(push_msg)) {
					wg.Done()
					return
				}
			}
		}(conn)
		err = conn.WriteMessage(websocket.TextMessage, []byte(sub_msg))
		if err != nil {
			conn.Close()
			continue
		}
	}

	listen_wg.Wait()
	log.Infof("%v connect finish", connTotal)
	//push start
	v := url.Values{}

	v.Add("data", push_msg)
	req, err := http.NewRequest("POST", pushurl.String(), bytes.NewBufferString(v.Encode()))
	if err != nil {
		log.Fatal(err)
	}
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Add("Content-Length", strconv.Itoa(len(v.Encode())))

	if err != nil {
		log.Fatal(err)
	}
	var pushStart time.Time
	err = work.Execute(req, func(resp *http.Response, e error) (err error) {
		if e != nil {
			return
		}
		defer resp.Body.Close()
		b, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return err
		}
		if c.Bool("debug") {
			log.Println("master response", string(b))
		}
		pushStart = time.Now()
		return
	})
	log.Println("Waiting...")
	wg.Wait()
	t := time.Now().Sub(pushStart)
	if connTotal == 0 {
		log.Error("0 client connect, please check slave server!")
	} else if connTotal == int(counter) {
		log.Error("no client read message, please check master server!")
	} else {

		log.Infof("%v client connect, %v error read , receive msg time:%s", connTotal, counter, t)
	}

	return
}

func main() {
	cli.AppHelpTemplate += "\nWEBSITE:\n\t\thttps://github.com/syhlion/gusher.cluster/tree/master/test/conn-test\n\n"
	gusher := cli.NewApp()
	gusher.Usage = "simple connection test for gusher.cluster"
	gusher.Name = name
	gusher.Author = "Scott (syhlion)"
	gusher.Version = version
	gusher.Compiled = time.Now()
	gusher.Commands = []cli.Command{
		cmdStart,
	}
	gusher.Run(os.Args)
}
<|endoftext|>


<commit_before>package cmd

import (
	"errors"
	"os"

	"github.com/spf13/cobra"
)

// completionCmdGroup represents the completion command
var completionCmd = &cobra.Command{
	Use:   "completion [shell]",
	Short: "Output shell completion code for the specified shell",
	Long: `
Output shell completion code for the specified shell (bash or zsh).
The shell code must be evalutated to provide interactive
completion of kubectl commands.  This can be done by sourcing it from
the .bash_profile.

Note: this requires the bash-completion framework, which is not installed
by default on Mac.  This can be installed by using homebrew:

    $ brew install bash-completion

Once installed, bash_completion must be evaluated.  This can be done by adding the
following line to the .bash_profile

    $ source $(brew --prefix)/etc/bash_completion`,
	Example:   `# cozy-stack completion bash > /etc/bash_completion.d/cozy-stack`,
	ValidArgs: []string{"bash"},
	RunE: func(cmd *cobra.Command, args []string) error {
		if len(args) != 1 {
			return cmd.Usage()
		}
		switch args[0] {
		case "bash":
			return RootCmd.GenBashCompletion(os.Stdout)
		}
		// TODO add zsh - https://github.com/spf13/cobra/issues/107
		return errors.New("Unsupported shell")
	},
}

func init() {
	RootCmd.AddCommand(completionCmd)
}
<commit_msg>Add basic completion support for Zsh<commit_after>package cmd

import (
	"errors"
	"os"

	"github.com/spf13/cobra"
)

// completionCmdGroup represents the completion command
var completionCmd = &cobra.Command{
	Use:   "completion [shell]",
	Short: "Output shell completion code for the specified shell",
	Long: `
Output shell completion code for the specified shell (bash or zsh).
The shell code must be evalutated to provide interactive
completion of kubectl commands.  This can be done by sourcing it from
the .bash_profile.

Note: this requires the bash-completion framework, which is not installed
by default on Mac.  This can be installed by using homebrew:

    $ brew install bash-completion

Once installed, bash_completion must be evaluated.  This can be done by adding the
following line to the .bash_profile

    $ source $(brew --prefix)/etc/bash_completion`,
	Example:   `# cozy-stack completion bash > /etc/bash_completion.d/cozy-stack`,
	ValidArgs: []string{"bash"},
	RunE: func(cmd *cobra.Command, args []string) error {
		if len(args) != 1 {
			return cmd.Usage()
		}
		switch args[0] {
		case "bash":
			return RootCmd.GenBashCompletion(os.Stdout)
		case "zsh":
			// Zsh completion support is still basic
			// https://github.com/spf13/cobra/issues/107
			return RootCmd.GenZshCompletion(os.Stdout)
		}
		return errors.New("Unsupported shell")
	},
}

func init() {
	RootCmd.AddCommand(completionCmd)
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// 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 env

import (
	"github.com/spf13/cobra"
	"github.com/srinandan/apigeecli/apiclient"
	"github.com/srinandan/apigeecli/client/env"
)

//Cmd to get env details
var CreateCmd = &cobra.Command{
	Use:   "create",
	Short: "Create a new environment",
	Long:  "Create a new environment",
	Args: func(cmd *cobra.Command, args []string) (err error) {
		apiclient.SetApigeeEnv(environment)
		return apiclient.SetApigeeOrg(org)
	},
	RunE: func(cmd *cobra.Command, args []string) (err error) {
		_, err = env.Create(deploymentType)
		return
	},
}

var deploymentType string

func init() {

	CreateCmd.Flags().StringVarP(&environment, "env", "e",
		"", "Apigee environment name")
	CreateCmd.Flags().StringVarP(&deploymentType, "deptype", "d",
		"", "Deployment type - must be PROXY or ARCHIVE")

	_ = CreateCmd.MarkFlagRequired("env")
}
<commit_msg>support proxy types<commit_after>// Copyright 2020 Google LLC
//
// 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 env

import (
	"github.com/spf13/cobra"
	"github.com/srinandan/apigeecli/apiclient"
	"github.com/srinandan/apigeecli/client/env"
)

//Cmd to get env details
var CreateCmd = &cobra.Command{
	Use:   "create",
	Short: "Create a new environment",
	Long:  "Create a new environment",
	Args: func(cmd *cobra.Command, args []string) (err error) {
		apiclient.SetApigeeEnv(environment)
		return apiclient.SetApigeeOrg(org)
	},
	RunE: func(cmd *cobra.Command, args []string) (err error) {
		_, err = env.Create(deploymentType, apiProxyType)
		return
	},
}

var deploymentType, apiProxyType string

func init() {

	CreateCmd.Flags().StringVarP(&environment, "env", "e",
		"", "Apigee environment name")
	CreateCmd.Flags().StringVarP(&deploymentType, "deptype", "d",
		"", "Deployment type - must be PROXY or ARCHIVE")
	CreateCmd.Flags().StringVarP(&apiProxyType, "proxtype", "p",
		"", "Proxy type - must be PROGRAMMABLE or CONFIGURABLE")
	_ = CreateCmd.MarkFlagRequired("env")
}
<|endoftext|>


<commit_before>/*
Copyright The Helm 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 main

import (
	"errors"
	"fmt"
	"io"
	"os"
	"strings"

	"github.com/spf13/cobra"

	"k8s.io/client-go/kubernetes"

	"k8s.io/helm/cmd/helm/installer"
	"k8s.io/helm/pkg/helm"
	"k8s.io/helm/pkg/helm/helmpath"
	"k8s.io/helm/pkg/proto/hapi/release"
)

const resetDesc = `
This command uninstalls Tiller (the Helm server-side component) from your
Kubernetes Cluster and optionally deletes local configuration in
$HELM_HOME (default ~/.helm/)
`

type resetCmd struct {
	force          bool
	removeHelmHome bool
	namespace      string
	out            io.Writer
	home           helmpath.Home
	client         helm.Interface
	kubeClient     kubernetes.Interface
}

func newResetCmd(client helm.Interface, out io.Writer) *cobra.Command {
	d := &resetCmd{
		out:    out,
		client: client,
	}

	cmd := &cobra.Command{
		Use:   "reset",
		Short: "Uninstalls Tiller from a cluster",
		Long:  resetDesc,
		PreRunE: func(cmd *cobra.Command, args []string) error {
			err := setupConnection()
			if !d.force && err != nil {
				return err
			}
			if d.force && err != nil && strings.EqualFold(err.Error(), "could not find tiller") {
				return err
			}
			return nil
		},
		RunE: func(cmd *cobra.Command, args []string) error {
			if len(args) != 0 {
				return errors.New("This command does not accept arguments")
			}

			d.namespace = settings.TillerNamespace
			d.home = settings.Home
			d.client = ensureHelmClient(d.client)

			return d.run()
		},
	}

	f := cmd.Flags()
	settings.AddFlagsTLS(f)
	f.BoolVarP(&d.force, "force", "f", false, "Forces Tiller uninstall even if there are releases installed, or if Tiller is not in ready state. Releases are not deleted.)")
	f.BoolVar(&d.removeHelmHome, "remove-helm-home", false, "If set, deletes $HELM_HOME")

	// set defaults from environment
	settings.InitTLS(f)

	return cmd
}

// runReset uninstalls tiller from Kubernetes Cluster and deletes local config
func (d *resetCmd) run() error {
	if d.kubeClient == nil {
		_, c, err := getKubeClient(settings.KubeContext, settings.KubeConfig)
		if err != nil {
			return fmt.Errorf("could not get kubernetes client: %s", err)
		}
		d.kubeClient = c
	}

	res, err := d.client.ListReleases(
		helm.ReleaseListStatuses([]release.Status_Code{release.Status_DEPLOYED}),
	)
	if !d.force && err != nil {
		return prettyError(err)
	}

	if !d.force && res != nil && len(res.Releases) > 0 {
		return fmt.Errorf("there are still %d deployed releases (Tip: use --force to remove Tiller. Releases will not be deleted.)", len(res.Releases))
	}

	if err := installer.Uninstall(d.kubeClient, &installer.Options{Namespace: d.namespace}); err != nil {
		return fmt.Errorf("error unstalling Tiller: %s", err)
	}

	if d.removeHelmHome {
		if err := deleteDirectories(d.home, d.out); err != nil {
			return err
		}
	}

	fmt.Fprintln(d.out, "Tiller (the Helm server-side component) has been uninstalled from your Kubernetes Cluster.")
	return nil
}

// deleteDirectories deletes $HELM_HOME
func deleteDirectories(home helmpath.Home, out io.Writer) error {
	if _, err := os.Stat(home.String()); err == nil {
		fmt.Fprintf(out, "Deleting %s \n", home.String())
		if err := os.RemoveAll(home.String()); err != nil {
			return fmt.Errorf("Could not remove %s: %s", home.String(), err)
		}
	}

	return nil
}
<commit_msg>cleanup: log message typo fix<commit_after>/*
Copyright The Helm 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 main

import (
	"errors"
	"fmt"
	"io"
	"os"
	"strings"

	"github.com/spf13/cobra"

	"k8s.io/client-go/kubernetes"

	"k8s.io/helm/cmd/helm/installer"
	"k8s.io/helm/pkg/helm"
	"k8s.io/helm/pkg/helm/helmpath"
	"k8s.io/helm/pkg/proto/hapi/release"
)

const resetDesc = `
This command uninstalls Tiller (the Helm server-side component) from your
Kubernetes Cluster and optionally deletes local configuration in
$HELM_HOME (default ~/.helm/)
`

type resetCmd struct {
	force          bool
	removeHelmHome bool
	namespace      string
	out            io.Writer
	home           helmpath.Home
	client         helm.Interface
	kubeClient     kubernetes.Interface
}

func newResetCmd(client helm.Interface, out io.Writer) *cobra.Command {
	d := &resetCmd{
		out:    out,
		client: client,
	}

	cmd := &cobra.Command{
		Use:   "reset",
		Short: "Uninstalls Tiller from a cluster",
		Long:  resetDesc,
		PreRunE: func(cmd *cobra.Command, args []string) error {
			err := setupConnection()
			if !d.force && err != nil {
				return err
			}
			if d.force && err != nil && strings.EqualFold(err.Error(), "could not find tiller") {
				return err
			}
			return nil
		},
		RunE: func(cmd *cobra.Command, args []string) error {
			if len(args) != 0 {
				return errors.New("This command does not accept arguments")
			}

			d.namespace = settings.TillerNamespace
			d.home = settings.Home
			d.client = ensureHelmClient(d.client)

			return d.run()
		},
	}

	f := cmd.Flags()
	settings.AddFlagsTLS(f)
	f.BoolVarP(&d.force, "force", "f", false, "Forces Tiller uninstall even if there are releases installed, or if Tiller is not in ready state. Releases are not deleted.)")
	f.BoolVar(&d.removeHelmHome, "remove-helm-home", false, "If set, deletes $HELM_HOME")

	// set defaults from environment
	settings.InitTLS(f)

	return cmd
}

// runReset uninstalls tiller from Kubernetes Cluster and deletes local config
func (d *resetCmd) run() error {
	if d.kubeClient == nil {
		_, c, err := getKubeClient(settings.KubeContext, settings.KubeConfig)
		if err != nil {
			return fmt.Errorf("could not get kubernetes client: %s", err)
		}
		d.kubeClient = c
	}

	res, err := d.client.ListReleases(
		helm.ReleaseListStatuses([]release.Status_Code{release.Status_DEPLOYED}),
	)
	if !d.force && err != nil {
		return prettyError(err)
	}

	if !d.force && res != nil && len(res.Releases) > 0 {
		return fmt.Errorf("there are still %d deployed releases (Tip: use --force to remove Tiller. Releases will not be deleted.)", len(res.Releases))
	}

	if err := installer.Uninstall(d.kubeClient, &installer.Options{Namespace: d.namespace}); err != nil {
		return fmt.Errorf("error uninstalling Tiller: %s", err)
	}

	if d.removeHelmHome {
		if err := deleteDirectories(d.home, d.out); err != nil {
			return err
		}
	}

	fmt.Fprintln(d.out, "Tiller (the Helm server-side component) has been uninstalled from your Kubernetes Cluster.")
	return nil
}

// deleteDirectories deletes $HELM_HOME
func deleteDirectories(home helmpath.Home, out io.Writer) error {
	if _, err := os.Stat(home.String()); err == nil {
		fmt.Fprintf(out, "Deleting %s \n", home.String())
		if err := os.RemoveAll(home.String()); err != nil {
			return fmt.Errorf("Could not remove %s: %s", home.String(), err)
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/http"

	log "github.com/Sirupsen/logrus"
	"github.com/hellofresh/janus/pkg/api"
	"github.com/hellofresh/janus/pkg/jwt"
	"github.com/hellofresh/janus/pkg/middleware"
	"github.com/hellofresh/janus/pkg/oauth"
	"github.com/hellofresh/janus/pkg/proxy"
	"github.com/hellofresh/janus/pkg/router"
)

//loadAPIEndpoints register api endpoints
func loadAPIEndpoints(router router.Router, authMiddleware *jwt.Middleware, loader *api.Loader) {
	log.Debug("Loading API Endpoints")

	// Apis endpoints
	handler := api.NewController(loader)
	group := router.Group("/apis")
	group.Use(authMiddleware.Handler)
	{
		group.GET("", handler.Get())
		group.POST("", handler.Post())
		group.GET("/:id", handler.GetBy())
		group.PUT("/:id", handler.PutBy())
		group.DELETE("/:id", handler.DeleteBy())
	}
}

//loadOAuthEndpoints register api endpoints
func loadOAuthEndpoints(router router.Router, authMiddleware *jwt.Middleware, loader *oauth.Loader) {
	log.Debug("Loading OAuth Endpoints")

	// Oauth servers endpoints
	oAuthHandler := oauth.NewController(loader)
	oauthGroup := router.Group("/oauth/servers")
	oauthGroup.Use(authMiddleware.Handler)
	{
		oauthGroup.GET("", oAuthHandler.Get())
		oauthGroup.POST("", oAuthHandler.Post())
		oauthGroup.GET("/:id", oAuthHandler.GetBy())
		oauthGroup.PUT("/:id", oAuthHandler.PutBy())
		oauthGroup.DELETE("/:id", oAuthHandler.DeleteBy())
	}
}

func loadAuthEndpoints(router router.Router, authMiddleware *jwt.Middleware) {
	log.Debug("Loading Auth Endpoints")

	handlers := jwt.Handler{Config: authMiddleware.Config}
	router.POST("/login", handlers.Login())
	authGroup := router.Group("/auth")
	authGroup.Use(authMiddleware.Handler)
	{
		authGroup.GET("/refresh_token", handlers.Refresh())
	}
}

func main() {
	defer accessor.Close()
	defer statsdClient.Close()

	// create router
	r := router.NewHttpTreeMuxRouter()
	r.Use(middleware.NewLogger(globalConfig.Debug).Handler, middleware.NewRecovery(RecoveryHandler).Handler, middleware.NewMongoDB(accessor).Handler)

	// create the proxy
	manager := &oauth.Manager{Storage: storage}
	transport := oauth.NewAwareTransport(manager)
	p := proxy.WithParams(proxy.Params{
		Transport:              transport,
		FlushInterval:          globalConfig.BackendFlushInterval,
		IdleConnectionsPerHost: globalConfig.MaxIdleConnsPerHost,
		CloseIdleConnsPeriod:   globalConfig.CloseIdleConnsPeriod,
		InsecureSkipVerify:     globalConfig.InsecureSkipVerify,
	})
	defer p.Close()

	// create proxy register
	register := proxy.NewInMemoryRegister(r, p)

	apiLoader := api.NewLoader(register, storage, accessor, manager, globalConfig.Debug)
	apiLoader.Load()

	oauthLoader := oauth.NewLoader(register, accessor, globalConfig.Debug)
	oauthLoader.Load()

	// create authentication for Janus
	authConfig := jwt.NewConfig(globalConfig.Credentials)
	authMiddleware := jwt.NewMiddleware(authConfig)

	// create endpoints
	r.GET("/", Home(globalConfig.Application))
	r.GET("/status", Heartbeat())

	loadAuthEndpoints(r, authMiddleware)
	loadAPIEndpoints(r, authMiddleware, apiLoader)
	loadOAuthEndpoints(r, authMiddleware, oauthLoader)

	log.Fatal(listenAndServe(r))
}

func listenAndServe(handler http.Handler) error {
	address := fmt.Sprintf(":%v", globalConfig.Port)
	log.Infof("Listening on %v", address)
	if globalConfig.IsHTTPS() {
		return http.ListenAndServeTLS(address, globalConfig.CertPathTLS, globalConfig.KeyPathTLS, handler)
	}

	log.Infof("certPathTLS or keyPathTLS not found, defaulting to HTTP")
	return http.ListenAndServe(address, handler)
}
<commit_msg>Passing the redis storage<commit_after>package main

import (
	"fmt"
	"net/http"

	log "github.com/Sirupsen/logrus"
	"github.com/hellofresh/janus/pkg/api"
	"github.com/hellofresh/janus/pkg/jwt"
	"github.com/hellofresh/janus/pkg/middleware"
	"github.com/hellofresh/janus/pkg/oauth"
	"github.com/hellofresh/janus/pkg/proxy"
	"github.com/hellofresh/janus/pkg/router"
)

//loadAPIEndpoints register api endpoints
func loadAPIEndpoints(router router.Router, authMiddleware *jwt.Middleware, loader *api.Loader) {
	log.Debug("Loading API Endpoints")

	// Apis endpoints
	handler := api.NewController(loader)
	group := router.Group("/apis")
	group.Use(authMiddleware.Handler)
	{
		group.GET("", handler.Get())
		group.POST("", handler.Post())
		group.GET("/:id", handler.GetBy())
		group.PUT("/:id", handler.PutBy())
		group.DELETE("/:id", handler.DeleteBy())
	}
}

//loadOAuthEndpoints register api endpoints
func loadOAuthEndpoints(router router.Router, authMiddleware *jwt.Middleware, loader *oauth.Loader) {
	log.Debug("Loading OAuth Endpoints")

	// Oauth servers endpoints
	oAuthHandler := oauth.NewController(loader)
	oauthGroup := router.Group("/oauth/servers")
	oauthGroup.Use(authMiddleware.Handler)
	{
		oauthGroup.GET("", oAuthHandler.Get())
		oauthGroup.POST("", oAuthHandler.Post())
		oauthGroup.GET("/:id", oAuthHandler.GetBy())
		oauthGroup.PUT("/:id", oAuthHandler.PutBy())
		oauthGroup.DELETE("/:id", oAuthHandler.DeleteBy())
	}
}

func loadAuthEndpoints(router router.Router, authMiddleware *jwt.Middleware) {
	log.Debug("Loading Auth Endpoints")

	handlers := jwt.Handler{Config: authMiddleware.Config}
	router.POST("/login", handlers.Login())
	authGroup := router.Group("/auth")
	authGroup.Use(authMiddleware.Handler)
	{
		authGroup.GET("/refresh_token", handlers.Refresh())
	}
}

func main() {
	defer accessor.Close()
	defer statsdClient.Close()

	// create router
	r := router.NewHttpTreeMuxRouter()
	r.Use(middleware.NewLogger(globalConfig.Debug).Handler, middleware.NewRecovery(RecoveryHandler).Handler, middleware.NewMongoDB(accessor).Handler)

	// create the proxy
	manager := &oauth.Manager{Storage: storage}
	transport := oauth.NewAwareTransport(manager)
	p := proxy.WithParams(proxy.Params{
		Transport:              transport,
		FlushInterval:          globalConfig.BackendFlushInterval,
		IdleConnectionsPerHost: globalConfig.MaxIdleConnsPerHost,
		CloseIdleConnsPeriod:   globalConfig.CloseIdleConnsPeriod,
		InsecureSkipVerify:     globalConfig.InsecureSkipVerify,
	})
	defer p.Close()

	// create proxy register
	register := proxy.NewRegister(r, p, storage)
	apiLoader := api.NewLoader(register, storage, accessor, manager, globalConfig.Debug)
	apiLoader.Load()

	oauthLoader := oauth.NewLoader(register, accessor, globalConfig.Debug)
	oauthLoader.Load()

	// create authentication for Janus
	authConfig := jwt.NewConfig(globalConfig.Credentials)
	authMiddleware := jwt.NewMiddleware(authConfig)

	// create endpoints
	r.GET("/", Home(globalConfig.Application))
	r.GET("/status", Heartbeat())

	loadAuthEndpoints(r, authMiddleware)
	loadAPIEndpoints(r, authMiddleware, apiLoader)
	loadOAuthEndpoints(r, authMiddleware, oauthLoader)

	log.Fatal(listenAndServe(r))
}

func listenAndServe(handler http.Handler) error {
	address := fmt.Sprintf(":%v", globalConfig.Port)
	log.Infof("Listening on %v", address)
	if globalConfig.IsHTTPS() {
		return http.ListenAndServeTLS(address, globalConfig.CertPathTLS, globalConfig.KeyPathTLS, handler)
	}

	log.Infof("certPathTLS or keyPathTLS not found, defaulting to HTTP")
	return http.ListenAndServe(address, handler)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/calmh/mole/ansi"
	"github.com/calmh/mole/conf"
	"github.com/calmh/mole/table"
	"github.com/sbinet/liner"
	"io"
	"os"
	"os/signal"
	"strconv"
	"strings"
	"sync"
	"time"
)

var errTimeout = fmt.Errorf("connection timeout")

const maxOutstandingTests = 16 // max number of parallell connection attempts when performing test

func shell(fwdChan chan<- conf.ForwardLine, cfg *conf.Config, dialer Dialer) {
	help := func() {
		infoln("Available commands:")
		infoln("  help, ?                          - show help")
		infoln("  quit, ^D                         - stop forwarding and exit")
		infoln("  test                             - test each forward for connection")
		infoln("  stat                             - show forwarding statistics")
		infoln("  debug                            - enable debugging")
		infoln("  fwd srcip:srcport dstip:dstport  - add forward")
	}

	term := liner.NewLiner()
	atExit(func() {
		term.Close()
	})

	// Receive commands

	commands := make(chan string)
	next := make(chan bool)
	go func() {
		for {
			prompt := "mole> "
			if debugEnabled {
				prompt = "(debug) mole> "
			}
			cmd, err := term.Prompt(prompt)
			if err == io.EOF {
				fmt.Println("quit")
				commands <- "quit"
				return
			}

			if cmd != "" {
				commands <- cmd
				term.AppendHistory(cmd)
				_, ok := <-next
				if !ok {
					return
				}
			}
		}
	}()

	// Catch ^C and treat as "quit" command

	sigchan := make(chan os.Signal, 1)
	signal.Notify(sigchan, os.Interrupt)
	go func() {
		<-sigchan
		fmt.Println("quit")
		commands <- "quit"
	}()

	// Handle commands

	for {
		cmd := <-commands

		parts := strings.SplitN(cmd, " ", -1)

		switch parts[0] {
		case "quit":
			close(next)
			return
		case "help", "?":
			help()
		case "stat":
			printStats()
		case "test":
			results := testForwards(dialer, cfg)
			for res := range results {
				infof(ansi.Bold(ansi.Cyan(res.name)))
				for _, line := range res.results {
					if line.err == nil {
						infof("%22s %s in %.02f ms", line.dst, ansi.Bold(ansi.Green("-ok-")), line.ms)
					} else {
						infof("%22s %s in %.02f ms (%s)", line.dst, ansi.Bold(ansi.Red("fail")), line.ms, line.err)
					}
				}
			}
		case "debug":
			infoln(msgDebugEnabled)
			debugEnabled = true
		case "fwd":
			if len(parts) != 3 {
				warnf(msgErrIncorrectFwd, cmd)
				break
			}

			src := strings.SplitN(parts[1], ":", 2)
			if len(src) != 2 {
				warnf(msgErrIncorrectFwdSrc, parts[1])
				break
			}

			var ipExists bool
			for _, ip := range currentAddresses() {
				if ip == src[0] {
					ipExists = true
					break
				}
			}
			if !ipExists {
				warnf(msgErrIncorrectFwdIP, src[0])
				break
			}

			dst := strings.SplitN(parts[2], ":", 2)
			if len(dst) != 2 {
				warnf(msgErrIncorrectFwdDst, parts[2])
				break
			}

			srcp, err := strconv.Atoi(src[1])
			if err != nil {
				warnln(err)
				break
			}
			if srcp < 1024 {
				warnf(msgErrIncorrectFwdPriv, srcp)
				break
			}

			dstp, err := strconv.Atoi(dst[1])
			if err != nil {
				warnln(err)
				break
			}
			fwd := conf.ForwardLine{
				SrcIP:   src[0],
				SrcPort: srcp,
				DstIP:   dst[0],
				DstPort: dstp,
			}
			okln("add", fwd)
			fwdChan <- fwd
		default:
			warnf(msgErrNoSuchCommand, parts[0])
		}

		next <- true
	}
}

func printStats() {
	var rows [][]string
	rows = append(rows, []string{"FORWARD", "CONNS", "IN", "OUT"})
	total := trafficCounter{name: "Total"}
	for _, cnt := range globalConnectionStats {
		rows = append(rows, cnt.row())
		total.conns += cnt.conns
		total.in += cnt.in
		total.out += cnt.out
	}
	rows = append(rows, total.row())
	fmt.Println(table.Fmt("lrrr", rows))
}

func printTotalStats() {
	total := trafficCounter{}
	for _, cnt := range globalConnectionStats {
		total.conns += cnt.conns
		total.in += cnt.in
		total.out += cnt.out
	}
	if total.conns > 0 {
		infof("Total: %d connections, %sB in, %sB out", total.conns, formatBytes(total.in), formatBytes(total.out))
	}
}

type forwardTest struct {
	name    string
	results []testResult
}
type testResult struct {
	dst string
	ms  float64
	err error
}

func testForwards(dialer Dialer, cfg *conf.Config) <-chan forwardTest {
	results := make(chan forwardTest)
	outstanding := make(chan bool, maxOutstandingTests)

	// Do the test in the background
	go func() {
		var scanWg sync.WaitGroup
		scanWg.Add(len(cfg.Forwards))

		for _, fwd := range cfg.Forwards {
			// Do each forward in parallell
			go func(fwd conf.Forward) {
				nlines := 0
				for _, line := range fwd.Lines {
					nlines += line.Repeat + 1
				}

				res := forwardTest{name: fwd.Name}
				res.results = make([]testResult, nlines)

				var fwdWg sync.WaitGroup
				fwdWg.Add(nlines)
				j := 0

				for _, line := range fwd.Lines {
					for i := 0; i <= line.Repeat; i++ {
						// Do each line in parallell
						go func(i, j int) {
							outstanding <- true
							t0 := time.Now()
							err := <-testLineIndex(dialer, line, i)
							ms := time.Since(t0).Seconds() * 1000
							<-outstanding

							res.results[j] = testResult{dst: line.DstString(i), ms: ms, err: err}
							fwdWg.Done()
						}(i, j)
						j++
					}
				}

				fwdWg.Wait()
				results <- res
				scanWg.Done()
			}(fwd)
		}

		scanWg.Wait()
		close(results)
	}()

	return results
}

func testLineIndex(dialer Dialer, line conf.ForwardLine, i int) <-chan error {
	subres := make(chan error, 1)

	go func() {
		time.Sleep(5 * time.Second)
		subres <- errTimeout
	}()

	go func() {
		debugln("test", line.DstString(i))
		conn, err := dialer.Dial("tcp", line.DstString(i))
		if err == nil && conn != nil {
			conn.Close()
		}
		subres <- err
	}()

	return subres
}
<commit_msg>Race condition in connectivity test<commit_after>package main

import (
	"fmt"
	"github.com/calmh/mole/ansi"
	"github.com/calmh/mole/conf"
	"github.com/calmh/mole/table"
	"github.com/sbinet/liner"
	"io"
	"os"
	"os/signal"
	"strconv"
	"strings"
	"sync"
	"time"
)

var errTimeout = fmt.Errorf("connection timeout")

const maxOutstandingTests = 16 // max number of parallell connection attempts when performing test

func shell(fwdChan chan<- conf.ForwardLine, cfg *conf.Config, dialer Dialer) {
	help := func() {
		infoln("Available commands:")
		infoln("  help, ?                          - show help")
		infoln("  quit, ^D                         - stop forwarding and exit")
		infoln("  test                             - test each forward for connection")
		infoln("  stat                             - show forwarding statistics")
		infoln("  debug                            - enable debugging")
		infoln("  fwd srcip:srcport dstip:dstport  - add forward")
	}

	term := liner.NewLiner()
	atExit(func() {
		term.Close()
	})

	// Receive commands

	commands := make(chan string)
	next := make(chan bool)
	go func() {
		for {
			prompt := "mole> "
			if debugEnabled {
				prompt = "(debug) mole> "
			}
			cmd, err := term.Prompt(prompt)
			if err == io.EOF {
				fmt.Println("quit")
				commands <- "quit"
				return
			}

			if cmd != "" {
				commands <- cmd
				term.AppendHistory(cmd)
				_, ok := <-next
				if !ok {
					return
				}
			}
		}
	}()

	// Catch ^C and treat as "quit" command

	sigchan := make(chan os.Signal, 1)
	signal.Notify(sigchan, os.Interrupt)
	go func() {
		<-sigchan
		fmt.Println("quit")
		commands <- "quit"
	}()

	// Handle commands

	for {
		cmd := <-commands

		parts := strings.SplitN(cmd, " ", -1)

		switch parts[0] {
		case "quit":
			close(next)
			return
		case "help", "?":
			help()
		case "stat":
			printStats()
		case "test":
			results := testForwards(dialer, cfg)
			for res := range results {
				infof(ansi.Bold(ansi.Cyan(res.name)))
				for _, line := range res.results {
					if line.err == nil {
						infof("%22s %s in %.02f ms", line.dst, ansi.Bold(ansi.Green("-ok-")), line.ms)
					} else {
						infof("%22s %s in %.02f ms (%s)", line.dst, ansi.Bold(ansi.Red("fail")), line.ms, line.err)
					}
				}
			}
		case "debug":
			infoln(msgDebugEnabled)
			debugEnabled = true
		case "fwd":
			if len(parts) != 3 {
				warnf(msgErrIncorrectFwd, cmd)
				break
			}

			src := strings.SplitN(parts[1], ":", 2)
			if len(src) != 2 {
				warnf(msgErrIncorrectFwdSrc, parts[1])
				break
			}

			var ipExists bool
			for _, ip := range currentAddresses() {
				if ip == src[0] {
					ipExists = true
					break
				}
			}
			if !ipExists {
				warnf(msgErrIncorrectFwdIP, src[0])
				break
			}

			dst := strings.SplitN(parts[2], ":", 2)
			if len(dst) != 2 {
				warnf(msgErrIncorrectFwdDst, parts[2])
				break
			}

			srcp, err := strconv.Atoi(src[1])
			if err != nil {
				warnln(err)
				break
			}
			if srcp < 1024 {
				warnf(msgErrIncorrectFwdPriv, srcp)
				break
			}

			dstp, err := strconv.Atoi(dst[1])
			if err != nil {
				warnln(err)
				break
			}
			fwd := conf.ForwardLine{
				SrcIP:   src[0],
				SrcPort: srcp,
				DstIP:   dst[0],
				DstPort: dstp,
			}
			okln("add", fwd)
			fwdChan <- fwd
		default:
			warnf(msgErrNoSuchCommand, parts[0])
		}

		next <- true
	}
}

func printStats() {
	var rows [][]string
	rows = append(rows, []string{"FORWARD", "CONNS", "IN", "OUT"})
	total := trafficCounter{name: "Total"}
	for _, cnt := range globalConnectionStats {
		rows = append(rows, cnt.row())
		total.conns += cnt.conns
		total.in += cnt.in
		total.out += cnt.out
	}
	rows = append(rows, total.row())
	fmt.Println(table.Fmt("lrrr", rows))
}

func printTotalStats() {
	total := trafficCounter{}
	for _, cnt := range globalConnectionStats {
		total.conns += cnt.conns
		total.in += cnt.in
		total.out += cnt.out
	}
	if total.conns > 0 {
		infof("Total: %d connections, %sB in, %sB out", total.conns, formatBytes(total.in), formatBytes(total.out))
	}
}

type forwardTest struct {
	name    string
	results []testResult
}
type testResult struct {
	dst string
	ms  float64
	err error
}

func testForwards(dialer Dialer, cfg *conf.Config) <-chan forwardTest {
	results := make(chan forwardTest)
	outstanding := make(chan bool, maxOutstandingTests)

	// Do the test in the background
	go func() {
		var scanWg sync.WaitGroup
		scanWg.Add(len(cfg.Forwards))

		for _, fwd := range cfg.Forwards {
			// Do each forward in parallell
			go func(fwd conf.Forward) {
				nlines := 0
				for _, line := range fwd.Lines {
					nlines += line.Repeat + 1
				}

				res := forwardTest{name: fwd.Name}
				res.results = make([]testResult, nlines)

				var fwdWg sync.WaitGroup
				fwdWg.Add(nlines)
				j := 0

				for _, line := range fwd.Lines {
					for i := 0; i <= line.Repeat; i++ {
						// Do each line in parallell
						go func(line conf.ForwardLine, i, j int) {
							outstanding <- true
							t0 := time.Now()
							err := <-testLineIndex(dialer, line, i)
							ms := time.Since(t0).Seconds() * 1000
							<-outstanding

							res.results[j] = testResult{dst: line.DstString(i), ms: ms, err: err}
							fwdWg.Done()
						}(line, i, j)
						j++
					}
				}

				fwdWg.Wait()
				results <- res
				scanWg.Done()
			}(fwd)
		}

		scanWg.Wait()
		close(results)
	}()

	return results
}

func testLineIndex(dialer Dialer, line conf.ForwardLine, i int) <-chan error {
	subres := make(chan error, 1)

	go func() {
		time.Sleep(5 * time.Second)
		subres <- errTimeout
	}()

	go func() {
		debugln("test", line.DstString(i))
		conn, err := dialer.Dial("tcp", line.DstString(i))
		if err == nil && conn != nil {
			conn.Close()
		}
		subres <- err
	}()

	return subres
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/csv"
	"io"
	"net/http"
	"regexp"
	"strconv"
	"time"

	"github.com/line/line-bot-sdk-go/linebot"

	"golang.org/x/net/context"
	"golang.org/x/text/encoding/japanese"
	"golang.org/x/text/transform"

	"google.golang.org/appengine"
	"google.golang.org/appengine/datastore"
	"google.golang.org/appengine/log"
	"google.golang.org/appengine/urlfetch"
)

// 調整さんの開催日ごとの集計エントリ
type schedule struct {
	Date             time.Time // 開催日（時間は00:00:00JST）
	DateString       string    // 日程欄（文字列）
	Present          int       // ◯
	Absent           int       // ×
	Unknown          int       // △および未入力
	ParticipantsName string    // 参加者の名前を列挙したもの
	UnknownName      string    // △および未入力の名前を列挙したもの
}

// 送信メッセージ用のサマリを組み立てて返す
func (s *schedule) constructSummaryBody() string {
	return s.DateString + "の出欠状況をお知らせします\n\n" +
		"参加: " + strconv.Itoa(s.Present) + "名" + s.ParticipantsName +
		"\n不参加: " + strconv.Itoa(s.Absent) + "名\n" +
		"不明/未入力: " + strconv.Itoa(s.Unknown) + "名" + s.UnknownName
}

// 送信メッセージ用のサマリを組み立てて返す
func (s *schedule) constructSummary(hash string) string {
	return s.constructSummaryBody() +
		"\n\n詳細および出欠変更は「調整さん」へ\nhttps://chouseisan.com/s?h=" + hash
}

// 調整さんスケジュールのMap型
type scheduleMap map[string]schedule

/**
 * 調整さんcsvをパースして、参加人数などを集計する
 */
func parseCsv(c context.Context, csvBody io.ReadCloser, today time.Time) (m scheduleMap) {
	var (
		names    []string
		rowCount = 0
	)
	m = make(scheduleMap)

	reader := csv.NewReader(transform.NewReader(csvBody, japanese.ShiftJIS.NewDecoder()))
	for {
		row, err := reader.Read()
		if err == io.EOF {
			break
		} else if e2, ok := err.(*csv.ParseError); ok && e2.Err == csv.ErrFieldCount {
			//フィールド数エラーは無視
		} else if err != nil {
			log.Errorf(c, "Read chouseisan's csv failed. err: %v", err)
			return nil
		}

		if rowCount < 2 {
			//イベント名、詳細説明文はスキップ

		} else if rowCount == 2 {
			//名前行
			for i, v := range row {
				if i > 0 {
					names = append(names, v)
				}
			}

		} else {
			//データ行（最終のコメント行も含む）
			s := schedule{}
			for i, v := range row {
				if i == 0 {
					//日付カラムはパースしてキーにする
					tz, _ := time.LoadLocation("Asia/Tokyo")
					year := today.Year()
					r := regexp.MustCompile(`^(\d{1,2})/(\d{1,2}).*$`)
					md := r.FindAllStringSubmatch(v, -1)
					if len(md) == 0 {
						log.Debugf(c, "Month and day parse error. col:%v", v)
						continue
					}
					month, merr := strconv.Atoi(md[0][1])
					day, derr := strconv.Atoi(md[0][2])
					if merr != nil {
						log.Debugf(c, "Month parse error. col:%v error:%v", v, merr)
						continue
					} else if derr != nil {
						log.Debugf(c, "Month parse error. col:%v error:%v", v, merr)
						continue
					} else {
						//日付パース成功
						if time.Month(month) < today.Month() {
							year++ //来年として扱う
						}
						s.Date = time.Date(year, time.Month(month), day, 0, 0, 0, 0, tz)
						s.DateString = v
						s.Present = 0
						s.Absent = 0
						s.Unknown = 0
						s.ParticipantsName = ""
						s.UnknownName = ""
					}

				} else if len(names[i-1]) > 0 {
					//出欠カラムの内容を、scheduleに足しこむ
					if v == "○" {
						s.Present++
						if len(s.ParticipantsName) > 0 {
							s.ParticipantsName += ","
						}
						s.ParticipantsName += names[i-1]
					} else if v == "×" {
						s.Absent++
					} else {
						s.Unknown++
						if len(s.UnknownName) > 0 {
							s.UnknownName += ","
						}
						s.UnknownName += names[i-1]
					}
				}
			}
			if len(s.DateString) > 0 {
				if len(s.ParticipantsName) > 0 {
					s.ParticipantsName = "(" + s.ParticipantsName + ")"
				}
				if len(s.UnknownName) > 0 {
					s.UnknownName = "(" + s.UnknownName + ")"
				}
				m[s.Date.String()] = s
			}
		}
		rowCount++
	}
	return m
}

/**
 * 購読者ごとのイテレーション処理。調整さんをクロールして通知対象があれば集計して返す
 */
func chouseisanIterator(current *subscriber, c context.Context, client *http.Client, w http.ResponseWriter, r *http.Request) []schedule {
	result := []schedule{}

	//調整さんの"出欠表をダウンロード"リンクからcsv形式で取得
	url := "https://chouseisan.com/schedule/List/createCsv?h=" + current.ChouseisanHash
	res, err := client.Get(url)
	if err != nil {
		log.Errorf(c, "Get chouseisan's csv failed. err: %v", err)
		return result
	} else if res.StatusCode != 200 {
		log.Errorf(c, "Get chouseisan's csv failed. StatusCode: %v", res.StatusCode)
		return result
	}

	//csvをパース
	tz, _ := time.LoadLocation("Asia/Tokyo")
	today := time.Now().In(tz)
	m := parseCsv(c, res.Body, today)

	//当日の予定をピック
	targetDate := time.Date(today.Year(), today.Month(), today.Day(), 0, 0, 0, 0, tz)
	obj, exist := m[targetDate.String()]
	if exist {
		result = append(result, obj)
	} else {
		log.Debugf(c, "Not found schedule at today.")
	}

	//3日後の予定をピック
	targetDate = targetDate.AddDate(0, 0, 3)
	obj, exist = m[targetDate.String()]
	if exist {
		result = append(result, obj)
	} else {
		log.Debugf(c, "Not found schedule at 3 days after.")
	}

	return result
}

/**
 * 調整さんをクロールして出欠を通知
 *
 * 引数にContextとhttp.Clientを取るインナーメソッド
 */
func crawlChouseisanWithContext(c context.Context, client *http.Client, w http.ResponseWriter, r *http.Request) {
	bot, err := createBotClient(c, client)
	if err != nil {
		return
	}

	//hashの入ってるエンティティを抽出してループ
	ite := datastore.NewQuery("Subscriber").Run(c)
	for {
		var cSubscriber subscriber
		_, err = ite.Next(&cSubscriber)
		if err == datastore.Done {
			break
		} else if err != nil {
			log.Errorf(c, "Error occurred at fetch Subscriber. err:%v", err)
			break
		}

		if cSubscriber.ChouseisanHash != "" {
			// ハッシュが設定されていれば、調整さんイベントをクロール
			log.Infof(c, "Crawl chouseisan! subscriber:%v hash:%v", cSubscriber.DisplayName, cSubscriber.ChouseisanHash)
			result := chouseisanIterator(&cSubscriber, c, client, w, r)

			// リマインド対象イベントがあれば、Push Messageを送信
			for _, v := range result {
				log.Infof(c, "Remind event! subscriber:%v date:%v", cSubscriber.DisplayName, v.DateString)
				template := linebot.NewButtonsTemplate(
					"", //サムネイル
					"", //タイトル
					v.constructSummaryBody(), //画像もタイトルも指定しない場合：160文字以内
					linebot.NewURITemplateAction("出欠を登録（変更）する", "https://chouseisan.com/s?h="+cSubscriber.ChouseisanHash),
				)
				altText := v.DateString + "の出欠状況をお知らせします" +
					"\n（トークルームでもこのメッセージが見えている人は、お使いのLINEアプリのバージョンおよび機種名を教えてください）"
				if _, err = bot.PushMessage(cSubscriber.MID, linebot.NewTemplateMessage(altText, template)).Do(); err != nil {
					log.Errorf(c, "Error occurred at crawl chouseisan. subscriber:%v, date:%v, err: %v", cSubscriber.DisplayName, v.DateString, err)
				}
			}
		}
	}
}

/**
 * 調整さんをクロールして出欠を通知（cronからキックされる）
 */
func crawlChouseisan(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	crawlChouseisanWithContext(c, urlfetch.Client(c), w, r)
}
<commit_msg>Mod ButtonTemplate alt text<commit_after>package main

import (
	"encoding/csv"
	"io"
	"net/http"
	"regexp"
	"strconv"
	"time"

	"github.com/line/line-bot-sdk-go/linebot"

	"golang.org/x/net/context"
	"golang.org/x/text/encoding/japanese"
	"golang.org/x/text/transform"

	"google.golang.org/appengine"
	"google.golang.org/appengine/datastore"
	"google.golang.org/appengine/log"
	"google.golang.org/appengine/urlfetch"
)

// 調整さんの開催日ごとの集計エントリ
type schedule struct {
	Date             time.Time // 開催日（時間は00:00:00JST）
	DateString       string    // 日程欄（文字列）
	Present          int       // ◯
	Absent           int       // ×
	Unknown          int       // △および未入力
	ParticipantsName string    // 参加者の名前を列挙したもの
	UnknownName      string    // △および未入力の名前を列挙したもの
}

// 送信メッセージ用のサマリを組み立てて返す
func (s *schedule) constructSummaryBody() string {
	return s.DateString + "の出欠状況をお知らせします\n\n" +
		"参加: " + strconv.Itoa(s.Present) + "名" + s.ParticipantsName +
		"\n不参加: " + strconv.Itoa(s.Absent) + "名\n" +
		"不明/未入力: " + strconv.Itoa(s.Unknown) + "名" + s.UnknownName
}

// 送信メッセージ用のサマリを組み立てて返す
func (s *schedule) constructSummary(hash string) string {
	return s.constructSummaryBody() +
		"\n\n詳細および出欠変更は「調整さん」へ\nhttps://chouseisan.com/s?h=" + hash
}

// 調整さんスケジュールのMap型
type scheduleMap map[string]schedule

/**
 * 調整さんcsvをパースして、参加人数などを集計する
 */
func parseCsv(c context.Context, csvBody io.ReadCloser, today time.Time) (m scheduleMap) {
	var (
		names    []string
		rowCount = 0
	)
	m = make(scheduleMap)

	reader := csv.NewReader(transform.NewReader(csvBody, japanese.ShiftJIS.NewDecoder()))
	for {
		row, err := reader.Read()
		if err == io.EOF {
			break
		} else if e2, ok := err.(*csv.ParseError); ok && e2.Err == csv.ErrFieldCount {
			//フィールド数エラーは無視
		} else if err != nil {
			log.Errorf(c, "Read chouseisan's csv failed. err: %v", err)
			return nil
		}

		if rowCount < 2 {
			//イベント名、詳細説明文はスキップ

		} else if rowCount == 2 {
			//名前行
			for i, v := range row {
				if i > 0 {
					names = append(names, v)
				}
			}

		} else {
			//データ行（最終のコメント行も含む）
			s := schedule{}
			for i, v := range row {
				if i == 0 {
					//日付カラムはパースしてキーにする
					tz, _ := time.LoadLocation("Asia/Tokyo")
					year := today.Year()
					r := regexp.MustCompile(`^(\d{1,2})/(\d{1,2}).*$`)
					md := r.FindAllStringSubmatch(v, -1)
					if len(md) == 0 {
						log.Debugf(c, "Month and day parse error. col:%v", v)
						continue
					}
					month, merr := strconv.Atoi(md[0][1])
					day, derr := strconv.Atoi(md[0][2])
					if merr != nil {
						log.Debugf(c, "Month parse error. col:%v error:%v", v, merr)
						continue
					} else if derr != nil {
						log.Debugf(c, "Month parse error. col:%v error:%v", v, merr)
						continue
					} else {
						//日付パース成功
						if time.Month(month) < today.Month() {
							year++ //来年として扱う
						}
						s.Date = time.Date(year, time.Month(month), day, 0, 0, 0, 0, tz)
						s.DateString = v
						s.Present = 0
						s.Absent = 0
						s.Unknown = 0
						s.ParticipantsName = ""
						s.UnknownName = ""
					}

				} else if len(names[i-1]) > 0 {
					//出欠カラムの内容を、scheduleに足しこむ
					if v == "○" {
						s.Present++
						if len(s.ParticipantsName) > 0 {
							s.ParticipantsName += ","
						}
						s.ParticipantsName += names[i-1]
					} else if v == "×" {
						s.Absent++
					} else {
						s.Unknown++
						if len(s.UnknownName) > 0 {
							s.UnknownName += ","
						}
						s.UnknownName += names[i-1]
					}
				}
			}
			if len(s.DateString) > 0 {
				if len(s.ParticipantsName) > 0 {
					s.ParticipantsName = "(" + s.ParticipantsName + ")"
				}
				if len(s.UnknownName) > 0 {
					s.UnknownName = "(" + s.UnknownName + ")"
				}
				m[s.Date.String()] = s
			}
		}
		rowCount++
	}
	return m
}

/**
 * 購読者ごとのイテレーション処理。調整さんをクロールして通知対象があれば集計して返す
 */
func chouseisanIterator(current *subscriber, c context.Context, client *http.Client, w http.ResponseWriter, r *http.Request) []schedule {
	result := []schedule{}

	//調整さんの"出欠表をダウンロード"リンクからcsv形式で取得
	url := "https://chouseisan.com/schedule/List/createCsv?h=" + current.ChouseisanHash
	res, err := client.Get(url)
	if err != nil {
		log.Errorf(c, "Get chouseisan's csv failed. err: %v", err)
		return result
	} else if res.StatusCode != 200 {
		log.Errorf(c, "Get chouseisan's csv failed. StatusCode: %v", res.StatusCode)
		return result
	}

	//csvをパース
	tz, _ := time.LoadLocation("Asia/Tokyo")
	today := time.Now().In(tz)
	m := parseCsv(c, res.Body, today)

	//当日の予定をピック
	targetDate := time.Date(today.Year(), today.Month(), today.Day(), 0, 0, 0, 0, tz)
	obj, exist := m[targetDate.String()]
	if exist {
		result = append(result, obj)
	} else {
		log.Debugf(c, "Not found schedule at today.")
	}

	//3日後の予定をピック
	targetDate = targetDate.AddDate(0, 0, 3)
	obj, exist = m[targetDate.String()]
	if exist {
		result = append(result, obj)
	} else {
		log.Debugf(c, "Not found schedule at 3 days after.")
	}

	return result
}

/**
 * 調整さんをクロールして出欠を通知
 *
 * 引数にContextとhttp.Clientを取るインナーメソッド
 */
func crawlChouseisanWithContext(c context.Context, client *http.Client, w http.ResponseWriter, r *http.Request) {
	bot, err := createBotClient(c, client)
	if err != nil {
		return
	}

	//hashの入ってるエンティティを抽出してループ
	ite := datastore.NewQuery("Subscriber").Run(c)
	for {
		var cSubscriber subscriber
		_, err = ite.Next(&cSubscriber)
		if err == datastore.Done {
			break
		} else if err != nil {
			log.Errorf(c, "Error occurred at fetch Subscriber. err:%v", err)
			break
		}

		if cSubscriber.ChouseisanHash != "" {
			// ハッシュが設定されていれば、調整さんイベントをクロール
			log.Infof(c, "Crawl chouseisan! subscriber:%v hash:%v", cSubscriber.DisplayName, cSubscriber.ChouseisanHash)
			result := chouseisanIterator(&cSubscriber, c, client, w, r)

			// リマインド対象イベントがあれば、Push Messageを送信
			for _, v := range result {
				log.Infof(c, "Remind event! subscriber:%v date:%v", cSubscriber.DisplayName, v.DateString)
				template := linebot.NewButtonsTemplate(
					"", //サムネイル
					"", //タイトル
					v.constructSummaryBody(), //画像もタイトルも指定しない場合：160文字以内
					linebot.NewURITemplateAction("出欠を登録（変更）する", "https://chouseisan.com/s?h="+cSubscriber.ChouseisanHash),
				)
				altText := v.constructSummary(cSubscriber.ChouseisanHash)
				if _, err = bot.PushMessage(cSubscriber.MID, linebot.NewTemplateMessage(altText, template)).Do(); err != nil {
					log.Errorf(c, "Error occurred at crawl chouseisan. subscriber:%v, date:%v, err: %v", cSubscriber.DisplayName, v.DateString, err)
				}
			}
		}
	}
}

/**
 * 調整さんをクロールして出欠を通知（cronからキックされる）
 */
func crawlChouseisan(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	crawlChouseisanWithContext(c, urlfetch.Client(c), w, r)
}
<|endoftext|>


<commit_before>// run

// 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 main

import (
	"runtime"
	"sync"
	"sync/atomic"
	"time"
)

const N = 10
var count int64

func run() error {
	f1 := func() {}
	f2 := func() {
		func() {
			f1()
		}()
	}
	runtime.SetFinalizer(&f1, func(f *func()) {
		atomic.AddInt64(&count, -1)
	})
	go f2()
	return nil
}

func main() {
	count = N
	var wg sync.WaitGroup
	wg.Add(N)
	for i := 0; i < N; i++ {
		go func() {
			run()
			wg.Done()
		}()
	}
	wg.Wait()
	for i := 0; i < 2*N; i++ {
		time.Sleep(10 * time.Millisecond)
		runtime.GC()
	}
	if count != 0 {
		panic("not all finalizers are called")
	}
}

<commit_msg>test: do not run the test that relies on precise GC on 32-bits Currently most of the 32-bit builder are broken. Fixes issue 5516.<commit_after>// run

// 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 main

import (
	"runtime"
	"sync"
	"sync/atomic"
	"time"
)

const N = 10
var count int64

func run() error {
	f1 := func() {}
	f2 := func() {
		func() {
			f1()
		}()
	}
	runtime.SetFinalizer(&f1, func(f *func()) {
		atomic.AddInt64(&count, -1)
	})
	go f2()
	return nil
}

func main() {
	// Does not work on 32-bits due to partially conservative GC.
	// Try to enable when we have fully precise GC.
	if runtime.GOARCH != "amd64" {
		return
	}
	count = N
	var wg sync.WaitGroup
	wg.Add(N)
	for i := 0; i < N; i++ {
		go func() {
			run()
			wg.Done()
		}()
	}
	wg.Wait()
	for i := 0; i < 2*N; i++ {
		time.Sleep(10 * time.Millisecond)
		runtime.GC()
	}
	if count != 0 {
		println(count, "out of", N, "finalizer are called")
		panic("not all finalizers are called")
	}
}

<|endoftext|>


<commit_before>// run

// Copyright 2014 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 main

import "time"

func main() {
	now := time.Now()
	f := now.Unix
	if now.Unix() != f() {
		println("BUG: ", now.Unix(), "!=", f())
	}
}
<commit_msg>test: expand issue7863 test<commit_after>// run

// Copyright 2014 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 main

import (
	"fmt"
)

type Foo int64

func (f *Foo) F() int64 {
	return int64(*f)
}

type Bar int64

func (b Bar) F() int64 {
	return int64(b)
}

type Baz int32

func (b Baz) F() int64 {
	return int64(b)
}

func main() {
	foo := Foo(123)
	f := foo.F
	if foo.F() != f() {
		bug()
		fmt.Println("foo.F", foo.F(), f())
	}
	bar := Bar(123)
	f = bar.F
	if bar.F() != f() {
		bug()
		fmt.Println("bar.F", bar.F(), f()) // duh!
	}

	baz := Baz(123)
	f = baz.F
	if baz.F() != f() {
		bug()
		fmt.Println("baz.F", baz.F(), f())
	}
}

var bugged bool

func bug() {
	if !bugged {
		bugged = true
		fmt.Println("BUG")
	}
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014 Santiago Arias | Remy Jourde
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package teams

import (
	"errors"
	"fmt"
	"net/http"

	"appengine"

	"github.com/santiaago/gonawin/helpers"
	"github.com/santiaago/gonawin/helpers/log"
	templateshlp "github.com/santiaago/gonawin/helpers/templates"

	mdl "github.com/santiaago/gonawin/models"
)

// Search handler, use it to get all teams that match the search.
//	GET	/j/teams/search/			Search for all teams respecting the query "q"
//
func Search(w http.ResponseWriter, r *http.Request, u *mdl.User) error {
	keywords := r.FormValue("q")
	if r.Method != "GET" || len(keywords) == 0 {
		return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeNotSupported)}
	}

	c := appengine.NewContext(r)
	desc := "Team Search Handler:"

	words := helpers.SetOfStrings(keywords)

	var ids []int64
	var err error
	if ids, err = mdl.GetTeamInvertedIndexes(c, words); err != nil {
		return unableToPerformSearch(c, w, desc, err)
	}

	result := mdl.TeamScore(c, keywords, ids)
	log.Infof(c, "%s result from TeamScore: %v", desc, result)

	var teams []*mdl.Team
	if teams = mdl.TeamsByIds(c, result); len(teams) == 0 {
		return notFound(c, w, keywords)
	}

	log.Infof(c, "%s ByIds result %v", desc, teams)

	tvm := buildSearchTeamViewModel(teams)

	data := struct {
		Users []searchTeamViewModel `json:",omitempty"`
	}{
		tvm,
	}
	return templateshlp.RenderJson(w, c, data)
}

type searchTeamViewModel struct {
	Id           int64
	Name         string
	AdminIds     []int64
	Private      bool
	Accuracy     float64
	MembersCount int64
	ImageURL     string
}

func buildSearchTeamViewModel(teams []*mdl.Team) []searchTeamViewModel {
	tvm := make([]searchTeamViewModel, len(teams))
	for i, t := range teams {
		tvm[i].Id = t.Id
		tvm[i].Name = t.Name
		tvm[i].AdminIds = t.AdminIds
		tvm[i].Private = t.Private
		tvm[i].Accuracy = t.Accuracy
		tvm[i].MembersCount = t.MembersCount
		tvm[i].ImageURL = helpers.TeamImageURL(t.Name, t.Id)
	}
	return tvm
}

func notFound(c appengine.Context, w http.ResponseWriter, keywords string) error {
	msg := fmt.Sprintf("Oops! Your search - %s - did not match any %s.", keywords, "team")
	data := struct {
		MessageInfo string `json:",omitempty"`
	}{
		msg,
	}
	return templateshlp.RenderJson(w, c, data)
}

func unableToPerformSearch(c appengine.Context, w http.ResponseWriter, desc string, err error) error {
	log.Errorf(c, "%s teams.Index, error occurred when getting indexes of words: %v", desc, err)
	data := struct {
		MessageDanger string `json:",omitempty"`
	}{
		"Oops! something went wrong, we are unable to perform search query.",
	}
	return templateshlp.RenderJson(w, c, data)
}
<commit_msg>refactor Teams Search handler<commit_after>/*
 * Copyright (c) 2014 Santiago Arias | Remy Jourde
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package teams

import (
	"errors"
	"fmt"
	"net/http"

	"appengine"

	"github.com/santiaago/gonawin/helpers"
	"github.com/santiaago/gonawin/helpers/log"
	templateshlp "github.com/santiaago/gonawin/helpers/templates"

	mdl "github.com/santiaago/gonawin/models"
)

// Search handler returns the result of a team search in a JSON format.
// It uses parameter 'q' to make the query.
//
//	GET	/j/teams/search/			Search for all teams respecting the query "q"
//
func Search(w http.ResponseWriter, r *http.Request, u *mdl.User) error {

	keywords := r.FormValue("q")
	if r.Method != "GET" || len(keywords) == 0 {
		return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeNotSupported)}
	}

	c := appengine.NewContext(r)
	desc := "Team Search Handler:"

	words := helpers.SetOfStrings(keywords)

	var ids []int64
	var err error
	if ids, err = mdl.GetTeamInvertedIndexes(c, words); err != nil {
		return unableToPerformSearch(c, w, desc, err)
	}

	result := mdl.TeamScore(c, keywords, ids)
	log.Infof(c, "%s result from TeamScore: %v", desc, result)

	var teams []*mdl.Team
	if teams = mdl.TeamsByIds(c, result); len(teams) == 0 {
		return notFound(c, w, keywords)
	}

	log.Infof(c, "%s ByIds result %v", desc, teams)

	svm := buildTeamSearchViewModel(teams)

	return templateshlp.RenderJson(w, c, svm)
}

type teamSearchViewModel struct {
	Teams []teamSearchTeamViewModel
}

type teamSearchTeamViewModel struct {
	Id           int64
	Name         string
	AdminIds     []int64
	Private      bool
	Accuracy     float64
	MembersCount int64
	ImageURL     string
}

func buildTeamSearchViewModel(teams []*mdl.Team) teamSearchViewModel {
	tvm := make([]teamSearchTeamViewModel, len(teams))
	for i, t := range teams {
		tvm[i].Id = t.Id
		tvm[i].Name = t.Name
		tvm[i].AdminIds = t.AdminIds
		tvm[i].Private = t.Private
		tvm[i].Accuracy = t.Accuracy
		tvm[i].MembersCount = t.MembersCount
		tvm[i].ImageURL = helpers.TeamImageURL(t.Name, t.Id)
	}
	return teamSearchViewModel{Teams: tvm}
}

func notFound(c appengine.Context, w http.ResponseWriter, keywords string) error {
	msg := fmt.Sprintf("Oops! Your search - %s - did not match any %s.", keywords, "team")
	data := struct {
		MessageInfo string `json:",omitempty"`
	}{
		msg,
	}
	return templateshlp.RenderJson(w, c, data)
}

func unableToPerformSearch(c appengine.Context, w http.ResponseWriter, desc string, err error) error {
	log.Errorf(c, "%s teams.Index, error occurred when getting indexes of words: %v", desc, err)
	data := struct {
		MessageDanger string `json:",omitempty"`
	}{
		"Oops! something went wrong, we are unable to perform search query.",
	}
	return templateshlp.RenderJson(w, c, data)
}
<|endoftext|>


<commit_before>package command

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"strings"

	"github.com/hashicorp/terraform/remote"
	"github.com/hashicorp/terraform/terraform"
)

// remoteCommandConfig is used to encapsulate our configuration
type remoteCommandConfig struct {
	disableRemote bool
	pullOnDisable bool

	statePath  string
	backupPath string
}

// RemoteCommand is a Command implementation that is used to
// enable and disable remote state management
type RemoteCommand struct {
	Meta
	conf       remoteCommandConfig
	remoteConf terraform.RemoteState
}

func (c *RemoteCommand) Run(args []string) int {
	args = c.Meta.process(args, false)
	var address, accessToken, name, path string
	cmdFlags := flag.NewFlagSet("remote", flag.ContinueOnError)
	cmdFlags.BoolVar(&c.conf.disableRemote, "disable", false, "")
	cmdFlags.BoolVar(&c.conf.pullOnDisable, "pull", true, "")
	cmdFlags.StringVar(&c.conf.statePath, "state", DefaultStateFilename, "path")
	cmdFlags.StringVar(&c.conf.backupPath, "backup", "", "path")
	cmdFlags.StringVar(&c.remoteConf.Type, "backend", "atlas", "")
	cmdFlags.StringVar(&address, "address", "", "")
	cmdFlags.StringVar(&accessToken, "access-token", "", "")
	cmdFlags.StringVar(&name, "name", "", "")
	cmdFlags.StringVar(&path, "path", "", "")
	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
	if err := cmdFlags.Parse(args); err != nil {
		return 1
	}

	// Show help if given no inputs
	if !c.conf.disableRemote && c.remoteConf.Type == "atlas" &&
		name == "" && accessToken == "" {
		cmdFlags.Usage()
		return 1
	}

	// Populate the various configurations
	c.remoteConf.Config = map[string]string{
		"address":      address,
		"access_token": accessToken,
		"name":         name,
		"path":         path,
	}

	// Check if have an existing local state file
	haveLocal, err := remote.HaveLocalState()
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Failed to check for local state: %v", err))
		return 1
	}

	// Check if we have the non-managed state file
	haveNonManaged, err := remote.ExistsFile(c.conf.statePath)
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Failed to check for state file: %v", err))
		return 1
	}

	// Check if remote state is being disabled
	if c.conf.disableRemote {
		if !haveLocal {
			c.Ui.Error(fmt.Sprintf("Remote state management not enabled! Aborting."))
			return 1
		}
		if haveNonManaged {
			c.Ui.Error(fmt.Sprintf("State file already exists at '%s'. Aborting.",
				c.conf.statePath))
			return 1
		}
		return c.disableRemoteState()
	}

	// Ensure there is no conflict
	switch {
	case haveLocal && haveNonManaged:
		c.Ui.Error(fmt.Sprintf("Remote state is enabled, but non-managed state file '%s' is also present!",
			c.conf.statePath))
		return 1

	case !haveLocal && !haveNonManaged:
		// If we don't have either state file, initialize a blank state file
		return c.initBlankState()

	case haveLocal && !haveNonManaged:
		// Update the remote state target potentially
		return c.updateRemoteConfig()

	case !haveLocal && haveNonManaged:
		// Enable remote state management
		return c.enableRemoteState()

	default:
		panic("unhandled case")
	}
	return 0
}

// disableRemoteState is used to disable remote state management,
// and move the state file into place.
func (c *RemoteCommand) disableRemoteState() int {
	// Get the local state
	local, _, err := remote.ReadLocalState()
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Failed to read local state: %v", err))
		return 1
	}

	// Ensure we have the latest state before disabling
	if c.conf.pullOnDisable {
		log.Printf("[INFO] Refreshing local state from remote server")
		change, err := remote.RefreshState(local.Remote)
		if err != nil {
			c.Ui.Error(fmt.Sprintf(
				"Failed to refresh from remote state: %v", err))
			return 1
		}

		// Exit if we were unable to update
		if !change.SuccessfulPull() {
			c.Ui.Error(fmt.Sprintf("%s", change))
			return 1
		} else {
			log.Printf("[INFO] %s", change)
		}

		// Reload the local state after the refresh
		local, _, err = remote.ReadLocalState()
		if err != nil {
			c.Ui.Error(fmt.Sprintf("Failed to read local state: %v", err))
			return 1
		}
	}

	// Clear the remote management, and copy into place
	local.Remote = nil
	fh, err := os.Create(c.conf.statePath)
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Failed to create state file '%s': %v",
			c.conf.statePath, err))
		return 1
	}
	defer fh.Close()
	if err := terraform.WriteState(local, fh); err != nil {
		c.Ui.Error(fmt.Sprintf("Failed to encode state file: %v",
			c.conf.statePath, err))
		return 1
	}

	// Remove the old state file
	path, err := remote.HiddenStatePath()
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Failed to get local state path: %v", err))
		return 1
	}
	if err := os.Remove(path); err != nil {
		c.Ui.Error(fmt.Sprintf("Failed to remove the local state file: %v", err))
		return 1
	}
	return 0
}

// validateRemoteConfig is used to verify that the remote configuration
// we have is valid
func (c *RemoteCommand) validateRemoteConfig() error {
	err := remote.ValidConfig(&c.remoteConf)
	if err != nil {
		c.Ui.Error(fmt.Sprintf("%s", err))
	}
	return err
}

// initBlank state is used to initialize a blank state that is
// remote enabled
func (c *RemoteCommand) initBlankState() int {
	// Validate the remote configuration
	if err := c.validateRemoteConfig(); err != nil {
		return 1
	}

	// Make the hidden directory
	if err := remote.EnsureDirectory(); err != nil {
		c.Ui.Error(fmt.Sprintf("%s", err))
		return 1
	}

	// Make a blank state, attach the remote configuration
	blank := terraform.NewState()
	blank.Remote = &c.remoteConf

	// Persist the state
	if err := remote.PersistState(blank); err != nil {
		c.Ui.Error(fmt.Sprintf("Failed to initialize state file: %v", err))
		return 1
	}

	// Success!
	c.Ui.Output("Initialized blank state with remote state enabled!")
	return 0
}

// updateRemoteConfig is used to update the configuration of the
// remote state store
func (c *RemoteCommand) updateRemoteConfig() int {
	// Validate the remote configuration
	if err := c.validateRemoteConfig(); err != nil {
		return 1
	}

	// Read in the local state
	local, _, err := remote.ReadLocalState()
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Failed to read local state: %v", err))
		return 1
	}

	// Update the configuration
	local.Remote = &c.remoteConf
	if err := remote.PersistState(local); err != nil {
		c.Ui.Error(fmt.Sprintf("%s", err))
		return 1
	}

	// Success!
	c.Ui.Output("Remote configuration updated")
	return 0
}

// enableRemoteState is used to enable remote state management
// and to move a state file into place
func (c *RemoteCommand) enableRemoteState() int {
	// Validate the remote configuration
	if err := c.validateRemoteConfig(); err != nil {
		return 1
	}

	// Make the hidden directory
	if err := remote.EnsureDirectory(); err != nil {
		c.Ui.Error(fmt.Sprintf("%s", err))
		return 1
	}

	// Read the provided state file
	raw, err := ioutil.ReadFile(c.conf.statePath)
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Failed to read '%s': %v", c.conf.statePath, err))
		return 1
	}
	state, err := terraform.ReadState(bytes.NewReader(raw))
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Failed to decode '%s': %v", c.conf.statePath, err))
		return 1
	}

	// Backup the state file before we modify it
	backupPath := c.conf.backupPath
	if backupPath != "-" {
		// Provide default backup path if none provided
		if backupPath == "" {
			backupPath = c.conf.statePath + DefaultBackupExtention
		}

		log.Printf("[INFO] Writing backup state to: %s", backupPath)
		f, err := os.Create(backupPath)
		if err == nil {
			err = terraform.WriteState(state, f)
			f.Close()
		}
		if err != nil {
			c.Ui.Error(fmt.Sprintf("Error writing backup state file: %s", err))
			return 1
		}
	}

	// Update the local configuration, move into place
	state.Remote = &c.remoteConf
	if err := remote.PersistState(state); err != nil {
		c.Ui.Error(fmt.Sprintf("%s", err))
		return 1
	}

	// Remove the state file
	log.Printf("[INFO] Removing state file: %s", c.conf.statePath)
	if err := os.Remove(c.conf.statePath); err != nil {
		c.Ui.Error(fmt.Sprintf("Failed to remove state file '%s': %v",
			c.conf.statePath, err))
		return 1
	}

	// Success!
	c.Ui.Output("Remote state management enabled")
	return 0
}

func (c *RemoteCommand) Help() string {
	helpText := `
Usage: terraform remote [options]

  Configures Terraform to use a remote state server. This allows state
  to be pulled down when necessary and then pushed to the server when
  updated. In this mode, the state file does not need to be stored durably
  since the remote server provides the durability.

Options:

  -address=url           URL of the remote storage server.
                         Required for HTTP backend, optional for Atlas and Consul.

  -access-token=token    Authentication token for state storage server.
                         Required for Atlas backend, optional for Consul.

  -backend=Atlas         Specifies the type of remote backend. Must be one
                         of Atlas, Consul, or HTTP. Defaults to Atlas.

  -backup=path           Path to backup the existing state file before
                         modifying. Defaults to the "-state" path with
                         ".backup" extension. Set to "-" to disable backup.

  -disable               Disables remote state management and migrates the state
                         to the -state path.

  -name=name             Name of the state file in the state storage server.
                         Required for Atlas backend.

  -path=path             Path of the remote state in Consul. Required for the
                         Consul backend.

  -pull=true             Controls if the remote state is pulled before disabling.
                         This defaults to true to ensure the latest state is cached
						 before disabling.

  -state=path            Path to read state. Defaults to "terraform.tfstate"
                         unless remote state is enabled.

`
	return strings.TrimSpace(helpText)
}

func (c *RemoteCommand) Synopsis() string {
	return "Configures remote state management"
}
<commit_msg>command: vet fix<commit_after>package command

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"strings"

	"github.com/hashicorp/terraform/remote"
	"github.com/hashicorp/terraform/terraform"
)

// remoteCommandConfig is used to encapsulate our configuration
type remoteCommandConfig struct {
	disableRemote bool
	pullOnDisable bool

	statePath  string
	backupPath string
}

// RemoteCommand is a Command implementation that is used to
// enable and disable remote state management
type RemoteCommand struct {
	Meta
	conf       remoteCommandConfig
	remoteConf terraform.RemoteState
}

func (c *RemoteCommand) Run(args []string) int {
	args = c.Meta.process(args, false)
	var address, accessToken, name, path string
	cmdFlags := flag.NewFlagSet("remote", flag.ContinueOnError)
	cmdFlags.BoolVar(&c.conf.disableRemote, "disable", false, "")
	cmdFlags.BoolVar(&c.conf.pullOnDisable, "pull", true, "")
	cmdFlags.StringVar(&c.conf.statePath, "state", DefaultStateFilename, "path")
	cmdFlags.StringVar(&c.conf.backupPath, "backup", "", "path")
	cmdFlags.StringVar(&c.remoteConf.Type, "backend", "atlas", "")
	cmdFlags.StringVar(&address, "address", "", "")
	cmdFlags.StringVar(&accessToken, "access-token", "", "")
	cmdFlags.StringVar(&name, "name", "", "")
	cmdFlags.StringVar(&path, "path", "", "")
	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
	if err := cmdFlags.Parse(args); err != nil {
		return 1
	}

	// Show help if given no inputs
	if !c.conf.disableRemote && c.remoteConf.Type == "atlas" &&
		name == "" && accessToken == "" {
		cmdFlags.Usage()
		return 1
	}

	// Populate the various configurations
	c.remoteConf.Config = map[string]string{
		"address":      address,
		"access_token": accessToken,
		"name":         name,
		"path":         path,
	}

	// Check if have an existing local state file
	haveLocal, err := remote.HaveLocalState()
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Failed to check for local state: %v", err))
		return 1
	}

	// Check if we have the non-managed state file
	haveNonManaged, err := remote.ExistsFile(c.conf.statePath)
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Failed to check for state file: %v", err))
		return 1
	}

	// Check if remote state is being disabled
	if c.conf.disableRemote {
		if !haveLocal {
			c.Ui.Error(fmt.Sprintf("Remote state management not enabled! Aborting."))
			return 1
		}
		if haveNonManaged {
			c.Ui.Error(fmt.Sprintf("State file already exists at '%s'. Aborting.",
				c.conf.statePath))
			return 1
		}
		return c.disableRemoteState()
	}

	// Ensure there is no conflict
	switch {
	case haveLocal && haveNonManaged:
		c.Ui.Error(fmt.Sprintf("Remote state is enabled, but non-managed state file '%s' is also present!",
			c.conf.statePath))
		return 1

	case !haveLocal && !haveNonManaged:
		// If we don't have either state file, initialize a blank state file
		return c.initBlankState()

	case haveLocal && !haveNonManaged:
		// Update the remote state target potentially
		return c.updateRemoteConfig()

	case !haveLocal && haveNonManaged:
		// Enable remote state management
		return c.enableRemoteState()

	default:
		panic("unhandled case")
	}
	return 0
}

// disableRemoteState is used to disable remote state management,
// and move the state file into place.
func (c *RemoteCommand) disableRemoteState() int {
	// Get the local state
	local, _, err := remote.ReadLocalState()
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Failed to read local state: %v", err))
		return 1
	}

	// Ensure we have the latest state before disabling
	if c.conf.pullOnDisable {
		log.Printf("[INFO] Refreshing local state from remote server")
		change, err := remote.RefreshState(local.Remote)
		if err != nil {
			c.Ui.Error(fmt.Sprintf(
				"Failed to refresh from remote state: %v", err))
			return 1
		}

		// Exit if we were unable to update
		if !change.SuccessfulPull() {
			c.Ui.Error(fmt.Sprintf("%s", change))
			return 1
		} else {
			log.Printf("[INFO] %s", change)
		}

		// Reload the local state after the refresh
		local, _, err = remote.ReadLocalState()
		if err != nil {
			c.Ui.Error(fmt.Sprintf("Failed to read local state: %v", err))
			return 1
		}
	}

	// Clear the remote management, and copy into place
	local.Remote = nil
	fh, err := os.Create(c.conf.statePath)
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Failed to create state file '%s': %v",
			c.conf.statePath, err))
		return 1
	}
	defer fh.Close()
	if err := terraform.WriteState(local, fh); err != nil {
		c.Ui.Error(fmt.Sprintf("Failed to encode state file '%s': %v",
			c.conf.statePath, err))
		return 1
	}

	// Remove the old state file
	path, err := remote.HiddenStatePath()
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Failed to get local state path: %v", err))
		return 1
	}
	if err := os.Remove(path); err != nil {
		c.Ui.Error(fmt.Sprintf("Failed to remove the local state file: %v", err))
		return 1
	}
	return 0
}

// validateRemoteConfig is used to verify that the remote configuration
// we have is valid
func (c *RemoteCommand) validateRemoteConfig() error {
	err := remote.ValidConfig(&c.remoteConf)
	if err != nil {
		c.Ui.Error(fmt.Sprintf("%s", err))
	}
	return err
}

// initBlank state is used to initialize a blank state that is
// remote enabled
func (c *RemoteCommand) initBlankState() int {
	// Validate the remote configuration
	if err := c.validateRemoteConfig(); err != nil {
		return 1
	}

	// Make the hidden directory
	if err := remote.EnsureDirectory(); err != nil {
		c.Ui.Error(fmt.Sprintf("%s", err))
		return 1
	}

	// Make a blank state, attach the remote configuration
	blank := terraform.NewState()
	blank.Remote = &c.remoteConf

	// Persist the state
	if err := remote.PersistState(blank); err != nil {
		c.Ui.Error(fmt.Sprintf("Failed to initialize state file: %v", err))
		return 1
	}

	// Success!
	c.Ui.Output("Initialized blank state with remote state enabled!")
	return 0
}

// updateRemoteConfig is used to update the configuration of the
// remote state store
func (c *RemoteCommand) updateRemoteConfig() int {
	// Validate the remote configuration
	if err := c.validateRemoteConfig(); err != nil {
		return 1
	}

	// Read in the local state
	local, _, err := remote.ReadLocalState()
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Failed to read local state: %v", err))
		return 1
	}

	// Update the configuration
	local.Remote = &c.remoteConf
	if err := remote.PersistState(local); err != nil {
		c.Ui.Error(fmt.Sprintf("%s", err))
		return 1
	}

	// Success!
	c.Ui.Output("Remote configuration updated")
	return 0
}

// enableRemoteState is used to enable remote state management
// and to move a state file into place
func (c *RemoteCommand) enableRemoteState() int {
	// Validate the remote configuration
	if err := c.validateRemoteConfig(); err != nil {
		return 1
	}

	// Make the hidden directory
	if err := remote.EnsureDirectory(); err != nil {
		c.Ui.Error(fmt.Sprintf("%s", err))
		return 1
	}

	// Read the provided state file
	raw, err := ioutil.ReadFile(c.conf.statePath)
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Failed to read '%s': %v", c.conf.statePath, err))
		return 1
	}
	state, err := terraform.ReadState(bytes.NewReader(raw))
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Failed to decode '%s': %v", c.conf.statePath, err))
		return 1
	}

	// Backup the state file before we modify it
	backupPath := c.conf.backupPath
	if backupPath != "-" {
		// Provide default backup path if none provided
		if backupPath == "" {
			backupPath = c.conf.statePath + DefaultBackupExtention
		}

		log.Printf("[INFO] Writing backup state to: %s", backupPath)
		f, err := os.Create(backupPath)
		if err == nil {
			err = terraform.WriteState(state, f)
			f.Close()
		}
		if err != nil {
			c.Ui.Error(fmt.Sprintf("Error writing backup state file: %s", err))
			return 1
		}
	}

	// Update the local configuration, move into place
	state.Remote = &c.remoteConf
	if err := remote.PersistState(state); err != nil {
		c.Ui.Error(fmt.Sprintf("%s", err))
		return 1
	}

	// Remove the state file
	log.Printf("[INFO] Removing state file: %s", c.conf.statePath)
	if err := os.Remove(c.conf.statePath); err != nil {
		c.Ui.Error(fmt.Sprintf("Failed to remove state file '%s': %v",
			c.conf.statePath, err))
		return 1
	}

	// Success!
	c.Ui.Output("Remote state management enabled")
	return 0
}

func (c *RemoteCommand) Help() string {
	helpText := `
Usage: terraform remote [options]

  Configures Terraform to use a remote state server. This allows state
  to be pulled down when necessary and then pushed to the server when
  updated. In this mode, the state file does not need to be stored durably
  since the remote server provides the durability.

Options:

  -address=url           URL of the remote storage server.
                         Required for HTTP backend, optional for Atlas and Consul.

  -access-token=token    Authentication token for state storage server.
                         Required for Atlas backend, optional for Consul.

  -backend=Atlas         Specifies the type of remote backend. Must be one
                         of Atlas, Consul, or HTTP. Defaults to Atlas.

  -backup=path           Path to backup the existing state file before
                         modifying. Defaults to the "-state" path with
                         ".backup" extension. Set to "-" to disable backup.

  -disable               Disables remote state management and migrates the state
                         to the -state path.

  -name=name             Name of the state file in the state storage server.
                         Required for Atlas backend.

  -path=path             Path of the remote state in Consul. Required for the
                         Consul backend.

  -pull=true             Controls if the remote state is pulled before disabling.
                         This defaults to true to ensure the latest state is cached
						 before disabling.

  -state=path            Path to read state. Defaults to "terraform.tfstate"
                         unless remote state is enabled.

`
	return strings.TrimSpace(helpText)
}

func (c *RemoteCommand) Synopsis() string {
	return "Configures remote state management"
}
<|endoftext|>