<commit_before>/*
Copyright 2014 The Camlistore Authors

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

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

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

// Package feed implements an importer for RSS, Atom, and RDF feeds.
package feed

import (
	"bytes"
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"strings"
	"sync"

	"camlistore.org/pkg/blob"
	"camlistore.org/pkg/context"
	"camlistore.org/pkg/httputil"
	"camlistore.org/pkg/importer"
	"camlistore.org/pkg/schema"
	"camlistore.org/third_party/code.google.com/p/go.net/html"
	"camlistore.org/third_party/code.google.com/p/go.net/html/atom"
)

const (
	// Permanode attributes on account node:
	acctAttrFeedURL = "feedURL"
)

func init() {
	importer.Register("feed", &imp{
		urlFileRef: make(map[string]blob.Ref),
	})
}

type imp struct {
	mu         sync.Mutex          // guards following
	urlFileRef map[string]blob.Ref // url to file schema blob

	importer.OAuth1 // for CallbackRequestAccount and CallbackURLParameters
}

func (im *imp) NeedsAPIKey() bool { return false }

func (im *imp) IsAccountReady(acctNode *importer.Object) (ok bool, err error) {
	if acctNode.Attr(acctAttrFeedURL) != "" {
		return true, nil
	}
	return false, nil
}

func (im *imp) SummarizeAccount(acct *importer.Object) string {
	ok, err := im.IsAccountReady(acct)
	if err != nil {
		return "Not configured; error = " + err.Error()
	}
	if !ok {
		return "Not configured"
	}
	return fmt.Sprintf("feed %s", acct.Attr(acctAttrFeedURL))
}

// A run is our state for a given run of the importer.
type run struct {
	*importer.RunContext
	im *imp
}

func (im *imp) Run(ctx *importer.RunContext) error {
	r := &run{
		RunContext: ctx,
		im:         im,
	}

	if err := r.importFeed(); err != nil {
		return err
	}
	return nil
}

func (r *run) importFeed() error {
	feedURL, err := url.Parse(r.RunContext.AccountNode().Attr(acctAttrFeedURL))
	if err != nil {
		return err
	}
	body, err := doGet(r.Context, feedURL.String())
	if err != nil {
		return err
	}
	if auto, err := autoDiscover(body); err == nil {
		if autoURL, err := url.Parse(auto); err == nil {
			if autoURL.Scheme == "" {
				autoURL.Scheme = feedURL.Scheme
			}
			if autoURL.Host == "" {
				autoURL.Host = feedURL.Host
			}
			body, err = doGet(r.Context, autoURL.String())
			if err != nil {
				return err
			}
		}
	}
	feed, err := parseFeed(body, feedURL.String())
	if err != nil {
		return err
	}
	itemsNode, err := r.getTopLevelNode("items", "Items")
	if err != nil {
		return err
	}
	for _, item := range feed.Items {
		if err := r.importItem(itemsNode, item); err != nil {
			log.Printf("Feed importer: error importing item %s %v", item.ID, err)
			continue
		}
	}
	return nil
}

func (r *run) importItem(parent *importer.Object, item *item) error {
	itemNode, err := parent.ChildPathObject(item.ID)
	if err != nil {
		return err
	}
	fileRef, err := schema.WriteFileFromReader(r.Host.Target(), "", bytes.NewBufferString(item.Content))
	if err != nil {
		return err
	}
	if err := itemNode.SetAttrs(
		"feedItemId", item.ID,
		"camliNodeType", "feed:item",
		"title", item.Title,
		"link", item.Link,
		"author", item.Author,
		"camliContent", fileRef.String(),
		"feedMediaContentURL", item.MediaContent,
	); err != nil {
		return err
	}
	return nil
}

func (r *run) getTopLevelNode(path string, title string) (*importer.Object, error) {
	childObject, err := r.RootNode().ChildPathObject(path)
	if err != nil {
		return nil, err
	}

	if err := childObject.SetAttr("title", title); err != nil {
		return nil, err
	}
	return childObject, nil
}

// autodiscover takes an HTML document and returns the autodiscovered feed
// URL. Returns an error if there is no such URL.
func autoDiscover(body []byte) (feedURL string, err error) {
	r := bytes.NewReader(body)
	z := html.NewTokenizer(r)
	for {
		if z.Next() == html.ErrorToken {
			break
		}
		t := z.Token()
		switch t.DataAtom {
		case atom.Link:
			if t.Type == html.StartTagToken || t.Type == html.SelfClosingTagToken {
				attrs := make(map[string]string)
				for _, a := range t.Attr {
					attrs[a.Key] = a.Val
				}
				if attrs["rel"] == "alternate" && attrs["href"] != "" &&
					(attrs["type"] == "application/rss+xml" || attrs["type"] == "application/atom+xml") {
					return attrs["href"], nil
				}
			}
		}
	}
	return "", fmt.Errorf("No feed link found")
}

func doGet(ctx *context.Context, url string) ([]byte, error) {
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}
	res, err := ctx.HTTPClient().Do(req)
	if err != nil {
		log.Printf("Error fetching %s: %v", url, err)
		return nil, err
	}
	defer httputil.CloseBody(res.Body)
	if res.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("Get request on %s failed with: %s", url, res.Status)
	}
	return ioutil.ReadAll(io.LimitReader(res.Body, 8<<20))
}

// urlFileRef slurps urlstr from the net, writes to a file and returns its
// fileref or "" on error
func (r *run) urlFileRef(urlstr string) string {
	if urlstr == "" {
		return ""
	}
	im := r.im
	im.mu.Lock()
	if br, ok := im.urlFileRef[urlstr]; ok {
		im.mu.Unlock()
		return br.String()
	}
	im.mu.Unlock()

	res, err := r.Host.HTTPClient().Get(urlstr)
	if err != nil {
		log.Printf("couldn't get file: %v", err)
		return ""
	}
	defer res.Body.Close()

	filename := urlstr[strings.LastIndex(urlstr, "/")+1:]
	fileRef, err := schema.WriteFileFromReader(r.Host.Target(), filename, res.Body)
	if err != nil {
		log.Printf("couldn't write file: %v", err)
		return ""
	}

	im.mu.Lock()
	defer im.mu.Unlock()
	im.urlFileRef[urlstr] = fileRef
	return fileRef.String()
}

func (im *imp) ServeSetup(w http.ResponseWriter, r *http.Request, ctx *importer.SetupContext) error {
	return tmpl.ExecuteTemplate(w, "serveSetup", ctx)
}

var tmpl = template.Must(template.New("root").Parse(`
{{define "serveSetup"}}

Configuring Feed

<form method="get" action="{{.CallbackURL}}">
  <input type="hidden" name="acct" value="{{.AccountNode.PermanodeRef}}">

Feed URL	<input name="feedURL" size=50>

	<input type="submit" value="Add">

</form>
{{end}}
`))

func (im *imp) ServeCallback(w http.ResponseWriter, r *http.Request, ctx *importer.SetupContext) {
	u := r.FormValue("feedURL")
	if u == "" {
		http.Error(w, "Expected a feed URL", 400)
		return
	}
	feed, err := url.Parse(u)
	if err != nil {
		httputil.ServeError(w, r, err)
		return
	}
	if feed.Scheme == "" {
		feed.Scheme = "http"
	}
	if err := ctx.AccountNode.SetAttrs(
		acctAttrFeedURL, feed.String(),
	); err != nil {
		httputil.ServeError(w, r, fmt.Errorf("Error setting attribute: %v", err))
		return
	}
	http.Redirect(w, r, ctx.AccountURL(), http.StatusFound)
}
<commit_msg>feed importer: meaningful names for permanodes<commit_after>/*
Copyright 2014 The Camlistore Authors

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

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

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

// Package feed implements an importer for RSS, Atom, and RDF feeds.
package feed

import (
	"bytes"
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"strings"
	"sync"

	"camlistore.org/pkg/blob"
	"camlistore.org/pkg/context"
	"camlistore.org/pkg/httputil"
	"camlistore.org/pkg/importer"
	"camlistore.org/pkg/schema"
	"camlistore.org/third_party/code.google.com/p/go.net/html"
	"camlistore.org/third_party/code.google.com/p/go.net/html/atom"
)

const (
	// Permanode attributes on account node:
	acctAttrFeedURL = "feedURL"
)

func init() {
	importer.Register("feed", &imp{
		urlFileRef: make(map[string]blob.Ref),
	})
}

type imp struct {
	mu         sync.Mutex          // guards following
	urlFileRef map[string]blob.Ref // url to file schema blob

	importer.OAuth1 // for CallbackRequestAccount and CallbackURLParameters
}

func (im *imp) NeedsAPIKey() bool { return false }

func (im *imp) IsAccountReady(acctNode *importer.Object) (ok bool, err error) {
	if acctNode.Attr(acctAttrFeedURL) != "" {
		return true, nil
	}
	return false, nil
}

func (im *imp) SummarizeAccount(acct *importer.Object) string {
	ok, err := im.IsAccountReady(acct)
	if err != nil {
		return "Not configured; error = " + err.Error()
	}
	if !ok {
		return "Not configured"
	}
	return fmt.Sprintf("feed %s", acct.Attr(acctAttrFeedURL))
}

// A run is our state for a given run of the importer.
type run struct {
	*importer.RunContext
	im *imp
}

func (im *imp) Run(ctx *importer.RunContext) error {
	r := &run{
		RunContext: ctx,
		im:         im,
	}

	if err := r.importFeed(); err != nil {
		return err
	}
	return nil
}

func (r *run) importFeed() error {
	accountNode := r.RunContext.AccountNode()
	feedURL, err := url.Parse(accountNode.Attr(acctAttrFeedURL))
	if err != nil {
		return err
	}
	body, err := doGet(r.Context, feedURL.String())
	if err != nil {
		return err
	}
	if auto, err := autoDiscover(body); err == nil {
		if autoURL, err := url.Parse(auto); err == nil {
			if autoURL.Scheme == "" {
				autoURL.Scheme = feedURL.Scheme
			}
			if autoURL.Host == "" {
				autoURL.Host = feedURL.Host
			}
			body, err = doGet(r.Context, autoURL.String())
			if err != nil {
				return err
			}
		}
	}
	feed, err := parseFeed(body, feedURL.String())
	if err != nil {
		return err
	}
	itemsNode := r.RootNode()
	if accountNode.Attr("title") == "" {
		accountNode.SetAttr("title", fmt.Sprintf("%s Feed", feed.Title))
	}
	if itemsNode.Attr("title") == "" {
		itemsNode.SetAttr("title", fmt.Sprintf("%s Items", feed.Title))
	}
	for _, item := range feed.Items {
		if err := r.importItem(itemsNode, item); err != nil {
			log.Printf("Feed importer: error importing item %s %v", item.ID, err)
			continue
		}
	}
	return nil
}

func (r *run) importItem(parent *importer.Object, item *item) error {
	itemNode, err := parent.ChildPathObject(item.ID)
	if err != nil {
		return err
	}
	fileRef, err := schema.WriteFileFromReader(r.Host.Target(), "", bytes.NewBufferString(item.Content))
	if err != nil {
		return err
	}
	if err := itemNode.SetAttrs(
		"feedItemId", item.ID,
		"camliNodeType", "feed:item",
		"title", item.Title,
		"link", item.Link,
		"author", item.Author,
		"camliContent", fileRef.String(),
		"feedMediaContentURL", item.MediaContent,
	); err != nil {
		return err
	}
	return nil
}

// autodiscover takes an HTML document and returns the autodiscovered feed
// URL. Returns an error if there is no such URL.
func autoDiscover(body []byte) (feedURL string, err error) {
	r := bytes.NewReader(body)
	z := html.NewTokenizer(r)
	for {
		if z.Next() == html.ErrorToken {
			break
		}
		t := z.Token()
		switch t.DataAtom {
		case atom.Link:
			if t.Type == html.StartTagToken || t.Type == html.SelfClosingTagToken {
				attrs := make(map[string]string)
				for _, a := range t.Attr {
					attrs[a.Key] = a.Val
				}
				if attrs["rel"] == "alternate" && attrs["href"] != "" &&
					(attrs["type"] == "application/rss+xml" || attrs["type"] == "application/atom+xml") {
					return attrs["href"], nil
				}
			}
		}
	}
	return "", fmt.Errorf("No feed link found")
}

func doGet(ctx *context.Context, url string) ([]byte, error) {
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}
	res, err := ctx.HTTPClient().Do(req)
	if err != nil {
		log.Printf("Error fetching %s: %v", url, err)
		return nil, err
	}
	defer httputil.CloseBody(res.Body)
	if res.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("Get request on %s failed with: %s", url, res.Status)
	}
	return ioutil.ReadAll(io.LimitReader(res.Body, 8<<20))
}

// urlFileRef slurps urlstr from the net, writes to a file and returns its
// fileref or "" on error
func (r *run) urlFileRef(urlstr string) string {
	if urlstr == "" {
		return ""
	}
	im := r.im
	im.mu.Lock()
	if br, ok := im.urlFileRef[urlstr]; ok {
		im.mu.Unlock()
		return br.String()
	}
	im.mu.Unlock()

	res, err := r.Host.HTTPClient().Get(urlstr)
	if err != nil {
		log.Printf("couldn't get file: %v", err)
		return ""
	}
	defer res.Body.Close()

	filename := urlstr[strings.LastIndex(urlstr, "/")+1:]
	fileRef, err := schema.WriteFileFromReader(r.Host.Target(), filename, res.Body)
	if err != nil {
		log.Printf("couldn't write file: %v", err)
		return ""
	}

	im.mu.Lock()
	defer im.mu.Unlock()
	im.urlFileRef[urlstr] = fileRef
	return fileRef.String()
}

func (im *imp) ServeSetup(w http.ResponseWriter, r *http.Request, ctx *importer.SetupContext) error {
	return tmpl.ExecuteTemplate(w, "serveSetup", ctx)
}

var tmpl = template.Must(template.New("root").Parse(`
{{define "serveSetup"}}

Configuring Feed

<form method="get" action="{{.CallbackURL}}">
  <input type="hidden" name="acct" value="{{.AccountNode.PermanodeRef}}">

Feed URL	<input name="feedURL" size=50>

	<input type="submit" value="Add">

</form>
{{end}}
`))

func (im *imp) ServeCallback(w http.ResponseWriter, r *http.Request, ctx *importer.SetupContext) {
	u := r.FormValue("feedURL")
	if u == "" {
		http.Error(w, "Expected a feed URL", 400)
		return
	}
	feed, err := url.Parse(u)
	if err != nil {
		httputil.ServeError(w, r, err)
		return
	}
	if feed.Scheme == "" {
		feed.Scheme = "http"
	}
	if err := ctx.AccountNode.SetAttrs(
		acctAttrFeedURL, feed.String(),
	); err != nil {
		httputil.ServeError(w, r, fmt.Errorf("Error setting attribute: %v", err))
		return
	}
	http.Redirect(w, r, ctx.AccountURL(), http.StatusFound)
}
<|endoftext|>


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

import (
	"fmt"
	"io"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl"
	"github.com/spf13/cobra"
)

func (f *Factory) NewCmdCreate(out io.Writer) *cobra.Command {
	cmd := &cobra.Command{
		Use:   "create -f filename",
		Short: "Create a resource by filename or stdin",
		Long: `Create a resource by filename or stdin.

JSON and YAML formats are accepted.

Examples:
  $ kubectl create -f pod.json
  <create a pod using the data in pod.json>

  $ cat pod.json | kubectl create -f -
  <create a pod based on the json passed into stdin>`,
		Run: func(cmd *cobra.Command, args []string) {
			filename := getFlagString(cmd, "filename")
			if len(filename) == 0 {
				usageError(cmd, "Must specify filename to create")
			}
			mapping, namespace, name, data := ResourceFromFile(filename, f.Typer, f.Mapper)
			client, err := f.Client(cmd, mapping)
			checkErr(err)

			err = kubectl.NewRESTHelper(client, mapping).Create(namespace, true, data)
			checkErr(err)
			fmt.Fprintf(out, "%s\n", name)
		},
	}
	cmd.Flags().StringP("filename", "f", "", "Filename or URL to file to use to create the resource")
	return cmd
}
<commit_msg>Check namespace on create of objects like update<commit_after>/*
Copyright 2014 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 cmd

import (
	"fmt"
	"io"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl"
	"github.com/spf13/cobra"
)

func (f *Factory) NewCmdCreate(out io.Writer) *cobra.Command {
	cmd := &cobra.Command{
		Use:   "create -f filename",
		Short: "Create a resource by filename or stdin",
		Long: `Create a resource by filename or stdin.

JSON and YAML formats are accepted.

Examples:
  $ kubectl create -f pod.json
  <create a pod using the data in pod.json>

  $ cat pod.json | kubectl create -f -
  <create a pod based on the json passed into stdin>`,
		Run: func(cmd *cobra.Command, args []string) {
			filename := getFlagString(cmd, "filename")
			if len(filename) == 0 {
				usageError(cmd, "Must specify filename to create")
			}
			mapping, namespace, name, data := ResourceFromFile(filename, f.Typer, f.Mapper)
			client, err := f.Client(cmd, mapping)
			checkErr(err)

			// use the default namespace if not specified, or check for conflict with the file's namespace
			if len(namespace) == 0 {
				namespace = getKubeNamespace(cmd)
			} else {
				err = CompareNamespaceFromFile(cmd, namespace)
				checkErr(err)
			}

			err = kubectl.NewRESTHelper(client, mapping).Create(namespace, true, data)
			checkErr(err)
			fmt.Fprintf(out, "%s\n", name)
		},
	}
	cmd.Flags().StringP("filename", "f", "", "Filename or URL to file to use to create the resource")
	return cmd
}
<|endoftext|>


<commit_before>/*
Copyright 2015 The Kubernetes Authors All rights reserved.

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

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

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

package tcp

import (
	"net"
	"net/http"
	"net/http/httptest"
	"net/url"
	"strconv"
	"strings"
	"testing"
	"time"

	"k8s.io/kubernetes/pkg/probe"
)

func containsAny(s string, substrs []string) bool {
	for _, substr := range substrs {
		if strings.Contains(s, substr) {
			return true
		}
	}
	return false
}

func TestTcpHealthChecker(t *testing.T) {
	prober := New()
	tests := []struct {
		expectedStatus probe.Result
		usePort        bool
		expectError    bool
		// Some errors are different depending on your system, make
		// the test pass on all of them
		accOutputs []string
	}{
		// The probe will be filled in below.  This is primarily testing that a connection is made.
		{probe.Success, true, false, []string{""}},
		{probe.Failure, false, false, []string{"unknown port", "Servname not supported for ai_socktype"}},
	}

	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
	}))
	defer server.Close()
	u, err := url.Parse(server.URL)
	if err != nil {
		t.Errorf("Unexpected error: %v", err)
	}
	host, port, err := net.SplitHostPort(u.Host)
	if err != nil {
		t.Errorf("Unexpected error: %v", err)
	}
	for _, test := range tests {
		p, err := strconv.Atoi(port)
		if err != nil {
			t.Errorf("unexpected error: %v", err)
		}
		if !test.usePort {
			p = -1
		}
		status, output, err := prober.Probe(host, p, 1*time.Second)
		if status != test.expectedStatus {
			t.Errorf("expected: %v, got: %v", test.expectedStatus, status)
		}
		if err != nil && !test.expectError {
			t.Errorf("unexpected error: %v", err)
		}
		if err == nil && test.expectError {
			t.Errorf("unexpected non-error.")
		}
		if !containsAny(output, test.accOutputs) {
			t.Errorf("expected one of %#v, got %s", test.accOutputs, output)
		}
	}
}
<commit_msg>testing: fix TCP health checker failure on Mac<commit_after>/*
Copyright 2015 The Kubernetes Authors All rights reserved.

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

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

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

package tcp

import (
	"net"
	"net/http"
	"net/http/httptest"
	"net/url"
	"strconv"
	"strings"
	"testing"
	"time"

	"k8s.io/kubernetes/pkg/probe"
)

func containsAny(s string, substrs []string) bool {
	for _, substr := range substrs {
		if strings.Contains(s, substr) {
			return true
		}
	}
	return false
}

func TestTcpHealthChecker(t *testing.T) {
	prober := New()
	tests := []struct {
		expectedStatus probe.Result
		usePort        bool
		expectError    bool
		// Some errors are different depending on your system, make
		// the test pass on all of them
		accOutputs []string
	}{
		// The probe will be filled in below.  This is primarily testing that a connection is made.
		{probe.Success, true, false, []string{""}},
		{probe.Failure, false, false, []string{"unknown port", "Servname not supported for ai_socktype", "nodename nor servname provided, or not known"}},
	}

	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
	}))
	defer server.Close()
	u, err := url.Parse(server.URL)
	if err != nil {
		t.Errorf("Unexpected error: %v", err)
	}
	host, port, err := net.SplitHostPort(u.Host)
	if err != nil {
		t.Errorf("Unexpected error: %v", err)
	}
	for _, test := range tests {
		p, err := strconv.Atoi(port)
		if err != nil {
			t.Errorf("unexpected error: %v", err)
		}
		if !test.usePort {
			p = -1
		}
		status, output, err := prober.Probe(host, p, 1*time.Second)
		if status != test.expectedStatus {
			t.Errorf("expected: %v, got: %v", test.expectedStatus, status)
		}
		if err != nil && !test.expectError {
			t.Errorf("unexpected error: %v", err)
		}
		if err == nil && test.expectError {
			t.Errorf("unexpected non-error.")
		}
		if !containsAny(output, test.accOutputs) {
			t.Errorf("expected one of %#v, got %s", test.accOutputs, output)
		}
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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

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

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

package repo

import (
	"github.com/kubernetes/helm/pkg/chart"

	"os"
	"reflect"
	"regexp"
	"testing"
)

var (
	TestArchiveURL         = os.Getenv("TEST_ARCHIVE_URL")
	TestChartName          = "frobnitz"
	TestChartVersion       = "0.0.1"
	TestArchiveName        = TestChartName + "-" + TestChartVersion + ".tgz"
	TestChartFile          = "testdata/frobnitz/Chart.yaml"
	TestShouldFindRegex    = regexp.MustCompile(TestArchiveName)
	TestShouldNotFindRegex = regexp.MustCompile("foobar")
	TestName               = "bucket-name"
)

func TestValidGSURL(t *testing.T) {
	tr := getTestRepo(t)
	err := validateRepo(tr, TestRepoURL, TestRepoCredentialName, TestRepoFormat, TestRepoType)
	if err != nil {
		t.Fatal(err)
	}

	wantBucket := TestRepoBucket
	haveBucket := tr.GetBucket()
	if haveBucket != wantBucket {
		t.Fatalf("unexpected bucket; want: %s, have %s.", wantBucket, haveBucket)
	}
}

func TestInvalidGSURL(t *testing.T) {
	var invalidGSURL = "https://valid.url/wrong/scheme"
	_, err := NewGCSRepo(invalidGSURL, TestRepoCredentialName, TestName, nil)
	if err == nil {
		t.Fatalf("expected error did not occur for invalid GS URL")
	}
}

func TestListCharts(t *testing.T) {
	tr := getTestRepo(t)
	charts, err := tr.ListCharts(nil)
	if err != nil {
		t.Fatal(err)
	}

	if len(charts) != 1 {
		t.Fatalf("expected one chart in list, got %d", len(charts))
	}

	haveName := charts[0]
	wantName := TestArchiveName
	if haveName != wantName {
		t.Fatalf("expected chart named %s, got %s", wantName, haveName)
	}
}

func TestListChartsWithShouldFindRegex(t *testing.T) {
	tr := getTestRepo(t)
	charts, err := tr.ListCharts(TestShouldFindRegex)
	if err != nil {
		t.Fatal(err)
	}

	if len(charts) != 1 {
		t.Fatalf("expected one chart to match regex, got %d", len(charts))
	}
}

func TestListChartsWithShouldNotFindRegex(t *testing.T) {
	tr := getTestRepo(t)
	charts, err := tr.ListCharts(TestShouldNotFindRegex)
	if err != nil {
		t.Fatal(err)
	}

	if len(charts) != 0 {
		t.Fatalf("expected zero charts to match regex, got %d", len(charts))
	}
}

func TestGetChart(t *testing.T) {
	tr := getTestRepo(t)
	tc, err := tr.GetChart(TestArchiveName)
	if err != nil {
		t.Fatal(err)
	}

	haveFile := tc.Chartfile()
	wantFile, err := chart.LoadChartfile(TestChartFile)
	if err != nil {
		t.Fatal(err)
	}

	if !reflect.DeepEqual(wantFile, haveFile) {
		t.Fatalf("retrieved invalid chart\nwant:%#v\nhave:\n%#v\n", wantFile, haveFile)
	}
}

func TestGetChartWithInvalidName(t *testing.T) {
	tr := getTestRepo(t)
	_, err := tr.GetChart("NotAValidArchiveName")
	if err == nil {
		t.Fatalf("found chart using invalid archive name")
	}
}

func getTestRepo(t *testing.T) IStorageRepo {
	tr, err := NewGCSRepo(TestRepoURL, TestRepoCredentialName, TestName, nil)
	if err != nil {
		t.Fatal(err)
	}

	return tr
}
<commit_msg>Correct invalid assumption about test repository<commit_after>/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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

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

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

package repo

import (
	"github.com/kubernetes/helm/pkg/chart"

	"os"
	"reflect"
	"regexp"
	"testing"
)

var (
	TestArchiveURL         = os.Getenv("TEST_ARCHIVE_URL")
	TestChartName          = "frobnitz"
	TestChartVersion       = "0.0.1"
	TestArchiveName        = TestChartName + "-" + TestChartVersion + ".tgz"
	TestChartFile          = "testdata/frobnitz/Chart.yaml"
	TestShouldFindRegex    = regexp.MustCompile(TestArchiveName)
	TestShouldNotFindRegex = regexp.MustCompile("foobar")
	TestName               = "bucket-name"
)

func TestValidGSURL(t *testing.T) {
	tr := getTestRepo(t)
	err := validateRepo(tr, TestRepoURL, TestRepoCredentialName, TestRepoFormat, TestRepoType)
	if err != nil {
		t.Fatal(err)
	}

	wantBucket := TestRepoBucket
	haveBucket := tr.GetBucket()
	if haveBucket != wantBucket {
		t.Fatalf("unexpected bucket; want: %s, have %s.", wantBucket, haveBucket)
	}
}

func TestInvalidGSURL(t *testing.T) {
	var invalidGSURL = "https://valid.url/wrong/scheme"
	_, err := NewGCSRepo(invalidGSURL, TestRepoCredentialName, TestName, nil)
	if err == nil {
		t.Fatalf("expected error did not occur for invalid GS URL")
	}
}

func TestListCharts(t *testing.T) {
	tr := getTestRepo(t)
	charts, err := tr.ListCharts(nil)
	if err != nil {
		t.Fatal(err)
	}

	if len(charts) < 1 {
		t.Fatalf("expected at least one chart in test repository %s", TestRepoURL)
	}

	for _, ch := range charts {
		if ch == TestArchiveName {
			return
		}
	}

	t.Fatalf("expected chart named %s in test repository %s", TestArchiveName, TestRepoURL)
}

func TestListChartsWithShouldFindRegex(t *testing.T) {
	tr := getTestRepo(t)
	charts, err := tr.ListCharts(TestShouldFindRegex)
	if err != nil {
		t.Fatal(err)
	}

	if len(charts) != 1 {
		t.Fatalf("expected one chart to match regex, got %d", len(charts))
	}
}

func TestListChartsWithShouldNotFindRegex(t *testing.T) {
	tr := getTestRepo(t)
	charts, err := tr.ListCharts(TestShouldNotFindRegex)
	if err != nil {
		t.Fatal(err)
	}

	if len(charts) != 0 {
		t.Fatalf("expected zero charts to match regex, got %d", len(charts))
	}
}

func TestGetChart(t *testing.T) {
	tr := getTestRepo(t)
	tc, err := tr.GetChart(TestArchiveName)
	if err != nil {
		t.Fatal(err)
	}

	haveFile := tc.Chartfile()
	wantFile, err := chart.LoadChartfile(TestChartFile)
	if err != nil {
		t.Fatal(err)
	}

	if !reflect.DeepEqual(wantFile, haveFile) {
		t.Fatalf("retrieved invalid chart\nwant:%#v\nhave:\n%#v\n", wantFile, haveFile)
	}
}

func TestGetChartWithInvalidName(t *testing.T) {
	tr := getTestRepo(t)
	_, err := tr.GetChart("NotAValidArchiveName")
	if err == nil {
		t.Fatalf("found chart using invalid archive name")
	}
}

func getTestRepo(t *testing.T) IStorageRepo {
	tr, err := NewGCSRepo(TestRepoURL, TestRepoCredentialName, TestName, nil)
	if err != nil {
		t.Fatal(err)
	}

	return tr
}
<|endoftext|>


<commit_before>package plugin

import (
	"fmt"
	"net"
	"strings"
	"time"

	log "github.com/golang/glog"

	kapi "k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/types"
	utilruntime "k8s.io/kubernetes/pkg/util/runtime"
	utilwait "k8s.io/kubernetes/pkg/util/wait"
	"k8s.io/kubernetes/pkg/watch"

	osapi "github.com/openshift/origin/pkg/sdn/api"
	"github.com/openshift/origin/pkg/util/netutils"
)

func (master *OsdnMaster) SubnetStartMaster(clusterNetwork *net.IPNet, hostSubnetLength uint32) error {
	subrange := make([]string, 0)
	subnets, err := master.registry.GetSubnets()
	if err != nil {
		log.Errorf("Error in initializing/fetching subnets: %v", err)
		return err
	}
	for _, sub := range subnets {
		subrange = append(subrange, sub.Subnet)
		if err = master.registry.ValidateNodeIP(sub.HostIP); err != nil {
			// Don't error out; just warn so the error can be corrected with 'oc'
			log.Errorf("Failed to validate HostSubnet %s: %v", hostSubnetToString(&sub), err)
		} else {
			log.Infof("Found existing HostSubnet %s", hostSubnetToString(&sub))
		}
	}

	master.subnetAllocator, err = netutils.NewSubnetAllocator(clusterNetwork.String(), hostSubnetLength, subrange)
	if err != nil {
		return err
	}

	go utilwait.Forever(master.watchNodes, 0)
	return nil
}

func (master *OsdnMaster) addNode(nodeName string, nodeIP string) error {
	// Validate node IP before proceeding
	if err := master.registry.ValidateNodeIP(nodeIP); err != nil {
		return err
	}

	// Check if subnet needs to be created or updated
	sub, err := master.registry.GetSubnet(nodeName)
	if err == nil {
		if sub.HostIP == nodeIP {
			return nil
		} else {
			// Node IP changed, update old subnet
			sub.HostIP = nodeIP
			sub, err = master.registry.UpdateSubnet(sub)
			if err != nil {
				return fmt.Errorf("Error updating subnet %s for node %s: %v", sub.Subnet, nodeName, err)
			}
			log.Infof("Updated HostSubnet %s", hostSubnetToString(sub))
			return nil
		}
	}

	// Create new subnet
	sn, err := master.subnetAllocator.GetNetwork()
	if err != nil {
		return fmt.Errorf("Error allocating network for node %s: %v", nodeName, err)
	}

	sub, err = master.registry.CreateSubnet(nodeName, nodeIP, sn.String())
	if err != nil {
		master.subnetAllocator.ReleaseNetwork(sn)
		return fmt.Errorf("Error creating subnet %s for node %s: %v", sn.String(), nodeName, err)
	}
	log.Infof("Created HostSubnet %s", hostSubnetToString(sub))
	return nil
}

func (master *OsdnMaster) deleteNode(nodeName string) error {
	sub, err := master.registry.GetSubnet(nodeName)
	if err != nil {
		return fmt.Errorf("Error fetching subnet for node %q for deletion: %v", nodeName, err)
	}
	_, ipnet, err := net.ParseCIDR(sub.Subnet)
	if err != nil {
		return fmt.Errorf("Error parsing subnet %q for node %q for deletion: %v", sub.Subnet, nodeName, err)
	}
	master.subnetAllocator.ReleaseNetwork(ipnet)
	err = master.registry.DeleteSubnet(nodeName)
	if err != nil {
		return fmt.Errorf("Error deleting subnet %v for node %q: %v", sub, nodeName, err)
	}

	log.Infof("Deleted HostSubnet %s", hostSubnetToString(sub))
	return nil
}

func getNodeIP(node *kapi.Node) (string, error) {
	if len(node.Status.Addresses) > 0 && node.Status.Addresses[0].Address != "" {
		return node.Status.Addresses[0].Address, nil
	} else {
		return netutils.GetNodeIP(node.Name)
	}
}

func (master *OsdnMaster) watchNodes() {
	eventQueue := master.registry.RunEventQueue(Nodes)
	nodeAddressMap := map[types.UID]string{}

	for {
		eventType, obj, err := eventQueue.Pop()
		if err != nil {
			utilruntime.HandleError(fmt.Errorf("EventQueue failed for nodes: %v", err))
			return
		}
		node := obj.(*kapi.Node)
		name := node.ObjectMeta.Name
		uid := node.ObjectMeta.UID

		nodeIP, err := getNodeIP(node)
		if err != nil {
			log.Errorf("Failed to get node IP for %s, skipping event: %v, node: %v", name, eventType, node)
			continue
		}

		switch eventType {
		case watch.Added, watch.Modified:
			if oldNodeIP, ok := nodeAddressMap[uid]; ok && (oldNodeIP == nodeIP) {
				continue
			}
			// Node status is frequently updated by kubelet, so log only if the above condition is not met
			log.V(5).Infof("Watch %s event for Node %q", strings.Title(string(eventType)), name)

			err = master.addNode(name, nodeIP)
			if err != nil {
				log.Errorf("Error creating subnet for node %s, ip %s: %v", name, nodeIP, err)
				continue
			}
			nodeAddressMap[uid] = nodeIP
		case watch.Deleted:
			log.V(5).Infof("Watch %s event for Node %q", strings.Title(string(eventType)), name)
			delete(nodeAddressMap, uid)

			err = master.deleteNode(name)
			if err != nil {
				log.Errorf("Error deleting node %s: %v", name, err)
			}
		}
	}
}

func (node *OsdnNode) SubnetStartNode(mtu uint32) (bool, error) {
	err := node.initSelfSubnet()
	if err != nil {
		return false, err
	}

	// Assume we are working with IPv4
	ni, err := node.registry.GetNetworkInfo()
	if err != nil {
		return false, err
	}
	networkChanged, err := node.SetupSDN(node.localSubnet.Subnet, ni.ClusterNetwork.String(), ni.ServiceNetwork.String(), mtu)
	if err != nil {
		return false, err
	}

	go utilwait.Forever(node.watchSubnets, 0)
	return networkChanged, nil
}

func (node *OsdnNode) initSelfSubnet() error {
	// timeout: 30 secs
	retries := 60
	retryInterval := 500 * time.Millisecond

	var err error
	var subnet *osapi.HostSubnet
	// Try every retryInterval and bail-out if it exceeds max retries
	for i := 0; i < retries; i++ {
		// Get subnet for current node
		subnet, err = node.registry.GetSubnet(node.hostName)
		if err == nil {
			break
		}
		log.Warningf("Could not find an allocated subnet for node: %s, Waiting...", node.hostName)
		time.Sleep(retryInterval)
	}
	if err != nil {
		return fmt.Errorf("Failed to get subnet for this host: %s, error: %v", node.hostName, err)
	}

	if err = node.registry.ValidateNodeIP(subnet.HostIP); err != nil {
		return fmt.Errorf("Failed to validate own HostSubnet: %v", err)
	}

	log.Infof("Found local HostSubnet %s", hostSubnetToString(subnet))
	node.localSubnet = subnet
	return nil
}

// Only run on the nodes
func (node *OsdnNode) watchSubnets() {
	subnets := make(map[string]*osapi.HostSubnet)
	eventQueue := node.registry.RunEventQueue(HostSubnets)

	for {
		eventType, obj, err := eventQueue.Pop()
		if err != nil {
			utilruntime.HandleError(fmt.Errorf("EventQueue failed for subnets: %v", err))
			return
		}
		hs := obj.(*osapi.HostSubnet)

		if hs.HostIP == node.localIP {
			continue
		}

		log.V(5).Infof("Watch %s event for HostSubnet %q", strings.Title(string(eventType)), hs.ObjectMeta.Name)
		switch eventType {
		case watch.Added, watch.Modified:
			oldSubnet, exists := subnets[string(hs.UID)]
			if exists {
				if oldSubnet.HostIP == hs.HostIP {
					continue
				} else {
					// Delete old subnet rules
					if err = node.DeleteHostSubnetRules(oldSubnet); err != nil {
						log.Error(err)
					}
				}
			}
			if err = node.registry.ValidateNodeIP(hs.HostIP); err != nil {
				log.Errorf("Ignoring invalid subnet for node %s: %v", hs.HostIP, err)
				continue
			}

			if err = node.AddHostSubnetRules(hs); err != nil {
				log.Error(err)
				continue
			}
			subnets[string(hs.UID)] = hs
		case watch.Deleted:
			delete(subnets, string(hs.UID))

			if err = node.DeleteHostSubnetRules(hs); err != nil {
				log.Error(err)
			}
		}
	}
}
<commit_msg>sdn: clear kubelet-created initial NetworkUnavailable condition on GCE<commit_after>package plugin

import (
	"fmt"
	"net"
	"strings"
	"time"

	log "github.com/golang/glog"

	kapi "k8s.io/kubernetes/pkg/api"
	kapiunversioned "k8s.io/kubernetes/pkg/api/unversioned"
	kclient "k8s.io/kubernetes/pkg/client/unversioned"
	"k8s.io/kubernetes/pkg/types"
	utilruntime "k8s.io/kubernetes/pkg/util/runtime"
	utilwait "k8s.io/kubernetes/pkg/util/wait"
	"k8s.io/kubernetes/pkg/watch"

	osapi "github.com/openshift/origin/pkg/sdn/api"
	"github.com/openshift/origin/pkg/util/netutils"
)

func (master *OsdnMaster) SubnetStartMaster(clusterNetwork *net.IPNet, hostSubnetLength uint32) error {
	subrange := make([]string, 0)
	subnets, err := master.registry.GetSubnets()
	if err != nil {
		log.Errorf("Error in initializing/fetching subnets: %v", err)
		return err
	}
	for _, sub := range subnets {
		subrange = append(subrange, sub.Subnet)
		if err = master.registry.ValidateNodeIP(sub.HostIP); err != nil {
			// Don't error out; just warn so the error can be corrected with 'oc'
			log.Errorf("Failed to validate HostSubnet %s: %v", hostSubnetToString(&sub), err)
		} else {
			log.Infof("Found existing HostSubnet %s", hostSubnetToString(&sub))
		}
	}

	master.subnetAllocator, err = netutils.NewSubnetAllocator(clusterNetwork.String(), hostSubnetLength, subrange)
	if err != nil {
		return err
	}

	go utilwait.Forever(master.watchNodes, 0)
	return nil
}

func (master *OsdnMaster) addNode(nodeName string, nodeIP string) error {
	// Validate node IP before proceeding
	if err := master.registry.ValidateNodeIP(nodeIP); err != nil {
		return err
	}

	// Check if subnet needs to be created or updated
	sub, err := master.registry.GetSubnet(nodeName)
	if err == nil {
		if sub.HostIP == nodeIP {
			return nil
		} else {
			// Node IP changed, update old subnet
			sub.HostIP = nodeIP
			sub, err = master.registry.UpdateSubnet(sub)
			if err != nil {
				return fmt.Errorf("Error updating subnet %s for node %s: %v", sub.Subnet, nodeName, err)
			}
			log.Infof("Updated HostSubnet %s", hostSubnetToString(sub))
			return nil
		}
	}

	// Create new subnet
	sn, err := master.subnetAllocator.GetNetwork()
	if err != nil {
		return fmt.Errorf("Error allocating network for node %s: %v", nodeName, err)
	}

	sub, err = master.registry.CreateSubnet(nodeName, nodeIP, sn.String())
	if err != nil {
		master.subnetAllocator.ReleaseNetwork(sn)
		return fmt.Errorf("Error creating subnet %s for node %s: %v", sn.String(), nodeName, err)
	}
	log.Infof("Created HostSubnet %s", hostSubnetToString(sub))
	return nil
}

func (master *OsdnMaster) deleteNode(nodeName string) error {
	sub, err := master.registry.GetSubnet(nodeName)
	if err != nil {
		return fmt.Errorf("Error fetching subnet for node %q for deletion: %v", nodeName, err)
	}
	_, ipnet, err := net.ParseCIDR(sub.Subnet)
	if err != nil {
		return fmt.Errorf("Error parsing subnet %q for node %q for deletion: %v", sub.Subnet, nodeName, err)
	}
	master.subnetAllocator.ReleaseNetwork(ipnet)
	err = master.registry.DeleteSubnet(nodeName)
	if err != nil {
		return fmt.Errorf("Error deleting subnet %v for node %q: %v", sub, nodeName, err)
	}

	log.Infof("Deleted HostSubnet %s", hostSubnetToString(sub))
	return nil
}

func getNodeIP(node *kapi.Node) (string, error) {
	if len(node.Status.Addresses) > 0 && node.Status.Addresses[0].Address != "" {
		return node.Status.Addresses[0].Address, nil
	} else {
		return netutils.GetNodeIP(node.Name)
	}
}

// Because openshift-sdn uses an overlay and doesn't need GCE Routes, we need to
// clear the NetworkUnavailable condition that kubelet adds to initial node
// status when using GCE.
// TODO: make upstream kubelet more flexible with overlays and GCE so this
// condition doesn't get added for network plugins that don't want it, and then
// we can remove this function.
func (master *OsdnMaster) clearInitialNodeNetworkUnavailableCondition(node *kapi.Node) {
	knode := node
	cleared := false
	resultErr := kclient.RetryOnConflict(kclient.DefaultBackoff, func() error {
		var err error

		if knode != node {
			knode, err = master.registry.kClient.Nodes().Get(node.ObjectMeta.Name)
			if err != nil {
				return err
			}
		}

		// Let caller modify knode's status, then push to api server.
		_, condition := kapi.GetNodeCondition(&node.Status, kapi.NodeNetworkUnavailable)
		if condition != nil && condition.Status != kapi.ConditionFalse && condition.Reason == "NoRouteCreated" {
			condition.Status = kapi.ConditionFalse
			condition.Reason = "RouteCreated"
			condition.Message = "openshift-sdn cleared kubelet-set NoRouteCreated"
			condition.LastTransitionTime = kapiunversioned.Now()
			knode, err = master.registry.kClient.Nodes().UpdateStatus(knode)
			if err == nil {
				cleared = true
			}
		}
		return err
	})
	if resultErr != nil {
		utilruntime.HandleError(fmt.Errorf("Status update failed for local node: %v", resultErr))
	} else if cleared {
		log.Infof("Cleared node NetworkUnavailable/NoRouteCreated condition for %s", node.ObjectMeta.Name)
	}
}

func (master *OsdnMaster) watchNodes() {
	eventQueue := master.registry.RunEventQueue(Nodes)
	nodeAddressMap := map[types.UID]string{}

	for {
		eventType, obj, err := eventQueue.Pop()
		if err != nil {
			utilruntime.HandleError(fmt.Errorf("EventQueue failed for nodes: %v", err))
			return
		}
		node := obj.(*kapi.Node)
		name := node.ObjectMeta.Name
		uid := node.ObjectMeta.UID

		nodeIP, err := getNodeIP(node)
		if err != nil {
			log.Errorf("Failed to get node IP for %s, skipping event: %v, node: %v", name, eventType, node)
			continue
		}

		switch eventType {
		case watch.Added, watch.Modified:
			master.clearInitialNodeNetworkUnavailableCondition(node)

			if oldNodeIP, ok := nodeAddressMap[uid]; ok && (oldNodeIP == nodeIP) {
				continue
			}
			// Node status is frequently updated by kubelet, so log only if the above condition is not met
			log.V(5).Infof("Watch %s event for Node %q", strings.Title(string(eventType)), name)

			err = master.addNode(name, nodeIP)
			if err != nil {
				log.Errorf("Error creating subnet for node %s, ip %s: %v", name, nodeIP, err)
				continue
			}
			nodeAddressMap[uid] = nodeIP
		case watch.Deleted:
			log.V(5).Infof("Watch %s event for Node %q", strings.Title(string(eventType)), name)
			delete(nodeAddressMap, uid)

			err = master.deleteNode(name)
			if err != nil {
				log.Errorf("Error deleting node %s: %v", name, err)
			}
		}
	}
}

func (node *OsdnNode) SubnetStartNode(mtu uint32) (bool, error) {
	err := node.initSelfSubnet()
	if err != nil {
		return false, err
	}

	// Assume we are working with IPv4
	ni, err := node.registry.GetNetworkInfo()
	if err != nil {
		return false, err
	}
	networkChanged, err := node.SetupSDN(node.localSubnet.Subnet, ni.ClusterNetwork.String(), ni.ServiceNetwork.String(), mtu)
	if err != nil {
		return false, err
	}

	go utilwait.Forever(node.watchSubnets, 0)
	return networkChanged, nil
}

func (node *OsdnNode) initSelfSubnet() error {
	// timeout: 30 secs
	retries := 60
	retryInterval := 500 * time.Millisecond

	var err error
	var subnet *osapi.HostSubnet
	// Try every retryInterval and bail-out if it exceeds max retries
	for i := 0; i < retries; i++ {
		// Get subnet for current node
		subnet, err = node.registry.GetSubnet(node.hostName)
		if err == nil {
			break
		}
		log.Warningf("Could not find an allocated subnet for node: %s, Waiting...", node.hostName)
		time.Sleep(retryInterval)
	}
	if err != nil {
		return fmt.Errorf("Failed to get subnet for this host: %s, error: %v", node.hostName, err)
	}

	if err = node.registry.ValidateNodeIP(subnet.HostIP); err != nil {
		return fmt.Errorf("Failed to validate own HostSubnet: %v", err)
	}

	log.Infof("Found local HostSubnet %s", hostSubnetToString(subnet))
	node.localSubnet = subnet
	return nil
}

// Only run on the nodes
func (node *OsdnNode) watchSubnets() {
	subnets := make(map[string]*osapi.HostSubnet)
	eventQueue := node.registry.RunEventQueue(HostSubnets)

	for {
		eventType, obj, err := eventQueue.Pop()
		if err != nil {
			utilruntime.HandleError(fmt.Errorf("EventQueue failed for subnets: %v", err))
			return
		}
		hs := obj.(*osapi.HostSubnet)

		if hs.HostIP == node.localIP {
			continue
		}

		log.V(5).Infof("Watch %s event for HostSubnet %q", strings.Title(string(eventType)), hs.ObjectMeta.Name)
		switch eventType {
		case watch.Added, watch.Modified:
			oldSubnet, exists := subnets[string(hs.UID)]
			if exists {
				if oldSubnet.HostIP == hs.HostIP {
					continue
				} else {
					// Delete old subnet rules
					if err = node.DeleteHostSubnetRules(oldSubnet); err != nil {
						log.Error(err)
					}
				}
			}
			if err = node.registry.ValidateNodeIP(hs.HostIP); err != nil {
				log.Errorf("Ignoring invalid subnet for node %s: %v", hs.HostIP, err)
				continue
			}

			if err = node.AddHostSubnetRules(hs); err != nil {
				log.Error(err)
				continue
			}
			subnets[string(hs.UID)] = hs
		case watch.Deleted:
			delete(subnets, string(hs.UID))

			if err = node.DeleteHostSubnetRules(hs); err != nil {
				log.Error(err)
			}
		}
	}
}
<|endoftext|>


<commit_before>//
// Use and distribution licensed under the Apache license version 2.
//
// See the COPYING file in the root project directory for full text.
//

package snapshot

import (
	"io/ioutil"
	"os"
	"path/filepath"
)

// Attempting to tar up pseudofiles like /proc/cpuinfo is an exercise in
// futility. Notably, the pseudofiles, when read by syscalls, do not return the
// number of bytes read. This causes the tar writer to write zero-length files.
//
// Instead, it is necessary to build a directory structure in a tmpdir and
// create actual files with copies of the pseudofile contents

// CloneTreeInto copies all the pseudofiles that ghw will consume into the root
// `scratchDir`, preserving the hieratchy.
func CloneTreeInto(scratchDir string) error {
	var err error

	var createPaths = []string{
		"sys/block",
	}

	for _, path := range createPaths {
		if err = os.MkdirAll(filepath.Join(scratchDir, path), os.ModePerm); err != nil {
			return err
		}
	}

	if err = createBlockDevices(scratchDir); err != nil {
		return err
	}

	fileSpecs := ExpectedCloneContent()
	return CopyFilesInto(fileSpecs, scratchDir, nil)
}

// ExpectedCloneContent return a slice of glob patterns which represent the pseudofiles
// ghw cares about. The intended usage of this function is to validate a clone tree,
// checking that the content matches the expectations.
func ExpectedCloneContent() []string {
	return []string{
		"/etc/mtab",
		"/proc/cpuinfo",
		"/proc/meminfo",
		"/sys/bus/pci/devices/*",
		"/sys/devices/pci*/*/irq",
		"/sys/devices/pci*/*/local_cpulist",
		"/sys/devices/pci*/*/modalias",
		"/sys/devices/pci*/*/numa_node",
		"/sys/devices/pci*/pci_bus/*/cpulistaffinity",
		"/sys/devices/system/cpu/cpu*/cache/index*/*",
		"/sys/devices/system/cpu/cpu*/topology/*",
		"/sys/devices/system/memory/block_size_bytes",
		"/sys/devices/system/memory/memory*/online",
		"/sys/devices/system/memory/memory*/state",
		"/sys/devices/system/node/has_*",
		"/sys/devices/system/node/online",
		"/sys/devices/system/node/possible",
		"/sys/devices/system/node/node*/cpu*",
		"/sys/devices/system/node/node*/distance",
	}
}

// ValidateClonedTree checks the content of a cloned tree, whose root is `clonedDir`,
// against a slice of glob specs which must be included in the cloned tree.
// Is not wrong, and this functions doesn't enforce this, that the cloned tree includes
// more files than the necessary; ghw will just ignore the files it doesn't care about.
// Returns a slice of glob patters expected (given) but not found in the cloned tree,
// and the error during the validation (if any).
func ValidateClonedTree(fileSpecs []string, clonedDir string) ([]string, error) {
	missing := []string{}
	for _, fileSpec := range fileSpecs {
		matches, err := filepath.Glob(filepath.Join(clonedDir, fileSpec))
		if err != nil {
			return missing, err
		}
		if len(matches) == 0 {
			missing = append(missing, fileSpec)
		}
	}
	return missing, nil
}

func copyPseudoFile(path, targetPath string) error {
	buf, err := ioutil.ReadFile(path)
	if err != nil {
		return err
	}
	trace("creating %s\n", targetPath)
	f, err := os.Create(targetPath)
	if err != nil {
		return err
	}
	if _, err = f.Write(buf); err != nil {
		return err
	}
	f.Close()
	return nil
}

// CopyFileOptions allows to finetune the behaviour of the CopyFilesInto function
type CopyFileOptions struct {
	// IsSymlinkFn allows to control the behaviour when handling a symlink.
	// If this hook returns true, the source file is treated as symlink: the cloned
	// tree will thus contain a symlink, with its path adjusted to match the relative
	// path inside the cloned tree. If return false, the symlink will be deferred.
	// The easiest use case of this hook is if you want to avoid symlinks in your cloned
	// tree (having duplicated content). In this case you can just add a function
	// which always return false.
	IsSymlinkFn func(path string, info os.FileInfo) bool
}

// CopyFilesInto copies all the given glob files specs in the given `destDir` directory,
// preserving the directory structure. This means you can provide a deeply nested filespec
// like
// - /some/deeply/nested/file*
// and you DO NOT need to build the tree incrementally like
// - /some/
// - /some/deeply/
// ...
// all glob patterns supported in `filepath.Glob` are supported.
func CopyFilesInto(fileSpecs []string, destDir string, opts *CopyFileOptions) error {
	if opts == nil {
		opts = &CopyFileOptions{
			IsSymlinkFn: isSymlink,
		}
	}
	for _, fileSpec := range fileSpecs {
		trace("copying spec: %q\n", fileSpec)
		matches, err := filepath.Glob(fileSpec)
		if err != nil {
			return err
		}
		if err := copyFileTreeInto(matches, destDir, opts); err != nil {
			return err
		}
	}
	return nil
}

func copyFileTreeInto(paths []string, destDir string, opts *CopyFileOptions) error {
	for _, path := range paths {
		trace("  copying path: %q\n", path)
		baseDir := filepath.Dir(path)
		if err := os.MkdirAll(filepath.Join(destDir, baseDir), os.ModePerm); err != nil {
			return err
		}

		fi, err := os.Lstat(path)
		if err != nil {
			return err
		}
		if opts.IsSymlinkFn(path, fi) {
			trace("    copying link: %q\n", path)
			if err := copyLink(path, filepath.Join(destDir, path)); err != nil {
				return err
			}
		} else {
			trace("    copying file: %q\n", path)
			if err := copyPseudoFile(path, filepath.Join(destDir, path)); err != nil {
				return err
			}
		}
	}
	return nil
}

func isSymlink(path string, fi os.FileInfo) bool {
	return fi.Mode()&os.ModeSymlink != 0
}

func copyLink(path, targetPath string) error {
	target, err := os.Readlink(path)
	if err != nil {
		return err
	}
	if err := os.Symlink(target, targetPath); err != nil {
		return err
	}

	return nil
}
<commit_msg>snapshot: clonetree: skip glob-expanded dirs<commit_after>//
// Use and distribution licensed under the Apache license version 2.
//
// See the COPYING file in the root project directory for full text.
//

package snapshot

import (
	"io/ioutil"
	"os"
	"path/filepath"
)

// Attempting to tar up pseudofiles like /proc/cpuinfo is an exercise in
// futility. Notably, the pseudofiles, when read by syscalls, do not return the
// number of bytes read. This causes the tar writer to write zero-length files.
//
// Instead, it is necessary to build a directory structure in a tmpdir and
// create actual files with copies of the pseudofile contents

// CloneTreeInto copies all the pseudofiles that ghw will consume into the root
// `scratchDir`, preserving the hieratchy.
func CloneTreeInto(scratchDir string) error {
	var err error

	var createPaths = []string{
		"sys/block",
	}

	for _, path := range createPaths {
		if err = os.MkdirAll(filepath.Join(scratchDir, path), os.ModePerm); err != nil {
			return err
		}
	}

	if err = createBlockDevices(scratchDir); err != nil {
		return err
	}

	fileSpecs := ExpectedCloneContent()
	return CopyFilesInto(fileSpecs, scratchDir, nil)
}

// ExpectedCloneContent return a slice of glob patterns which represent the pseudofiles
// ghw cares about. The intended usage of this function is to validate a clone tree,
// checking that the content matches the expectations.
func ExpectedCloneContent() []string {
	return []string{
		"/etc/mtab",
		"/proc/cpuinfo",
		"/proc/meminfo",
		"/sys/bus/pci/devices/*",
		"/sys/devices/pci*/*/irq",
		"/sys/devices/pci*/*/local_cpulist",
		"/sys/devices/pci*/*/modalias",
		"/sys/devices/pci*/*/numa_node",
		"/sys/devices/pci*/pci_bus/*/cpulistaffinity",
		"/sys/devices/system/cpu/cpu*/cache/index*/*",
		"/sys/devices/system/cpu/cpu*/topology/*",
		"/sys/devices/system/memory/block_size_bytes",
		"/sys/devices/system/memory/memory*/online",
		"/sys/devices/system/memory/memory*/state",
		"/sys/devices/system/node/has_*",
		"/sys/devices/system/node/online",
		"/sys/devices/system/node/possible",
		"/sys/devices/system/node/node*/cpu*",
		"/sys/devices/system/node/node*/distance",
	}
}

// ValidateClonedTree checks the content of a cloned tree, whose root is `clonedDir`,
// against a slice of glob specs which must be included in the cloned tree.
// Is not wrong, and this functions doesn't enforce this, that the cloned tree includes
// more files than the necessary; ghw will just ignore the files it doesn't care about.
// Returns a slice of glob patters expected (given) but not found in the cloned tree,
// and the error during the validation (if any).
func ValidateClonedTree(fileSpecs []string, clonedDir string) ([]string, error) {
	missing := []string{}
	for _, fileSpec := range fileSpecs {
		matches, err := filepath.Glob(filepath.Join(clonedDir, fileSpec))
		if err != nil {
			return missing, err
		}
		if len(matches) == 0 {
			missing = append(missing, fileSpec)
		}
	}
	return missing, nil
}

func copyPseudoFile(path, targetPath string) error {
	buf, err := ioutil.ReadFile(path)
	if err != nil {
		return err
	}
	trace("creating %s\n", targetPath)
	f, err := os.Create(targetPath)
	if err != nil {
		return err
	}
	if _, err = f.Write(buf); err != nil {
		return err
	}
	f.Close()
	return nil
}

// CopyFileOptions allows to finetune the behaviour of the CopyFilesInto function
type CopyFileOptions struct {
	// IsSymlinkFn allows to control the behaviour when handling a symlink.
	// If this hook returns true, the source file is treated as symlink: the cloned
	// tree will thus contain a symlink, with its path adjusted to match the relative
	// path inside the cloned tree. If return false, the symlink will be deferred.
	// The easiest use case of this hook is if you want to avoid symlinks in your cloned
	// tree (having duplicated content). In this case you can just add a function
	// which always return false.
	IsSymlinkFn func(path string, info os.FileInfo) bool
}

// CopyFilesInto copies all the given glob files specs in the given `destDir` directory,
// preserving the directory structure. This means you can provide a deeply nested filespec
// like
// - /some/deeply/nested/file*
// and you DO NOT need to build the tree incrementally like
// - /some/
// - /some/deeply/
// ...
// all glob patterns supported in `filepath.Glob` are supported.
func CopyFilesInto(fileSpecs []string, destDir string, opts *CopyFileOptions) error {
	if opts == nil {
		opts = &CopyFileOptions{
			IsSymlinkFn: isSymlink,
		}
	}
	for _, fileSpec := range fileSpecs {
		trace("copying spec: %q\n", fileSpec)
		matches, err := filepath.Glob(fileSpec)
		if err != nil {
			return err
		}
		if err := copyFileTreeInto(matches, destDir, opts); err != nil {
			return err
		}
	}
	return nil
}

func copyFileTreeInto(paths []string, destDir string, opts *CopyFileOptions) error {
	for _, path := range paths {
		trace("  copying path: %q\n", path)
		baseDir := filepath.Dir(path)
		if err := os.MkdirAll(filepath.Join(destDir, baseDir), os.ModePerm); err != nil {
			return err
		}

		fi, err := os.Lstat(path)
		if err != nil {
			return err
		}
		// directories must be listed explicitely and created separately.
		// In the future we may want to expose this decision as hook point in
		// CopyFileOptions, when clear use cases emerge.
		if fi.IsDir() {
			trace("expanded glob path %q is a directory - skipped", path)
			continue
		}
		if opts.IsSymlinkFn(path, fi) {
			trace("    copying link: %q\n", path)
			if err := copyLink(path, filepath.Join(destDir, path)); err != nil {
				return err
			}
		} else {
			trace("    copying file: %q\n", path)
			if err := copyPseudoFile(path, filepath.Join(destDir, path)); err != nil {
				return err
			}
		}
	}
	return nil
}

func isSymlink(path string, fi os.FileInfo) bool {
	return fi.Mode()&os.ModeSymlink != 0
}

func copyLink(path, targetPath string) error {
	target, err := os.Readlink(path)
	if err != nil {
		return err
	}
	if err := os.Symlink(target, targetPath); err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2016 The Cockroach Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.
//
// Author: Raphael 'kena' Poss (knz@cockroachlabs.com)

package sql

import (
	"fmt"

	"github.com/cockroachdb/cockroach/pkg/sql/parser"
)

// setNeededColumns informs the node about which columns are
// effectively needed by the consumer of its result rows.
func setNeededColumns(plan planNode, needed []bool) {
	switch n := plan.(type) {
	case *createTableNode:
		if n.n.As() {
			setNeededColumns(n.sourcePlan, allColumns(n.sourcePlan))
		}

	case *createViewNode:
		setNeededColumns(n.sourcePlan, allColumns(n.sourcePlan))

	case *explainDebugNode:
		setNeededColumns(n.plan, allColumns(n.plan))

	case *explainTraceNode:
		setNeededColumns(n.plan, allColumns(n.plan))

	case *explainPlanNode:
		if n.optimized {
			setNeededColumns(n.plan, allColumns(n.plan))
		}

	case *limitNode:
		setNeededColumns(n.plan, needed)

	case *indexJoinNode:
		// Currently all the needed result columns are provided by the
		// table sub-source; from the index sub-source we only need the PK
		// columns sufficient to configure the table sub-source.
		// TODO(radu/knz) see the comments at the start of index_join.go,
		// perhaps this can be optimized to utilize the column values
		// already provided by the index instead of re-retrieving them
		// using the table scanNode.
		setNeededColumns(n.table, needed)
		setNeededColumns(n.index, n.primaryKeyColumns)

	case *unionNode:
		if !n.emitAll {
			// For UNION (as opposed to UNION ALL) we have to check for
			// uniqueness so we need all the columns.
			needed = allColumns(n)
		}
		setNeededColumns(n.left, needed)
		setNeededColumns(n.right, needed)

	case *joinNode:
		// Note: getNeededColumns takes into account both the columns
		// tested for equality and the join predicate expression.
		leftNeeded, rightNeeded := n.pred.getNeededColumns(needed)
		setNeededColumns(n.left.plan, leftNeeded)
		setNeededColumns(n.right.plan, rightNeeded)
		markOmitted(n.columns, needed)

	case *ordinalityNode:
		setNeededColumns(n.source, needed[:len(needed)-1])
		markOmitted(n.columns[:len(needed)-1], needed[:len(needed)-1])

	case *valuesNode:
		markOmitted(n.columns, needed)

	case *scanNode:
		copy(n.valNeededForCol, needed)
		for i := range needed {
			// All the values involved in the filter expression are needed too.
			if n.filterVars.IndexedVarUsed(i) {
				n.valNeededForCol[i] = true
			}
		}
		markOmitted(n.resultColumns, n.valNeededForCol)

	case *distinctNode:
		sourceNeeded := make([]bool, len(n.plan.Columns()))
		copy(sourceNeeded, needed)
		// All the sorting columns are also needed.
		for i, o := range n.columnsInOrder {
			sourceNeeded[i] = sourceNeeded[i] || o
		}
		setNeededColumns(n.plan, sourceNeeded)

	case *selectNode:
		// Optimization: remove all the render expressions that are not
		// needed. While doing so, some indexed vars may disappear
		// entirely, which may enable omission of more columns from the
		// source. To detect this, we need to reset the IndexedVarHelper
		// and re-bind all the expressions.
		n.ivarHelper.Reset()
		for i, val := range needed {
			if !val {
				// This render is not used, so reduce its expression to NULL.
				n.render[i] = parser.DNull
				continue
			}
			n.render[i] = n.ivarHelper.Rebind(n.render[i])
		}
		n.filter = n.ivarHelper.Rebind(n.filter)

		// Now detect which columns from the source are still needed.
		neededFromSource := make([]bool, len(n.source.info.sourceColumns))
		for i := range neededFromSource {
			neededFromSource[i] = n.ivarHelper.IndexedVarUsed(i)
		}
		setNeededColumns(n.source.plan, neededFromSource)
		markOmitted(n.columns, needed)

	case *selectTopNode:
		if n.plan == nil {
			// Not yet expanded: we don't know what the relationship is
			// between the sub-nodes, so the best we can do is to trigger
			// the optimization in the source node as if all columns were
			// needed.
			setNeededColumns(n.source, allColumns(n.source))
		} else {
			setNeededColumns(n.plan, needed)
		}

	case *sortNode:
		sourceNeeded := make([]bool, len(n.plan.Columns()))
		copy(sourceNeeded[:len(needed)], needed)

		// All the ordering columns are also needed.
		for _, o := range n.ordering {
			sourceNeeded[o.ColIdx] = true
		}

		setNeededColumns(n.plan, sourceNeeded)
		markOmitted(n.columns, sourceNeeded[:len(n.columns)])

	case *groupNode:
		// TODO(knz) This can be optimized by removing the aggregation
		// results that are not needed, then removing additional renders
		// from the source that would otherwise only be needed for the
		// omitted aggregation results.
		setNeededColumns(n.plan, allColumns(n.plan))

	case *windowNode:
		// TODO(knz) This can be optimized by removing the window function
		// definitions that are not needed, then removing additional
		// renders from the source that would otherwise only be needed for
		// the omitted window definitions.
		setNeededColumns(n.plan, allColumns(n.plan))

	case *deleteNode:
		// TODO(knz) This can be optimized by omitting the columns that
		// are not part of the primary key, do not participate in
		// foreign key relations and that are not needed for RETURNING.
		setNeededColumns(n.run.rows, allColumns(n.run.rows))

	case *updateNode:
		// TODO(knz) This can be optimized by omitting the columns that
		// are not part of the primary key, do not participate in
		// foreign key relations and that are not needed for RETURNING.
		setNeededColumns(n.run.rows, allColumns(n.run.rows))

	case *insertNode:
		// TODO(knz) This can be optimized by omitting the columns that
		// are not part of the primary key, do not participate in
		// foreign key relations and that are not needed for RETURNING.
		setNeededColumns(n.run.rows, allColumns(n.run.rows))

	case *alterTableNode:
	case *copyNode:
	case *createDatabaseNode:
	case *createIndexNode:
	case *createUserNode:
	case *delayedNode:
	case *dropDatabaseNode:
	case *dropIndexNode:
	case *dropTableNode:
	case *dropViewNode:
	case *emptyNode:
	case *hookFnNode:
	case *splitNode:
	case *valueGenerator:

	default:
		panic(fmt.Sprintf("unhandled node type: %T", plan))
	}
}

// allColumns returns true for every column produced by the plan.
func allColumns(plan planNode) []bool {
	needed := make([]bool, len(plan.Columns()))
	for i := range needed {
		needed[i] = true
	}
	return needed
}

// markOmitted propagates the information from the needed array back
// to the ResultColumns array.
func markOmitted(cols ResultColumns, needed []bool) {
	for i, val := range needed {
		cols[i].omitted = !val
	}
}
<commit_msg>sql: make variable naming consistent.<commit_after>// Copyright 2016 The Cockroach Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.
//
// Author: Raphael 'kena' Poss (knz@cockroachlabs.com)

package sql

import (
	"fmt"

	"github.com/cockroachdb/cockroach/pkg/sql/parser"
)

// setNeededColumns informs the node about which columns are
// effectively needed by the consumer of its result rows.
func setNeededColumns(plan planNode, needed []bool) {
	switch n := plan.(type) {
	case *createTableNode:
		if n.n.As() {
			setNeededColumns(n.sourcePlan, allColumns(n.sourcePlan))
		}

	case *createViewNode:
		setNeededColumns(n.sourcePlan, allColumns(n.sourcePlan))

	case *explainDebugNode:
		setNeededColumns(n.plan, allColumns(n.plan))

	case *explainTraceNode:
		setNeededColumns(n.plan, allColumns(n.plan))

	case *explainPlanNode:
		if n.optimized {
			setNeededColumns(n.plan, allColumns(n.plan))
		}

	case *limitNode:
		setNeededColumns(n.plan, needed)

	case *indexJoinNode:
		// Currently all the needed result columns are provided by the
		// table sub-source; from the index sub-source we only need the PK
		// columns sufficient to configure the table sub-source.
		// TODO(radu/knz) see the comments at the start of index_join.go,
		// perhaps this can be optimized to utilize the column values
		// already provided by the index instead of re-retrieving them
		// using the table scanNode.
		setNeededColumns(n.table, needed)
		setNeededColumns(n.index, n.primaryKeyColumns)

	case *unionNode:
		if !n.emitAll {
			// For UNION (as opposed to UNION ALL) we have to check for
			// uniqueness so we need all the columns.
			needed = allColumns(n)
		}
		setNeededColumns(n.left, needed)
		setNeededColumns(n.right, needed)

	case *joinNode:
		// Note: getNeededColumns takes into account both the columns
		// tested for equality and the join predicate expression.
		leftNeeded, rightNeeded := n.pred.getNeededColumns(needed)
		setNeededColumns(n.left.plan, leftNeeded)
		setNeededColumns(n.right.plan, rightNeeded)
		markOmitted(n.columns, needed)

	case *ordinalityNode:
		setNeededColumns(n.source, needed[:len(needed)-1])
		markOmitted(n.columns[:len(needed)-1], needed[:len(needed)-1])

	case *valuesNode:
		markOmitted(n.columns, needed)

	case *scanNode:
		copy(n.valNeededForCol, needed)
		for i := range needed {
			// All the values involved in the filter expression are needed too.
			if n.filterVars.IndexedVarUsed(i) {
				n.valNeededForCol[i] = true
			}
		}
		markOmitted(n.resultColumns, n.valNeededForCol)

	case *distinctNode:
		sourceNeeded := make([]bool, len(n.plan.Columns()))
		copy(sourceNeeded, needed)
		// All the sorting columns are also needed.
		for i, o := range n.columnsInOrder {
			sourceNeeded[i] = sourceNeeded[i] || o
		}
		setNeededColumns(n.plan, sourceNeeded)

	case *selectNode:
		// Optimization: remove all the render expressions that are not
		// needed. While doing so, some indexed vars may disappear
		// entirely, which may enable omission of more columns from the
		// source. To detect this, we need to reset the IndexedVarHelper
		// and re-bind all the expressions.
		n.ivarHelper.Reset()
		for i, val := range needed {
			if !val {
				// This render is not used, so reduce its expression to NULL.
				n.render[i] = parser.DNull
				continue
			}
			n.render[i] = n.ivarHelper.Rebind(n.render[i])
		}
		n.filter = n.ivarHelper.Rebind(n.filter)

		// Now detect which columns from the source are still needed.
		sourceNeeded := make([]bool, len(n.source.info.sourceColumns))
		for i := range sourceNeeded {
			sourceNeeded[i] = n.ivarHelper.IndexedVarUsed(i)
		}
		setNeededColumns(n.source.plan, sourceNeeded)
		markOmitted(n.columns, needed)

	case *selectTopNode:
		if n.plan == nil {
			// Not yet expanded: we don't know what the relationship is
			// between the sub-nodes, so the best we can do is to trigger
			// the optimization in the source node as if all columns were
			// needed.
			setNeededColumns(n.source, allColumns(n.source))
		} else {
			setNeededColumns(n.plan, needed)
		}

	case *sortNode:
		sourceNeeded := make([]bool, len(n.plan.Columns()))
		copy(sourceNeeded[:len(needed)], needed)

		// All the ordering columns are also needed.
		for _, o := range n.ordering {
			sourceNeeded[o.ColIdx] = true
		}

		setNeededColumns(n.plan, sourceNeeded)
		markOmitted(n.columns, sourceNeeded[:len(n.columns)])

	case *groupNode:
		// TODO(knz) This can be optimized by removing the aggregation
		// results that are not needed, then removing additional renders
		// from the source that would otherwise only be needed for the
		// omitted aggregation results.
		setNeededColumns(n.plan, allColumns(n.plan))

	case *windowNode:
		// TODO(knz) This can be optimized by removing the window function
		// definitions that are not needed, then removing additional
		// renders from the source that would otherwise only be needed for
		// the omitted window definitions.
		setNeededColumns(n.plan, allColumns(n.plan))

	case *deleteNode:
		// TODO(knz) This can be optimized by omitting the columns that
		// are not part of the primary key, do not participate in
		// foreign key relations and that are not needed for RETURNING.
		setNeededColumns(n.run.rows, allColumns(n.run.rows))

	case *updateNode:
		// TODO(knz) This can be optimized by omitting the columns that
		// are not part of the primary key, do not participate in
		// foreign key relations and that are not needed for RETURNING.
		setNeededColumns(n.run.rows, allColumns(n.run.rows))

	case *insertNode:
		// TODO(knz) This can be optimized by omitting the columns that
		// are not part of the primary key, do not participate in
		// foreign key relations and that are not needed for RETURNING.
		setNeededColumns(n.run.rows, allColumns(n.run.rows))

	case *alterTableNode:
	case *copyNode:
	case *createDatabaseNode:
	case *createIndexNode:
	case *createUserNode:
	case *delayedNode:
	case *dropDatabaseNode:
	case *dropIndexNode:
	case *dropTableNode:
	case *dropViewNode:
	case *emptyNode:
	case *hookFnNode:
	case *splitNode:
	case *valueGenerator:

	default:
		panic(fmt.Sprintf("unhandled node type: %T", plan))
	}
}

// allColumns returns true for every column produced by the plan.
func allColumns(plan planNode) []bool {
	needed := make([]bool, len(plan.Columns()))
	for i := range needed {
		needed[i] = true
	}
	return needed
}

// markOmitted propagates the information from the needed array back
// to the ResultColumns array.
func markOmitted(cols ResultColumns, needed []bool) {
	for i, val := range needed {
		cols[i].omitted = !val
	}
}
<|endoftext|>


<commit_before>package models

type DesireAppRequestFromCC struct {
	AppId           string                `json:"app_id"`
	AppVersion      string                `json:"app_version"`
	DropletUri      string                `json:"droplet_uri"`
	Stack           string                `json:"stack"`
	StartCommand    string                `json:"start_command"`
	Environment     []EnvironmentVariable `json:"environment"`
	MemoryMB        int                   `json:"memory_mb"`
	DiskMB          int                   `json:"disk_mb"`
	FileDescriptors uint64                `json:"file_descriptors"`
	NumInstances    int                   `json:"num_instances"`
}
<commit_msg>add routes field to desired app message<commit_after>package models

type DesireAppRequestFromCC struct {
	AppId           string                `json:"app_id"`
	AppVersion      string                `json:"app_version"`
	DropletUri      string                `json:"droplet_uri"`
	Stack           string                `json:"stack"`
	StartCommand    string                `json:"start_command"`
	Environment     []EnvironmentVariable `json:"environment"`
	MemoryMB        int                   `json:"memory_mb"`
	DiskMB          int                   `json:"disk_mb"`
	FileDescriptors uint64                `json:"file_descriptors"`
	NumInstances    int                   `json:"num_instances"`
	Routes          []string              `json:"routes"`
}
<|endoftext|>


<commit_before>package core

import (
	"errors"
	"fmt"
	"log"
	"net"
	"net/rpc"
	"net/rpc/jsonrpc"
	"os"
	"os/exec"
	"strconv"
	"sync"
	"time"

	"github.com/tobscher/go_ne/plugins/shared"
)

// PluginCache stores loaded plugins
type PluginCache struct {
	sync.Mutex
	cache map[string]*Plugin
}

var pluginPrefix = "plugin"
var loadedPlugins = PluginCache{
	cache: make(map[string]*Plugin),
}
var maxAttempts = 5
var startPort = 8000

// Plugin stores information about the plugin and how to
// connect to it.
type Plugin struct {
	information *PluginInformation
	client      *rpc.Client
}

// PluginInformation stores the details about the plugin
// such as the host, port and the underlying command
type PluginInformation struct {
	Host string
	Port string
	Cmd  *exec.Cmd
}

// Address returns the full address and port, e.g. localhost:8001
func (p *PluginInformation) Address() string {
	return fmt.Sprintf("%v:%v", p.Host, p.Port)
}

// StartPlugin starts the plugin with the given name.
// This will try to boot an application called `plugin-<plugin-name>`
//
// This method will return an error when the plugin can not be found
// or the plugin exits with an exit code other than 0.
func StartPlugin(name string) (*Plugin, error) {
	command := fmt.Sprintf("%v-%v", pluginPrefix, name)
	host := "localhost"
	port := nextAvailblePort()

	logger.Debugf("Starting plugin `%v` on port %v", name, port)

	// Pass host and port to plugin
	cmd := exec.Command(command,
		fmt.Sprintf("-host=%v", host),
		fmt.Sprintf("-port=%v", port),
	)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	// Start the plugin
	err := cmd.Start()
	if err != nil {
		return nil, err
	}

	info := &PluginInformation{
		Host: host,
		Port: port,
		Cmd:  cmd,
	}

	// Try to establish connection to plugin
	var conn net.Conn
	for i := 1; i <= maxAttempts; i++ {
		logger.Tracef("Attempt %v to connect to plugin...", i)

		conn, err = net.Dial("tcp", info.Address())
		if err != nil {
			time.Sleep(100 * time.Millisecond)

			if i == maxAttempts {
				cmd.Process.Kill()
				return nil, errors.New("Could not connect to plugin.")
			}

			continue
		}

		break
	}

	client := jsonrpc.NewClient(conn)

	plugin := &Plugin{
		information: info,
		client:      client,
	}

	loadedPlugins.Lock()
	loadedPlugins.cache[name] = plugin
	loadedPlugins.Unlock()

	return plugin, nil
}

// GetPlugin returns a loaded plugin. If the plugin has
// not been loaded yet, it will load it.
func GetPlugin(name string) (*Plugin, error) {
	var val *Plugin
	var ok bool
	var err error

	val, ok = loadedPlugins.cache[name]
	if !ok {
		val, err = StartPlugin(name)
		if err != nil {
			return nil, err
		}
	}
	return val, nil
}

// GetCommands asks the plugin (via RPC) which commands should
// be executed on the remote system.
func (p *Plugin) GetCommands(args shared.Args) ([]*Command, error) {
	var reply shared.Response
	var commands []*Command

	err := p.client.Call("Command.Execute", args, &reply)
	if err != nil {
		return nil, err
	}

	for _, value := range reply.Commands {
		command := &Command{
			name: value.Name,
			args: value.Args,
		}

		commands = append(commands, command)
	}

	return commands, nil
}

func nextAvailblePort() string {
	startPort++
	return strconv.Itoa(startPort)
}

// StopAllPlugins will stop all plugins which are currently running.
//
// BUG(Tobscher) Send signal to gracefully shutdown the plugin
func StopAllPlugins() {
	loadedPlugins.Lock()
	defer loadedPlugins.Unlock()

	for k, v := range loadedPlugins.cache {
		logger.Debugf("Stopping plugin: %v", k)
		if err := v.information.Cmd.Process.Kill(); err != nil {
			log.Println(err)
		}
	}

	loadedPlugins.cache = make(map[string]*Plugin)
	startPort = 8000
}
<commit_msg>optimised code<commit_after>package core

import (
	"errors"
	"fmt"
	"net"
	"net/rpc"
	"net/rpc/jsonrpc"
	"os"
	"os/exec"
	"strconv"
	"sync"
	"time"

	"github.com/tobscher/go_ne/plugins/shared"
)

const (
	pluginPrefix = "plugin"
	maxAttempts  = 5 // to connect to plugin
)

// PluginCache stores loaded plugins
type PluginCache struct {
	sync.Mutex
	cache map[string]*Plugin
}

var (
	startPort     = 8000
	loadedPlugins = PluginCache{
		cache: make(map[string]*Plugin),
	}
)

// Plugin stores information about the plugin and how to
// connect to it.
type Plugin struct {
	information *PluginInformation
	client      *rpc.Client
}

// PluginInformation stores the details about the plugin
// such as the host, port and the underlying command
type PluginInformation struct {
	Host string
	Port string
	Cmd  *exec.Cmd
}

// Address returns the full address and port, e.g. localhost:8001
func (p *PluginInformation) Address() string {
	return fmt.Sprintf("%v:%v", p.Host, p.Port)
}

// StartPlugin starts the plugin with the given name.
// This will try to boot an application called `plugin-<plugin-name>`
//
// This method will return an error when the plugin can not be found
// or the plugin exits with an exit code other than 0.
func StartPlugin(name string) (*Plugin, error) {
	command := fmt.Sprintf("%v-%v", pluginPrefix, name)
	host := "localhost"
	port := nextAvailblePort()

	logger.Debugf("Starting plugin `%v` on port %v", name, port)

	// Pass host and port to plugin
	cmd := exec.Command(command,
		fmt.Sprintf("-host=%v", host),
		fmt.Sprintf("-port=%v", port),
	)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	// Start the plugin
	err := cmd.Start()
	if err != nil {
		return nil, err
	}

	info := &PluginInformation{
		Host: host,
		Port: port,
		Cmd:  cmd,
	}

	// Try to establish connection to plugin
	var conn net.Conn
	for i := 1; i <= maxAttempts; i++ {
		logger.Tracef("Attempt %v to connect to plugin...", i)

		conn, err = net.Dial("tcp", info.Address())
		if err != nil {
			time.Sleep(100 * time.Millisecond)

			if i == maxAttempts {
				cmd.Process.Kill()
				return nil, errors.New("Could not connect to plugin.")
			}

			continue
		}

		break
	}

	client := jsonrpc.NewClient(conn)

	plugin := &Plugin{
		information: info,
		client:      client,
	}

	loadedPlugins.Lock()
	loadedPlugins.cache[name] = plugin
	loadedPlugins.Unlock()

	return plugin, nil
}

// GetPlugin returns a loaded plugin. If the plugin has
// not been loaded yet, it will load it.
func GetPlugin(name string) (*Plugin, error) {
	var val *Plugin
	var ok bool
	var err error

	val, ok = loadedPlugins.cache[name]
	if !ok {
		val, err = StartPlugin(name)
		if err != nil {
			return nil, err
		}
	}
	return val, nil
}

// GetCommands asks the plugin (via RPC) which commands should
// be executed on the remote system.
func (p *Plugin) GetCommands(args shared.Args) ([]*Command, error) {
	var reply shared.Response
	var commands []*Command

	err := p.client.Call("Command.Execute", args, &reply)
	if err != nil {
		return nil, err
	}

	for _, value := range reply.Commands {
		command := &Command{
			name: value.Name,
			args: value.Args,
		}

		commands = append(commands, command)
	}

	return commands, nil
}

func nextAvailblePort() string {
	startPort++
	return strconv.Itoa(startPort)
}

// StopAllPlugins will stop all plugins which are currently running.
//
// BUG(Tobscher) Send signal to gracefully shutdown the plugin
func StopAllPlugins() {
	loadedPlugins.Lock()
	defer loadedPlugins.Unlock()

	for k, v := range loadedPlugins.cache {
		logger.Debugf("Stopping plugin: %v", k)
		if err := v.information.Cmd.Process.Kill(); err != nil {
			logger.Warn(err.Error())
		}
	}

	loadedPlugins.cache = make(map[string]*Plugin)
	startPort = 8000
}
<|endoftext|>


<commit_before>package classpath

import (
	. "jvmgo/testing"
	"strings"
	"testing"
)

func TestParseClassPath_Empty(t *testing.T) {
	cp := ParseClassPath("").compoundEntry
	AssertEquals(0, len(cp.entries))
}

func TestParseClassPath_OneDir(t *testing.T) {
	dirs := []string{".", "abc", "a/b/c"}
	for _, dir := range dirs {
		cp := ParseClassPath(dir).compoundEntry
		AssertEquals(1, len(cp.entries))
	}
}

func TestParseClassPath_List(t *testing.T) {
	pathList := []string{".", "rt.jar"}
	pathStr := strings.Join(pathList, pathListSeparator)
	cp := ParseClassPath(pathStr).compoundEntry
	AssertEquals(2, len(cp.entries))
}
<commit_msg>fix unit test<commit_after>package classpath

import (
	. "jvmgo/testing"
	"strings"
	"testing"
)

func TestParseClassPath_Empty(t *testing.T) {
	cp := ParseClassPath("").compoundEntry
	AssertEquals(2, len(cp.entries))
}

func TestParseClassPath_OneDir(t *testing.T) {
	dirs := []string{".", "abc", "a/b/c"}
	for _, dir := range dirs {
		cp := ParseClassPath(dir).compoundEntry
		AssertEquals(2, len(cp.entries))
	}
}

func TestParseClassPath_List(t *testing.T) {
	pathList := []string{".", "rt.jar"}
	pathStr := strings.Join(pathList, _pathListSeparator)
	cp := ParseClassPath(pathStr).compoundEntry
	AssertEquals(2, len(cp.entries))
}
<|endoftext|>


<commit_before>package terst

import (
    "testing"
    "fmt"
    "reflect"
    "runtime"
    "strings"
    "unsafe"
    "strconv"
    "math"
    "regexp"
)

// Pass

func Pass(have bool, arguments ...interface{}) bool {
    return OurTester().AtPass(1, have, arguments...)
}

func (self *Tester) Pass(have bool, arguments ...interface{}) bool {
    return self.AtPass(1, have, arguments...)
}

func (self *Tester) AtPass(callDepth int, have bool, arguments ...interface{}) bool {
    return self.atPassOrFail(true, 1, have, arguments...)
}

// Fail

func Fail(have bool, arguments ...interface{}) bool {
    return OurTester().AtFail(1, have, arguments...)
}

func (self *Tester) Fail(have bool, arguments ...interface{}) bool {
    return self.AtFail(1, have, arguments...)
}

func (self *Tester) AtFail(callDepth int, have bool, arguments ...interface{}) bool {
    return self.atPassOrFail(false, 1, have, arguments...)
}

func (self *Tester) atPassOrFail(want bool, callDepth int, have bool, arguments ...interface{}) bool {
    kind := "Pass"
    if want == false {
        kind = "Fail"
    }
    test := newTest(kind, callDepth + 1, have, want, arguments)
    pass := have == want
    if (!pass) {
        self.Log(self.failMessageForPass(test))
        self.TestingT.Fail()
        return false
    }
    return true
}

// Is

func Is(have, want interface{}, arguments ...interface{}) bool {
    return OurTester().AtIs(1, have, want, arguments...)
}

func (self *Tester) Is(have, want interface{}, arguments ...interface{}) bool {
    return self.AtIs(1, have, want, arguments...)
}

func (self *Tester) AtIs(callDepth int, have, want interface{}, arguments ...interface{}) bool {
    test := newTest("Is", callDepth + 1, have, want, arguments)
	pass := have == want
    if (!pass) {
        self.Log(self.failMessageForIs(test))
        self.TestingT.Fail()
        return false
    }
    return true
}

// IsNot

func IsNot(have, want interface{}, arguments ...interface{}) bool {
    return OurTester().AtIsNot(1, have, want, arguments...)
}

func (self *Tester) IsNot(have, want interface{}, arguments ...interface{}) bool {
    return self.AtIsNot(1, have, want, arguments...)
}

func (self *Tester) AtIsNot(callDepth int, have, want interface{}, arguments ...interface{}) bool {
    test := newTest("IsNot", callDepth + 1, have, want, arguments)
	pass := have != want
    if (!pass) {
        self.Log(self.failMessageForIs(test))
        self.TestingT.Fail()
        return false
    }
    return true
}

// Like

func Like(have, want interface{}, arguments ...interface{}) bool {
    return OurTester().AtLike(true, 1, have, want, arguments...)
}

func (self *Tester) Like(have, want interface{}, arguments ...interface{}) bool {
    return self.AtLike(true, 1, have, want, arguments...)
}

// Unlike

func Unlike(have, want interface{}, arguments ...interface{}) bool {
    return OurTester().AtLike(false, 1, have, want, arguments...)
}

func (self *Tester) Unlike(have, want interface{}, arguments ...interface{}) bool {
    return self.AtLike(false, 1, have, want, arguments...)
}

func (self *Tester) AtLike(wantMatch bool, callDepth int, have, want interface{}, arguments ...interface{}) bool {
    test := newTest("Like", callDepth + 1, have, want, arguments)
    switch want0 := want.(type) {
    case string:
        haveString := ToString(have)
        pass, error := regexp.Match(want0, []byte(haveString))
        if !wantMatch {
            pass = !pass
        }
        if error != nil {
            panic("regexp.Match(" + want0 + ", ...): " + error.Error())
        }
        if (!pass) {
            self.Log(self.failMessageForMatch(test, haveString, want0, wantMatch))
            self.TestingT.Fail()
            return false
        }
    }
    return true
}

// failMessage*

func (self *Tester) failMessageForPass(test *aTest) string {
    return self.FormatMessage(`
        %s:%d: %s
           Failed test (%s)
                  got: %s
             expected: %s
    `, test.file, test.line, test.Description(), test.kind, ToString(test.have), ToString(test.want))
}

func (self *Tester) failMessageForIs(test *aTest) string {
    return self.FormatMessage(`
        %s:%d: %s
           Failed test (%s)
                  got: %s
             expected: %s
    `, test.file, test.line, test.Description(), test.kind, test.have, test.want)
}

func (self *Tester) failMessageForMatch(test *aTest, have, want string, wantMatch bool) string {
    expect := "mismatched"
    if !wantMatch {
        expect = "   matched"
    }
    return self.FormatMessage(`
        %s:%d: %s
           Failed test (%s)
                  got: %s
           %s: %s
    `, test.file, test.line, test.Description(), test.kind, test.have, expect, test.want)
}

// ...

type Tester struct {
    TestingT *testing.T
}

var _ourTester *Tester = nil

func WithTester(t *testing.T) *Tester {
    _ourTester = NewTester(t)
    return _ourTester
}

func OurTester() *Tester {
    if _ourTester == nil {
        panic("_ourTester == nil")
    }
    return _ourTester
}

func HaveTester() bool {
    return _ourTester != nil
}

func NewTester(t *testing.T) *Tester {
    return &Tester{t}
}

type aTest struct {
    kind string
    have interface{}
    want interface{}
    arguments []interface{}

    file string
    line int
    functionPC uintptr
    function string
}

func newTest(kind string, callDepth int, have, want interface{}, arguments ...interface{}) *aTest {
    file, line, functionPC, function, _ := AtFileLineFunction(callDepth + 1)
    return &aTest{kind, have, want, arguments, file, line, functionPC, function}
}

func (self *aTest) Description() string {
    description := ""
    if len(self.arguments) > 0 {
        description = fmt.Sprintf("%s", self.arguments...)
    }
    return description
}

func AtFileLineFunction(callDepth int) (string, int, uintptr, string, bool) {
    functionPC, file, line, good := runtime.Caller(callDepth + 1)
    function := runtime.FuncForPC(functionPC).Name()
    if (good) {
        if index := strings.LastIndex(file, "/"); index >= 0 {
            file = file[index+1:]
        } else if index = strings.LastIndex(file, "\\"); index >= 0 {
            file = file[index+1:]
        }
        if index := strings.LastIndex(function, ".Test"); index >= 0 {
            function = function[index+1:]
        }
    } else {
        functionPC = 0
        file = "?"
        line = 1
    }
    return file, line, functionPC, function, good
}

func (self *Tester) FormatMessage(format string, arguments ...interface{}) string {
    message := fmt.Sprintf(format, arguments...)
    message = strings.TrimLeft(message, "\n")
    message = strings.TrimRight(message, " \n")
    return message + "\n\n"
}

func (self *Tester) Log(moreOutput string) {
    outputValue := reflect.ValueOf(self.TestingT).Elem().FieldByName("output")
    output := outputValue.Bytes()
    output = append(output, moreOutput...)
    *(*[]byte)(unsafe.Pointer(outputValue.UnsafeAddr())) = output;
}

func ToString(value interface{}) string {
    switch value0 := value.(type) {
        case bool:
            return strconv.FormatBool(value0)
        case int, int8, int16, int32, int64:
        case uint, uint8, uint16, uint32, uint64:
            return value0.(string)
        case float32:
            return strconv.FormatFloat(float64(value0), 'd', -1, 32)
        case float64:
            if math.IsNaN(value0) {
                return "NaN"
            } else if math.IsInf(value0, 0) {
                return "Infinity"
            }
            return strconv.FormatFloat(float64(value0), 'd', -1, 64)
        case string:
            return value0
    }
    return reflect.ValueOf(value).String()
}

<commit_msg>Fleshed out AtUnlike, etc.<commit_after>package terst

import (
    "testing"
    "fmt"
    "reflect"
    "runtime"
    "strings"
    "unsafe"
    "strconv"
    "math"
    "regexp"
)

// Pass

func Pass(have bool, arguments ...interface{}) bool {
    return OurTester().AtPass(1, have, arguments...)
}

func (self *Tester) Pass(have bool, arguments ...interface{}) bool {
    return self.AtPass(1, have, arguments...)
}

func (self *Tester) AtPass(callDepth int, have bool, arguments ...interface{}) bool {
    return self.atPassOrFail(true, 1, have, arguments...)
}

// Fail

func Fail(have bool, arguments ...interface{}) bool {
    return OurTester().AtFail(1, have, arguments...)
}

func (self *Tester) Fail(have bool, arguments ...interface{}) bool {
    return self.AtFail(1, have, arguments...)
}

func (self *Tester) AtFail(callDepth int, have bool, arguments ...interface{}) bool {
    return self.atPassOrFail(false, 1, have, arguments...)
}

func (self *Tester) atPassOrFail(want bool, callDepth int, have bool, arguments ...interface{}) bool {
    kind := "Pass"
    if want == false {
        kind = "Fail"
    }
    test := newTest(kind, callDepth + 1, have, want, arguments)
    pass := have == want
    if (!pass) {
        self.Log(self.failMessageForPass(test))
        self.TestingT.Fail()
        return false
    }
    return true
}

// Is

func Is(have, want interface{}, arguments ...interface{}) bool {
    return OurTester().AtIs(1, have, want, arguments...)
}

func (self *Tester) Is(have, want interface{}, arguments ...interface{}) bool {
    return self.AtIs(1, have, want, arguments...)
}

func (self *Tester) AtIs(callDepth int, have, want interface{}, arguments ...interface{}) bool {
    test := newTest("Is", callDepth + 1, have, want, arguments)
	pass := have == want
    if (!pass) {
        self.Log(self.failMessageForIs(test))
        self.TestingT.Fail()
        return false
    }
    return true
}

// IsNot

func IsNot(have, want interface{}, arguments ...interface{}) bool {
    return OurTester().AtIsNot(1, have, want, arguments...)
}

func (self *Tester) IsNot(have, want interface{}, arguments ...interface{}) bool {
    return self.AtIsNot(1, have, want, arguments...)
}

func (self *Tester) AtIsNot(callDepth int, have, want interface{}, arguments ...interface{}) bool {
    test := newTest("IsNot", callDepth + 1, have, want, arguments)
	pass := have != want
    if (!pass) {
        self.Log(self.failMessageForIs(test))
        self.TestingT.Fail()
        return false
    }
    return true
}

// Like

func Like(have, want interface{}, arguments ...interface{}) bool {
    return OurTester().AtLike(1, have, want, arguments...)
}

func (self *Tester) Like(have, want interface{}, arguments ...interface{}) bool {
    return self.AtLike(1, have, want, arguments...)
}

func (self *Tester) AtLike(callDepth int, have, want interface{}, arguments ...interface{}) bool {
    return self.atLikeOrUnlike(true, 1, have, want, arguments...)
}

// Unlike

func Unlike(have, want interface{}, arguments ...interface{}) bool {
    return OurTester().AtUnlike(1, have, want, arguments...)
}

func (self *Tester) Unlike(have, want interface{}, arguments ...interface{}) bool {
    return self.AtUnlike(1, have, want, arguments...)
}

func (self *Tester) AtUnlike(callDepth int, have, want interface{}, arguments ...interface{}) bool {
    return self.atLikeOrUnlike(false, 1, have, want, arguments...)
}

func (self *Tester) atLikeOrUnlike(wantLike bool, callDepth int, have, want interface{}, arguments ...interface{}) bool {
    test := newTest("Like", callDepth + 1, have, want, arguments)
    switch want0 := want.(type) {
    case string:
        haveString := ToString(have)
        pass, error := regexp.Match(want0, []byte(haveString))
        if !wantLike {
            pass = !pass
        }
        if error != nil {
            panic("regexp.Match(" + want0 + ", ...): " + error.Error())
        }
        if (!pass) {
            self.Log(self.failMessageForMatch(test, haveString, want0, wantLike))
            self.TestingT.Fail()
            return false
        }
    }
    return true
}

// failMessage*

func (self *Tester) failMessageForPass(test *aTest) string {
    return self.FormatMessage(`
        %s:%d: %s
           Failed test (%s)
                  got: %s
             expected: %s
    `, test.file, test.line, test.Description(), test.kind, ToString(test.have), ToString(test.want))
}

func (self *Tester) failMessageForIs(test *aTest) string {
    return self.FormatMessage(`
        %s:%d: %s
           Failed test (%s)
                  got: %s
             expected: %s
    `, test.file, test.line, test.Description(), test.kind, test.have, test.want)
}

func (self *Tester) failMessageForMatch(test *aTest, have, want string, wantMatch bool) string {
    expect := "mismatched"
    if !wantMatch {
        expect = "   matched"
    }
    return self.FormatMessage(`
        %s:%d: %s
           Failed test (%s)
                  got: %s
           %s: %s
    `, test.file, test.line, test.Description(), test.kind, test.have, expect, test.want)
}

// ...

type Tester struct {
    TestingT *testing.T
}

var _ourTester *Tester = nil

func WithTester(t *testing.T) *Tester {
    _ourTester = NewTester(t)
    return _ourTester
}

func OurTester() *Tester {
    if _ourTester == nil {
        panic("_ourTester == nil")
    }
    return _ourTester
}

func HaveTester() bool {
    return _ourTester != nil
}

func NewTester(t *testing.T) *Tester {
    return &Tester{t}
}

type aTest struct {
    kind string
    have interface{}
    want interface{}
    arguments []interface{}

    file string
    line int
    functionPC uintptr
    function string
}

func newTest(kind string, callDepth int, have, want interface{}, arguments ...interface{}) *aTest {
    file, line, functionPC, function, _ := AtFileLineFunction(callDepth + 1)
    return &aTest{kind, have, want, arguments, file, line, functionPC, function}
}

func (self *aTest) Description() string {
    description := ""
    if len(self.arguments) > 0 {
        description = fmt.Sprintf("%s", self.arguments...)
    }
    return description
}

func AtFileLineFunction(callDepth int) (string, int, uintptr, string, bool) {
    functionPC, file, line, good := runtime.Caller(callDepth + 1)
    function := runtime.FuncForPC(functionPC).Name()
    if (good) {
        if index := strings.LastIndex(file, "/"); index >= 0 {
            file = file[index+1:]
        } else if index = strings.LastIndex(file, "\\"); index >= 0 {
            file = file[index+1:]
        }
        if index := strings.LastIndex(function, ".Test"); index >= 0 {
            function = function[index+1:]
        }
    } else {
        functionPC = 0
        file = "?"
        line = 1
    }
    return file, line, functionPC, function, good
}

func (self *Tester) FormatMessage(format string, arguments ...interface{}) string {
    message := fmt.Sprintf(format, arguments...)
    message = strings.TrimLeft(message, "\n")
    message = strings.TrimRight(message, " \n")
    return message + "\n\n"
}

func (self *Tester) Log(moreOutput string) {
    outputValue := reflect.ValueOf(self.TestingT).Elem().FieldByName("output")
    output := outputValue.Bytes()
    output = append(output, moreOutput...)
    *(*[]byte)(unsafe.Pointer(outputValue.UnsafeAddr())) = output;
}

func ToString(value interface{}) string {
    switch value0 := value.(type) {
        case bool:
            return strconv.FormatBool(value0)
        case int, int8, int16, int32, int64:
        case uint, uint8, uint16, uint32, uint64:
            return value0.(string)
        case float32:
            return strconv.FormatFloat(float64(value0), 'd', -1, 32)
        case float64:
            if math.IsNaN(value0) {
                return "NaN"
            } else if math.IsInf(value0, 0) {
                return "Infinity"
            }
            return strconv.FormatFloat(float64(value0), 'd', -1, 64)
        case string:
            return value0
    }
    return reflect.ValueOf(value).String()
}

<|endoftext|>