<commit_before>// Copyright 2016 The go-github 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 github

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

	"github.com/google/go-cmp/cmp"
)

func TestRepositoriesService_ListTrafficReferrers(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/repos/o/r/traffic/popular/referrers", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "GET")
		fmt.Fprintf(w, `[{
			"referrer": "Google",
			"count": 4,
			"uniques": 3
 		}]`)
	})
	ctx := context.Background()
	got, _, err := client.Repositories.ListTrafficReferrers(ctx, "o", "r")
	if err != nil {
		t.Errorf("Repositories.ListTrafficReferrers returned error: %+v", err)
	}

	want := []*TrafficReferrer{{
		Referrer: String("Google"),
		Count:    Int(4),
		Uniques:  Int(3),
	}}
	if !cmp.Equal(got, want) {
		t.Errorf("Repositories.ListTrafficReferrers returned %+v, want %+v", got, want)
	}

	const methodName = "ListTrafficReferrers"
	testBadOptions(t, methodName, func() (err error) {
		_, _, err = client.Repositories.ListTrafficReferrers(ctx, "\n", "\n")
		return err
	})

	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
		got, resp, err := client.Repositories.ListTrafficReferrers(ctx, "o", "r")
		if got != nil {
			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
		}
		return resp, err
	})
}

func TestRepositoriesService_ListTrafficPaths(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/repos/o/r/traffic/popular/paths", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "GET")
		fmt.Fprintf(w, `[{
			"path": "/github/hubot",
			"title": "github/hubot: A customizable life embetterment robot.",
			"count": 3542,
			"uniques": 2225
 		}]`)
	})
	ctx := context.Background()
	got, _, err := client.Repositories.ListTrafficPaths(ctx, "o", "r")
	if err != nil {
		t.Errorf("Repositories.ListTrafficPaths returned error: %+v", err)
	}

	want := []*TrafficPath{{
		Path:    String("/github/hubot"),
		Title:   String("github/hubot: A customizable life embetterment robot."),
		Count:   Int(3542),
		Uniques: Int(2225),
	}}
	if !cmp.Equal(got, want) {
		t.Errorf("Repositories.ListTrafficPaths returned %+v, want %+v", got, want)
	}

	const methodName = "ListTrafficPaths"
	testBadOptions(t, methodName, func() (err error) {
		_, _, err = client.Repositories.ListTrafficPaths(ctx, "\n", "\n")
		return err
	})

	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
		got, resp, err := client.Repositories.ListTrafficPaths(ctx, "o", "r")
		if got != nil {
			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
		}
		return resp, err
	})
}

func TestRepositoriesService_ListTrafficViews(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/repos/o/r/traffic/views", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "GET")
		fmt.Fprintf(w, `{"count": 7,
			"uniques": 6,
			"views": [{
				"timestamp": "2016-05-31T16:00:00.000Z",
				"count": 7,
				"uniques": 6
		}]}`)
	})

	ctx := context.Background()
	got, _, err := client.Repositories.ListTrafficViews(ctx, "o", "r", nil)
	if err != nil {
		t.Errorf("Repositories.ListTrafficViews returned error: %+v", err)
	}

	want := &TrafficViews{
		Views: []*TrafficData{{
			Timestamp: &Timestamp{time.Date(2016, time.May, 31, 16, 0, 0, 0, time.UTC)},
			Count:     Int(7),
			Uniques:   Int(6),
		}},
		Count:   Int(7),
		Uniques: Int(6),
	}

	if !cmp.Equal(got, want) {
		t.Errorf("Repositories.ListTrafficViews returned %+v, want %+v", got, want)
	}

	const methodName = "ListTrafficViews"
	testBadOptions(t, methodName, func() (err error) {
		_, _, err = client.Repositories.ListTrafficViews(ctx, "\n", "\n", &TrafficBreakdownOptions{})
		return err
	})

	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
		got, resp, err := client.Repositories.ListTrafficViews(ctx, "o", "r", nil)
		if got != nil {
			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
		}
		return resp, err
	})
}

func TestRepositoriesService_ListTrafficClones(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/repos/o/r/traffic/clones", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "GET")
		fmt.Fprintf(w, `{"count": 7,
			"uniques": 6,
			"clones": [{
				"timestamp": "2016-05-31T16:00:00.00Z",
				"count": 7,
				"uniques": 6
		}]}`)
	})

	ctx := context.Background()
	got, _, err := client.Repositories.ListTrafficClones(ctx, "o", "r", nil)
	if err != nil {
		t.Errorf("Repositories.ListTrafficClones returned error: %+v", err)
	}

	want := &TrafficClones{
		Clones: []*TrafficData{{
			Timestamp: &Timestamp{time.Date(2016, time.May, 31, 16, 0, 0, 0, time.UTC)},
			Count:     Int(7),
			Uniques:   Int(6),
		}},
		Count:   Int(7),
		Uniques: Int(6),
	}

	if !cmp.Equal(got, want) {
		t.Errorf("Repositories.ListTrafficClones returned %+v, want %+v", got, want)
	}

	const methodName = "ListTrafficClones"
	testBadOptions(t, methodName, func() (err error) {
		_, _, err = client.Repositories.ListTrafficClones(ctx, "\n", "\n", &TrafficBreakdownOptions{})
		return err
	})

	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
		got, resp, err := client.Repositories.ListTrafficClones(ctx, "o", "r", nil)
		if got != nil {
			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
		}
		return resp, err
	})
}

func TestTrafficReferrer_Marshal(t *testing.T) {
	testJSONMarshal(t, &TrafficReferrer{}, "{}")

	u := &TrafficReferrer{
		Referrer: String("referrer"),
		Count:    Int(0),
		Uniques:  Int(0),
	}

	want := `{
		"referrer" : "referrer",
		"count" : 0,
		"uniques" : 0
	}`

	testJSONMarshal(t, u, want)
}
<commit_msg>Add test cases for JSON resource marshaling (#2170)<commit_after>// Copyright 2016 The go-github 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 github

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

	"github.com/google/go-cmp/cmp"
)

func TestRepositoriesService_ListTrafficReferrers(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/repos/o/r/traffic/popular/referrers", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "GET")
		fmt.Fprintf(w, `[{
			"referrer": "Google",
			"count": 4,
			"uniques": 3
 		}]`)
	})
	ctx := context.Background()
	got, _, err := client.Repositories.ListTrafficReferrers(ctx, "o", "r")
	if err != nil {
		t.Errorf("Repositories.ListTrafficReferrers returned error: %+v", err)
	}

	want := []*TrafficReferrer{{
		Referrer: String("Google"),
		Count:    Int(4),
		Uniques:  Int(3),
	}}
	if !cmp.Equal(got, want) {
		t.Errorf("Repositories.ListTrafficReferrers returned %+v, want %+v", got, want)
	}

	const methodName = "ListTrafficReferrers"
	testBadOptions(t, methodName, func() (err error) {
		_, _, err = client.Repositories.ListTrafficReferrers(ctx, "\n", "\n")
		return err
	})

	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
		got, resp, err := client.Repositories.ListTrafficReferrers(ctx, "o", "r")
		if got != nil {
			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
		}
		return resp, err
	})
}

func TestRepositoriesService_ListTrafficPaths(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/repos/o/r/traffic/popular/paths", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "GET")
		fmt.Fprintf(w, `[{
			"path": "/github/hubot",
			"title": "github/hubot: A customizable life embetterment robot.",
			"count": 3542,
			"uniques": 2225
 		}]`)
	})
	ctx := context.Background()
	got, _, err := client.Repositories.ListTrafficPaths(ctx, "o", "r")
	if err != nil {
		t.Errorf("Repositories.ListTrafficPaths returned error: %+v", err)
	}

	want := []*TrafficPath{{
		Path:    String("/github/hubot"),
		Title:   String("github/hubot: A customizable life embetterment robot."),
		Count:   Int(3542),
		Uniques: Int(2225),
	}}
	if !cmp.Equal(got, want) {
		t.Errorf("Repositories.ListTrafficPaths returned %+v, want %+v", got, want)
	}

	const methodName = "ListTrafficPaths"
	testBadOptions(t, methodName, func() (err error) {
		_, _, err = client.Repositories.ListTrafficPaths(ctx, "\n", "\n")
		return err
	})

	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
		got, resp, err := client.Repositories.ListTrafficPaths(ctx, "o", "r")
		if got != nil {
			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
		}
		return resp, err
	})
}

func TestRepositoriesService_ListTrafficViews(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/repos/o/r/traffic/views", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "GET")
		fmt.Fprintf(w, `{"count": 7,
			"uniques": 6,
			"views": [{
				"timestamp": "2016-05-31T16:00:00.000Z",
				"count": 7,
				"uniques": 6
		}]}`)
	})

	ctx := context.Background()
	got, _, err := client.Repositories.ListTrafficViews(ctx, "o", "r", nil)
	if err != nil {
		t.Errorf("Repositories.ListTrafficViews returned error: %+v", err)
	}

	want := &TrafficViews{
		Views: []*TrafficData{{
			Timestamp: &Timestamp{time.Date(2016, time.May, 31, 16, 0, 0, 0, time.UTC)},
			Count:     Int(7),
			Uniques:   Int(6),
		}},
		Count:   Int(7),
		Uniques: Int(6),
	}

	if !cmp.Equal(got, want) {
		t.Errorf("Repositories.ListTrafficViews returned %+v, want %+v", got, want)
	}

	const methodName = "ListTrafficViews"
	testBadOptions(t, methodName, func() (err error) {
		_, _, err = client.Repositories.ListTrafficViews(ctx, "\n", "\n", &TrafficBreakdownOptions{})
		return err
	})

	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
		got, resp, err := client.Repositories.ListTrafficViews(ctx, "o", "r", nil)
		if got != nil {
			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
		}
		return resp, err
	})
}

func TestRepositoriesService_ListTrafficClones(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/repos/o/r/traffic/clones", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "GET")
		fmt.Fprintf(w, `{"count": 7,
			"uniques": 6,
			"clones": [{
				"timestamp": "2016-05-31T16:00:00.00Z",
				"count": 7,
				"uniques": 6
		}]}`)
	})

	ctx := context.Background()
	got, _, err := client.Repositories.ListTrafficClones(ctx, "o", "r", nil)
	if err != nil {
		t.Errorf("Repositories.ListTrafficClones returned error: %+v", err)
	}

	want := &TrafficClones{
		Clones: []*TrafficData{{
			Timestamp: &Timestamp{time.Date(2016, time.May, 31, 16, 0, 0, 0, time.UTC)},
			Count:     Int(7),
			Uniques:   Int(6),
		}},
		Count:   Int(7),
		Uniques: Int(6),
	}

	if !cmp.Equal(got, want) {
		t.Errorf("Repositories.ListTrafficClones returned %+v, want %+v", got, want)
	}

	const methodName = "ListTrafficClones"
	testBadOptions(t, methodName, func() (err error) {
		_, _, err = client.Repositories.ListTrafficClones(ctx, "\n", "\n", &TrafficBreakdownOptions{})
		return err
	})

	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
		got, resp, err := client.Repositories.ListTrafficClones(ctx, "o", "r", nil)
		if got != nil {
			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
		}
		return resp, err
	})
}

func TestTrafficReferrer_Marshal(t *testing.T) {
	testJSONMarshal(t, &TrafficReferrer{}, "{}")

	u := &TrafficReferrer{
		Referrer: String("referrer"),
		Count:    Int(0),
		Uniques:  Int(0),
	}

	want := `{
		"referrer" : "referrer",
		"count" : 0,
		"uniques" : 0
	}`

	testJSONMarshal(t, u, want)
}

func TestTrafficViews_Marshal(t *testing.T) {
	testJSONMarshal(t, &TrafficViews{}, "{}")

	u := &TrafficViews{
		Views: []*TrafficData{{
			Timestamp: &Timestamp{time.Date(2016, time.May, 31, 16, 0, 0, 0, time.UTC)},
			Count:     Int(7),
			Uniques:   Int(6),
		}},
		Count:   Int(0),
		Uniques: Int(0),
	}

	want := `{
		"views": [{
			"timestamp": "2016-05-31T16:00:00.000Z",
			"count": 7,
			"uniques": 6
		}],
		"count" : 0,
		"uniques" : 0
	}`

	testJSONMarshal(t, u, want)
}
<|endoftext|>


<commit_before>package commands

import (
	"context"
	"io"
	"regexp"
	"strings"

	"github.com/zetamatta/go-findfile"

	"github.com/zetamatta/nyagos/completion"
	"github.com/zetamatta/nyagos/nodos"
	"github.com/zetamatta/nyagos/shell"
)

// Param is the interface for built-in command
type Param interface {
	Arg(int) string
	Args() []string
	SetArgs(s []string)
	In() io.Reader
	Out() io.Writer
	Err() io.Writer
	Term() io.Writer
	RawArgs() []string
	Spawnlp(context.Context, []string, []string) (int, error)
	Spawnlpe(context.Context, []string, []string, map[string]string) (int, error)
	Loop(context.Context, shell.Stream) (int, error)
	ReadCommand(context.Context) (context.Context, string, error)
	DumpEnv() []string
	Setenv(key, val string)
	GetHistory() shell.History
}

var buildInCommand map[string]func(context.Context, Param) (int, error)
var unscoNamePattern = regexp.MustCompile("^__(.*)__$")
var backslashPattern = regexp.MustCompile(`^\\(\w*)$`)

// Exec is the entry function to call built-in functions from Shell
func Exec(ctx context.Context, cmd Param) (int, bool, error) {
	name := strings.ToLower(cmd.Arg(0))
	if len(name) == 2 && strings.HasSuffix(name, ":") {
		_, err := nodos.Chdrive(name)
		return 0, true, err
	}
	function, ok := buildInCommand[name]
	if !ok {
		m := unscoNamePattern.FindStringSubmatch(name)
		if m != nil {
			name = m[1]
			function, ok = buildInCommand[name]
			if !ok {
				return 0, false, nil
			}
		} else {
			n := backslashPattern.FindStringSubmatch(name)
			if n == nil {
				return 0, false, nil
			}
			name = n[1]
			function, ok = buildInCommand[name]
			if !ok {
				return 0, false, nil
			}
		}
	}
	cmd.SetArgs(findfile.Globs(cmd.Args()))
	next, err := function(ctx, cmd)
	return next, true, err
}

// AllNames returns all command-names for completion package.
func AllNames(ctx context.Context) ([]completion.Element, error) {
	names := make([]completion.Element, 0, len(buildInCommand))
	for name1 := range buildInCommand {
		names = append(names, completion.Element1(name1))
	}
	return names, nil
}
<commit_msg>Fix: change drive(`x:`) did not push the last directory to directory history<commit_after>package commands

import (
	"context"
	"io"
	"regexp"
	"strings"

	"github.com/zetamatta/go-findfile"

	"github.com/zetamatta/nyagos/completion"
	"github.com/zetamatta/nyagos/nodos"
	"github.com/zetamatta/nyagos/shell"
)

// Param is the interface for built-in command
type Param interface {
	Arg(int) string
	Args() []string
	SetArgs(s []string)
	In() io.Reader
	Out() io.Writer
	Err() io.Writer
	Term() io.Writer
	RawArgs() []string
	Spawnlp(context.Context, []string, []string) (int, error)
	Spawnlpe(context.Context, []string, []string, map[string]string) (int, error)
	Loop(context.Context, shell.Stream) (int, error)
	ReadCommand(context.Context) (context.Context, string, error)
	DumpEnv() []string
	Setenv(key, val string)
	GetHistory() shell.History
}

var buildInCommand map[string]func(context.Context, Param) (int, error)
var unscoNamePattern = regexp.MustCompile("^__(.*)__$")
var backslashPattern = regexp.MustCompile(`^\\(\w*)$`)

// Exec is the entry function to call built-in functions from Shell
func Exec(ctx context.Context, cmd Param) (int, bool, error) {
	name := strings.ToLower(cmd.Arg(0))
	if len(name) == 2 && strings.HasSuffix(name, ":") {
		pushCdHistory()
		_, err := nodos.Chdrive(name)
		return 0, true, err
	}
	function, ok := buildInCommand[name]
	if !ok {
		m := unscoNamePattern.FindStringSubmatch(name)
		if m != nil {
			name = m[1]
			function, ok = buildInCommand[name]
			if !ok {
				return 0, false, nil
			}
		} else {
			n := backslashPattern.FindStringSubmatch(name)
			if n == nil {
				return 0, false, nil
			}
			name = n[1]
			function, ok = buildInCommand[name]
			if !ok {
				return 0, false, nil
			}
		}
	}
	cmd.SetArgs(findfile.Globs(cmd.Args()))
	next, err := function(ctx, cmd)
	return next, true, err
}

// AllNames returns all command-names for completion package.
func AllNames(ctx context.Context) ([]completion.Element, error) {
	names := make([]completion.Element, 0, len(buildInCommand))
	for name1 := range buildInCommand {
		names = append(names, completion.Element1(name1))
	}
	return names, nil
}
<|endoftext|>


<commit_before>// commands is where all cli logic is, including starting portal as a server.
package commands

import (
	"crypto/tls"
	"fmt"
	"io"
	"net/http"
	"os"
	"os/signal"
	"syscall"

	"github.com/jcelliott/lumber"
	"github.com/spf13/cobra"

	"github.com/nanopack/portal/api"
	"github.com/nanopack/portal/balance"
	"github.com/nanopack/portal/cluster"
	"github.com/nanopack/portal/config"
	"github.com/nanopack/portal/core"
	"github.com/nanopack/portal/database"
	"github.com/nanopack/portal/proxymgr"
	"github.com/nanopack/portal/vipmgr"
)

var (
	// to be populated by linker
	tag    string
	commit string

	Portal = &cobra.Command{
		Use:               "portal",
		Short:             "portal - load balancer/proxy",
		Long:              ``,
		PersistentPreRunE: readConfig,
		PreRunE:           preFlight,
		RunE:              startPortal,
		SilenceErrors:     true,
		SilenceUsage:      true,
	}
)

func init() {
	config.AddFlags(Portal)
	Portal.AddCommand(serviceAddCmd)
	Portal.AddCommand(serviceRemoveCmd)
	Portal.AddCommand(serviceShowCmd)
	Portal.AddCommand(servicesShowCmd)
	Portal.AddCommand(servicesSetCmd)
	Portal.AddCommand(serviceSetCmd)

	Portal.AddCommand(serverAddCmd)
	Portal.AddCommand(serverRemoveCmd)
	Portal.AddCommand(serverShowCmd)
	Portal.AddCommand(serversShowCmd)
	Portal.AddCommand(serversSetCmd)

	Portal.AddCommand(routeAddCmd)
	Portal.AddCommand(routesSetCmd)
	Portal.AddCommand(routesShowCmd)
	Portal.AddCommand(routeRemoveCmd)

	Portal.AddCommand(certAddCmd)
	Portal.AddCommand(certsSetCmd)
	Portal.AddCommand(certsShowCmd)
	Portal.AddCommand(certRemoveCmd)

	Portal.AddCommand(vipAddCmd)
	Portal.AddCommand(vipsSetCmd)
	Portal.AddCommand(vipsShowCmd)
	Portal.AddCommand(vipRemoveCmd)
}

func preFlight(ccmd *cobra.Command, args []string) error {
	if config.Version {
		return fmt.Errorf(fmt.Sprintf("portal %s (%s)", tag, commit))
	}

	if !config.Server {
		ccmd.HelpFunc()(ccmd, args)
		return fmt.Errorf("") // no error, just exit
	}

	return nil
}

func readConfig(ccmd *cobra.Command, args []string) error {
	if err := config.LoadConfigFile(); err != nil {
		return fmt.Errorf("ERROR: Failed to read config - %v", err)
	}

	return nil
}

func startPortal(ccmd *cobra.Command, args []string) error {
	if config.LogFile == "" {
		config.Log = lumber.NewConsoleLogger(lumber.LvlInt(config.LogLevel))
	} else {
		var err error
		config.Log, err = lumber.NewFileLogger(config.LogFile, lumber.LvlInt(config.LogLevel), lumber.ROTATE, 5000, 9, 100)
		if err != nil {
			config.Log.Fatal("File logger init failed - %v", err)
			return fmt.Errorf("")
		}
	}
	// initialize database
	err := database.Init()
	if err != nil {
		config.Log.Fatal("Database init failed - %v", err)
		return fmt.Errorf("")
	}
	// initialize balancer
	err = balance.Init()
	if err != nil {
		config.Log.Fatal("Balancer init failed - %v", err)
		return fmt.Errorf("")
	}
	// initialize proxymgr
	err = proxymgr.Init()
	if err != nil {
		config.Log.Fatal("Proxymgr init failed - %v", err)
		return fmt.Errorf("")
	}
	// initialize vipmgr
	err = vipmgr.Init()
	if err != nil {
		config.Log.Fatal("Vipmgr init failed - %v", err)
		return fmt.Errorf("")
	}
	// initialize cluster
	err = cluster.Init()
	if err != nil {
		config.Log.Fatal("Cluster init failed - %v", err)
		return fmt.Errorf("")
	}

	go sigHandle()

	// start api
	err = api.StartApi()
	if err != nil {
		config.Log.Fatal("Api start failed - %v", err)
		return fmt.Errorf("")
	}
	return nil
}

func sigHandle() {
	sigs := make(chan os.Signal, 1)
	signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
	go func() {
		switch <-sigs {
		default:
			// clear balancer rules - (stop balancing if we are offline)
			balance.SetServices(make([]core.Service, 0, 0))
			// clear vips
			vipmgr.SetVips(make([]core.Vip, 0, 0))
			fmt.Println()
			os.Exit(0)
		}
	}()
}

func rest(path string, method string, body io.Reader) (*http.Response, error) {
	var client *http.Client
	client = http.DefaultClient
	uri := fmt.Sprintf("https://%s:%s/%s", config.ApiHost, config.ApiPort, path)

	if config.Insecure {
		http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
	}

	req, err := http.NewRequest(method, uri, body)
	if err != nil {
		fmt.Printf("Failted to create request - %v\n", err.Error())
	}
	req.Header.Add("X-AUTH-TOKEN", config.ApiToken)
	res, err := client.Do(req)
	if err != nil {
		// if requesting `https://` failed, server may have been started with `-i`, try `http://`
		uri = fmt.Sprintf("http://%s:%s/%s", config.ApiHost, config.ApiPort, path)
		req, er := http.NewRequest(method, uri, body)
		if er != nil {
			fmt.Printf("Failted to create request - %v\n", er.Error())
		}
		req.Header.Add("X-AUTH-TOKEN", config.ApiToken)
		var err2 error
		res, err2 = client.Do(req)
		if err2 != nil {
			// return original error to client
			return nil, err
		}
	}
	if res.StatusCode == 401 {
		return nil, fmt.Errorf("401 Unauthorized. Please specify api token (-t 'token')")
	}
	return res, nil
}

func fail(format string, args ...interface{}) {
	fmt.Printf(fmt.Sprintf("%v\n", format), args...)
	os.Exit(1)
}
<commit_msg>Ensure listen ports are unique<commit_after>// commands is where all cli logic is, including starting portal as a server.
package commands

import (
	"crypto/tls"
	"fmt"
	"io"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"

	"github.com/jcelliott/lumber"
	"github.com/spf13/cobra"

	"github.com/nanopack/portal/api"
	"github.com/nanopack/portal/balance"
	"github.com/nanopack/portal/cluster"
	"github.com/nanopack/portal/config"
	"github.com/nanopack/portal/core"
	"github.com/nanopack/portal/database"
	"github.com/nanopack/portal/proxymgr"
	"github.com/nanopack/portal/vipmgr"
)

var (
	// to be populated by linker
	tag    string
	commit string

	Portal = &cobra.Command{
		Use:               "portal",
		Short:             "portal - load balancer/proxy",
		Long:              ``,
		PersistentPreRunE: readConfig,
		PreRunE:           preFlight,
		RunE:              startPortal,
		SilenceErrors:     true,
		SilenceUsage:      true,
	}
)

func init() {
	config.AddFlags(Portal)
	Portal.AddCommand(serviceAddCmd)
	Portal.AddCommand(serviceRemoveCmd)
	Portal.AddCommand(serviceShowCmd)
	Portal.AddCommand(servicesShowCmd)
	Portal.AddCommand(servicesSetCmd)
	Portal.AddCommand(serviceSetCmd)

	Portal.AddCommand(serverAddCmd)
	Portal.AddCommand(serverRemoveCmd)
	Portal.AddCommand(serverShowCmd)
	Portal.AddCommand(serversShowCmd)
	Portal.AddCommand(serversSetCmd)

	Portal.AddCommand(routeAddCmd)
	Portal.AddCommand(routesSetCmd)
	Portal.AddCommand(routesShowCmd)
	Portal.AddCommand(routeRemoveCmd)

	Portal.AddCommand(certAddCmd)
	Portal.AddCommand(certsSetCmd)
	Portal.AddCommand(certsShowCmd)
	Portal.AddCommand(certRemoveCmd)

	Portal.AddCommand(vipAddCmd)
	Portal.AddCommand(vipsSetCmd)
	Portal.AddCommand(vipsShowCmd)
	Portal.AddCommand(vipRemoveCmd)
}

func preFlight(ccmd *cobra.Command, args []string) error {
	if config.Version {
		return fmt.Errorf(fmt.Sprintf("portal %s (%s)", tag, commit))
	}

	if !config.Server {
		ccmd.HelpFunc()(ccmd, args)
		return fmt.Errorf("") // no error, just exit
	}

	return nil
}

func readConfig(ccmd *cobra.Command, args []string) error {
	if err := config.LoadConfigFile(); err != nil {
		return fmt.Errorf("ERROR: Failed to read config - %v", err)
	}

	return nil
}

func startPortal(ccmd *cobra.Command, args []string) error {
	if config.LogFile == "" {
		config.Log = lumber.NewConsoleLogger(lumber.LvlInt(config.LogLevel))
	} else {
		var err error
		config.Log, err = lumber.NewFileLogger(config.LogFile, lumber.LvlInt(config.LogLevel), lumber.ROTATE, 5000, 9, 100)
		if err != nil {
			config.Log.Fatal("File logger init failed - %v", err)
			return fmt.Errorf("")
		}
	}

	// ensure proxy ports are unique. we need to check because tls will not listen
	// until a cert is added. we want it to break sooner.
	if config.RouteHttp == config.RouteTls {
		config.Log.Fatal("Proxy addresses must be unique")
		return fmt.Errorf("")
	}
	// need ':' in case tls is double apiport (8080, 80)
	apiPort := fmt.Sprintf(":%s", config.ApiPort)
	if strings.HasSuffix(config.RouteTls, apiPort) {
		config.Log.Fatal("TLS proxy address must be unique")
		return fmt.Errorf("")
	}

	// initialize database
	err := database.Init()
	if err != nil {
		config.Log.Fatal("Database init failed - %v", err)
		return fmt.Errorf("")
	}
	// initialize balancer
	err = balance.Init()
	if err != nil {
		config.Log.Fatal("Balancer init failed - %v", err)
		return fmt.Errorf("")
	}
	// initialize proxymgr
	err = proxymgr.Init()
	if err != nil {
		config.Log.Fatal("Proxymgr init failed - %v", err)
		return fmt.Errorf("")
	}
	// initialize vipmgr
	err = vipmgr.Init()
	if err != nil {
		config.Log.Fatal("Vipmgr init failed - %v", err)
		return fmt.Errorf("")
	}
	// initialize cluster
	err = cluster.Init()
	if err != nil {
		config.Log.Fatal("Cluster init failed - %v", err)
		return fmt.Errorf("")
	}

	go sigHandle()

	// start api
	err = api.StartApi()
	if err != nil {
		config.Log.Fatal("Api start failed - %v", err)
		return fmt.Errorf("")
	}
	return nil
}

func sigHandle() {
	sigs := make(chan os.Signal, 1)
	signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
	go func() {
		switch <-sigs {
		default:
			// clear balancer rules - (stop balancing if we are offline)
			balance.SetServices(make([]core.Service, 0, 0))
			// clear vips
			vipmgr.SetVips(make([]core.Vip, 0, 0))
			fmt.Println()
			os.Exit(0)
		}
	}()
}

func rest(path string, method string, body io.Reader) (*http.Response, error) {
	var client *http.Client
	client = http.DefaultClient
	uri := fmt.Sprintf("https://%s:%s/%s", config.ApiHost, config.ApiPort, path)

	if config.Insecure {
		http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
	}

	req, err := http.NewRequest(method, uri, body)
	if err != nil {
		fmt.Printf("Failted to create request - %v\n", err.Error())
	}
	req.Header.Add("X-AUTH-TOKEN", config.ApiToken)
	res, err := client.Do(req)
	if err != nil {
		// if requesting `https://` failed, server may have been started with `-i`, try `http://`
		uri = fmt.Sprintf("http://%s:%s/%s", config.ApiHost, config.ApiPort, path)
		req, er := http.NewRequest(method, uri, body)
		if er != nil {
			fmt.Printf("Failted to create request - %v\n", er.Error())
		}
		req.Header.Add("X-AUTH-TOKEN", config.ApiToken)
		var err2 error
		res, err2 = client.Do(req)
		if err2 != nil {
			// return original error to client
			return nil, err
		}
	}
	if res.StatusCode == 401 {
		return nil, fmt.Errorf("401 Unauthorized. Please specify api token (-t 'token')")
	}
	return res, nil
}

func fail(format string, args ...interface{}) {
	fmt.Printf(fmt.Sprintf("%v\n", format), args...)
	os.Exit(1)
}
<|endoftext|>


<commit_before>package commands

import (
	"bytes"
	"fmt"
	"github.com/github/git-lfs/lfs"
	"github.com/spf13/cobra"
	"io"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"
)

var (
	Debugging    = false
	ErrorBuffer  = &bytes.Buffer{}
	ErrorWriter  = io.MultiWriter(os.Stderr, ErrorBuffer)
	OutputWriter = io.MultiWriter(os.Stdout, ErrorBuffer)
	RootCmd      = &cobra.Command{
		Use:   "git-lfs",
		Short: "Git LFS provides large file storage to Git.",
		Run: func(cmd *cobra.Command, args []string) {
			versionCommand(cmd, args)
			cmd.Usage()
		},
	}
)

// Error prints a formatted message to Stderr.  It also gets printed to the
// panic log if one is created for this command.
func Error(format string, args ...interface{}) {
	line := fmt.Sprintf(format, args...)
	fmt.Fprintln(ErrorWriter, line)
}

// Print prints a formatted message to Stdout.  It also gets printed to the
// panic log if one is created for this command.
func Print(format string, args ...interface{}) {
	line := fmt.Sprintf(format, args...)
	fmt.Fprintln(OutputWriter, line)
}

// Exit prints a formatted message and exits.
func Exit(format string, args ...interface{}) {
	Error(format, args...)
	os.Exit(2)
}

// Debug prints a formatted message if debugging is enabled.  The formatted
// message also shows up in the panic log, if created.
func Debug(format string, args ...interface{}) {
	if !Debugging {
		return
	}
	log.Printf(format, args...)
}

// LoggedError prints a formatted message to Stderr and writes a stack trace for
// the error to a log file without exiting.
func LoggedError(err error, format string, args ...interface{}) {
	Error(format, args...)
	file := handlePanic(err)

	if len(file) > 0 {
		fmt.Fprintf(os.Stderr, "\nErrors logged to %s.\nUse `git lfs logs last` to view the log.\n", file)
	}
}

// Panic prints a formatted message, and writes a stack trace for the error to
// a log file before exiting.
func Panic(err error, format string, args ...interface{}) {
	LoggedError(err, format, args...)
	os.Exit(2)
}

func Run() {
	RootCmd.Execute()
}

func PipeMediaCommand(name string, args ...string) error {
	return PipeCommand("bin/"+name, args...)
}

func PipeCommand(name string, args ...string) error {
	cmd := exec.Command(name, args...)
	cmd.Stdin = os.Stdin
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout
	return cmd.Run()
}

func requireStdin(msg string) {
	stat, _ := os.Stdin.Stat()
	if (stat.Mode() & os.ModeCharDevice) != 0 {
		Error("Cannot read from STDIN. %s", msg)
		os.Exit(1)
	}
}

func handlePanic(err error) string {
	if err == nil {
		return ""
	}

	return logPanic(err, false)
}

func logEnv(w io.Writer) {
	for _, env := range lfs.Environ() {
		fmt.Fprintln(w, env)
	}
}

func logPanic(loggedError error, recursive bool) string {
	var fmtWriter io.Writer = os.Stderr

	if err := os.MkdirAll(lfs.LocalLogDir, 0755); err != nil {
		fmt.Fprintf(fmtWriter, "Unable to log panic to %s: %s\n\n", lfs.LocalLogDir, err.Error())
		return ""
	}

	now := time.Now()
	name := now.Format("20060102T150405.999999999")
	full := filepath.Join(lfs.LocalLogDir, name+".log")

	file, err := os.Create(full)
	if err == nil {
		fmtWriter = file
		defer file.Close()
	}

	fmt.Fprintf(fmtWriter, "> %s", filepath.Base(os.Args[0]))
	if len(os.Args) > 0 {
		fmt.Fprintf(fmtWriter, " %s", strings.Join(os.Args[1:], " "))
	}
	fmt.Fprint(fmtWriter, "\n")

	logEnv(fmtWriter)
	fmt.Fprint(fmtWriter, "\n")

	fmtWriter.Write(ErrorBuffer.Bytes())
	fmt.Fprint(fmtWriter, "\n")

	fmt.Fprintln(fmtWriter, loggedError.Error())

	if wErr, ok := loggedError.(ErrorWithStack); ok {
		fmt.Fprintln(fmtWriter, wErr.InnerError())
		for key, value := range wErr.Context() {
			fmt.Fprintf(fmtWriter, "%s=%s\n", key, value)
		}
		fmtWriter.Write(wErr.Stack())
	} else {
		fmtWriter.Write(lfs.Stack())
	}

	if err != nil && !recursive {
		fmt.Fprintf(fmtWriter, "Unable to log panic to %s\n\n", full)
		logPanic(err, true)
	}

	return full
}

type ErrorWithStack interface {
	Context() map[string]string
	InnerError() string
	Stack() []byte
}

func init() {
	log.SetOutput(ErrorWriter)
}
<commit_msg>ラララララ ラー ララララー<commit_after>package commands

import (
	"bytes"
	"fmt"
	"github.com/github/git-lfs/lfs"
	"github.com/spf13/cobra"
	"io"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"
)

var (
	Debugging    = false
	ErrorBuffer  = &bytes.Buffer{}
	ErrorWriter  = io.MultiWriter(os.Stderr, ErrorBuffer)
	OutputWriter = io.MultiWriter(os.Stdout, ErrorBuffer)
	RootCmd      = &cobra.Command{
		Use:   "git-lfs",
		Short: "Git LFS provides large file storage to Git.",
		Run: func(cmd *cobra.Command, args []string) {
			versionCommand(cmd, args)
			cmd.Usage()
		},
	}
)

// Error prints a formatted message to Stderr.  It also gets printed to the
// panic log if one is created for this command.
func Error(format string, args ...interface{}) {
	line := fmt.Sprintf(format, args...)
	fmt.Fprintln(ErrorWriter, line)
}

// Print prints a formatted message to Stdout.  It also gets printed to the
// panic log if one is created for this command.
func Print(format string, args ...interface{}) {
	line := fmt.Sprintf(format, args...)
	fmt.Fprintln(OutputWriter, line)
}

// Exit prints a formatted message and exits.
func Exit(format string, args ...interface{}) {
	Error(format, args...)
	os.Exit(2)
}

// Debug prints a formatted message if debugging is enabled.  The formatted
// message also shows up in the panic log, if created.
func Debug(format string, args ...interface{}) {
	if !Debugging {
		return
	}
	log.Printf(format, args...)
}

// LoggedError prints a formatted message to Stderr and writes a stack trace for
// the error to a log file without exiting.
func LoggedError(err error, format string, args ...interface{}) {
	Error(format, args...)
	file := handlePanic(err)

	if len(file) > 0 {
		fmt.Fprintf(os.Stderr, "\nErrors logged to %s\nUse `git lfs logs last` to view the log.\n", file)
	}
}

// Panic prints a formatted message, and writes a stack trace for the error to
// a log file before exiting.
func Panic(err error, format string, args ...interface{}) {
	LoggedError(err, format, args...)
	os.Exit(2)
}

func Run() {
	RootCmd.Execute()
}

func PipeMediaCommand(name string, args ...string) error {
	return PipeCommand("bin/"+name, args...)
}

func PipeCommand(name string, args ...string) error {
	cmd := exec.Command(name, args...)
	cmd.Stdin = os.Stdin
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout
	return cmd.Run()
}

func requireStdin(msg string) {
	stat, _ := os.Stdin.Stat()
	if (stat.Mode() & os.ModeCharDevice) != 0 {
		Error("Cannot read from STDIN. %s", msg)
		os.Exit(1)
	}
}

func handlePanic(err error) string {
	if err == nil {
		return ""
	}

	return logPanic(err, false)
}

func logEnv(w io.Writer) {
	for _, env := range lfs.Environ() {
		fmt.Fprintln(w, env)
	}
}

func logPanic(loggedError error, recursive bool) string {
	var fmtWriter io.Writer = os.Stderr

	if err := os.MkdirAll(lfs.LocalLogDir, 0755); err != nil {
		fmt.Fprintf(fmtWriter, "Unable to log panic to %s: %s\n\n", lfs.LocalLogDir, err.Error())
		return ""
	}

	now := time.Now()
	name := now.Format("20060102T150405.999999999")
	full := filepath.Join(lfs.LocalLogDir, name+".log")

	file, err := os.Create(full)
	if err == nil {
		fmtWriter = file
		defer file.Close()
	}

	fmt.Fprintf(fmtWriter, "> %s", filepath.Base(os.Args[0]))
	if len(os.Args) > 0 {
		fmt.Fprintf(fmtWriter, " %s", strings.Join(os.Args[1:], " "))
	}
	fmt.Fprint(fmtWriter, "\n")

	logEnv(fmtWriter)
	fmt.Fprint(fmtWriter, "\n")

	fmtWriter.Write(ErrorBuffer.Bytes())
	fmt.Fprint(fmtWriter, "\n")

	fmt.Fprintln(fmtWriter, loggedError.Error())

	if wErr, ok := loggedError.(ErrorWithStack); ok {
		fmt.Fprintln(fmtWriter, wErr.InnerError())
		for key, value := range wErr.Context() {
			fmt.Fprintf(fmtWriter, "%s=%s\n", key, value)
		}
		fmtWriter.Write(wErr.Stack())
	} else {
		fmtWriter.Write(lfs.Stack())
	}

	if err != nil && !recursive {
		fmt.Fprintf(fmtWriter, "Unable to log panic to %s\n\n", full)
		logPanic(err, true)
	}

	return full
}

type ErrorWithStack interface {
	Context() map[string]string
	InnerError() string
	Stack() []byte
}

func init() {
	log.SetOutput(ErrorWriter)
}
<|endoftext|>


<commit_before>package bgp

import (
	"encoding/binary"
	"fmt"
)

// pack converts a header into wireformat and stores the result in buf
func (h *Header) pack(buf []byte) (int, error) {
	if len(buf) < headerLen {
		return 0, NewError(1, 2, "buffer size too small")
	}
	buf[0], buf[1], buf[2], buf[3] = 0xff, 0xff, 0xff, 0xff
	buf[4], buf[4], buf[6], buf[7] = 0xff, 0xff, 0xff, 0xff
	buf[8], buf[9], buf[10], buf[11] = 0xff, 0xff, 0xff, 0xff
	buf[12], buf[13], buf[14], buf[15] = 0xff, 0xff, 0xff, 0xff

	binary.BigEndian.PutUint16(buf[16:], h.Length)

	buf[18] = h.Type
	return 19, nil
}

// unpack converts the wireformat to a header
func (h *Header) unpack(buf []byte) (int, error) {
	if len(buf) < headerLen {
		return 0, NewError(1, 2, "buffer size too small")
	}
	h.Marker[0], h.Marker[1], h.Marker[2], h.Marker[3] = buf[0], buf[1], buf[2], buf[3]
	h.Marker[4], h.Marker[5], h.Marker[6], h.Marker[7] = buf[4], buf[5], buf[6], buf[7]
	h.Marker[8], h.Marker[9], h.Marker[10], h.Marker[11] = buf[8], buf[9], buf[10], buf[11]
	h.Marker[12], h.Marker[13], h.Marker[14], h.Marker[15] = buf[12], buf[13], buf[14], buf[15]

	h.Length = binary.BigEndian.Uint16(buf[16:])

	h.Type = buf[18]
	return 19, nil
}

// pack convert LengthPrefix into wireformat.
func (lp *LengthPrefix) pack(buf []byte) (int, error) {
	if len(buf) < 1 {
		return 0, fmt.Errorf("bgp: buffer size too small")
	}
	buf[0] = byte(lp.Length)

	if len(buf[1:]) < int(lp.Length/8) {
		return 0, fmt.Errorf("bgp: buffer size too small")
	}

	for i := 0; i < int(lp.Length/8); i++ {
		buf[1+i] = lp.Prefix[i]
	}
	return 1 + int(lp.Length/8), nil
}

// unpack convert the wireformat to a LengthPrefix.
func (lp *LengthPrefix) unpack(buf []byte) (int, error) {
	if len(buf) < 1 {
		return 0, fmt.Errorf("bgp: buffer size too small")
	}

	lp.Length = buf[0]

	if len(buf[1:]) < int(lp.Length/8) {
		return 0, fmt.Errorf("bgp: buffer size too small")
	}

	for i := 0; i < int(lp.Length/8); i++ {
		lp.Prefix[i] = buf[1+i]
	}
	// now zero the last byte, otherwise there could be random crap in there.
	return 1 + int(lp.Length/8), nil
}

// pack convert to writeformat.
func (pa *PathAttr) pack(buf []byte) (int, error) {
	if len(buf) < 4 {
		return 0, fmt.Errorf("bgp: buffer size too small")
	}
	buf[0] = pa.Flags
	buf[1] = pa.Code
	if pa.Flags&FlagLength == FlagLength {
		binary.BigEndian.PutUint16(buf[2:], uint16(len(pa.Value)))
	} else {
		buf[2] = uint8(len(pa.Value))
	}
	return 0, nil
}

// unpack converts to a PathAttr
func (pa *PathAttr) unpack(buf []byte) (int, error) {
	return 0, nil
}

// convert to wireformat.
func (p *Parameter) pack(buf []byte) (int, error) {
	if len(buf) < 3 {
		return 0, fmt.Errorf("bgp: buffer size too small")
	}
	buf[0] = p.Type
	buf[1] = uint8(len(p.Value))
	if len(buf[2:]) < len(p.Value) {
		return 0, fmt.Errorf("bgp: buffer size too small")
	}
	for i := 0; i < len(p.Value); i++ {
		buf[i+2] = p.Value[i]
	}
	return 2 + len(p.Value), nil
}

// unpack converts the wireformat  back to a Parameter
func (p *Parameter) unpack(buf []byte) (int, error) {
	if len(buf) < 3 {
		return 0, fmt.Errorf("bgp: buffer size too small")
	}
	p.Type = buf[0]
	length := int(buf[1])
	if len(buf[2:]) < length {
		return 0, fmt.Errorf("bgp: buffer size too small")
	}
	p.Value = make([]byte, length)
	for i := 0; i < length; i++ {
		p.Value[i] = buf[i+2]
	}
	return 2 + length, nil
}

// Pack converts an OPEN message to wire format. Note that unlike Unpack, Pack also
// handles the header of the message.
func (m *OPEN) Pack(buf []byte) (int, error) {
	if len(buf) < 29 || len(buf) < m.Len() { // 29 octets is minimum size.
		return 0, fmt.Errorf("bgp: buffer size too small")
	}

	m.Length = uint16(m.Len())
	m.Type = typeOpen // be sure we're encoding an OPEN message

	offset := 0

	n, err := m.Header.pack(buf[offset:])
	if err != nil {
		return offset, err
	}
	offset += n
	buf[offset] = m.Version
	offset++

	binary.BigEndian.PutUint16(buf[offset:], m.MyAS)
	offset += 2

	binary.BigEndian.PutUint16(buf[offset:], m.HoldTime)
	offset += 2

	buf[offset], buf[offset+1], buf[offset+2], buf[offset+3] =
		m.BGPIdentifier[0], m.BGPIdentifier[1], m.BGPIdentifier[2], m.BGPIdentifier[3]
	offset += 4

	// Save for parameter length
	plengthOffset := offset
	offset++

	l := 0
	for _, p := range m.Parameters {
		n, err := p.pack(buf[offset:])
		if err != nil {
			return offset, err
		}
		l += p.len()
		offset += n
	}
	buf[plengthOffset] = uint8(l)
	return offset, nil
}

// Unpack converts wire format in buf to an OPEN message.
// The header should be already parsed and buf should start on the
// beginning of the message. The header should also already be set in m.
// Unpack returns the amount of bytes parsed or an error.
func (m *OPEN) Unpack(buf []byte) (int, error) {
	if len(buf) < int(m.Length) {
		return 0, fmt.Errorf("bgp: buffer size too small")
	}

	offset := 0

	m.Version = buf[offset]
	offset++

	m.MyAS = binary.BigEndian.Uint16(buf[offset:])
	offset += 2

	m.HoldTime = binary.BigEndian.Uint16(buf[offset:])
	offset += 2

	m.BGPIdentifier[0], m.BGPIdentifier[1], m.BGPIdentifier[2], m.BGPIdentifier[3] =
		buf[offset], buf[offset+1], buf[offset+2], buf[offset+3]
	offset += 4

	pLength := int(buf[offset])
	offset++
	if len(buf) < offset+pLength {
		return offset, fmt.Errorf("bgp: buffer size too small")
	}

	i := 0
	for i < pLength {
		p := Parameter{}
		n, e := p.unpack(buf[i+offset:])
		if e != nil {
			return offset, e
		}
		i += n
		offset += n
		m.Parameters = append(m.Parameters, p)
	}
	return offset, nil
}

// Unpack converts the wire format in buf to a BGP message. The first parsed
// message is returned together with the new offset in buf. If the parsing
// fails an error is returned.
func Unpack(buf []byte) (Message, int, error) {
	offset := 0

	h := new(Header)
	n, e := h.unpack(buf)
	offset += n
	if e != nil {
		return nil, offset, e
	}

	switch h.Type {
	case typeOpen:
		o := new(OPEN)
		o.Header = h
		n, e = o.Unpack(buf[offset:])
		offset += n
		if e != nil {
			return nil, offset, e
		}
		return o, offset, nil
	case typeUpdate:
		u := new(UPDATE)
		return u, offset, nil
		// TODO
	case typeKeepalive:
		k := new(KEEPALIVE)
		return k, offset, nil
	}
	return nil, n, NewError(1, 3, fmt.Sprintf("bad type: %d", h.Type))
}

// Packs convert Message into wireformat and stores the result in buf. It
// returns the new offset in buf or an error.
func Pack(buf []byte, m Message) (int, error) {
	switch m.(type) {
	case *OPEN:
		return m.(*OPEN).Pack(buf)
	}
	return 0, NewError(1, 3, "")
}
<commit_msg>Parsing of keepalive messages<commit_after>package bgp

import (
	"encoding/binary"
	"fmt"
)

// pack converts a header into wireformat and stores the result in buf
func (h *Header) pack(buf []byte) (int, error) {
	if len(buf) < headerLen {
		return 0, NewError(1, 2, "buffer size too small")
	}
	buf[0], buf[1], buf[2], buf[3] = 0xff, 0xff, 0xff, 0xff
	buf[4], buf[4], buf[6], buf[7] = 0xff, 0xff, 0xff, 0xff
	buf[8], buf[9], buf[10], buf[11] = 0xff, 0xff, 0xff, 0xff
	buf[12], buf[13], buf[14], buf[15] = 0xff, 0xff, 0xff, 0xff

	binary.BigEndian.PutUint16(buf[16:], h.Length)

	buf[18] = h.Type
	return 19, nil
}

// unpack converts the wireformat to a header
func (h *Header) unpack(buf []byte) (int, error) {
	if len(buf) < headerLen {
		return 0, NewError(1, 2, "buffer size too small")
	}
	h.Marker[0], h.Marker[1], h.Marker[2], h.Marker[3] = buf[0], buf[1], buf[2], buf[3]
	h.Marker[4], h.Marker[5], h.Marker[6], h.Marker[7] = buf[4], buf[5], buf[6], buf[7]
	h.Marker[8], h.Marker[9], h.Marker[10], h.Marker[11] = buf[8], buf[9], buf[10], buf[11]
	h.Marker[12], h.Marker[13], h.Marker[14], h.Marker[15] = buf[12], buf[13], buf[14], buf[15]

	h.Length = binary.BigEndian.Uint16(buf[16:])

	h.Type = buf[18]
	return 19, nil
}

// pack convert LengthPrefix into wireformat.
func (lp *LengthPrefix) pack(buf []byte) (int, error) {
	if len(buf) < 1 {
		return 0, fmt.Errorf("bgp: buffer size too small")
	}
	buf[0] = byte(lp.Length)

	if len(buf[1:]) < int(lp.Length/8) {
		return 0, fmt.Errorf("bgp: buffer size too small")
	}

	for i := 0; i < int(lp.Length/8); i++ {
		buf[1+i] = lp.Prefix[i]
	}
	return 1 + int(lp.Length/8), nil
}

// unpack convert the wireformat to a LengthPrefix.
func (lp *LengthPrefix) unpack(buf []byte) (int, error) {
	if len(buf) < 1 {
		return 0, fmt.Errorf("bgp: buffer size too small")
	}

	lp.Length = buf[0]

	if len(buf[1:]) < int(lp.Length/8) {
		return 0, fmt.Errorf("bgp: buffer size too small")
	}

	for i := 0; i < int(lp.Length/8); i++ {
		lp.Prefix[i] = buf[1+i]
	}
	// now zero the last byte, otherwise there could be random crap in there.
	return 1 + int(lp.Length/8), nil
}

// pack convert to writeformat.
func (pa *PathAttr) pack(buf []byte) (int, error) {
	if len(buf) < 4 {
		return 0, fmt.Errorf("bgp: buffer size too small")
	}
	buf[0] = pa.Flags
	buf[1] = pa.Code
	if pa.Flags&FlagLength == FlagLength {
		binary.BigEndian.PutUint16(buf[2:], uint16(len(pa.Value)))
	} else {
		buf[2] = uint8(len(pa.Value))
	}
	return 0, nil
}

// unpack converts to a PathAttr
func (pa *PathAttr) unpack(buf []byte) (int, error) {
	return 0, nil
}

// pack converts a Parameter to wireformat.
func (p *Parameter) pack(buf []byte) (int, error) {
	if len(buf) < 3 {
		return 0, fmt.Errorf("bgp: buffer size too small")
	}
	buf[0] = p.Type
	buf[1] = uint8(len(p.Value))
	if len(buf[2:]) < len(p.Value) {
		return 0, fmt.Errorf("bgp: buffer size too small")
	}
	for i := 0; i < len(p.Value); i++ {
		buf[i+2] = p.Value[i]
	}
	return 2 + len(p.Value), nil
}

// unpack converts the wireformat back to a Parameter.
func (p *Parameter) unpack(buf []byte) (int, error) {
	if len(buf) < 3 {
		return 0, fmt.Errorf("bgp: buffer size too small")
	}
	p.Type = buf[0]
	length := int(buf[1])
	if len(buf[2:]) < length {
		return 0, fmt.Errorf("bgp: buffer size too small")
	}
	p.Value = make([]byte, length)
	for i := 0; i < length; i++ {
		p.Value[i] = buf[i+2]
	}
	return 2 + length, nil
}

// Pack converts an OPEN message to wire format. Note that unlike Unpack, Pack also
// handles the header of the message.
func (m *OPEN) Pack(buf []byte) (int, error) {
	if len(buf) < 29 || len(buf) < m.Len() { // 29 octets is minimum size.
		return 0, NewError(1, 2, "buffer size too small")
	}

	m.Length = uint16(m.Len())
	m.Type = typeOpen // be sure we're encoding an OPEN message

	offset := 0

	n, err := m.Header.pack(buf[offset:])
	if err != nil {
		return offset, err
	}
	offset += n
	buf[offset] = m.Version
	offset++

	binary.BigEndian.PutUint16(buf[offset:], m.MyAS)
	offset += 2

	binary.BigEndian.PutUint16(buf[offset:], m.HoldTime)
	offset += 2

	buf[offset], buf[offset+1], buf[offset+2], buf[offset+3] =
		m.BGPIdentifier[0], m.BGPIdentifier[1], m.BGPIdentifier[2], m.BGPIdentifier[3]
	offset += 4

	// Save for parameter length
	plengthOffset := offset
	offset++

	l := 0
	for _, p := range m.Parameters {
		n, err := p.pack(buf[offset:])
		if err != nil {
			return offset, err
		}
		l += p.len()
		offset += n
	}
	buf[plengthOffset] = uint8(l)
	return offset, nil
}

// Unpack converts wire format in buf to an OPEN message.
// The header should be already parsed and buf should start on the
// beginning of the message. The header should also already be set in m.
// Unpack returns the amount of bytes parsed or an error.
func (m *OPEN) Unpack(buf []byte) (int, error) {
	if len(buf) < int(m.Length) {
		return 0, NewError(1, 2, "buffer size too small")
	}

	offset := 0

	m.Version = buf[offset]
	offset++

	m.MyAS = binary.BigEndian.Uint16(buf[offset:])
	offset += 2

	m.HoldTime = binary.BigEndian.Uint16(buf[offset:])
	offset += 2

	m.BGPIdentifier[0], m.BGPIdentifier[1], m.BGPIdentifier[2], m.BGPIdentifier[3] =
		buf[offset], buf[offset+1], buf[offset+2], buf[offset+3]
	offset += 4

	pLength := int(buf[offset])
	offset++
	if len(buf) < offset+pLength {
		return offset, fmt.Errorf("bgp: buffer size too small")
	}

	i := 0
	for i < pLength {
		p := Parameter{}
		n, e := p.unpack(buf[i+offset:])
		if e != nil {
			return offset, e
		}
		i += n
		offset += n
		m.Parameters = append(m.Parameters, p)
	}
	return offset, nil
}

// Pack converts an KEEPALIVE mesasge to wire format.
func (m *KEEPALIVE) Pack(buf []byte) (int, error) {
	if len(buf) < m.Len() {
		return 0, NewError(1, 2, "buffer size too small")
	}

	m.Length = uint16(m.Len())
	m.Type = typeKeepalive

	n, err := m.Header.pack(buf)
	if err != nil {
		return n, err
	}
	return n, nil
}

// Unpack converts wire format in buf to an KEEPALIVE message.
func (m *KEEPALIVE) Unpack(buf []byte) (int, error) {
	// a noop because a KEEPALIVE is *just* the header and it should
	// already parsed.
	return 0, nil
}

// Unpack converts the wire format in buf to a BGP message. The first parsed
// message is returned together with the new offset in buf. If the parsing
// fails an error is returned.
func Unpack(buf []byte) (Message, int, error) {
	offset := 0

	h := new(Header)
	n, e := h.unpack(buf)
	offset += n
	if e != nil {
		return nil, offset, e
	}

	switch h.Type {
	case typeOpen:
		o := new(OPEN)
		o.Header = h
		n, e = o.Unpack(buf[offset:])
		offset += n
		if e != nil {
			return nil, offset, e
		}
		return o, offset, nil
	case typeUpdate:
		u := new(UPDATE)
		return u, offset, nil
		// TODO
	case typeKeepalive:
		k := new(KEEPALIVE)
		return k, offset, nil
	}
	return nil, n, NewError(1, 3, fmt.Sprintf("bad type: %d", h.Type))
}

// Packs convert Message into wireformat and stores the result in buf. It
// returns the new offset in buf or an error.
func Pack(buf []byte, m Message) (int, error) {
	switch m.(type) {
	case *OPEN:
		return m.(*OPEN).Pack(buf)
	}
	return 0, NewError(1, 3, "")
}
<|endoftext|>


<commit_before>package ovn

import (
	"github.com/Sirupsen/logrus"
	"github.com/openvswitch/ovn-kubernetes/go-controller/pkg/kube"
	kapi "k8s.io/client-go/pkg/api/v1"
	kapisnetworking "k8s.io/client-go/pkg/apis/networking/v1"
	"k8s.io/client-go/tools/cache"
	"reflect"
	"sync"
)

// Controller structure is the object which holds the controls for starting
// and reacting upon the watched resources (e.g. pods, endpoints)
type Controller struct {
	Kube kube.Interface

	StartPodWatch       func(handler cache.ResourceEventHandler)
	StartEndpointWatch  func(handler cache.ResourceEventHandler)
	StartServiceWatch   func(handler cache.ResourceEventHandler)
	StartPolicyWatch    func(handler cache.ResourceEventHandler)
	StartNamespaceWatch func(handler cache.ResourceEventHandler)

	gatewayCache map[string]string
	// For TCP and UDP type traffic, cache OVN load-balancers used for the
	// cluster's east-west traffic.
	loadbalancerClusterCache map[string]string

	// A cache of all logical switches seen by the watcher
	logicalSwitchCache map[string]bool

	// For each namespace, an address_set that has all the pod IP
	// address in that namespace
	namespaceAddressSet map[string]map[string]bool

	// For each namespace, a lock to protect critical regions
	namespaceMutex map[string]*sync.Mutex

	// For each namespace, a map of policy name to 'namespacePolicy'.
	namespacePolicies map[string]map[string]*namespacePolicy

	// For each logical port, the number of network policies that want
	// to add a deny rule.
	lspIngressDenyCache map[string]int

	// A mutex for logicalPortIngressDenyCache
	lspMutex *sync.Mutex
}

const (
	// OvnNbctl is the constant string for the ovn-nbctl shell command
	OvnNbctl = "ovn-nbctl"

	// TCP is the constant string for the string "TCP"
	TCP = "TCP"

	// UDP is the constant string for the string "UDP"
	UDP = "UDP"
)

// Run starts the actual watching. Also initializes any local structures needed.
func (oc *Controller) Run() {
	oc.gatewayCache = make(map[string]string)
	oc.WatchPods()
	oc.WatchServices()
	oc.WatchEndpoints()
	oc.WatchNamespaces()

	oc.initializePolicyData()
	oc.WatchNetworkPolicy()
}

func (oc *Controller) initializePolicyData() {
	oc.logicalSwitchCache = make(map[string]bool)
	oc.namespaceAddressSet = make(map[string]map[string]bool)
	oc.namespacePolicies = make(map[string]map[string]*namespacePolicy)
	oc.namespaceMutex = make(map[string]*sync.Mutex)
	oc.lspIngressDenyCache = make(map[string]int)
	oc.lspMutex = &sync.Mutex{}
}

// WatchPods starts the watching of Pod resource and calls back the appropriate handler logic
func (oc *Controller) WatchPods() {
	oc.StartPodWatch(cache.ResourceEventHandlerFuncs{
		AddFunc: func(obj interface{}) {
			pod := obj.(*kapi.Pod)
			oc.addLogicalPort(pod)
		},
		UpdateFunc: func(old, new interface{}) {
		},
		DeleteFunc: func(obj interface{}) {
			pod, ok := obj.(*kapi.Pod)
			if !ok {
				tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
				if !ok {
					logrus.Errorf("couldn't get object from tombstone %+v", obj)
					return
				}
				pod, ok = tombstone.Obj.(*kapi.Pod)
				if !ok {
					logrus.Errorf("tombstone contained object that is not a pod %#v", obj)
					return
				}
			}
			oc.deleteLogicalPort(pod)
		},
	})
}

// WatchServices starts the watching of Service resource and calls back the
// appropriate handler logic
func (oc *Controller) WatchServices() {
	oc.StartServiceWatch(cache.ResourceEventHandlerFuncs{
		AddFunc: func(obj interface{}) {
		},
		UpdateFunc: func(old, new interface{}) {
		},
		DeleteFunc: func(obj interface{}) {
			service, ok := obj.(*kapi.Service)
			if !ok {
				tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
				if !ok {
					logrus.Errorf("couldn't get object from tombstone %+v", obj)
					return
				}
				service, ok = tombstone.Obj.(*kapi.Service)
				if !ok {
					logrus.Errorf("tombstone contained object that is not a Service %#v", obj)
					return
				}
			}
			oc.deleteService(service)
		},
	})
}

// WatchEndpoints starts the watching of Endpoint resource and calls back the appropriate handler logic
func (oc *Controller) WatchEndpoints() {
	oc.loadbalancerClusterCache = make(map[string]string)

	oc.StartEndpointWatch(cache.ResourceEventHandlerFuncs{
		AddFunc: func(obj interface{}) {
			ep := obj.(*kapi.Endpoints)
			err := oc.addEndpoints(ep)
			if err != nil {
				logrus.Errorf("Error in adding load balancer: %v", err)
			}
		},
		UpdateFunc: func(old, new interface{}) {
			epNew := new.(*kapi.Endpoints)
			epOld := old.(*kapi.Endpoints)
			if reflect.DeepEqual(epNew.Subsets, epOld.Subsets) {
				return
			}
			if len(epNew.Subsets) == 0 {
				err := oc.deleteEndpoints(epNew)
				if err != nil {
					logrus.Errorf("Error in deleting endpoints - %v", err)
				}
			} else {
				err := oc.addEndpoints(epNew)
				if err != nil {
					logrus.Errorf("Error in modifying endpoints: %v", err)
				}
			}
		},
		DeleteFunc: func(obj interface{}) {
			ep, ok := obj.(*kapi.Endpoints)
			if !ok {
				tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
				if !ok {
					logrus.Errorf("couldn't get object from tombstone %+v", obj)
					return
				}
				ep, ok = tombstone.Obj.(*kapi.Endpoints)
				if !ok {
					logrus.Errorf("tombstone contained object that is not a pod %#v", obj)
					return
				}
			}
			err := oc.deleteEndpoints(ep)
			if err != nil {
				logrus.Errorf("Error in deleting endpoints - %v", err)
			}
		},
	})
}

// WatchNetworkPolicy starts the watching of network policy resource and calls
// back the appropriate handler logic
func (oc *Controller) WatchNetworkPolicy() {
	oc.StartPolicyWatch(cache.ResourceEventHandlerFuncs{
		AddFunc: func(obj interface{}) {
			policy := obj.(*kapisnetworking.NetworkPolicy)
			oc.addNetworkPolicy(policy)
			return
		},
		UpdateFunc: func(old, newer interface{}) {
			oldPolicy := old.(*kapisnetworking.NetworkPolicy)
			newPolicy := newer.(*kapisnetworking.NetworkPolicy)
			oc.deleteNetworkPolicy(oldPolicy)
			oc.addNetworkPolicy(newPolicy)
			return
		},
		DeleteFunc: func(obj interface{}) {
			policy, ok := obj.(*kapisnetworking.NetworkPolicy)
			if !ok {
				tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
				if !ok {
					logrus.Errorf("couldn't get object from tombstone %+v", obj)
					return
				}
				policy, ok = tombstone.Obj.(*kapisnetworking.NetworkPolicy)
				if !ok {
					logrus.Errorf("tombstone contained object that is not a pod %#v", obj)
					return
				}
			}
			oc.deleteNetworkPolicy(policy)
			return
		},
	})
}

// WatchNamespaces starts the watching of namespace resource and calls
// back the appropriate handler logic
func (oc *Controller) WatchNamespaces() {
	oc.StartNamespaceWatch(cache.ResourceEventHandlerFuncs{
		AddFunc: func(obj interface{}) {
			ns := obj.(*kapi.Namespace)
			oc.addNamespace(ns)
			return
		},
		UpdateFunc: func(old, newer interface{}) {
			ns := newer.(*kapi.Namespace)
			oc.addNamespace(ns)
			return
		},
		DeleteFunc: func(obj interface{}) {
			ns, ok := obj.(*kapi.Namespace)
			if !ok {
				tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
				if !ok {
					logrus.Errorf("couldn't get object from tombstone %+v", obj)
					return
				}
				ns, ok = tombstone.Obj.(*kapi.Namespace)
				if !ok {
					logrus.Errorf("tombstone contained object that is not a namespace %#v", obj)
					return
				}
			}
			oc.deleteNamespace(ns)
			return
		},
	})
}
<commit_msg>move the policy init function prior to PodWatch because a new pod refers to logicalSwitchCache and an init race can result in null pointer exception<commit_after>package ovn

import (
	"github.com/Sirupsen/logrus"
	"github.com/openvswitch/ovn-kubernetes/go-controller/pkg/kube"
	kapi "k8s.io/client-go/pkg/api/v1"
	kapisnetworking "k8s.io/client-go/pkg/apis/networking/v1"
	"k8s.io/client-go/tools/cache"
	"reflect"
	"sync"
)

// Controller structure is the object which holds the controls for starting
// and reacting upon the watched resources (e.g. pods, endpoints)
type Controller struct {
	Kube kube.Interface

	StartPodWatch       func(handler cache.ResourceEventHandler)
	StartEndpointWatch  func(handler cache.ResourceEventHandler)
	StartServiceWatch   func(handler cache.ResourceEventHandler)
	StartPolicyWatch    func(handler cache.ResourceEventHandler)
	StartNamespaceWatch func(handler cache.ResourceEventHandler)

	gatewayCache map[string]string
	// For TCP and UDP type traffic, cache OVN load-balancers used for the
	// cluster's east-west traffic.
	loadbalancerClusterCache map[string]string

	// A cache of all logical switches seen by the watcher
	logicalSwitchCache map[string]bool

	// For each namespace, an address_set that has all the pod IP
	// address in that namespace
	namespaceAddressSet map[string]map[string]bool

	// For each namespace, a lock to protect critical regions
	namespaceMutex map[string]*sync.Mutex

	// For each namespace, a map of policy name to 'namespacePolicy'.
	namespacePolicies map[string]map[string]*namespacePolicy

	// For each logical port, the number of network policies that want
	// to add a deny rule.
	lspIngressDenyCache map[string]int

	// A mutex for logicalPortIngressDenyCache
	lspMutex *sync.Mutex
}

const (
	// OvnNbctl is the constant string for the ovn-nbctl shell command
	OvnNbctl = "ovn-nbctl"

	// TCP is the constant string for the string "TCP"
	TCP = "TCP"

	// UDP is the constant string for the string "UDP"
	UDP = "UDP"
)

// Run starts the actual watching. Also initializes any local structures needed.
func (oc *Controller) Run() {
	oc.gatewayCache = make(map[string]string)
	oc.initializePolicyData()

	oc.WatchPods()
	oc.WatchServices()
	oc.WatchEndpoints()
	oc.WatchNamespaces()

	oc.WatchNetworkPolicy()
}

func (oc *Controller) initializePolicyData() {
	oc.logicalSwitchCache = make(map[string]bool)
	oc.namespaceAddressSet = make(map[string]map[string]bool)
	oc.namespacePolicies = make(map[string]map[string]*namespacePolicy)
	oc.namespaceMutex = make(map[string]*sync.Mutex)
	oc.lspIngressDenyCache = make(map[string]int)
	oc.lspMutex = &sync.Mutex{}
}

// WatchPods starts the watching of Pod resource and calls back the appropriate handler logic
func (oc *Controller) WatchPods() {
	oc.StartPodWatch(cache.ResourceEventHandlerFuncs{
		AddFunc: func(obj interface{}) {
			pod := obj.(*kapi.Pod)
			oc.addLogicalPort(pod)
		},
		UpdateFunc: func(old, new interface{}) {
		},
		DeleteFunc: func(obj interface{}) {
			pod, ok := obj.(*kapi.Pod)
			if !ok {
				tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
				if !ok {
					logrus.Errorf("couldn't get object from tombstone %+v", obj)
					return
				}
				pod, ok = tombstone.Obj.(*kapi.Pod)
				if !ok {
					logrus.Errorf("tombstone contained object that is not a pod %#v", obj)
					return
				}
			}
			oc.deleteLogicalPort(pod)
		},
	})
}

// WatchServices starts the watching of Service resource and calls back the
// appropriate handler logic
func (oc *Controller) WatchServices() {
	oc.StartServiceWatch(cache.ResourceEventHandlerFuncs{
		AddFunc: func(obj interface{}) {
		},
		UpdateFunc: func(old, new interface{}) {
		},
		DeleteFunc: func(obj interface{}) {
			service, ok := obj.(*kapi.Service)
			if !ok {
				tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
				if !ok {
					logrus.Errorf("couldn't get object from tombstone %+v", obj)
					return
				}
				service, ok = tombstone.Obj.(*kapi.Service)
				if !ok {
					logrus.Errorf("tombstone contained object that is not a Service %#v", obj)
					return
				}
			}
			oc.deleteService(service)
		},
	})
}

// WatchEndpoints starts the watching of Endpoint resource and calls back the appropriate handler logic
func (oc *Controller) WatchEndpoints() {
	oc.loadbalancerClusterCache = make(map[string]string)

	oc.StartEndpointWatch(cache.ResourceEventHandlerFuncs{
		AddFunc: func(obj interface{}) {
			ep := obj.(*kapi.Endpoints)
			err := oc.addEndpoints(ep)
			if err != nil {
				logrus.Errorf("Error in adding load balancer: %v", err)
			}
		},
		UpdateFunc: func(old, new interface{}) {
			epNew := new.(*kapi.Endpoints)
			epOld := old.(*kapi.Endpoints)
			if reflect.DeepEqual(epNew.Subsets, epOld.Subsets) {
				return
			}
			if len(epNew.Subsets) == 0 {
				err := oc.deleteEndpoints(epNew)
				if err != nil {
					logrus.Errorf("Error in deleting endpoints - %v", err)
				}
			} else {
				err := oc.addEndpoints(epNew)
				if err != nil {
					logrus.Errorf("Error in modifying endpoints: %v", err)
				}
			}
		},
		DeleteFunc: func(obj interface{}) {
			ep, ok := obj.(*kapi.Endpoints)
			if !ok {
				tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
				if !ok {
					logrus.Errorf("couldn't get object from tombstone %+v", obj)
					return
				}
				ep, ok = tombstone.Obj.(*kapi.Endpoints)
				if !ok {
					logrus.Errorf("tombstone contained object that is not a pod %#v", obj)
					return
				}
			}
			err := oc.deleteEndpoints(ep)
			if err != nil {
				logrus.Errorf("Error in deleting endpoints - %v", err)
			}
		},
	})
}

// WatchNetworkPolicy starts the watching of network policy resource and calls
// back the appropriate handler logic
func (oc *Controller) WatchNetworkPolicy() {
	oc.StartPolicyWatch(cache.ResourceEventHandlerFuncs{
		AddFunc: func(obj interface{}) {
			policy := obj.(*kapisnetworking.NetworkPolicy)
			oc.addNetworkPolicy(policy)
			return
		},
		UpdateFunc: func(old, newer interface{}) {
			oldPolicy := old.(*kapisnetworking.NetworkPolicy)
			newPolicy := newer.(*kapisnetworking.NetworkPolicy)
			oc.deleteNetworkPolicy(oldPolicy)
			oc.addNetworkPolicy(newPolicy)
			return
		},
		DeleteFunc: func(obj interface{}) {
			policy, ok := obj.(*kapisnetworking.NetworkPolicy)
			if !ok {
				tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
				if !ok {
					logrus.Errorf("couldn't get object from tombstone %+v", obj)
					return
				}
				policy, ok = tombstone.Obj.(*kapisnetworking.NetworkPolicy)
				if !ok {
					logrus.Errorf("tombstone contained object that is not a pod %#v", obj)
					return
				}
			}
			oc.deleteNetworkPolicy(policy)
			return
		},
	})
}

// WatchNamespaces starts the watching of namespace resource and calls
// back the appropriate handler logic
func (oc *Controller) WatchNamespaces() {
	oc.StartNamespaceWatch(cache.ResourceEventHandlerFuncs{
		AddFunc: func(obj interface{}) {
			ns := obj.(*kapi.Namespace)
			oc.addNamespace(ns)
			return
		},
		UpdateFunc: func(old, newer interface{}) {
			ns := newer.(*kapi.Namespace)
			oc.addNamespace(ns)
			return
		},
		DeleteFunc: func(obj interface{}) {
			ns, ok := obj.(*kapi.Namespace)
			if !ok {
				tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
				if !ok {
					logrus.Errorf("couldn't get object from tombstone %+v", obj)
					return
				}
				ns, ok = tombstone.Obj.(*kapi.Namespace)
				if !ok {
					logrus.Errorf("tombstone contained object that is not a namespace %#v", obj)
					return
				}
			}
			oc.deleteNamespace(ns)
			return
		},
	})
}
<|endoftext|>


<commit_before>package tao

import (
	"fmt"
	"os"
)

const (
	HostTaoEnvVar = "GOOGLE_HOST_TAO"

	SharedSecretPolicyDefault = "self"
	SharedSecretPolicyConservative = "few"
	SharedSecretPolicyLiberal = "any"

	SealPolicyDefault = "self"
	SealPolicyConservative = "few"
	SealPolicyLiberal = "any"
)

// Tao is the fundamental Trustworthy Computing interface provided by a host to
// its hosted programs. Each level of a system can act as a host by exporting
// the Tao interface and providing Tao services to higher-level hosted programs.
//
// In most cases, a hosted program will use a stub Tao that performs RPC over a
// channel to its host. The details of such RPC depend on the specific
// implementation of the host: some hosted programs may use pipes to communicate
// with their host, others may use sockets, etc.
type Tao interface {
	// GetTaoName returns the Tao principal name assigned to the caller.
	GetTaoName() (name string, err error)

	/// ExtendTaoName irreversibly extends the Tao principal name of the caller.
	ExtendTaoName(subprin string) error

	// GetRandomBytes returns a slice of n random bytes.
	GetRandomBytes(n int) (bytes []byte, err error)

	// GetSharedSecret returns a slice of n secret bytes.
	GetSharedSecret(n int, policy string) (bytes []byte, err error)

	// Attest requests the Tao host sign a Statement on behalf of the caller.
	Attest(stmt *Statement) (*Attestation, error)

	// Seal encrypts data so only certain hosted programs can unseal it.
	Seal(data []byte, policy string) (sealed []byte, err error)

	// Unseal decrypts data that has been sealed by the Seal() operation, but only
	// if the policy specified during the Seal() operation is satisfied.
	Unseal(sealed []byte) (data []byte, policy string, err error)
}

// Host is a pointer to host Tao underlying this hosted program.
var Host Tao

func init() {
	tao, err := DeserializeTaoRPC(os.Getenv(HostTaoEnvVar))
	if err != nil {
		fmt.Println(err.Error())
	} else {
		Host = tao
	}
}
<commit_msg>use glog, not fmt<commit_after>// File: tao.go
// Author: Kevin Walsh <kwalsh@holycross.edu>
// Description: Interface to a host Tao.
//
// Copyright (c) 2013, Google Inc.  All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package tao

import (
	"fmt"
	"github.com/golang/glog"
	"os"
)

const (
	HostTaoEnvVar = "GOOGLE_HOST_TAO"

	SharedSecretPolicyDefault = "self"
	SharedSecretPolicyConservative = "few"
	SharedSecretPolicyLiberal = "any"

	SealPolicyDefault = "self"
	SealPolicyConservative = "few"
	SealPolicyLiberal = "any"
)

// Tao is the fundamental Trustworthy Computing interface provided by a host to
// its hosted programs. Each level of a system can act as a host by exporting
// the Tao interface and providing Tao services to higher-level hosted programs.
//
// In most cases, a hosted program will use a stub Tao that performs RPC over a
// channel to its host. The details of such RPC depend on the specific
// implementation of the host: some hosted programs may use pipes to communicate
// with their host, others may use sockets, etc.
type Tao interface {
	// GetTaoName returns the Tao principal name assigned to the caller.
	GetTaoName() (name string, err error)

	/// ExtendTaoName irreversibly extends the Tao principal name of the caller.
	ExtendTaoName(subprin string) error

	// GetRandomBytes returns a slice of n random bytes.
	GetRandomBytes(n int) (bytes []byte, err error)

	// GetSharedSecret returns a slice of n secret bytes.
	GetSharedSecret(n int, policy string) (bytes []byte, err error)

	// Attest requests the Tao host sign a Statement on behalf of the caller.
	Attest(stmt *Statement) (*Attestation, error)

	// Seal encrypts data so only certain hosted programs can unseal it.
	Seal(data []byte, policy string) (sealed []byte, err error)

	// Unseal decrypts data that has been sealed by the Seal() operation, but only
	// if the policy specified during the Seal() operation is satisfied.
	Unseal(sealed []byte) (data []byte, policy string, err error)
}

// Host is a pointer to host Tao underlying this hosted program.
var Host Tao

func init() {
	host, err := DeserializeTaoRPC(os.Getenv(HostTaoEnvVar))
	if err != nil {
		glog.Error(err)
		return
	}
	Host = host
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"syscall"
)

func main() {
	if os.Args[0] == "/proc/self/exe" {
		inner()
	} else {
		os.Exit(outer())
	}
}

func outer() int {
	rootFS := flag.String("rootFS", "", "rootFS")
	privileged := flag.Bool("privileged", false, "if true, user namespace is not used")
	flag.Parse()
	if *rootFS == "" {
		fmt.Println("must set -rootFS")
		return 1
	}

	cowRootFS, err := ioutil.TempDir("", "container-run")
	must(err)

	mappingSize := 100000
	chownTo := mappingSize
	if *privileged {
		chownTo = 0
	}
	containerRootFSPath, err := createUniqueRootFS(*rootFS, cowRootFS, chownTo)
	must(err)
	defer func() {
		must(syscall.Unmount(containerRootFSPath, 0))
		must(os.RemoveAll(cowRootFS))
	}()

	must(syscall.Mount("", "/", "", syscall.MS_PRIVATE|syscall.MS_REC, "remount"))

	cmd := exec.Command("/proc/self/exe", append([]string{containerRootFSPath}, flag.Args()...)...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	cmd.SysProcAttr = &syscall.SysProcAttr{
		Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWNS | syscall.CLONE_NEWPID,
	}
	if !*privileged {
		cmd.SysProcAttr.Cloneflags = cmd.SysProcAttr.Cloneflags | syscall.CLONE_NEWUSER
		mapping := []syscall.SysProcIDMap{
			{
				ContainerID: 0,
				HostID:      mappingSize,
				Size:        1,
			},
			{
				ContainerID: 1,
				HostID:      1,
				Size:        mappingSize - 1,
			},
		}
		cmd.SysProcAttr.UidMappings = mapping
		cmd.SysProcAttr.GidMappings = mapping
		cmd.SysProcAttr.Credential = &syscall.Credential{Uid: 0, Gid: 0}
	}

	if err := cmd.Run(); err != nil {
		if exitErr, ok := err.(*exec.ExitError); ok {
			return exitErr.Sys().(syscall.WaitStatus).ExitStatus()
		}

		must(err)
	}

	return 0
}

func inner() {
	rootFS := os.Args[1]

	oldRootFS := filepath.Join(rootFS, "oldrootfs")
	must(os.Mkdir(oldRootFS, 0700))
	must(syscall.Mount(rootFS, rootFS, "", syscall.MS_BIND, ""))
	must(syscall.PivotRoot(rootFS, oldRootFS))
	must(os.Chdir("/"))
	must(syscall.Mount("proc", "/proc", "proc", 0, ""))
	must(syscall.Unmount("/oldrootfs", syscall.MNT_DETACH))

	cmd := exec.Command(os.Args[2], os.Args[3:]...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	if err := cmd.Run(); err != nil {
		if exitErr, ok := err.(*exec.ExitError); ok {
			fmt.Println(err)
			os.Exit(exitErr.Sys().(syscall.WaitStatus).ExitStatus())
		}

		must(err)
	}
}

func createUniqueRootFS(rootFS, cowRootFS string, chownTo int) (string, error) {
	lowerLayer := rootFS
	if chownTo != 0 {
		var err error
		lowerLayer, err = createUnprivilegedRootFS(rootFS, chownTo)
		if err != nil {
			return "", err
		}
	}

	if err := os.Chown(cowRootFS, chownTo, chownTo); err != nil {
		return "", nil
	}

	containerRootFS := filepath.Join(cowRootFS, "union")
	workDir := filepath.Join(cowRootFS, "work")
	upperDir := filepath.Join(cowRootFS, "upper")
	for _, dir := range []string{containerRootFS, workDir, upperDir} {
		if err := os.Mkdir(dir, 0700); err != nil {
			return "", err
		}
		if err := os.Chown(dir, chownTo, chownTo); err != nil {
			return "", nil
		}
	}
	if err := mountOverlay(lowerLayer, upperDir, workDir, containerRootFS); err != nil {
		return "", err
	}
	return containerRootFS, nil
}

func createUnprivilegedRootFS(rootFS string, uid int) (string, error) {
	fssDir := filepath.Dir(rootFS)
	fsName := filepath.Base(rootFS)
	unprivilegedRootFSPath := filepath.Join(fssDir, fsName+"-unprivileged")

	lockPath := filepath.Join(fssDir, fsName+"-chownlock")
	lockFile, err := os.OpenFile(lockPath, os.O_CREATE, 0600)
	if err != nil {
		return "", err
	}
	if err := syscall.Flock(int(lockFile.Fd()), syscall.LOCK_EX); err != nil {
		return "", err
	}
	defer func() {
		syscall.Flock(int(lockFile.Fd()), syscall.LOCK_UN)
		lockFile.Close()
	}()

	if _, err := os.Stat(unprivilegedRootFSPath); err == nil {
		return unprivilegedRootFSPath, nil
	}

	if err := filepath.Walk(rootFS, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		relativePath, err := filepath.Rel(rootFS, path)
		if err != nil {
			return err
		}
		newPath := filepath.Join(unprivilegedRootFSPath, relativePath)

		if info.IsDir() {
			if err := os.MkdirAll(newPath, info.Mode()); err != nil {
				return err
			}
			return os.Chown(newPath, uid, uid)
		}

		if info.Mode()&os.ModeSymlink != 0 {
			linkTarget, err := os.Readlink(path)
			if err != nil {
				return err
			}
			if err := os.Symlink(linkTarget, newPath); err != nil {
				return err
			}
			return os.Lchown(newPath, uid, uid)
		}

		if info.Mode()&os.ModeDevice != 0 {
			// Don't bother setting up devices for the container
			return nil
		}

		originalFile, err := os.Open(path)
		if err != nil {
			return err
		}
		defer originalFile.Close()
		newFile, err := os.OpenFile(newPath, os.O_CREATE|os.O_WRONLY, info.Mode())
		if err != nil {
			return err
		}
		defer newFile.Close()
		if _, err := io.Copy(newFile, originalFile); err != nil {
			return err
		}

		return os.Chown(newPath, uid, uid)
	}); err != nil {
		return "", err
	}

	return unprivilegedRootFSPath, nil
}

func mountOverlay(lowerDir, upperDir, workDir, unionDir string) error {
	overlayMountOpts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", lowerDir, upperDir, workDir)
	return syscall.Mount("overlay", unionDir, "overlay", 0, overlayMountOpts)
}

func must(err error) {
	if err != nil {
		panic(err)
	}
}
<commit_msg>remove empty dir /oldrootfs from pivotted-root<commit_after>package main

import (
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"syscall"
)

func main() {
	if os.Args[0] == "/proc/self/exe" {
		inner()
	} else {
		os.Exit(outer())
	}
}

func outer() int {
	rootFS := flag.String("rootFS", "", "rootFS")
	privileged := flag.Bool("privileged", false, "if true, user namespace is not used")
	flag.Parse()
	if *rootFS == "" {
		fmt.Println("must set -rootFS")
		return 1
	}

	cowRootFS, err := ioutil.TempDir("", "container-run")
	must(err)

	mappingSize := 100000
	chownTo := mappingSize
	if *privileged {
		chownTo = 0
	}
	containerRootFSPath, err := createUniqueRootFS(*rootFS, cowRootFS, chownTo)
	must(err)
	defer func() {
		must(syscall.Unmount(containerRootFSPath, 0))
		must(os.RemoveAll(cowRootFS))
	}()

	must(syscall.Mount("", "/", "", syscall.MS_PRIVATE|syscall.MS_REC, "remount"))

	cmd := exec.Command("/proc/self/exe", append([]string{containerRootFSPath}, flag.Args()...)...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	cmd.SysProcAttr = &syscall.SysProcAttr{
		Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWNS | syscall.CLONE_NEWPID,
	}
	if !*privileged {
		cmd.SysProcAttr.Cloneflags = cmd.SysProcAttr.Cloneflags | syscall.CLONE_NEWUSER
		mapping := []syscall.SysProcIDMap{
			{
				ContainerID: 0,
				HostID:      mappingSize,
				Size:        1,
			},
			{
				ContainerID: 1,
				HostID:      1,
				Size:        mappingSize - 1,
			},
		}
		cmd.SysProcAttr.UidMappings = mapping
		cmd.SysProcAttr.GidMappings = mapping
		cmd.SysProcAttr.Credential = &syscall.Credential{Uid: 0, Gid: 0}
	}

	if err := cmd.Run(); err != nil {
		if exitErr, ok := err.(*exec.ExitError); ok {
			return exitErr.Sys().(syscall.WaitStatus).ExitStatus()
		}

		must(err)
	}

	return 0
}

func inner() {
	rootFS := os.Args[1]

	oldRootFS := filepath.Join(rootFS, "oldrootfs")
	must(os.Mkdir(oldRootFS, 0700))
	must(syscall.Mount(rootFS, rootFS, "", syscall.MS_BIND, ""))
	must(syscall.PivotRoot(rootFS, oldRootFS))
	must(os.Chdir("/"))
	must(syscall.Mount("proc", "/proc", "proc", 0, ""))
	must(syscall.Unmount("/oldrootfs", syscall.MNT_DETACH))
	must(os.Remove("/oldrootfs"))

	cmd := exec.Command(os.Args[2], os.Args[3:]...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	if err := cmd.Run(); err != nil {
		if exitErr, ok := err.(*exec.ExitError); ok {
			fmt.Println(err)
			os.Exit(exitErr.Sys().(syscall.WaitStatus).ExitStatus())
		}

		must(err)
	}
}

func createUniqueRootFS(rootFS, cowRootFS string, chownTo int) (string, error) {
	lowerLayer := rootFS
	if chownTo != 0 {
		var err error
		lowerLayer, err = createUnprivilegedRootFS(rootFS, chownTo)
		if err != nil {
			return "", err
		}
	}

	if err := os.Chown(cowRootFS, chownTo, chownTo); err != nil {
		return "", nil
	}

	containerRootFS := filepath.Join(cowRootFS, "union")
	workDir := filepath.Join(cowRootFS, "work")
	upperDir := filepath.Join(cowRootFS, "upper")
	for _, dir := range []string{containerRootFS, workDir, upperDir} {
		if err := os.Mkdir(dir, 0700); err != nil {
			return "", err
		}
		if err := os.Chown(dir, chownTo, chownTo); err != nil {
			return "", nil
		}
	}
	if err := mountOverlay(lowerLayer, upperDir, workDir, containerRootFS); err != nil {
		return "", err
	}
	return containerRootFS, nil
}

func createUnprivilegedRootFS(rootFS string, uid int) (string, error) {
	fssDir := filepath.Dir(rootFS)
	fsName := filepath.Base(rootFS)
	unprivilegedRootFSPath := filepath.Join(fssDir, fsName+"-unprivileged")

	lockPath := filepath.Join(fssDir, fsName+"-chownlock")
	lockFile, err := os.OpenFile(lockPath, os.O_CREATE, 0600)
	if err != nil {
		return "", err
	}
	if err := syscall.Flock(int(lockFile.Fd()), syscall.LOCK_EX); err != nil {
		return "", err
	}
	defer func() {
		syscall.Flock(int(lockFile.Fd()), syscall.LOCK_UN)
		lockFile.Close()
	}()

	if _, err := os.Stat(unprivilegedRootFSPath); err == nil {
		return unprivilegedRootFSPath, nil
	}

	if err := filepath.Walk(rootFS, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		relativePath, err := filepath.Rel(rootFS, path)
		if err != nil {
			return err
		}
		newPath := filepath.Join(unprivilegedRootFSPath, relativePath)

		if info.IsDir() {
			if err := os.MkdirAll(newPath, info.Mode()); err != nil {
				return err
			}
			return os.Chown(newPath, uid, uid)
		}

		if info.Mode()&os.ModeSymlink != 0 {
			linkTarget, err := os.Readlink(path)
			if err != nil {
				return err
			}
			if err := os.Symlink(linkTarget, newPath); err != nil {
				return err
			}
			return os.Lchown(newPath, uid, uid)
		}

		if info.Mode()&os.ModeDevice != 0 {
			// Don't bother setting up devices for the container
			return nil
		}

		originalFile, err := os.Open(path)
		if err != nil {
			return err
		}
		defer originalFile.Close()
		newFile, err := os.OpenFile(newPath, os.O_CREATE|os.O_WRONLY, info.Mode())
		if err != nil {
			return err
		}
		defer newFile.Close()
		if _, err := io.Copy(newFile, originalFile); err != nil {
			return err
		}

		return os.Chown(newPath, uid, uid)
	}); err != nil {
		return "", err
	}

	return unprivilegedRootFSPath, nil
}

func mountOverlay(lowerDir, upperDir, workDir, unionDir string) error {
	overlayMountOpts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", lowerDir, upperDir, workDir)
	return syscall.Mount("overlay", unionDir, "overlay", 0, overlayMountOpts)
}

func must(err error) {
	if err != nil {
		panic(err)
	}
}
<|endoftext|>


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

// +build linux darwin

package interp_test

import (
	"bytes"
	"fmt"
	"go/build"
	"go/types"
	"os"
	"path/filepath"
	"strings"
	"testing"
	"time"

	"golang.org/x/tools/go/loader"
	"golang.org/x/tools/go/ssa"
	"golang.org/x/tools/go/ssa/interp"
	"golang.org/x/tools/go/ssa/ssautil"
)

// Each line contains a space-separated list of $GOROOT/test/
// filenames comprising the main package of a program.
// They are ordered quickest-first, roughly.
//
// TODO(adonovan): integrate into the $GOROOT/test driver scripts,
// golden file checking, etc.
var gorootTestTests = []string{
	"235.go",
	"alias1.go",
	"chancap.go",
	"func5.go",
	"func6.go",
	"func7.go",
	"func8.go",
	"helloworld.go",
	"varinit.go",
	"escape3.go",
	"initcomma.go",
	"cmp.go",
	"compos.go",
	"turing.go",
	"indirect.go",
	"complit.go",
	"for.go",
	"struct0.go",
	"intcvt.go",
	"printbig.go",
	"deferprint.go",
	"escape.go",
	"range.go",
	"const4.go",
	"float_lit.go",
	"bigalg.go",
	"decl.go",
	"if.go",
	"named.go",
	"bigmap.go",
	"func.go",
	"reorder2.go",
	"closure.go",
	"gc.go",
	"simassign.go",
	"iota.go",
	"nilptr2.go",
	"goprint.go", // doesn't actually assert anything (cmpout)
	"utf.go",
	"method.go",
	"char_lit.go",
	"env.go",
	"int_lit.go",
	"string_lit.go",
	"defer.go",
	"typeswitch.go",
	"stringrange.go",
	"reorder.go",
	"method3.go",
	"literal.go",
	"nul1.go", // doesn't actually assert anything (errorcheckoutput)
	"zerodivide.go",
	"convert.go",
	"convT2X.go",
	"switch.go",
	"initialize.go",
	"ddd.go",
	"blank.go", // partly disabled
	"map.go",
	"closedchan.go",
	"divide.go",
	"rename.go",
	"const3.go",
	"nil.go",
	"recover.go", // reflection parts disabled
	"recover1.go",
	"recover2.go",
	"recover3.go",
	"typeswitch1.go",
	"floatcmp.go",
	"crlf.go", // doesn't actually assert anything (runoutput)
	// Slow tests follow.
	"bom.go", // ~1.7s
	"gc1.go", // ~1.7s
	"cmplxdivide.go cmplxdivide1.go", // ~2.4s

	// Working, but not worth enabling:
	// "append.go",    // works, but slow (15s).
	// "gc2.go",       // works, but slow, and cheats on the memory check.
	// "sigchld.go",   // works, but only on POSIX.
	// "peano.go",     // works only up to n=9, and slow even then.
	// "stack.go",     // works, but too slow (~30s) by default.
	// "solitaire.go", // works, but too slow (~30s).
	// "const.go",     // works but for but one bug: constant folder doesn't consider representations.
	// "init1.go",     // too slow (80s) and not that interesting. Cheats on ReadMemStats check too.
	// "rotate.go rotate0.go", // emits source for a test
	// "rotate.go rotate1.go", // emits source for a test
	// "rotate.go rotate2.go", // emits source for a test
	// "rotate.go rotate3.go", // emits source for a test
	// "64bit.go",             // emits source for a test
	// "run.go",               // test driver, not a test.

	// Broken.  TODO(adonovan): fix.
	// copy.go         // very slow; but with N=4 quickly crashes, slice index out of range.
	// nilptr.go       // interp: V > uintptr not implemented. Slow test, lots of mem
	// args.go         // works, but requires specific os.Args from the driver.
	// index.go        // a template, not a real test.
	// mallocfin.go    // SetFinalizer not implemented.

	// TODO(adonovan): add tests from $GOROOT/test/* subtrees:
	// bench chan bugs fixedbugs interface ken.
}

// These are files in go.tools/go/ssa/interp/testdata/.
var testdataTests = []string{
	"boundmeth.go",
	"complit.go",
	"coverage.go",
	"defer.go",
	"fieldprom.go",
	"ifaceconv.go",
	"ifaceprom.go",
	"initorder.go",
	"methprom.go",
	"mrvchain.go",
	"range.go",
	"recover.go",
	"reflect.go",
	"static.go",
	"callstack.go",
}

type successPredicate func(exitcode int, output string) error

func run(t *testing.T, dir, input string, success successPredicate) bool {
	fmt.Printf("Input: %s\n", input)

	start := time.Now()

	var inputs []string
	for _, i := range strings.Split(input, " ") {
		if strings.HasSuffix(i, ".go") {
			i = dir + i
		}
		inputs = append(inputs, i)
	}

	var conf loader.Config
	if _, err := conf.FromArgs(inputs, true); err != nil {
		t.Errorf("FromArgs(%s) failed: %s", inputs, err)
		return false
	}

	conf.Import("runtime")

	// Print a helpful hint if we don't make it to the end.
	var hint string
	defer func() {
		if hint != "" {
			fmt.Println("FAIL")
			fmt.Println(hint)
		} else {
			fmt.Println("PASS")
		}

		interp.CapturedOutput = nil
	}()

	hint = fmt.Sprintf("To dump SSA representation, run:\n%% go build golang.org/x/tools/cmd/ssadump && ./ssadump -test -build=CFP %s\n", input)

	iprog, err := conf.Load()
	if err != nil {
		t.Errorf("conf.Load(%s) failed: %s", inputs, err)
		return false
	}

	prog := ssautil.CreateProgram(iprog, ssa.SanityCheckFunctions)
	prog.Build()

	// Find first main or test package among the initial packages.
	var mainPkg *ssa.Package
	for _, info := range iprog.InitialPackages() {
		if info.Pkg.Path() == "runtime" {
			continue // not an initial package
		}
		p := prog.Package(info.Pkg)
		if p.Pkg.Name() == "main" && p.Func("main") != nil {
			mainPkg = p
			break
		}

		mainPkg = prog.CreateTestMainPackage(p)
		if mainPkg != nil {
			break
		}
	}
	if mainPkg == nil {
		t.Fatalf("no main or test packages among initial packages: %s", inputs)
	}

	var out bytes.Buffer
	interp.CapturedOutput = &out

	hint = fmt.Sprintf("To trace execution, run:\n%% go build golang.org/x/tools/cmd/ssadump && ./ssadump -build=C -test -run --interp=T %s\n", input)
	exitCode := interp.Interpret(mainPkg, 0, &types.StdSizes{WordSize: 8, MaxAlign: 8}, inputs[0], []string{})

	// The definition of success varies with each file.
	if err := success(exitCode, out.String()); err != nil {
		t.Errorf("interp.Interpret(%s) failed: %s", inputs, err)
		return false
	}

	hint = "" // call off the hounds

	if false {
		fmt.Println(input, time.Since(start)) // test profiling
	}

	return true
}

const slash = string(os.PathSeparator)

func printFailures(failures []string) {
	if failures != nil {
		fmt.Println("The following tests failed:")
		for _, f := range failures {
			fmt.Printf("\t%s\n", f)
		}
	}
}

func success(exitcode int, output string) error {
	if exitcode != 0 {
		return fmt.Errorf("exit code was %d", exitcode)
	}
	if strings.Contains(output, "BUG") {
		return fmt.Errorf("exited zero but output contained 'BUG'")
	}
	return nil
}

// TestTestdataFiles runs the interpreter on testdata/*.go.
func TestTestdataFiles(t *testing.T) {
	var failures []string
	start := time.Now()
	for _, input := range testdataTests {
		if testing.Short() && time.Since(start) > 30*time.Second {
			printFailures(failures)
			t.Skipf("timeout - aborting test")
		}
		if !run(t, "testdata"+slash, input, success) {
			failures = append(failures, input)
		}
	}
	printFailures(failures)
}

// TestGorootTest runs the interpreter on $GOROOT/test/*.go.
func TestGorootTest(t *testing.T) {
	if testing.Short() {
		t.Skip() // too slow (~30s)
	}

	var failures []string

	for _, input := range gorootTestTests {
		if !run(t, filepath.Join(build.Default.GOROOT, "test")+slash, input, success) {
			failures = append(failures, input)
		}
	}
	printFailures(failures)
}

// CreateTestMainPackage should return nil if there were no tests.
func TestNullTestmainPackage(t *testing.T) {
	var conf loader.Config
	conf.CreateFromFilenames("", "testdata/b_test.go")
	iprog, err := conf.Load()
	if err != nil {
		t.Fatalf("CreatePackages failed: %s", err)
	}
	prog := ssautil.CreateProgram(iprog, ssa.SanityCheckFunctions)
	mainPkg := prog.Package(iprog.Created[0].Pkg)
	if mainPkg.Func("main") != nil {
		t.Fatalf("unexpected main function")
	}
	if prog.CreateTestMainPackage(mainPkg) != nil {
		t.Fatalf("CreateTestMainPackage returned non-nil")
	}
}
<commit_msg>go/ssa/interp: skip tests on darwin until crashes are fixed<commit_after>// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build linux darwin

package interp_test

import (
	"bytes"
	"fmt"
	"go/build"
	"go/types"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"testing"
	"time"

	"golang.org/x/tools/go/loader"
	"golang.org/x/tools/go/ssa"
	"golang.org/x/tools/go/ssa/interp"
	"golang.org/x/tools/go/ssa/ssautil"
)

// Each line contains a space-separated list of $GOROOT/test/
// filenames comprising the main package of a program.
// They are ordered quickest-first, roughly.
//
// TODO(adonovan): integrate into the $GOROOT/test driver scripts,
// golden file checking, etc.
var gorootTestTests = []string{
	"235.go",
	"alias1.go",
	"chancap.go",
	"func5.go",
	"func6.go",
	"func7.go",
	"func8.go",
	"helloworld.go",
	"varinit.go",
	"escape3.go",
	"initcomma.go",
	"cmp.go",
	"compos.go",
	"turing.go",
	"indirect.go",
	"complit.go",
	"for.go",
	"struct0.go",
	"intcvt.go",
	"printbig.go",
	"deferprint.go",
	"escape.go",
	"range.go",
	"const4.go",
	"float_lit.go",
	"bigalg.go",
	"decl.go",
	"if.go",
	"named.go",
	"bigmap.go",
	"func.go",
	"reorder2.go",
	"closure.go",
	"gc.go",
	"simassign.go",
	"iota.go",
	"nilptr2.go",
	"goprint.go", // doesn't actually assert anything (cmpout)
	"utf.go",
	"method.go",
	"char_lit.go",
	"env.go",
	"int_lit.go",
	"string_lit.go",
	"defer.go",
	"typeswitch.go",
	"stringrange.go",
	"reorder.go",
	"method3.go",
	"literal.go",
	"nul1.go", // doesn't actually assert anything (errorcheckoutput)
	"zerodivide.go",
	"convert.go",
	"convT2X.go",
	"switch.go",
	"initialize.go",
	"ddd.go",
	"blank.go", // partly disabled
	"map.go",
	"closedchan.go",
	"divide.go",
	"rename.go",
	"const3.go",
	"nil.go",
	"recover.go", // reflection parts disabled
	"recover1.go",
	"recover2.go",
	"recover3.go",
	"typeswitch1.go",
	"floatcmp.go",
	"crlf.go", // doesn't actually assert anything (runoutput)
	// Slow tests follow.
	"bom.go", // ~1.7s
	"gc1.go", // ~1.7s
	"cmplxdivide.go cmplxdivide1.go", // ~2.4s

	// Working, but not worth enabling:
	// "append.go",    // works, but slow (15s).
	// "gc2.go",       // works, but slow, and cheats on the memory check.
	// "sigchld.go",   // works, but only on POSIX.
	// "peano.go",     // works only up to n=9, and slow even then.
	// "stack.go",     // works, but too slow (~30s) by default.
	// "solitaire.go", // works, but too slow (~30s).
	// "const.go",     // works but for but one bug: constant folder doesn't consider representations.
	// "init1.go",     // too slow (80s) and not that interesting. Cheats on ReadMemStats check too.
	// "rotate.go rotate0.go", // emits source for a test
	// "rotate.go rotate1.go", // emits source for a test
	// "rotate.go rotate2.go", // emits source for a test
	// "rotate.go rotate3.go", // emits source for a test
	// "64bit.go",             // emits source for a test
	// "run.go",               // test driver, not a test.

	// Broken.  TODO(adonovan): fix.
	// copy.go         // very slow; but with N=4 quickly crashes, slice index out of range.
	// nilptr.go       // interp: V > uintptr not implemented. Slow test, lots of mem
	// args.go         // works, but requires specific os.Args from the driver.
	// index.go        // a template, not a real test.
	// mallocfin.go    // SetFinalizer not implemented.

	// TODO(adonovan): add tests from $GOROOT/test/* subtrees:
	// bench chan bugs fixedbugs interface ken.
}

// These are files in go.tools/go/ssa/interp/testdata/.
var testdataTests = []string{
	"boundmeth.go",
	"complit.go",
	"coverage.go",
	"defer.go",
	"fieldprom.go",
	"ifaceconv.go",
	"ifaceprom.go",
	"initorder.go",
	"methprom.go",
	"mrvchain.go",
	"range.go",
	"recover.go",
	"reflect.go",
	"static.go",
	"callstack.go",
}

type successPredicate func(exitcode int, output string) error

func run(t *testing.T, dir, input string, success successPredicate) bool {
	if runtime.GOOS == "darwin" {
		t.Skip("skipping on darwin until golang.org/issue/23166 is fixed")
	}
	fmt.Printf("Input: %s\n", input)

	start := time.Now()

	var inputs []string
	for _, i := range strings.Split(input, " ") {
		if strings.HasSuffix(i, ".go") {
			i = dir + i
		}
		inputs = append(inputs, i)
	}

	var conf loader.Config
	if _, err := conf.FromArgs(inputs, true); err != nil {
		t.Errorf("FromArgs(%s) failed: %s", inputs, err)
		return false
	}

	conf.Import("runtime")

	// Print a helpful hint if we don't make it to the end.
	var hint string
	defer func() {
		if hint != "" {
			fmt.Println("FAIL")
			fmt.Println(hint)
		} else {
			fmt.Println("PASS")
		}

		interp.CapturedOutput = nil
	}()

	hint = fmt.Sprintf("To dump SSA representation, run:\n%% go build golang.org/x/tools/cmd/ssadump && ./ssadump -test -build=CFP %s\n", input)

	iprog, err := conf.Load()
	if err != nil {
		t.Errorf("conf.Load(%s) failed: %s", inputs, err)
		return false
	}

	prog := ssautil.CreateProgram(iprog, ssa.SanityCheckFunctions)
	prog.Build()

	// Find first main or test package among the initial packages.
	var mainPkg *ssa.Package
	for _, info := range iprog.InitialPackages() {
		if info.Pkg.Path() == "runtime" {
			continue // not an initial package
		}
		p := prog.Package(info.Pkg)
		if p.Pkg.Name() == "main" && p.Func("main") != nil {
			mainPkg = p
			break
		}

		mainPkg = prog.CreateTestMainPackage(p)
		if mainPkg != nil {
			break
		}
	}
	if mainPkg == nil {
		t.Fatalf("no main or test packages among initial packages: %s", inputs)
	}

	var out bytes.Buffer
	interp.CapturedOutput = &out

	hint = fmt.Sprintf("To trace execution, run:\n%% go build golang.org/x/tools/cmd/ssadump && ./ssadump -build=C -test -run --interp=T %s\n", input)
	exitCode := interp.Interpret(mainPkg, 0, &types.StdSizes{WordSize: 8, MaxAlign: 8}, inputs[0], []string{})

	// The definition of success varies with each file.
	if err := success(exitCode, out.String()); err != nil {
		t.Errorf("interp.Interpret(%s) failed: %s", inputs, err)
		return false
	}

	hint = "" // call off the hounds

	if false {
		fmt.Println(input, time.Since(start)) // test profiling
	}

	return true
}

const slash = string(os.PathSeparator)

func printFailures(failures []string) {
	if failures != nil {
		fmt.Println("The following tests failed:")
		for _, f := range failures {
			fmt.Printf("\t%s\n", f)
		}
	}
}

func success(exitcode int, output string) error {
	if exitcode != 0 {
		return fmt.Errorf("exit code was %d", exitcode)
	}
	if strings.Contains(output, "BUG") {
		return fmt.Errorf("exited zero but output contained 'BUG'")
	}
	return nil
}

// TestTestdataFiles runs the interpreter on testdata/*.go.
func TestTestdataFiles(t *testing.T) {
	var failures []string
	start := time.Now()
	for _, input := range testdataTests {
		if testing.Short() && time.Since(start) > 30*time.Second {
			printFailures(failures)
			t.Skipf("timeout - aborting test")
		}
		if !run(t, "testdata"+slash, input, success) {
			failures = append(failures, input)
		}
	}
	printFailures(failures)
}

// TestGorootTest runs the interpreter on $GOROOT/test/*.go.
func TestGorootTest(t *testing.T) {
	if testing.Short() {
		t.Skip() // too slow (~30s)
	}

	var failures []string

	for _, input := range gorootTestTests {
		if !run(t, filepath.Join(build.Default.GOROOT, "test")+slash, input, success) {
			failures = append(failures, input)
		}
	}
	printFailures(failures)
}

// CreateTestMainPackage should return nil if there were no tests.
func TestNullTestmainPackage(t *testing.T) {
	var conf loader.Config
	conf.CreateFromFilenames("", "testdata/b_test.go")
	iprog, err := conf.Load()
	if err != nil {
		t.Fatalf("CreatePackages failed: %s", err)
	}
	prog := ssautil.CreateProgram(iprog, ssa.SanityCheckFunctions)
	mainPkg := prog.Package(iprog.Created[0].Pkg)
	if mainPkg.Func("main") != nil {
		t.Fatalf("unexpected main function")
	}
	if prog.CreateTestMainPackage(mainPkg) != nil {
		t.Fatalf("CreateTestMainPackage returned non-nil")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"unicode"
	"unicode/utf8"
)

func trimmer(arr []byte) []byte {
	seen := false
	for i := 0; i < len(arr); {

		r, size := utf8.DecodeRune(arr[i:])

		if unicode.IsSpace(r) {
			if !seen {
				arr = arr[:i+1+copy(arr[i+1:], arr[i+size:])]
				arr[i] = 0x20
				i++
			} else {
				arr = arr[:i+copy(arr[i:], arr[i+size:])]
			}
			seen = true
		} else {
			seen = false
			i += size
		}
	}
	return arr
}

func main() {
	s := "　　　FIRST　　　　　SECOND　　　"
	fmt.Printf("'%s'\n", s)
	s = string(trimmer([]byte(s)))
	fmt.Printf("'%s'\n", s)
}
<commit_msg>A little obfuscated task 4.6<commit_after>package main

import (
	"fmt"
	"unicode"
	"unicode/utf8"
)

func trimmer(arr []byte) []byte {
	keep := 1 // Keep replaced space or skip as repeated.
	for i := 0; i < len(arr); {
		r, size := utf8.DecodeRune(arr[i:])

		if unicode.IsSpace(r) {
			arr = arr[:i+keep+copy(arr[i+keep:], arr[i+size:])]
			if keep == 1 {
				arr[i] = 0x20
				i++
			}
			keep = 0
		} else {
			keep = 1
			i += size
		}
	}
	return arr
}

func main() {
	s := "　　　FIRST　　　　　SECOND　　　"
	fmt.Printf("'%s'\n", s)
	s = string(trimmer([]byte(s)))
	fmt.Printf("'%s'\n", s)
}
<|endoftext|>