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

package main

import (
	"errors"
	"io/ioutil"
	"os"
	"path/filepath"
	"time"

	"github.com/cilium/cilium/common"
	"github.com/cilium/cilium/daemon/options"
	"github.com/cilium/cilium/pkg/endpoint"
	"github.com/cilium/cilium/pkg/kvstore"
	"github.com/cilium/cilium/pkg/labels"
	"github.com/cilium/cilium/pkg/option"
	"github.com/cilium/cilium/pkg/policy"

	. "gopkg.in/check.v1"
)

var (
	lbls = labels.Labels{
		"foo":    labels.NewLabel("foo", "bar", labels.LabelSourceContainer),
		"foo2":   labels.NewLabel("foo2", "=bar2", labels.LabelSourceContainer),
		"key":    labels.NewLabel("key", "", labels.LabelSourceContainer),
		"foo==":  labels.NewLabel("foo==", "==", labels.LabelSourceContainer),
		`foo\\=`: labels.NewLabel(`foo\\=`, `\=`, labels.LabelSourceContainer),
		`//=/`:   labels.NewLabel(`//=/`, "", labels.LabelSourceContainer),
		`%`:      labels.NewLabel(`%`, `%ed`, labels.LabelSourceContainer),
	}
	lbls2 = labels.Labels{
		"foo":  labels.NewLabel("foo", "bar", labels.LabelSourceContainer),
		"foo2": labels.NewLabel("foo2", "=bar2", labels.LabelSourceContainer),
	}
	wantSecCtxLbls = policy.Identity{
		ID: 123,
		Endpoints: map[string]time.Time{
			"cc08ff400e355f736dce1c291a6a4007ab9f2d56d42e1f3630ba87b861d45307": time.Now().UTC(),
		},
		Labels: lbls,
	}
)

func (ds *DaemonSuite) SetUpTest(c *C) {
	time.Local = time.UTC
	tempRunDir, err := ioutil.TempDir("", "cilium-test-run")
	c.Assert(err, IsNil)
	err = os.Mkdir(filepath.Join(tempRunDir, "globals"), 0777)
	c.Assert(err, IsNil)

	daemonConf := &Config{
		DryMode: true,
		Opts:    option.NewBoolOptions(&options.Library),
	}
	daemonConf.RunDir = tempRunDir
	daemonConf.StateDir = tempRunDir
	// Get the default labels prefix filter
	err = labels.ParseLabelPrefixCfg(nil, "")
	c.Assert(err, IsNil)
	daemonConf.Opts.Set(endpoint.OptionDropNotify, true)
	daemonConf.Opts.Set(endpoint.OptionTraceNotify, true)
	daemonConf.Device = "undefined"

	kvstore.SetupDummy()

	d, err := NewDaemon(daemonConf)
	c.Assert(err, IsNil)
	ds.d = d
	kvstore.Client().DeleteTree(common.OperationalPath)
	// Needs to be less than 1 second otherwise GetCachedMaxLabelID might
	// not work properly
	d.EnableKVStoreWatcher(time.Nanosecond)
}

func (ds *DaemonSuite) TearDownTest(c *C) {
	os.RemoveAll(ds.d.conf.RunDir)
}

func (ds *DaemonSuite) TestLabels(c *C) {
	//Set up last free ID with zero
	id, err := GetMaxLabelID()
	c.Assert(err, IsNil)
	c.Assert(id, Equals, policy.MinimalNumericIdentity)

	secCtxLbl, new, err := ds.d.CreateOrUpdateIdentity(lbls, "containerLabel1-1")
	c.Assert(err, IsNil)
	c.Assert(secCtxLbl.ID, Equals, policy.MinimalNumericIdentity)
	c.Assert(secCtxLbl.RefCount(), Equals, 1)
	c.Assert(new, Equals, true)

	secCtxLbl, new, err = ds.d.CreateOrUpdateIdentity(lbls, "containerLabel1-2")
	c.Assert(err, IsNil)
	c.Assert(secCtxLbl.ID, Equals, policy.MinimalNumericIdentity)
	c.Assert(secCtxLbl.RefCount(), Equals, 2)
	c.Assert(new, Equals, false)

	secCtxLbl, new, err = ds.d.CreateOrUpdateIdentity(lbls2, "containerLabel2-1")
	c.Assert(err, IsNil)
	c.Assert(secCtxLbl.ID, Equals, policy.MinimalNumericIdentity+1)
	c.Assert(secCtxLbl.RefCount(), Equals, 1)
	c.Assert(new, Equals, true)

	secCtxLbl, new, err = ds.d.CreateOrUpdateIdentity(lbls2, "containerLabel2-2")
	c.Assert(err, IsNil)
	c.Assert(secCtxLbl.ID, Equals, policy.MinimalNumericIdentity+1)
	c.Assert(secCtxLbl.RefCount(), Equals, 2)
	c.Assert(new, Equals, false)

	secCtxLbl, new, err = ds.d.CreateOrUpdateIdentity(lbls, "containerLabel1-3")
	c.Assert(err, IsNil)
	c.Assert(secCtxLbl.ID, Equals, policy.MinimalNumericIdentity)
	c.Assert(secCtxLbl.RefCount(), Equals, 3)
	c.Assert(new, Equals, false)

	//Get labels from ID
	gotSecCtxLbl, err := ds.d.LookupIdentity(policy.MinimalNumericIdentity)
	c.Assert(err, IsNil)
	wantSecCtxLbls.ID = policy.MinimalNumericIdentity
	wantSecCtxLbls.Labels = lbls
	c.Assert(gotSecCtxLbl.ID, Equals, wantSecCtxLbls.ID)
	c.Assert(gotSecCtxLbl.Labels, DeepEquals, wantSecCtxLbls.Labels)
	c.Assert(gotSecCtxLbl.RefCount(), Equals, 3)

	err = ds.d.DeleteIdentity(policy.MinimalNumericIdentity, "containerLabel1-1")
	c.Assert(err, IsNil)
	gotSecCtxLbl, err = ds.d.LookupIdentity(policy.MinimalNumericIdentity)
	c.Assert(err, IsNil)
	wantSecCtxLbls.ID = policy.MinimalNumericIdentity
	wantSecCtxLbls.Labels = lbls
	c.Assert(gotSecCtxLbl.ID, Equals, wantSecCtxLbls.ID)
	c.Assert(gotSecCtxLbl.Labels, DeepEquals, wantSecCtxLbls.Labels)
	c.Assert(gotSecCtxLbl.RefCount(), Equals, 2)

	gotSecCtxLbl, err = ds.d.LookupIdentity(policy.MinimalNumericIdentity + 1)
	c.Assert(err, IsNil)
	wantSecCtxLbls.ID = policy.MinimalNumericIdentity + 1
	wantSecCtxLbls.Labels = lbls2
	c.Assert(gotSecCtxLbl.ID, Equals, wantSecCtxLbls.ID)
	c.Assert(gotSecCtxLbl.Labels, DeepEquals, wantSecCtxLbls.Labels)
	c.Assert(gotSecCtxLbl.RefCount(), Equals, 2)

	err = ds.d.DeleteIdentity(policy.MinimalNumericIdentity, "containerLabel1-2")
	c.Assert(err, IsNil)
	gotSecCtxLbl, err = ds.d.LookupIdentity(policy.MinimalNumericIdentity)
	c.Assert(err, IsNil)
	wantSecCtxLbls.ID = policy.MinimalNumericIdentity
	wantSecCtxLbls.Labels = lbls
	c.Assert(gotSecCtxLbl.ID, Equals, wantSecCtxLbls.ID)
	c.Assert(gotSecCtxLbl.Labels, DeepEquals, wantSecCtxLbls.Labels)
	c.Assert(gotSecCtxLbl.RefCount(), Equals, 1)

	err = ds.d.DeleteIdentity(policy.MinimalNumericIdentity, "containerLabel1-3")
	c.Assert(err, IsNil)
	gotSecCtxLbl, err = ds.d.LookupIdentity(policy.MinimalNumericIdentity)
	c.Assert(err, IsNil)
	var emptySecCtxLblPtr *policy.Identity
	c.Assert(gotSecCtxLbl, Equals, emptySecCtxLblPtr)

	err = kvstore.Client().SetMaxID(common.LastFreeLabelIDKeyPath, policy.MinimalNumericIdentity.Uint32(), policy.MinimalNumericIdentity.Uint32())
	c.Assert(err, IsNil)

	err = ds.d.DeleteIdentity(policy.MinimalNumericIdentity, "containerLabel1-non-existent")
	c.Assert(err, DeepEquals, errors.New("identity not found"))
	gotSecCtxLbl, err = ds.d.LookupIdentity(policy.MinimalNumericIdentity)
	c.Assert(err, IsNil)
	c.Assert(gotSecCtxLbl, Equals, emptySecCtxLblPtr)

	secCtxLbl, new, err = ds.d.CreateOrUpdateIdentity(lbls2, "containerLabel2-3")
	c.Assert(err, IsNil)
	c.Assert(secCtxLbl.ID, Equals, policy.MinimalNumericIdentity+1)
	c.Assert(secCtxLbl.RefCount(), Equals, 3)
	c.Assert(new, Equals, false)

	sha256sum := lbls2.SHA256Sum()
	gotSecCtxLbl, err = LookupIdentityBySHA256(sha256sum)
	c.Assert(err, IsNil)
	c.Assert(gotSecCtxLbl, DeepEquals, secCtxLbl)

	err = ds.d.DeleteIdentityBySHA256(sha256sum, "containerLabel2-1")
	c.Assert(err, IsNil)
	err = ds.d.DeleteIdentity(policy.MinimalNumericIdentity+1, "containerLabel2-2")
	c.Assert(err, IsNil)
	err = ds.d.DeleteIdentity(policy.MinimalNumericIdentity+1, "containerLabel2-3")
	c.Assert(err, IsNil)

	secCtxLbl, new, err = ds.d.CreateOrUpdateIdentity(lbls2, "containerLabel2-3")
	c.Assert(err, IsNil)
	c.Assert(secCtxLbl.ID, Equals, policy.MinimalNumericIdentity)
	c.Assert(secCtxLbl.RefCount(), Equals, 1)
	c.Assert(new, Equals, true)

	secCtxLbl, new, err = ds.d.CreateOrUpdateIdentity(lbls, "containerLabel2-3")
	c.Assert(err, IsNil)
	c.Assert(secCtxLbl.ID, Equals, policy.MinimalNumericIdentity+1)
	c.Assert(secCtxLbl.RefCount(), Equals, 1)
	c.Assert(new, Equals, true)
}

func (ds *DaemonSuite) TestGetMaxID(c *C) {
	lastID := policy.NumericIdentity(common.MaxSetOfLabels - 1)
	err := kvstore.Client().SetValue(common.LastFreeLabelIDKeyPath, lastID)
	c.Assert(err, IsNil)

	id, err := GetMaxLabelID()
	c.Assert(err, IsNil)
	c.Assert(id, Equals, lastID)
}
<commit_msg>daemon: Fix unit test panic in daemon init failure<commit_after>// Copyright 2016-2017 Authors of Cilium
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"errors"
	"io/ioutil"
	"os"
	"path/filepath"
	"time"

	"github.com/cilium/cilium/common"
	"github.com/cilium/cilium/daemon/options"
	"github.com/cilium/cilium/pkg/endpoint"
	"github.com/cilium/cilium/pkg/kvstore"
	"github.com/cilium/cilium/pkg/labels"
	"github.com/cilium/cilium/pkg/option"
	"github.com/cilium/cilium/pkg/policy"

	. "gopkg.in/check.v1"
)

var (
	lbls = labels.Labels{
		"foo":    labels.NewLabel("foo", "bar", labels.LabelSourceContainer),
		"foo2":   labels.NewLabel("foo2", "=bar2", labels.LabelSourceContainer),
		"key":    labels.NewLabel("key", "", labels.LabelSourceContainer),
		"foo==":  labels.NewLabel("foo==", "==", labels.LabelSourceContainer),
		`foo\\=`: labels.NewLabel(`foo\\=`, `\=`, labels.LabelSourceContainer),
		`//=/`:   labels.NewLabel(`//=/`, "", labels.LabelSourceContainer),
		`%`:      labels.NewLabel(`%`, `%ed`, labels.LabelSourceContainer),
	}
	lbls2 = labels.Labels{
		"foo":  labels.NewLabel("foo", "bar", labels.LabelSourceContainer),
		"foo2": labels.NewLabel("foo2", "=bar2", labels.LabelSourceContainer),
	}
	wantSecCtxLbls = policy.Identity{
		ID: 123,
		Endpoints: map[string]time.Time{
			"cc08ff400e355f736dce1c291a6a4007ab9f2d56d42e1f3630ba87b861d45307": time.Now().UTC(),
		},
		Labels: lbls,
	}
)

func (ds *DaemonSuite) SetUpTest(c *C) {
	time.Local = time.UTC
	tempRunDir, err := ioutil.TempDir("", "cilium-test-run")
	c.Assert(err, IsNil)
	err = os.Mkdir(filepath.Join(tempRunDir, "globals"), 0777)
	c.Assert(err, IsNil)

	daemonConf := &Config{
		DryMode: true,
		Opts:    option.NewBoolOptions(&options.Library),
	}
	daemonConf.RunDir = tempRunDir
	daemonConf.StateDir = tempRunDir
	// Get the default labels prefix filter
	err = labels.ParseLabelPrefixCfg(nil, "")
	c.Assert(err, IsNil)
	daemonConf.Opts.Set(endpoint.OptionDropNotify, true)
	daemonConf.Opts.Set(endpoint.OptionTraceNotify, true)
	daemonConf.Device = "undefined"

	kvstore.SetupDummy()

	d, err := NewDaemon(daemonConf)
	c.Assert(err, IsNil)
	ds.d = d
	kvstore.Client().DeleteTree(common.OperationalPath)
	// Needs to be less than 1 second otherwise GetCachedMaxLabelID might
	// not work properly
	d.EnableKVStoreWatcher(time.Nanosecond)
}

func (ds *DaemonSuite) TearDownTest(c *C) {
	if ds.d != nil {
		os.RemoveAll(ds.d.conf.RunDir)
	}
}

func (ds *DaemonSuite) TestLabels(c *C) {
	//Set up last free ID with zero
	id, err := GetMaxLabelID()
	c.Assert(err, IsNil)
	c.Assert(id, Equals, policy.MinimalNumericIdentity)

	secCtxLbl, new, err := ds.d.CreateOrUpdateIdentity(lbls, "containerLabel1-1")
	c.Assert(err, IsNil)
	c.Assert(secCtxLbl.ID, Equals, policy.MinimalNumericIdentity)
	c.Assert(secCtxLbl.RefCount(), Equals, 1)
	c.Assert(new, Equals, true)

	secCtxLbl, new, err = ds.d.CreateOrUpdateIdentity(lbls, "containerLabel1-2")
	c.Assert(err, IsNil)
	c.Assert(secCtxLbl.ID, Equals, policy.MinimalNumericIdentity)
	c.Assert(secCtxLbl.RefCount(), Equals, 2)
	c.Assert(new, Equals, false)

	secCtxLbl, new, err = ds.d.CreateOrUpdateIdentity(lbls2, "containerLabel2-1")
	c.Assert(err, IsNil)
	c.Assert(secCtxLbl.ID, Equals, policy.MinimalNumericIdentity+1)
	c.Assert(secCtxLbl.RefCount(), Equals, 1)
	c.Assert(new, Equals, true)

	secCtxLbl, new, err = ds.d.CreateOrUpdateIdentity(lbls2, "containerLabel2-2")
	c.Assert(err, IsNil)
	c.Assert(secCtxLbl.ID, Equals, policy.MinimalNumericIdentity+1)
	c.Assert(secCtxLbl.RefCount(), Equals, 2)
	c.Assert(new, Equals, false)

	secCtxLbl, new, err = ds.d.CreateOrUpdateIdentity(lbls, "containerLabel1-3")
	c.Assert(err, IsNil)
	c.Assert(secCtxLbl.ID, Equals, policy.MinimalNumericIdentity)
	c.Assert(secCtxLbl.RefCount(), Equals, 3)
	c.Assert(new, Equals, false)

	//Get labels from ID
	gotSecCtxLbl, err := ds.d.LookupIdentity(policy.MinimalNumericIdentity)
	c.Assert(err, IsNil)
	wantSecCtxLbls.ID = policy.MinimalNumericIdentity
	wantSecCtxLbls.Labels = lbls
	c.Assert(gotSecCtxLbl.ID, Equals, wantSecCtxLbls.ID)
	c.Assert(gotSecCtxLbl.Labels, DeepEquals, wantSecCtxLbls.Labels)
	c.Assert(gotSecCtxLbl.RefCount(), Equals, 3)

	err = ds.d.DeleteIdentity(policy.MinimalNumericIdentity, "containerLabel1-1")
	c.Assert(err, IsNil)
	gotSecCtxLbl, err = ds.d.LookupIdentity(policy.MinimalNumericIdentity)
	c.Assert(err, IsNil)
	wantSecCtxLbls.ID = policy.MinimalNumericIdentity
	wantSecCtxLbls.Labels = lbls
	c.Assert(gotSecCtxLbl.ID, Equals, wantSecCtxLbls.ID)
	c.Assert(gotSecCtxLbl.Labels, DeepEquals, wantSecCtxLbls.Labels)
	c.Assert(gotSecCtxLbl.RefCount(), Equals, 2)

	gotSecCtxLbl, err = ds.d.LookupIdentity(policy.MinimalNumericIdentity + 1)
	c.Assert(err, IsNil)
	wantSecCtxLbls.ID = policy.MinimalNumericIdentity + 1
	wantSecCtxLbls.Labels = lbls2
	c.Assert(gotSecCtxLbl.ID, Equals, wantSecCtxLbls.ID)
	c.Assert(gotSecCtxLbl.Labels, DeepEquals, wantSecCtxLbls.Labels)
	c.Assert(gotSecCtxLbl.RefCount(), Equals, 2)

	err = ds.d.DeleteIdentity(policy.MinimalNumericIdentity, "containerLabel1-2")
	c.Assert(err, IsNil)
	gotSecCtxLbl, err = ds.d.LookupIdentity(policy.MinimalNumericIdentity)
	c.Assert(err, IsNil)
	wantSecCtxLbls.ID = policy.MinimalNumericIdentity
	wantSecCtxLbls.Labels = lbls
	c.Assert(gotSecCtxLbl.ID, Equals, wantSecCtxLbls.ID)
	c.Assert(gotSecCtxLbl.Labels, DeepEquals, wantSecCtxLbls.Labels)
	c.Assert(gotSecCtxLbl.RefCount(), Equals, 1)

	err = ds.d.DeleteIdentity(policy.MinimalNumericIdentity, "containerLabel1-3")
	c.Assert(err, IsNil)
	gotSecCtxLbl, err = ds.d.LookupIdentity(policy.MinimalNumericIdentity)
	c.Assert(err, IsNil)
	var emptySecCtxLblPtr *policy.Identity
	c.Assert(gotSecCtxLbl, Equals, emptySecCtxLblPtr)

	err = kvstore.Client().SetMaxID(common.LastFreeLabelIDKeyPath, policy.MinimalNumericIdentity.Uint32(), policy.MinimalNumericIdentity.Uint32())
	c.Assert(err, IsNil)

	err = ds.d.DeleteIdentity(policy.MinimalNumericIdentity, "containerLabel1-non-existent")
	c.Assert(err, DeepEquals, errors.New("identity not found"))
	gotSecCtxLbl, err = ds.d.LookupIdentity(policy.MinimalNumericIdentity)
	c.Assert(err, IsNil)
	c.Assert(gotSecCtxLbl, Equals, emptySecCtxLblPtr)

	secCtxLbl, new, err = ds.d.CreateOrUpdateIdentity(lbls2, "containerLabel2-3")
	c.Assert(err, IsNil)
	c.Assert(secCtxLbl.ID, Equals, policy.MinimalNumericIdentity+1)
	c.Assert(secCtxLbl.RefCount(), Equals, 3)
	c.Assert(new, Equals, false)

	sha256sum := lbls2.SHA256Sum()
	gotSecCtxLbl, err = LookupIdentityBySHA256(sha256sum)
	c.Assert(err, IsNil)
	c.Assert(gotSecCtxLbl, DeepEquals, secCtxLbl)

	err = ds.d.DeleteIdentityBySHA256(sha256sum, "containerLabel2-1")
	c.Assert(err, IsNil)
	err = ds.d.DeleteIdentity(policy.MinimalNumericIdentity+1, "containerLabel2-2")
	c.Assert(err, IsNil)
	err = ds.d.DeleteIdentity(policy.MinimalNumericIdentity+1, "containerLabel2-3")
	c.Assert(err, IsNil)

	secCtxLbl, new, err = ds.d.CreateOrUpdateIdentity(lbls2, "containerLabel2-3")
	c.Assert(err, IsNil)
	c.Assert(secCtxLbl.ID, Equals, policy.MinimalNumericIdentity)
	c.Assert(secCtxLbl.RefCount(), Equals, 1)
	c.Assert(new, Equals, true)

	secCtxLbl, new, err = ds.d.CreateOrUpdateIdentity(lbls, "containerLabel2-3")
	c.Assert(err, IsNil)
	c.Assert(secCtxLbl.ID, Equals, policy.MinimalNumericIdentity+1)
	c.Assert(secCtxLbl.RefCount(), Equals, 1)
	c.Assert(new, Equals, true)
}

func (ds *DaemonSuite) TestGetMaxID(c *C) {
	lastID := policy.NumericIdentity(common.MaxSetOfLabels - 1)
	err := kvstore.Client().SetValue(common.LastFreeLabelIDKeyPath, lastID)
	c.Assert(err, IsNil)

	id, err := GetMaxLabelID()
	c.Assert(err, IsNil)
	c.Assert(id, Equals, lastID)
}
<|endoftext|>


<commit_before>package middleware

import (
	"fmt"
	"os"
	"path"
	"path/filepath"
	"strings"

	"github.com/labstack/echo"
)

type (
	// StaticConfig defines the config for Static middleware.
	StaticConfig struct {
		// Skipper defines a function to skip middleware.
		Skipper Skipper

		// Root directory from where the static content is served.
		// Required.
		Root string `json:"root"`

		// Index file for serving a directory.
		// Optional. Default value "index.html".
		Index string `json:"index"`

		// Enable HTML5 mode by forwarding all not-found requests to root so that
		// SPA (single-page application) can handle the routing.
		// Optional. Default value false.
		HTML5 bool `json:"html5"`

		// Enable directory browsing.
		// Optional. Default value false.
		Browse bool `json:"browse"`
	}
)

var (
	// DefaultStaticConfig is the default Static middleware config.
	DefaultStaticConfig = StaticConfig{
		Skipper: DefaultSkipper,
		Index:   "index.html",
	}
)

// Static returns a Static middleware to serves static content from the provided
// root directory.
func Static(root string) echo.MiddlewareFunc {
	c := DefaultStaticConfig
	c.Root = root
	return StaticWithConfig(c)
}

// StaticWithConfig returns a Static middleware with config.
// See `Static()`.
func StaticWithConfig(config StaticConfig) echo.MiddlewareFunc {
	// Defaults
	if config.Root == "" {
		config.Root = "." // For security we want to restrict to CWD.
	}
	if config.Skipper == nil {
		config.Skipper = DefaultStaticConfig.Skipper
	}
	if config.Index == "" {
		config.Index = DefaultStaticConfig.Index
	}

	return func(next echo.HandlerFunc) echo.HandlerFunc {
		return func(c echo.Context) error {
			p := c.Request().URL.Path
			if strings.HasSuffix(c.Path(), "*") { // When serving from a group, e.g. `/static*`.
				p = c.Param("*")
			}
			name := filepath.Join(config.Root, path.Clean("/"+p)) // "/"+ for security

			fi, err := os.Stat(name)
			if err != nil {
				if os.IsNotExist(err) {
					if config.HTML5 {
						return c.File(filepath.Join(config.Root, config.Index))
					}
					return next(c)
				}
				return err
			}

			if fi.IsDir() {
				index := filepath.Join(name, config.Index)
				fi, err = os.Stat(index)

				if err != nil {
					if config.Browse {
						return listDir(name, c.Response())
					}
					if os.IsNotExist(err) {
						return next(c)
					}
					return err
				}

				return c.File(index)
			}

			return c.File(name)
		}
	}
}

func listDir(name string, res *echo.Response) error {
	dir, err := os.Open(name)
	if err != nil {
		return err
	}
	dirs, err := dir.Readdir(-1)
	if err != nil {
		return err
	}

	// Create a directory index
	res.Header().Set(echo.HeaderContentType, echo.MIMETextHTMLCharsetUTF8)
	if _, err = fmt.Fprintf(res, "
\n"); err != nil {
		return err
	}
	for _, d := range dirs {
		name := d.Name()
		color := "#212121"
		if d.IsDir() {
			color = "#e91e63"
			name += "/"
		}
		if _, err = fmt.Fprintf(res, "%s\n", name, color, name); err != nil {
			return err
		}
	}
	_, err = fmt.Fprintf(res, "
\n")
	return err
}
<commit_msg>Fixed skipper for static middleware (#896)<commit_after>package middleware

import (
	"fmt"
	"os"
	"path"
	"path/filepath"
	"strings"

	"github.com/labstack/echo"
)

type (
	// StaticConfig defines the config for Static middleware.
	StaticConfig struct {
		// Skipper defines a function to skip middleware.
		Skipper Skipper

		// Root directory from where the static content is served.
		// Required.
		Root string `json:"root"`

		// Index file for serving a directory.
		// Optional. Default value "index.html".
		Index string `json:"index"`

		// Enable HTML5 mode by forwarding all not-found requests to root so that
		// SPA (single-page application) can handle the routing.
		// Optional. Default value false.
		HTML5 bool `json:"html5"`

		// Enable directory browsing.
		// Optional. Default value false.
		Browse bool `json:"browse"`
	}
)

var (
	// DefaultStaticConfig is the default Static middleware config.
	DefaultStaticConfig = StaticConfig{
		Skipper: DefaultSkipper,
		Index:   "index.html",
	}
)

// Static returns a Static middleware to serves static content from the provided
// root directory.
func Static(root string) echo.MiddlewareFunc {
	c := DefaultStaticConfig
	c.Root = root
	return StaticWithConfig(c)
}

// StaticWithConfig returns a Static middleware with config.
// See `Static()`.
func StaticWithConfig(config StaticConfig) echo.MiddlewareFunc {
	// Defaults
	if config.Root == "" {
		config.Root = "." // For security we want to restrict to CWD.
	}
	if config.Skipper == nil {
		config.Skipper = DefaultStaticConfig.Skipper
	}
	if config.Index == "" {
		config.Index = DefaultStaticConfig.Index
	}

	return func(next echo.HandlerFunc) echo.HandlerFunc {
		return func(c echo.Context) error {
			if config.Skipper(c) {
				return next(c)
			}

			p := c.Request().URL.Path
			if strings.HasSuffix(c.Path(), "*") { // When serving from a group, e.g. `/static*`.
				p = c.Param("*")
			}
			name := filepath.Join(config.Root, path.Clean("/"+p)) // "/"+ for security

			fi, err := os.Stat(name)
			if err != nil {
				if os.IsNotExist(err) {
					if config.HTML5 {
						return c.File(filepath.Join(config.Root, config.Index))
					}
					return next(c)
				}
				return err
			}

			if fi.IsDir() {
				index := filepath.Join(name, config.Index)
				fi, err = os.Stat(index)

				if err != nil {
					if config.Browse {
						return listDir(name, c.Response())
					}
					if os.IsNotExist(err) {
						return next(c)
					}
					return err
				}

				return c.File(index)
			}

			return c.File(name)
		}
	}
}

func listDir(name string, res *echo.Response) error {
	dir, err := os.Open(name)
	if err != nil {
		return err
	}
	dirs, err := dir.Readdir(-1)
	if err != nil {
		return err
	}

	// Create a directory index
	res.Header().Set(echo.HeaderContentType, echo.MIMETextHTMLCharsetUTF8)
	if _, err = fmt.Fprintf(res, "
\n"); err != nil {
		return err
	}
	for _, d := range dirs {
		name := d.Name()
		color := "#212121"
		if d.IsDir() {
			color = "#e91e63"
			name += "/"
		}
		if _, err = fmt.Fprintf(res, "%s\n", name, color, name); err != nil {
			return err
		}
	}
	_, err = fmt.Fprintf(res, "
\n")
	return err
}
<|endoftext|>


<commit_before>/*
 * This file is part of the KubeVirt project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Copyright 2020 Red Hat, Inc.
 *
 */

package libvmi

import (
	kvirtv1 "kubevirt.io/client-go/api/v1"

	cd "kubevirt.io/kubevirt/tests/containerdisk"
)

// Default VMI values
const (
	DefaultTestGracePeriod int64 = 0
	DefaultVmiName               = "testvmi"
)

// NewFedora instantiates a new Fedora based VMI configuration,
// building its extra properties based on the specified With* options.
func NewFedora(opts ...Option) *kvirtv1.VirtualMachineInstance {
	return newFedora(cd.ContainerDiskFedora, opts...)
}

// NewTestToolingFedora instantiates a new Fedora based VMI configuration,
// building its extra properties based on the specified With* options.
// This image has tooling for the guest agent, stress, and more
func NewTestToolingFedora(opts ...Option) *kvirtv1.VirtualMachineInstance {
	return newFedora(cd.ContainerDiskFedoraTestTooling, opts...)
}

// NewSriovFedora instantiates a new Fedora based VMI configuration,
// building its extra properties based on the specified With* options, the
// image used include Guest Agent and some moduled needed by SRIOV.
func NewSriovFedora(opts ...Option) *kvirtv1.VirtualMachineInstance {
	return newFedora(cd.ContainerDiskFedoraSRIOVLane, opts...)
}

// NewFedora instantiates a new Fedora based VMI configuration with specified
// containerDisk, building its extra properties based on the specified With*
// options.
func newFedora(containerDisk cd.ContainerDisk, opts ...Option) *kvirtv1.VirtualMachineInstance {
	configurePassword := `#!/bin/bash
	echo "fedora" |passwd fedora --stdin
	echo `

	fedoraOptions := []Option{
		WithTerminationGracePeriod(DefaultTestGracePeriod),
		WithResourceMemory("512M"),
		WithRng(),
		WithContainerImage(cd.ContainerDiskFor(containerDisk)),
		WithCloudInitNoCloudUserData(configurePassword, false),
	}
	opts = append(fedoraOptions, opts...)
	return New(RandName(DefaultVmiName), opts...)
}

// NewCirros instantiates a new CirrOS based VMI configuration
func NewCirros(opts ...Option) *kvirtv1.VirtualMachineInstance {
	cirrosOpts := []Option{
		WithContainerImage(cd.ContainerDiskFor(cd.ContainerDiskCirros)),
		WithCloudInitNoCloudUserData("#!/bin/bash\necho 'hello'\n", true),
		WithResourceMemory("128Mi"),
		WithTerminationGracePeriod(DefaultTestGracePeriod),
	}
	cirrosOpts = append(cirrosOpts, opts...)
	return New(RandName(DefaultVmiName), cirrosOpts...)
}
<commit_msg>sriov, Remove setting of the password as part of UserData<commit_after>/*
 * This file is part of the KubeVirt project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Copyright 2020 Red Hat, Inc.
 *
 */

package libvmi

import (
	kvirtv1 "kubevirt.io/client-go/api/v1"

	cd "kubevirt.io/kubevirt/tests/containerdisk"
)

// Default VMI values
const (
	DefaultTestGracePeriod int64 = 0
	DefaultVmiName               = "testvmi"

	userDataSetPassword = `#!/bin/bash
	echo "fedora" | passwd fedora --stdin
	echo `
)

// NewFedora instantiates a new Fedora based VMI configuration,
// building its extra properties based on the specified With* options.
func NewFedora(opts ...Option) *kvirtv1.VirtualMachineInstance {
	opts = append([]Option{WithCloudInitNoCloudUserData(userDataSetPassword, false)}, opts...)
	return newFedora(cd.ContainerDiskFedora, opts...)
}

// NewTestToolingFedora instantiates a new Fedora based VMI configuration,
// building its extra properties based on the specified With* options.
// This image has tooling for the guest agent, stress, and more
func NewTestToolingFedora(opts ...Option) *kvirtv1.VirtualMachineInstance {
	opts = append([]Option{WithCloudInitNoCloudUserData(userDataSetPassword, false)}, opts...)
	return newFedora(cd.ContainerDiskFedoraTestTooling, opts...)
}

// NewSriovFedora instantiates a new Fedora based VMI configuration,
// building its extra properties based on the specified With* options, the
// image used include Guest Agent and some moduled needed by SRIOV.
func NewSriovFedora(opts ...Option) *kvirtv1.VirtualMachineInstance {
	return newFedora(cd.ContainerDiskFedoraSRIOVLane, opts...)
}

// NewFedora instantiates a new Fedora based VMI configuration with specified
// containerDisk, building its extra properties based on the specified With*
// options.
func newFedora(containerDisk cd.ContainerDisk, opts ...Option) *kvirtv1.VirtualMachineInstance {
	fedoraOptions := []Option{
		WithTerminationGracePeriod(DefaultTestGracePeriod),
		WithResourceMemory("512M"),
		WithRng(),
		WithContainerImage(cd.ContainerDiskFor(containerDisk)),
	}
	opts = append(fedoraOptions, opts...)
	return New(RandName(DefaultVmiName), opts...)
}

// NewCirros instantiates a new CirrOS based VMI configuration
func NewCirros(opts ...Option) *kvirtv1.VirtualMachineInstance {
	cirrosOpts := []Option{
		WithContainerImage(cd.ContainerDiskFor(cd.ContainerDiskCirros)),
		WithCloudInitNoCloudUserData("#!/bin/bash\necho 'hello'\n", true),
		WithResourceMemory("128Mi"),
		WithTerminationGracePeriod(DefaultTestGracePeriod),
	}
	cirrosOpts = append(cirrosOpts, opts...)
	return New(RandName(DefaultVmiName), cirrosOpts...)
}
<|endoftext|>


<commit_before>/*
 * This file is part of the KubeVirt project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Copyright 2018 Red Hat, Inc.
 *
 */

package tests_test

import (
	"flag"
	"fmt"
	"time"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/rand"

	v1 "kubevirt.io/kubevirt/pkg/api/v1"
	"kubevirt.io/kubevirt/pkg/kubecli"
	"kubevirt.io/kubevirt/tests"
)

var _ = Describe("Migrations", func() {
	flag.Parse()

	virtClient, err := kubecli.GetKubevirtClient()
	tests.PanicOnError(err)

	BeforeEach(func() {
		tests.BeforeTestCleanup()

		nodes, err := virtClient.CoreV1().Nodes().List(metav1.ListOptions{LabelSelector: v1.NodeSchedulable + "=" + "true"})
		Expect(err).To(BeNil())

		if len(nodes.Items) < 2 {
			Skip("Migration tests require at least 2 nodes")
		}
	})

	AfterEach(func() {
	})

	runVMIAndExpectLaunch := func(vmi *v1.VirtualMachineInstance, timeout int) *v1.VirtualMachineInstance {
		By("Starting a VirtualMachineInstance")
		var obj *v1.VirtualMachineInstance
		var err error
		Eventually(func() error {
			obj, err = virtClient.VirtualMachineInstance(tests.NamespaceTestDefault).Create(vmi)
			return err
		}, timeout, 1*time.Second).ShouldNot(HaveOccurred())
		By("Waiting until the VirtualMachineInstance starts")
		tests.WaitForSuccessfulVMIStartWithTimeout(obj, timeout)
		return obj
	}

	confirmVMIPostMigration := func(vmi *v1.VirtualMachineInstance, migrationUID string) {
		By("Retrieving the VMI post migration")
		vmi, err = virtClient.VirtualMachineInstance(vmi.Namespace).Get(vmi.Name, &metav1.GetOptions{})
		Expect(err).To(BeNil())

		By("Verifying the VMI's migration state")
		Expect(vmi.Status.MigrationState).ToNot(BeNil())
		Expect(vmi.Status.MigrationState.StartTimestamp).ToNot(BeNil())
		Expect(vmi.Status.MigrationState.EndTimestamp).ToNot(BeNil())
		Expect(vmi.Status.MigrationState.TargetNode).To(Equal(vmi.Status.NodeName))
		Expect(vmi.Status.MigrationState.TargetNode).ToNot(Equal(vmi.Status.MigrationState.SourceNode))
		Expect(vmi.Status.MigrationState.Completed).To(Equal(true))
		Expect(vmi.Status.MigrationState.Failed).To(Equal(false))
		Expect(vmi.Status.MigrationState.TargetNodeAddress).ToNot(Equal(""))
		Expect(string(vmi.Status.MigrationState.MigrationUID)).To(Equal(migrationUID))

		By("Verifying the VMI's is in the running state")
		Expect(vmi.Status.Phase).To(Equal(v1.Running))
	}

	runMigrationAndExpectCompletion := func(migration *v1.VirtualMachineInstanceMigration, timeout int) string {
		By("Starting a Migration")
		Eventually(func() error {
			_, err := virtClient.VirtualMachineInstanceMigration(migration.Namespace).Create(migration)
			return err
		}, timeout, 1*time.Second).ShouldNot(HaveOccurred())
		By("Waiting until the Migration Completes")

		uid := ""
		Eventually(func() bool {
			migration, err := virtClient.VirtualMachineInstanceMigration(migration.Namespace).Get(migration.Name, &metav1.GetOptions{})
			Expect(err).To(BeNil())

			Expect(migration.Status.Phase).ToNot(Equal(v1.MigrationFailed))

			uid = string(migration.UID)
			if migration.Status.Phase == v1.MigrationSucceeded {
				return true
			}
			return false

		}, timeout, 1*time.Second).Should(Equal(true))
		return uid
	}

	Describe("Starting a VirtualMachineInstance ", func() {
		Context("with an Alpine read only disk", func() {
			It("should be successfully migrated multiple times", func() {

				vmi := tests.NewRandomVMIWithEphemeralDisk(tests.ContainerDiskFor(tests.ContainerDiskAlpine))
				vmi.Spec.Domain.Devices.Disks[0].DiskDevice.Disk.ReadOnly = true

				By("Starting the VirtualMachineInstance")
				vmi = runVMIAndExpectLaunch(vmi, 240)

				By("Checking that the VirtualMachineInstance console has expected output")
				expecter, err := tests.LoggedInAlpineExpecter(vmi)
				Expect(err).To(BeNil())
				expecter.Close()

				num := 2

				for i := 0; i < num; i++ {
					// execute a migration, wait for finalized state
					By(fmt.Sprintf("Starting the Migration for iteration %d", i))
					migration := tests.NewRandomMigration(vmi.Name, vmi.Namespace)
					migrationUID := runMigrationAndExpectCompletion(migration, 180)

					// check VMI, confirm migration state
					confirmVMIPostMigration(vmi, migrationUID)
				}
				// delete VMI
				By("Deleting the VMI")
				err = virtClient.VirtualMachineInstance(vmi.Namespace).Delete(vmi.Name, &metav1.DeleteOptions{})
				Expect(err).To(BeNil())

				By("Waiting for VMI to disappear")
				tests.WaitForVirtualMachineToDisappearWithTimeout(vmi, 240)

			})
		})
		Context("with an Alpine shared ISCSI PVC", func() {
			var pvName string
			BeforeEach(func() {
				pvName = "test-iscsi-lun" + rand.String(48)
				// Start a ISCSI POD and service
				By("Starting an iSCSI POD")
				iscsiIP := tests.CreateISCSITargetPOD()
				// create a new PV and PVC (PVs can't be reused)
				By("create a new iSCSI PV and PVC")
				tests.CreateISCSIPvAndPvc(pvName, "1Gi", iscsiIP)
			}, 60)

			AfterEach(func() {
				// create a new PV and PVC (PVs can't be reused)
				tests.DeletePvAndPvc(pvName)
			}, 60)
			It("should reject migration specs with shared and non-shared disks", func() {
				// Start the VirtualMachineInstance with PVC and Ephemeral Disks
				vmi := tests.NewRandomVMIWithPVC(pvName)
				image := tests.ContainerDiskFor(tests.ContainerDiskAlpine)
				tests.AddEphemeralDisk(vmi, "myephemeral", "virtio", image)

				By("Starting the VirtualMachineInstance")
				vmi = runVMIAndExpectLaunch(vmi, 120)

				By("Checking that the VirtualMachineInstance console has expected output")
				expecter, err := tests.LoggedInAlpineExpecter(vmi)
				Expect(err).To(BeNil())
				expecter.Close()

				By("Starting a Migration and expecting it to be rejected")
				migration := tests.NewRandomMigration(vmi.Name, vmi.Namespace)
				Eventually(func() error {
					_, err := virtClient.VirtualMachineInstanceMigration(migration.Namespace).Create(migration)
					return err
				}, 120, 1*time.Second).Should(HaveOccurred())
			})
			It("should be successfully migrated multiple times", func() {
				// Start the VirtualMachineInstance with the PVC attached
				vmi := tests.NewRandomVMIWithPVC(pvName)

				vmi = runVMIAndExpectLaunch(vmi, 180)

				By("Checking that the VirtualMachineInstance console has expected output")
				expecter, err := tests.LoggedInAlpineExpecter(vmi)
				Expect(err).To(BeNil())
				expecter.Close()

				num := 2

				for i := 0; i < num; i++ {
					// execute a migration, wait for finalized state
					By(fmt.Sprintf("Starting the Migration for iteration %d", i))
					migration := tests.NewRandomMigration(vmi.Name, vmi.Namespace)
					migrationUID := runMigrationAndExpectCompletion(migration, 180)

					// check VMI, confirm migration state
					confirmVMIPostMigration(vmi, migrationUID)
				}
				// delete VMI
				By("Deleting the VMI")
				err = virtClient.VirtualMachineInstance(vmi.Namespace).Delete(vmi.Name, &metav1.DeleteOptions{})
				Expect(err).To(BeNil())

				By("Waiting for VMI to disappear")
				tests.WaitForVirtualMachineToDisappearWithTimeout(vmi, 120)

			})
		})
	})

})
<commit_msg>add a functioal test to verify live migration with mixed vloumes<commit_after>/*
 * This file is part of the KubeVirt project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Copyright 2018 Red Hat, Inc.
 *
 */

package tests_test

import (
	"flag"
	"fmt"
	"time"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/rand"

	v1 "kubevirt.io/kubevirt/pkg/api/v1"
	"kubevirt.io/kubevirt/pkg/kubecli"
	"kubevirt.io/kubevirt/tests"
)

var _ = Describe("Migrations", func() {
	flag.Parse()

	virtClient, err := kubecli.GetKubevirtClient()
	tests.PanicOnError(err)

	BeforeEach(func() {
		tests.BeforeTestCleanup()

		nodes, err := virtClient.CoreV1().Nodes().List(metav1.ListOptions{LabelSelector: v1.NodeSchedulable + "=" + "true"})
		Expect(err).To(BeNil())

		if len(nodes.Items) < 2 {
			Skip("Migration tests require at least 2 nodes")
		}
	})

	AfterEach(func() {
	})

	runVMIAndExpectLaunch := func(vmi *v1.VirtualMachineInstance, timeout int) *v1.VirtualMachineInstance {
		By("Starting a VirtualMachineInstance")
		var obj *v1.VirtualMachineInstance
		var err error
		Eventually(func() error {
			obj, err = virtClient.VirtualMachineInstance(tests.NamespaceTestDefault).Create(vmi)
			return err
		}, timeout, 1*time.Second).ShouldNot(HaveOccurred())
		By("Waiting until the VirtualMachineInstance starts")
		tests.WaitForSuccessfulVMIStartWithTimeout(obj, timeout)
		return obj
	}

	confirmVMIPostMigration := func(vmi *v1.VirtualMachineInstance, migrationUID string) {
		By("Retrieving the VMI post migration")
		vmi, err = virtClient.VirtualMachineInstance(vmi.Namespace).Get(vmi.Name, &metav1.GetOptions{})
		Expect(err).To(BeNil())

		By("Verifying the VMI's migration state")
		Expect(vmi.Status.MigrationState).ToNot(BeNil())
		Expect(vmi.Status.MigrationState.StartTimestamp).ToNot(BeNil())
		Expect(vmi.Status.MigrationState.EndTimestamp).ToNot(BeNil())
		Expect(vmi.Status.MigrationState.TargetNode).To(Equal(vmi.Status.NodeName))
		Expect(vmi.Status.MigrationState.TargetNode).ToNot(Equal(vmi.Status.MigrationState.SourceNode))
		Expect(vmi.Status.MigrationState.Completed).To(Equal(true))
		Expect(vmi.Status.MigrationState.Failed).To(Equal(false))
		Expect(vmi.Status.MigrationState.TargetNodeAddress).ToNot(Equal(""))
		Expect(string(vmi.Status.MigrationState.MigrationUID)).To(Equal(migrationUID))

		By("Verifying the VMI's is in the running state")
		Expect(vmi.Status.Phase).To(Equal(v1.Running))
	}

	runMigrationAndExpectCompletion := func(migration *v1.VirtualMachineInstanceMigration, timeout int) string {
		By("Starting a Migration")
		Eventually(func() error {
			_, err := virtClient.VirtualMachineInstanceMigration(migration.Namespace).Create(migration)
			return err
		}, timeout, 1*time.Second).ShouldNot(HaveOccurred())
		By("Waiting until the Migration Completes")

		uid := ""
		Eventually(func() bool {
			migration, err := virtClient.VirtualMachineInstanceMigration(migration.Namespace).Get(migration.Name, &metav1.GetOptions{})
			Expect(err).To(BeNil())

			Expect(migration.Status.Phase).ToNot(Equal(v1.MigrationFailed))

			uid = string(migration.UID)
			if migration.Status.Phase == v1.MigrationSucceeded {
				return true
			}
			return false

		}, timeout, 1*time.Second).Should(Equal(true))
		return uid
	}

	Describe("Starting a VirtualMachineInstance ", func() {
		Context("with an Alpine read only disk", func() {
			It("should be successfully migrated multiple times", func() {

				vmi := tests.NewRandomVMIWithEphemeralDisk(tests.ContainerDiskFor(tests.ContainerDiskAlpine))
				vmi.Spec.Domain.Devices.Disks[0].DiskDevice.Disk.ReadOnly = true

				By("Starting the VirtualMachineInstance")
				vmi = runVMIAndExpectLaunch(vmi, 240)

				By("Checking that the VirtualMachineInstance console has expected output")
				expecter, err := tests.LoggedInAlpineExpecter(vmi)
				Expect(err).To(BeNil())
				expecter.Close()

				num := 2

				for i := 0; i < num; i++ {
					// execute a migration, wait for finalized state
					By(fmt.Sprintf("Starting the Migration for iteration %d", i))
					migration := tests.NewRandomMigration(vmi.Name, vmi.Namespace)
					migrationUID := runMigrationAndExpectCompletion(migration, 180)

					// check VMI, confirm migration state
					confirmVMIPostMigration(vmi, migrationUID)
				}
				// delete VMI
				By("Deleting the VMI")
				err = virtClient.VirtualMachineInstance(vmi.Namespace).Delete(vmi.Name, &metav1.DeleteOptions{})
				Expect(err).To(BeNil())

				By("Waiting for VMI to disappear")
				tests.WaitForVirtualMachineToDisappearWithTimeout(vmi, 240)

			})
		})
		Context("with an Alpine shared ISCSI PVC", func() {
			var pvName string
			BeforeEach(func() {
				pvName = "test-iscsi-lun" + rand.String(48)
				// Start a ISCSI POD and service
				By("Starting an iSCSI POD")
				iscsiIP := tests.CreateISCSITargetPOD()
				// create a new PV and PVC (PVs can't be reused)
				By("create a new iSCSI PV and PVC")
				tests.CreateISCSIPvAndPvc(pvName, "1Gi", iscsiIP)
			}, 60)

			AfterEach(func() {
				// create a new PV and PVC (PVs can't be reused)
				tests.DeletePvAndPvc(pvName)
			}, 60)
			It("should migrate a VMI with shared and non-shared disks", func() {
				// Start the VirtualMachineInstance with PVC and Ephemeral Disks
				vmi := tests.NewRandomVMIWithPVC(pvName)
				image := tests.ContainerDiskFor(tests.ContainerDiskAlpine)
				tests.AddEphemeralDisk(vmi, "myephemeral", "virtio", image)

				By("Starting the VirtualMachineInstance")
				vmi = runVMIAndExpectLaunch(vmi, 120)

				By("Checking that the VirtualMachineInstance console has expected output")
				expecter, err := tests.LoggedInAlpineExpecter(vmi)
				Expect(err).To(BeNil())
				expecter.Close()

				By("Starting a Migration")
				migration := tests.NewRandomMigration(vmi.Name, vmi.Namespace)
				migrationUID := runMigrationAndExpectCompletion(migration, 180)

				// check VMI, confirm migration state
				confirmVMIPostMigration(vmi, migrationUID)

				// delete VMI
				By("Deleting the VMI")
				err = virtClient.VirtualMachineInstance(vmi.Namespace).Delete(vmi.Name, &metav1.DeleteOptions{})
				Expect(err).To(BeNil())

				By("Waiting for VMI to disappear")
				tests.WaitForVirtualMachineToDisappearWithTimeout(vmi, 120)
			})
			It("should be successfully migrated multiple times", func() {
				// Start the VirtualMachineInstance with the PVC attached
				vmi := tests.NewRandomVMIWithPVC(pvName)

				vmi = runVMIAndExpectLaunch(vmi, 180)

				By("Checking that the VirtualMachineInstance console has expected output")
				expecter, err := tests.LoggedInAlpineExpecter(vmi)
				Expect(err).To(BeNil())
				expecter.Close()

				num := 2

				for i := 0; i < num; i++ {
					// execute a migration, wait for finalized state
					By(fmt.Sprintf("Starting the Migration for iteration %d", i))
					migration := tests.NewRandomMigration(vmi.Name, vmi.Namespace)
					migrationUID := runMigrationAndExpectCompletion(migration, 180)

					// check VMI, confirm migration state
					confirmVMIPostMigration(vmi, migrationUID)
				}
				// delete VMI
				By("Deleting the VMI")
				err = virtClient.VirtualMachineInstance(vmi.Namespace).Delete(vmi.Name, &metav1.DeleteOptions{})
				Expect(err).To(BeNil())

				By("Waiting for VMI to disappear")
				tests.WaitForVirtualMachineToDisappearWithTimeout(vmi, 120)

			})
			It("should be successfully with a cloud init", func() {
				// Start the VirtualMachineInstance with the PVC attached
				vmi := tests.NewRandomVMIWithPVC(pvName)
				tests.AddUserData(vmi, "cloud-init", "#!/bin/bash\necho 'hello'\n")

				vmi = runVMIAndExpectLaunch(vmi, 180)

				By("Checking that the VirtualMachineInstance console has expected output")
				expecter, err := tests.LoggedInAlpineExpecter(vmi)
				Expect(err).To(BeNil())
				expecter.Close()

				// execute a migration, wait for finalized state
				By("Starting the Migration for iteration")
				migration := tests.NewRandomMigration(vmi.Name, vmi.Namespace)
				migrationUID := runMigrationAndExpectCompletion(migration, 180)

				// check VMI, confirm migration state
				confirmVMIPostMigration(vmi, migrationUID)

				// delete VMI
				By("Deleting the VMI")
				err = virtClient.VirtualMachineInstance(vmi.Namespace).Delete(vmi.Name, &metav1.DeleteOptions{})
				Expect(err).To(BeNil())

				By("Waiting for VMI to disappear")
				tests.WaitForVirtualMachineToDisappearWithTimeout(vmi, 120)
			})
		})
	})

})
<|endoftext|>


<commit_before>package agent

import (
	"encoding/json"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"runtime"
	"strings"
	"sync"
	"time"

	"github.com/codegangsta/cli"

	"github.com/subutai-io/base/agent/agent/alert"
	"github.com/subutai-io/base/agent/agent/connect"
	"github.com/subutai-io/base/agent/agent/container"
	"github.com/subutai-io/base/agent/agent/executer"
	"github.com/subutai-io/base/agent/agent/utils"
	"github.com/subutai-io/base/agent/cli"
	"github.com/subutai-io/base/agent/config"
	"github.com/subutai-io/base/agent/lib/gpg"
	"github.com/subutai-io/base/agent/log"
)

type Response struct {
	Beat Heartbeat `json:"response"`
}

type Heartbeat struct {
	Type       string                `json:"type"`
	Hostname   string                `json:"hostname"`
	Id         string                `json:"id"`
	Arch       string                `json:"arch"`
	Instance   string                `json:"instance"`
	Interfaces []utils.Iface         `json:"interfaces,omitempty"`
	Containers []container.Container `json:"containers,omitempty"`
	Alert      []alert.Load          `json:"alert,omitempty"`
}

var (
	lastHeartbeat     []byte
	mutex             sync.Mutex
	fingerprint       string
	hostname          string
	client            *http.Client
	instanceType      string
	instanceArch      string
	lastHeartbeatTime time.Time
	pool              []container.Container
)

func initAgent() {
	// move .gnupg dir to app home
	os.Setenv("GNUPGHOME", config.Agent.DataPrefix+".gnupg")

	instanceType = utils.InstanceType()
	instanceArch = strings.ToUpper(runtime.GOARCH)
	client = tlsConfig()
}

func Start(c *cli.Context) {
	http.HandleFunc("/trigger", trigger)
	http.HandleFunc("/ping", ping)
	http.HandleFunc("/heartbeat", heartbeatCall)
	go http.ListenAndServe(":7070", nil)

	initAgent()
	go lib.Collect()
	go connectionMonitor()
	go alert.AlertProcessing()

	for {
		if heartbeat() {
			time.Sleep(30 * time.Second)
		} else {
			time.Sleep(5 * time.Second)
		}
		container.ContainersRestoreState(pool)
	}
}

func connectionMonitor() {
	for {
		hostname, _ = os.Hostname()
		if fingerprint == "" || config.Management.GpgUser == "" {
			fingerprint = gpg.GetFingerprint(hostname + "@subutai.io")
			connect.Connect(config.Management.Host, config.Management.Port, config.Agent.GpgUser, config.Management.Secret)
		} else {
			resp, err := client.Get("https://" + config.Management.Host + ":8444/rest/v1/agent/check/" + fingerprint)
			if err == nil && resp.StatusCode == http.StatusOK {
				resp.Body.Close()
				log.Debug("Connection monitor check - success")
			} else {
				log.Debug("Connection monitor check - failed")
				connect.Connect(config.Management.Host, config.Management.Port, config.Agent.GpgUser, config.Management.Secret)
				lastHeartbeat = []byte{}
				go heartbeat()
			}
		}

		time.Sleep(time.Second * 10)
	}
}

func heartbeat() bool {
	if time.Since(lastHeartbeatTime) < time.Second*3 {
		return false
	}
	lastHeartbeatTime = time.Now()
	mutex.Lock()
	defer mutex.Unlock()

	pool = container.GetActiveContainers(false)
	beat := Heartbeat{
		Type:       "HEARTBEAT",
		Hostname:   hostname,
		Id:         fingerprint,
		Arch:       instanceArch,
		Instance:   instanceType,
		Containers: pool,
		Interfaces: utils.GetInterfaces(),
		Alert:      alert.CurrentAlerts(pool),
	}
	res := Response{Beat: beat}
	jbeat, _ := json.Marshal(&res)

	if string(jbeat) == string(lastHeartbeat) {
		return true
	}
	lastHeartbeat = jbeat

	message, err := json.Marshal(map[string]string{
		"hostId":   fingerprint,
		"response": gpg.EncryptWrapper(config.Agent.GpgUser, config.Management.GpgUser, string(jbeat)),
	})
	log.Check(log.WarnLevel, "Marshal response json", err)

	resp, err := client.PostForm("https://"+config.Management.Host+":8444/rest/v1/agent/heartbeat", url.Values{"heartbeat": {string(message)}})
	if !log.Check(log.WarnLevel, "Sending heartbeat: "+string(jbeat), err) {
		log.Debug(resp.Status)
		resp.Body.Close()
		if resp.StatusCode == http.StatusAccepted {
			return true
		}
	}
	lastHeartbeat = []byte{}
	return false
}

func execute(rsp executer.EncRequest) {
	var req executer.Request
	var md, contName, pub, keyring, payload string
	var err error

	if rsp.HostId == fingerprint {
		md = gpg.DecryptWrapper(rsp.Request)
	} else {
		contName = nameById(rsp.HostId)
		if contName == "" {
			lastHeartbeat = []byte{}
			heartbeat()
			contName = nameById(rsp.HostId)
			if contName == "" {
				return
			}
		}

		pub = config.Agent.LxcPrefix + contName + "/public.pub"
		keyring = config.Agent.LxcPrefix + contName + "/secret.sec"
		log.Info("Getting public keyring", "keyring", keyring)
		md = gpg.DecryptNoDefaultKeyring(rsp.Request, keyring, pub)
	}
	i := strings.Index(md, "{")
	j := strings.LastIndex(md, "}") + 1
	if i > j && i > 0 {
		log.Warn("Error getting JSON request")
		return
	}
	request := md[i:j]

	err = json.Unmarshal([]byte(request), &req.Request)
	log.Check(log.WarnLevel, "Decrypting request", err)

	//create channels for stdout and stderr
	sOut := make(chan executer.ResponseOptions)
	if rsp.HostId == fingerprint {
		go executer.ExecHost(req.Request, sOut)
	} else {
		go executer.AttachContainer(contName, req.Request, sOut)
	}

	for sOut != nil {
		select {
		case elem, ok := <-sOut:
			if ok {
				resp := executer.Response{ResponseOpts: elem}
				jsonR, err := json.Marshal(resp)
				log.Check(log.WarnLevel, "Marshal response", err)
				if rsp.HostId == fingerprint {
					payload = gpg.EncryptWrapper(config.Agent.GpgUser, config.Management.GpgUser, string(jsonR))
				} else {
					payload = gpg.EncryptWrapperNoDefaultKeyring(contName, config.Management.GpgUser, string(jsonR), pub, keyring)
				}
				message, err := json.Marshal(map[string]string{
					"hostId":   elem.Id,
					"response": payload,
				})
				log.Check(log.WarnLevel, "Marshal response json "+elem.CommandId, err)
				go response(message)
			} else {
				sOut = nil
			}
		}
	}
	go heartbeat()
}

func tlsConfig() *http.Client {
	tlsconfig := newTLSConfig()
	for tlsconfig == nil || len(tlsconfig.Certificates[0].Certificate) == 0 {
		time.Sleep(time.Second * 2)
		for utils.PublicCert() == "" {
			x509generate()
		}
		tlsconfig = newTLSConfig()
	}

	transport := &http.Transport{TLSClientConfig: tlsconfig}
	return &http.Client{Transport: transport, Timeout: time.Second * 30}
}

func response(msg []byte) {
	resp, err := client.PostForm("https://"+config.Management.Host+":8444/rest/v1/agent/response", url.Values{"response": {string(msg)}})
	if !log.Check(log.WarnLevel, "Sending response "+string(msg), err) {
		resp.Body.Close()
		if resp.StatusCode == http.StatusAccepted {
			return
		}
	}
	time.Sleep(time.Second * 5)
	go response(msg)

}

func command() {
	var rsp []executer.EncRequest

	resp, err := client.Get("https://" + config.Management.Host + ":8444/rest/v1/agent/requests/" + fingerprint)
	if log.Check(log.WarnLevel, "Getting requests", err) {
		return
	}
	defer resp.Body.Close()
	if resp.StatusCode == http.StatusNoContent {
		return
	}

	data, err := ioutil.ReadAll(resp.Body)
	if !log.Check(log.WarnLevel, "Reading body", err) {
		log.Check(log.WarnLevel, "Unmarshal payload", json.Unmarshal(data, &rsp))
		for _, request := range rsp {
			go execute(request)
		}
	}
}

func ping(rw http.ResponseWriter, request *http.Request) {
	if request.Method == http.MethodGet && strings.Split(request.RemoteAddr, ":")[0] == config.Management.Host {
		rw.WriteHeader(http.StatusOK)
	} else {
		rw.WriteHeader(http.StatusForbidden)
	}
}

func trigger(rw http.ResponseWriter, request *http.Request) {
	if request.Method == http.MethodPost && strings.Split(request.RemoteAddr, ":")[0] == config.Management.Host {
		rw.WriteHeader(http.StatusAccepted)
		go command()
	} else {
		rw.WriteHeader(http.StatusForbidden)
	}
}

func heartbeatCall(rw http.ResponseWriter, request *http.Request) {
	if request.Method == http.MethodGet && strings.Split(request.RemoteAddr, ":")[0] == config.Management.Host {
		rw.WriteHeader(http.StatusOK)
		lastHeartbeat = []byte{}
		heartbeat()
	} else {
		rw.WriteHeader(http.StatusForbidden)
	}
}

func nameById(id string) string {
	for _, c := range pool {
		if c.Id == id {
			return c.Name
		}
	}
	return ""
}
<commit_msg>Test commit<commit_after>package agent

import (
	"encoding/json"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"runtime"
	"strings"
	"sync"
	"time"

	"github.com/codegangsta/cli"

	"github.com/subutai-io/base/agent/agent/alert"
	"github.com/subutai-io/base/agent/agent/connect"
	"github.com/subutai-io/base/agent/agent/container"
	"github.com/subutai-io/base/agent/agent/executer"
	"github.com/subutai-io/base/agent/agent/utils"
	"github.com/subutai-io/base/agent/cli"
	"github.com/subutai-io/base/agent/config"
	"github.com/subutai-io/base/agent/lib/gpg"
	"github.com/subutai-io/base/agent/log"
)

type Response struct {
	Beat Heartbeat `json:"response"`
}

type Heartbeat struct {
	Type       string                `json:"type"`
	Hostname   string                `json:"hostname"`
	Id         string                `json:"id"`
	Arch       string                `json:"arch"`
	Instance   string                `json:"instance"`
	Interfaces []utils.Iface         `json:"interfaces,omitempty"`
	Containers []container.Container `json:"containers,omitempty"`
	Alert      []alert.Load          `json:"alert,omitempty"`
}

var (
	lastHeartbeat     []byte
	mutex             sync.Mutex
	fingerprint       string
	hostname          string
	client            *http.Client
	instanceType      string
	instanceArch      string
	lastHeartbeatTime time.Time
	pool              []container.Container
)

func initAgent() {
	// move .gnupg dir to app home
	os.Setenv("GNUPGHOME", config.Agent.DataPrefix+".gnupg")

	instanceType = utils.InstanceType()
	instanceArch = strings.ToUpper(runtime.GOARCH)
	client = tlsConfig()
}

func Start(c *cli.Context) {
	http.HandleFunc("/trigger", trigger)
	http.HandleFunc("/ping", ping)
	http.HandleFunc("/heartbeat", heartbeatCall)
	go http.ListenAndServe(":7070", nil)

	initAgent()
	go lib.Collect()
	go connectionMonitor()
	go alert.AlertProcessing()

	for {
		if heartbeat() {
			time.Sleep(30 * time.Second)
		} else {
			time.Sleep(5 * time.Second)
		}
		container.ContainersRestoreState(pool)
	}
}

func connectionMonitor() {
	for {
		hostname, _ = os.Hostname()
		if fingerprint == "" || config.Management.GpgUser == "" {
			fingerprint = gpg.GetFingerprint(hostname + "@subutai.io")
			connect.Connect(config.Management.Host, config.Management.Port, config.Agent.GpgUser, config.Management.Secret)
		} else {
			resp, err := client.Get("https://" + config.Management.Host + ":8444/rest/v1/agent/check/" + fingerprint)
			if err == nil && resp.StatusCode == http.StatusOK {
				resp.Body.Close()
				log.Debug("Connection monitor check - success")
			} else {
				log.Debug("Connection monitor check - failed")
				connect.Connect(config.Management.Host, config.Management.Port, config.Agent.GpgUser, config.Management.Secret)
				lastHeartbeat = []byte{}
				go heartbeat()
			}
		}

		time.Sleep(time.Second * 10)
	}
}

func heartbeat() bool {
	if time.Since(lastHeartbeatTime) < time.Second*3 {
		return false
	}
	lastHeartbeatTime = time.Now()
	mutex.Lock()
	defer mutex.Unlock()

	pool = container.GetActiveContainers(false)
	beat := Heartbeat{
		Type:       "HEARTBEAT",
		Hostname:   hostname,
		Id:         fingerprint,
		Arch:       instanceArch,
		Instance:   instanceType,
		Containers: pool,
		Interfaces: utils.GetInterfaces(),
		Alert:      alert.CurrentAlerts(pool),
	}
	res := Response{Beat: beat}
	jbeat, _ := json.Marshal(&res)

	if string(jbeat) == string(lastHeartbeat) {
		return true
	}
	lastHeartbeat = jbeat

	message, err := json.Marshal(map[string]string{
		"hostId":   fingerprint,
		"response": gpg.EncryptWrapper(config.Agent.GpgUser, config.Management.GpgUser, string(jbeat)),
	})
	log.Check(log.WarnLevel, "Marshal response json", err)

	resp, err := client.PostForm("https://"+config.Management.Host+":8444/rest/v1/agent/heartbeat", url.Values{"heartbeat": {string(message)}})
	if !log.Check(log.WarnLevel, "Sending heartbeat: "+string(jbeat), err) {
		log.Debug(resp.Status)
		resp.Body.Close()
		if resp.StatusCode == http.StatusAccepted {
			return true
		}
	}
	lastHeartbeat = []byte{}
	return false
}

func execute(rsp executer.EncRequest) {
	var req executer.Request
	var md, contName, pub, keyring, payload string
	var err error

	if rsp.HostId == fingerprint {
		md = gpg.DecryptWrapper(rsp.Request)
	} else {
		contName = nameById(rsp.HostId)
		if contName == "" {
			lastHeartbeat = []byte{}
			heartbeat()
			contName = nameById(rsp.HostId)
			if contName == "" {
				return
			}
		}

		pub = config.Agent.LxcPrefix + contName + "/public.pub"
		keyring = config.Agent.LxcPrefix + contName + "/secret.sec"
		log.Info("Getting public keyring", "keyring", keyring)
		md = gpg.DecryptNoDefaultKeyring(rsp.Request, keyring, pub)
	}
	i := strings.Index(md, "{")
	j := strings.LastIndex(md, "}") + 1
	if i > j && i > 0 {
		log.Warn("Error getting JSON request")
		return
	}
	request := md[i:j]

	err = json.Unmarshal([]byte(request), &req.Request)
	log.Check(log.WarnLevel, "Decrypting request", err)

	//create channels for stdout and stderr
	sOut := make(chan executer.ResponseOptions)
	if rsp.HostId == fingerprint {
		go executer.ExecHost(req.Request, sOut)
	} else {
		go executer.AttachContainer(contName, req.Request, sOut)
	}

	for sOut != nil {
		select {
		case elem, ok := <-sOut:
			if ok {
				resp := executer.Response{ResponseOpts: elem}
				jsonR, err := json.Marshal(resp)
				log.Check(log.WarnLevel, "Marshal response", err)
				if rsp.HostId == fingerprint {
					payload = gpg.EncryptWrapper(config.Agent.GpgUser, config.Management.GpgUser, string(jsonR))
				} else {
					payload = gpg.EncryptWrapperNoDefaultKeyring(contName, config.Management.GpgUser, string(jsonR), pub, keyring)
				}
				message, err := json.Marshal(map[string]string{
					"hostId":   elem.Id,
					"response": payload,
				})
				log.Check(log.WarnLevel, "Marshal response json "+elem.CommandId, err)
				go response(message)
			} else {
				sOut = nil
			}
		}
	}
	go heartbeat()
}

func tlsConfig() *http.Client {
	tlsconfig := newTLSConfig()
	for tlsconfig == nil || len(tlsconfig.Certificates[0].Certificate) == 0 {
		time.Sleep(time.Second * 2)
		for utils.PublicCert() == "" {
			x509generate()
		}
		tlsconfig = newTLSConfig()
	}
	transport := &http.Transport{TLSClientConfig: tlsconfig}
	return &http.Client{Transport: transport, Timeout: time.Second * 30}
}

func response(msg []byte) {
	resp, err := client.PostForm("https://"+config.Management.Host+":8444/rest/v1/agent/response", url.Values{"response": {string(msg)}})
	if !log.Check(log.WarnLevel, "Sending response "+string(msg), err) {
		resp.Body.Close()
		if resp.StatusCode == http.StatusAccepted {
			return
		}
	}
	time.Sleep(time.Second * 5)
	go response(msg)

}

func command() {
	var rsp []executer.EncRequest

	resp, err := client.Get("https://" + config.Management.Host + ":8444/rest/v1/agent/requests/" + fingerprint)
	if log.Check(log.WarnLevel, "Getting requests", err) {
		return
	}
	defer resp.Body.Close()
	if resp.StatusCode == http.StatusNoContent {
		return
	}

	data, err := ioutil.ReadAll(resp.Body)
	if !log.Check(log.WarnLevel, "Reading body", err) {
		log.Check(log.WarnLevel, "Unmarshal payload", json.Unmarshal(data, &rsp))
		for _, request := range rsp {
			go execute(request)
		}
	}
}

func ping(rw http.ResponseWriter, request *http.Request) {
	if request.Method == http.MethodGet && strings.Split(request.RemoteAddr, ":")[0] == config.Management.Host {
		rw.WriteHeader(http.StatusOK)
	} else {
		rw.WriteHeader(http.StatusForbidden)
	}
}

func trigger(rw http.ResponseWriter, request *http.Request) {
	if request.Method == http.MethodPost && strings.Split(request.RemoteAddr, ":")[0] == config.Management.Host {
		rw.WriteHeader(http.StatusAccepted)
		go command()
	} else {
		rw.WriteHeader(http.StatusForbidden)
	}
}

func heartbeatCall(rw http.ResponseWriter, request *http.Request) {
	if request.Method == http.MethodGet && strings.Split(request.RemoteAddr, ":")[0] == config.Management.Host {
		rw.WriteHeader(http.StatusOK)
		lastHeartbeat = []byte{}
		heartbeat()
	} else {
		rw.WriteHeader(http.StatusForbidden)
	}
}

func nameById(id string) string {
	for _, c := range pool {
		if c.Id == id {
			return c.Name
		}
	}
	return ""
}
<|endoftext|>


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

package config

import (
	"bytes"
	"os"
	"os/exec"
)

func Compare() string {
	configActive.WriteTo("/tmp/config.1")
	configCandidate.WriteTo("/tmp/config.2")

	var config string
	out, err := exec.Command("diff", "-U", "-1", "/tmp/config.1", "/tmp/config.2").Output()
	if err != nil {
		lines := bytes.Split(out, []byte{'\n'})
		if len(lines) > 3 {
			lines = lines[3:]
		}
		config = ""
		for _, s := range lines {
			config = config + string(s) + "\n"
		}
	} else {
		config = configCandidate.String()
	}

	os.Remove("/tmp/config.1")
	os.Remove("/tmp/config.2")

	return config
}

func JsonMarshal() string {
	return configCandidate.JsonMarshal()
}

func CompareCommand() string {
	configActive.WriteCommandTo("/tmp/config.1")
	configCandidate.WriteCommandTo("/tmp/config.2")

	var config string
	out, err := exec.Command("diff", "-U", "-1", "/tmp/config.1", "/tmp/config.2").Output()
	if err != nil {
		lines := bytes.Split(out, []byte{'\n'})
		if len(lines) > 3 {
			lines = lines[3:]
		}
		config = ""
		for _, s := range lines {
			config = config + string(s) + "\n"
		}
	}

	os.Remove("/tmp/config.1")
	os.Remove("/tmp/config.2")

	return config
}

func Commands() string {
	return configActive.CommandString()
}
<commit_msg>Fix diff -U arugemnt for diff 3.8.<commit_after>// Copyright 2016 OpenConfigd Project.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package config

import (
	"bytes"
	"os"
	"os/exec"
)

func Compare() string {
	configActive.WriteTo("/tmp/config.1")
	configCandidate.WriteTo("/tmp/config.2")

	var config string
	out, err := exec.Command("diff", "-U", "65535", "/tmp/config.1", "/tmp/config.2").Output()
	if err != nil {
		lines := bytes.Split(out, []byte{'\n'})
		if len(lines) > 3 {
			lines = lines[3:]
		}
		config = ""
		for _, s := range lines {
			config = config + string(s) + "\n"
		}
	} else {
		config = configCandidate.String()
	}

	os.Remove("/tmp/config.1")
	os.Remove("/tmp/config.2")

	return config
}

func JsonMarshal() string {
	return configCandidate.JsonMarshal()
}

func CompareCommand() string {
	configActive.WriteCommandTo("/tmp/config.1")
	configCandidate.WriteCommandTo("/tmp/config.2")

	var config string
	out, err := exec.Command("diff", "-U", "65535", "/tmp/config.1", "/tmp/config.2").Output()
	if err != nil {
		lines := bytes.Split(out, []byte{'\n'})
		if len(lines) > 3 {
			lines = lines[3:]
		}
		config = ""
		for _, s := range lines {
			config = config + string(s) + "\n"
		}
	}

	os.Remove("/tmp/config.1")
	os.Remove("/tmp/config.2")

	return config
}

func Commands() string {
	return configActive.CommandString()
}
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2016 Magicshui
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */
/**
 * Copyright (c) 2017 yunify
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

package qingcloud

import (
	"fmt"

	"github.com/hashicorp/terraform/helper/schema"
	qc "github.com/yunify/qingcloud-sdk-go/service"
)

const (
	resourceVpcType            = "type"
	resourceVpcNetwork         = "vpc_network"
	resourceVpcEipID           = "eip_id"
	resourceVpcSecurityGroupID = "security_group_id"
	resourceVpcPrivateIP       = "private_ip"
	resourceVpcPublicIP        = "public_ip"
)

func resourceQingcloudVpc() *schema.Resource {
	return &schema.Resource{
		Create: resourceQingcloudVpcCreate,
		Read:   resourceQingcloudVpcRead,
		Update: resourceQingcloudVpcUpdate,
		Delete: resourceQingcloudVpcDelete,
		Schema: map[string]*schema.Schema{
			resourceName: &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},
			resourceVpcType: &schema.Schema{
				Type:         schema.TypeInt,
				Optional:     true,
				ForceNew:     true,
				Default:      1,
				ValidateFunc: withinArrayInt(0, 1, 2, 3),
			},
			resourceVpcNetwork: &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
				ValidateFunc: withinArrayString("192.168.0.0/16", "172.16.0.0/16", "172.17.0.0/16",
					"172.18.0.0/16", "172.19.0.0/16", "172.20.0.0/16", "172.21.0.0/16", "172.22.0.0/16",
					"172.23.0.0/16", "172.24.0.0/16", "172.25.0.0/16"),
			},
			resourceTagIds:   tagIdsSchema(),
			resourceTagNames: tagNamesSchema(),
			resourceVpcEipID: &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},
			resourceVpcSecurityGroupID: &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},
			resourceDescription: &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},
			resourceVpcPrivateIP: &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
			resourceVpcPublicIP: &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
		},
	}
}

// resourceQingcloudRouterCreate
func resourceQingcloudVpcCreate(d *schema.ResourceData, meta interface{}) error {
	clt := meta.(*QingCloudClient).router
	input := new(qc.CreateRoutersInput)
	input.RouterName, _ = getNamePointer(d)
	input.VpcNetwork = getSetStringPointer(d, resourceVpcNetwork)
	input.SecurityGroup = getSetStringPointer(d, resourceVpcSecurityGroupID)
	input.RouterType = qc.Int(d.Get(resourceVpcType).(int))
	input.Count = qc.Int(1)
	var output *qc.CreateRoutersOutput
	var err error
	simpleRetry(func() error {
		output, err = clt.CreateRouters(input)
		return isServerBusy(err)
	})
	if err != nil {
		return err
	}
	d.SetId(qc.StringValue(output.Routers[0]))
	if _, err = RouterTransitionStateRefresh(clt, d.Id()); err != nil {
		return fmt.Errorf("Error waiting for router (%s) to start: %s", d.Id(), err.Error())
	}
	return resourceQingcloudVpcUpdate(d, meta)
}

func resourceQingcloudVpcRead(d *schema.ResourceData, meta interface{}) error {
	clt := meta.(*QingCloudClient).router
	input := new(qc.DescribeRoutersInput)
	input.Routers = []*string{qc.String(d.Id())}
	input.Verbose = qc.Int(1)
	var output *qc.DescribeRoutersOutput
	var err error
	simpleRetry(func() error {
		output, err = clt.DescribeRouters(input)
		return isServerBusy(err)
	})
	if err != nil {
		return err
	}
	if isRouterDeleted(output.RouterSet) {
		d.SetId("")
		return nil
	}
	rtr := output.RouterSet[0]
	d.Set(resourceName, qc.StringValue(rtr.RouterName))
	d.Set(resourceVpcType, qc.IntValue(rtr.RouterType))
	d.Set(resourceVpcSecurityGroupID, qc.StringValue(rtr.SecurityGroupID))
	d.Set(resourceDescription, qc.StringValue(rtr.Description))
	d.Set(resourceVpcPrivateIP, qc.StringValue(rtr.PrivateIP))
	d.Set(resourceVpcEipID, qc.StringValue(rtr.EIP.EIPID))
	d.Set(resourceVpcPublicIP, qc.StringValue(rtr.EIP.EIPAddr))
	resourceSetTag(d, rtr.Tags)
	return nil
}

func resourceQingcloudVpcUpdate(d *schema.ResourceData, meta interface{}) error {
	clt := meta.(*QingCloudClient).router
	if _, err := RouterTransitionStateRefresh(clt, d.Id()); err != nil {
		return err
	}
	if err := waitRouterLease(d, meta); err != nil {
		return err
	}
	d.Partial(true)
	if err := modifyRouterAttributes(d, meta); err != nil {
		return err
	}
	d.SetPartial(resourceName)
	d.SetPartial(resourceDescription)
	if d.HasChange(resourceVpcEipID) {
		if err := applyRouterUpdate(qc.String(d.Id()), meta); err != nil {
			return err
		}
	}
	d.SetPartial(resourceVpcEipID)
	if d.HasChange(resourceVpcSecurityGroupID) && !d.IsNewResource() {
		if err := applySecurityGroupRule(qc.String(resourceVpcSecurityGroupID), meta); err != nil {
			return err
		}
	}
	d.SetPartial(resourceVpcSecurityGroupID)
	if err := resourceUpdateTag(d, meta, qingcloudResourceTypeRouter); err != nil {
		return err
	}
	d.SetPartial(resourceTagIds)
	d.Partial(false)
	return resourceQingcloudVpcRead(d, meta)
}

func resourceQingcloudVpcDelete(d *schema.ResourceData, meta interface{}) error {
	clt := meta.(*QingCloudClient).router
	if _, err := RouterTransitionStateRefresh(clt, d.Id()); err != nil {
		return err
	}
	if err := waitRouterLease(d, meta); err != nil {
		return err
	}
	input := new(qc.DeleteRoutersInput)
	input.Routers = []*string{qc.String(d.Id())}
	var output *qc.DeleteRoutersOutput
	var err error
	simpleRetry(func() error {
		output, err = clt.DeleteRouters(input)
		return isServerBusy(err)
	})
	if err != nil {
		return err
	}
	if _, err := RouterTransitionStateRefresh(clt, d.Id()); err != nil {
		return err
	}
	d.SetId("")
	return nil
}
<commit_msg>add new ip range<commit_after>/**
 * Copyright (c) 2016 Magicshui
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */
/**
 * Copyright (c) 2017 yunify
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

package qingcloud

import (
	"fmt"

	"github.com/hashicorp/terraform/helper/schema"
	qc "github.com/yunify/qingcloud-sdk-go/service"
)

const (
	resourceVpcType            = "type"
	resourceVpcNetwork         = "vpc_network"
	resourceVpcEipID           = "eip_id"
	resourceVpcSecurityGroupID = "security_group_id"
	resourceVpcPrivateIP       = "private_ip"
	resourceVpcPublicIP        = "public_ip"
)

func resourceQingcloudVpc() *schema.Resource {
	return &schema.Resource{
		Create: resourceQingcloudVpcCreate,
		Read:   resourceQingcloudVpcRead,
		Update: resourceQingcloudVpcUpdate,
		Delete: resourceQingcloudVpcDelete,
		Schema: map[string]*schema.Schema{
			resourceName: &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},
			resourceVpcType: &schema.Schema{
				Type:         schema.TypeInt,
				Optional:     true,
				ForceNew:     true,
				Default:      1,
				ValidateFunc: withinArrayInt(0, 1, 2, 3),
			},
			resourceVpcNetwork: &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
				ValidateFunc: withinArrayString("192.168.0.0/16", "172.16.0.0/16", "172.17.0.0/16",
					"172.18.0.0/16", "172.19.0.0/16", "172.20.0.0/16", "172.21.0.0/16", "172.22.0.0/16",
					"172.23.0.0/16", "172.24.0.0/16", "172.25.0.0/16", "172.26.0.0/16", "172.27.0.0/16",
					"172.28.0.0/16", "172.29.0.0/16", "172.30.0.0/16", "172.31.0.0/16"),
			},
			resourceTagIds:   tagIdsSchema(),
			resourceTagNames: tagNamesSchema(),
			resourceVpcEipID: &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},
			resourceVpcSecurityGroupID: &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},
			resourceDescription: &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},
			resourceVpcPrivateIP: &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
			resourceVpcPublicIP: &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
		},
	}
}

// resourceQingcloudRouterCreate
func resourceQingcloudVpcCreate(d *schema.ResourceData, meta interface{}) error {
	clt := meta.(*QingCloudClient).router
	input := new(qc.CreateRoutersInput)
	input.RouterName, _ = getNamePointer(d)
	input.VpcNetwork = getSetStringPointer(d, resourceVpcNetwork)
	input.SecurityGroup = getSetStringPointer(d, resourceVpcSecurityGroupID)
	input.RouterType = qc.Int(d.Get(resourceVpcType).(int))
	input.Count = qc.Int(1)
	var output *qc.CreateRoutersOutput
	var err error
	simpleRetry(func() error {
		output, err = clt.CreateRouters(input)
		return isServerBusy(err)
	})
	if err != nil {
		return err
	}
	d.SetId(qc.StringValue(output.Routers[0]))
	if _, err = RouterTransitionStateRefresh(clt, d.Id()); err != nil {
		return fmt.Errorf("Error waiting for router (%s) to start: %s", d.Id(), err.Error())
	}
	return resourceQingcloudVpcUpdate(d, meta)
}

func resourceQingcloudVpcRead(d *schema.ResourceData, meta interface{}) error {
	clt := meta.(*QingCloudClient).router
	input := new(qc.DescribeRoutersInput)
	input.Routers = []*string{qc.String(d.Id())}
	input.Verbose = qc.Int(1)
	var output *qc.DescribeRoutersOutput
	var err error
	simpleRetry(func() error {
		output, err = clt.DescribeRouters(input)
		return isServerBusy(err)
	})
	if err != nil {
		return err
	}
	if isRouterDeleted(output.RouterSet) {
		d.SetId("")
		return nil
	}
	rtr := output.RouterSet[0]
	d.Set(resourceName, qc.StringValue(rtr.RouterName))
	d.Set(resourceVpcType, qc.IntValue(rtr.RouterType))
	d.Set(resourceVpcSecurityGroupID, qc.StringValue(rtr.SecurityGroupID))
	d.Set(resourceDescription, qc.StringValue(rtr.Description))
	d.Set(resourceVpcPrivateIP, qc.StringValue(rtr.PrivateIP))
	d.Set(resourceVpcEipID, qc.StringValue(rtr.EIP.EIPID))
	d.Set(resourceVpcPublicIP, qc.StringValue(rtr.EIP.EIPAddr))
	resourceSetTag(d, rtr.Tags)
	return nil
}

func resourceQingcloudVpcUpdate(d *schema.ResourceData, meta interface{}) error {
	clt := meta.(*QingCloudClient).router
	if _, err := RouterTransitionStateRefresh(clt, d.Id()); err != nil {
		return err
	}
	if err := waitRouterLease(d, meta); err != nil {
		return err
	}
	d.Partial(true)
	if err := modifyRouterAttributes(d, meta); err != nil {
		return err
	}
	d.SetPartial(resourceName)
	d.SetPartial(resourceDescription)
	if d.HasChange(resourceVpcEipID) {
		if err := applyRouterUpdate(qc.String(d.Id()), meta); err != nil {
			return err
		}
	}
	d.SetPartial(resourceVpcEipID)
	if d.HasChange(resourceVpcSecurityGroupID) && !d.IsNewResource() {
		if err := applySecurityGroupRule(qc.String(resourceVpcSecurityGroupID), meta); err != nil {
			return err
		}
	}
	d.SetPartial(resourceVpcSecurityGroupID)
	if err := resourceUpdateTag(d, meta, qingcloudResourceTypeRouter); err != nil {
		return err
	}
	d.SetPartial(resourceTagIds)
	d.Partial(false)
	return resourceQingcloudVpcRead(d, meta)
}

func resourceQingcloudVpcDelete(d *schema.ResourceData, meta interface{}) error {
	clt := meta.(*QingCloudClient).router
	if _, err := RouterTransitionStateRefresh(clt, d.Id()); err != nil {
		return err
	}
	if err := waitRouterLease(d, meta); err != nil {
		return err
	}
	input := new(qc.DeleteRoutersInput)
	input.Routers = []*string{qc.String(d.Id())}
	var output *qc.DeleteRoutersOutput
	var err error
	simpleRetry(func() error {
		output, err = clt.DeleteRouters(input)
		return isServerBusy(err)
	})
	if err != nil {
		return err
	}
	if _, err := RouterTransitionStateRefresh(clt, d.Id()); err != nil {
		return err
	}
	d.SetId("")
	return nil
}
<|endoftext|>


<commit_before>package metadata

import (
	"fmt"
	"time"

	"github.com/socialengine/rancher-cron/model"

	"github.com/Sirupsen/logrus"
	"github.com/rancher/go-rancher-metadata/metadata"
)

const (
	metadataURL = "http://rancher-metadata/latest"
)

// Client is a Struct that holds all metadata-specific data
type Client struct {
	MetadataClient  *metadata.Client
	EnvironmentName string
	CronLabelName   string
	Schedules       *model.Schedules
}

// NewClient creates a new metadata client
func NewClient(cronLabelName string) (*Client, error) {
	m, err := metadata.NewClientAndWait(metadataURL)
	if err != nil {
		logrus.Fatalf("Failed to configure rancher-metadata: %v", err)
	}

	envName, err := getEnvironmentName(m)
	if err != nil {
		logrus.Fatalf("Error reading stack info: %v", err)
	}

	schedules := make(model.Schedules)

	return &Client{
		MetadataClient:  m,
		EnvironmentName: envName,
		CronLabelName:   cronLabelName,
		Schedules:       &schedules,
	}, nil
}

// GetVersion grabs the version of metadata client we're using
func (m *Client) GetVersion() (string, error) {
	return m.MetadataClient.GetVersion()
}

// GetCronSchedules returns a map of schedules with ContainerUUID as a key
func (m *Client) GetCronSchedules() (*model.Schedules, error) {
	schedules := *m.Schedules
	services, err := m.MetadataClient.GetServices()

	if err != nil {
		logrus.Infof("Error reading services %v", err)
		return &schedules, err
	}

	markScheduleForCleanup(m.Schedules)

	for _, service := range services {
		cronExpression, ok := service.Labels[m.CronLabelName]
		if !ok {
			continue
		}
		containerUUID, err := m.getCronContainer(service)
		if err != nil {
			continue
		}

		existingSchedule, ok := schedules[containerUUID]
		// we already have schedule for this container
		if ok {
			// do not cleanup
			existingSchedule.ToCleanup = false

			logrus.WithFields(logrus.Fields{
				"uuid":           containerUUID,
				"cronExpression": cronExpression,
			}).Debugf("already have container")

			continue
		}
		//label exists, configure schedule
		schedule := model.NewSchedule()

		schedule.CronExpression = cronExpression
		schedule.ContainerUUID = containerUUID
		schedules[containerUUID] = schedule
	}

	return &schedules, nil
}

func (m *Client) getCronContainer(service metadata.Service) (string, error) {
	containers := service.Containers

	for _, container := range containers {
		if len(container.ServiceName) == 0 {
			continue
		}

		if len(service.Name) != 0 {
			if service.Name != container.ServiceName {
				continue
			}
			if service.StackName != container.StackName {
				continue
			}
		}

		return container.UUID, nil
	}

	return "", fmt.Errorf("could not find container UUID with %s", m.CronLabelName)
}

func markScheduleForCleanup(schedules *model.Schedules) {
	for _, schedule := range *schedules {
		schedule.ToCleanup = true
	}
}

func getEnvironmentName(m *metadata.Client) (string, error) {
	timeout := 30 * time.Second
	var err error
	var stack metadata.Stack
	for i := 1 * time.Second; i < timeout; i *= time.Duration(2) {
		stack, err = m.GetSelfStack()
		if err != nil {
			logrus.Errorf("Error reading stack info: %v...will retry", err)
			time.Sleep(i)
		} else {
			return stack.EnvironmentName, nil
		}
	}
	return "", fmt.Errorf("Error reading stack info: %v", err)
}
<commit_msg>Updates metadata to allow multiple containers to be registered per service. (#4)<commit_after>package metadata

import (
	"fmt"
	"time"

	"github.com/socialengine/rancher-cron/model"

	"github.com/Sirupsen/logrus"
	"github.com/rancher/go-rancher-metadata/metadata"
)

const (
	metadataURL = "http://rancher-metadata/latest"
)

// Client is a Struct that holds all metadata-specific data
type Client struct {
	MetadataClient  *metadata.Client
	EnvironmentName string
	CronLabelName   string
	Schedules       *model.Schedules
}

// NewClient creates a new metadata client
func NewClient(cronLabelName string) (*Client, error) {
	m, err := metadata.NewClientAndWait(metadataURL)
	if err != nil {
		logrus.Fatalf("Failed to configure rancher-metadata: %v", err)
	}

	envName, err := getEnvironmentName(m)
	if err != nil {
		logrus.Fatalf("Error reading stack info: %v", err)
	}

	schedules := make(model.Schedules)

	return &Client{
		MetadataClient:  m,
		EnvironmentName: envName,
		CronLabelName:   cronLabelName,
		Schedules:       &schedules,
	}, nil
}

// GetVersion grabs the version of metadata client we're using
func (m *Client) GetVersion() (string, error) {
	return m.MetadataClient.GetVersion()
}

// GetCronSchedules returns a map of schedules with ContainerUUID as a key
func (m *Client) GetCronSchedules() (*model.Schedules, error) {
	schedules := *m.Schedules
	services, err := m.MetadataClient.GetServices()

	if err != nil {
		logrus.Infof("Error reading services %v", err)
		return &schedules, err
	}

	markScheduleForCleanup(m.Schedules)

	for _, service := range services {
		cronExpression, ok := service.Labels[m.CronLabelName]
		if !ok {
			continue
		}
		containerUUIDs, err := m.getCronContainers(service)
		if err != nil {
			continue
		}

		for _, containerUUID := range containerUUIDs {
			existingSchedule, ok := schedules[containerUUID]
			// we already have schedule for this container
			if ok {
				// do not cleanup
				existingSchedule.ToCleanup = false

				logrus.WithFields(logrus.Fields{
					"uuid":           containerUUID,
					"cronExpression": cronExpression,
				}).Debugf("already have container")

				continue
			}
			//label exists, configure schedule
			schedule := model.NewSchedule()

			schedule.CronExpression = cronExpression
			schedule.ContainerUUID = containerUUID
			schedules[containerUUID] = schedule
		}
	}

	return &schedules, nil
}

func (m *Client) getCronContainers(service metadata.Service) ([]string, error) {
	containers := service.Containers
	var uuids []string

	for _, container := range containers {
		if len(container.ServiceName) == 0 {
			continue
		}

		if len(service.Name) != 0 {
			if service.Name != container.ServiceName {
				continue
			}
			if service.StackName != container.StackName {
				continue
			}
		}

		uuids = append(uuids, container.UUID)
	}

	if len(uuids) > 0 {
		return uuids, nil
	}

	return uuids, fmt.Errorf("could not find container UUID with %s", m.CronLabelName)
}

func markScheduleForCleanup(schedules *model.Schedules) {
	for _, schedule := range *schedules {
		schedule.ToCleanup = true
	}
}

func getEnvironmentName(m *metadata.Client) (string, error) {
	timeout := 30 * time.Second
	var err error
	var stack metadata.Stack
	for i := 1 * time.Second; i < timeout; i *= time.Duration(2) {
		stack, err = m.GetSelfStack()
		if err != nil {
			logrus.Errorf("Error reading stack info: %v...will retry", err)
			time.Sleep(i)
		} else {
			return stack.EnvironmentName, nil
		}
	}
	return "", fmt.Errorf("Error reading stack info: %v", err)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/gob"
	"fmt"

	//"github.com/dgryski/go-tsz"
	"github.com/raintank/go-tsz"
)

// Chunk is a chunk of data. not concurrency safe.
type Chunk struct {
	*tsz.Series
	T0        uint32
	LastTs    uint32
	NumPoints uint32
	Saved     bool
}

func NewChunk(t0 uint32) *Chunk {
	return &Chunk{tsz.New(t0), t0, 0, 0, false}
}

func (c *Chunk) String() string {
	return fmt.Sprintf("<chunk t0 at %s, %d points>", TS(c.T0), c.NumPoints)

}
func (c *Chunk) Push(t uint32, v float64) error {
	if t <= c.LastTs {
		return fmt.Errorf("Can't push points that are older then points already added. t:%d lastTs: %d", t.c.LastTs)
	}
	c.Series.Push(t, v)
	c.NumPoints += 1
	c.LastTs = t
	return nil
}

type chunkOnDisk struct {
	Series    *tsz.Series
	T0        uint32
	LastTs    uint32
	NumPoints uint32
	Saved     bool
}

func (c *Chunk) GobEncode() ([]byte, error) {
	// create an OnDisk format of our data.
	cOnDisk := chunkOnDisk{
		Series:    c.Series,
		T0:        c.T0,
		LastTs:    c.LastTs,
		NumPoints: c.NumPoints,
		Saved:     c.Saved,
	}
	var b bytes.Buffer
	enc := gob.NewEncoder(&b)
	err := enc.Encode(cOnDisk)
	return b.Bytes(), err
}

func (c *Chunk) GobDecode(data []byte) error {
	//decode our data bytes into our onDisk struct
	r := bytes.NewReader(data)
	dec := gob.NewDecoder(r)
	cOnDisk := &chunkOnDisk{}
	err := dec.Decode(cOnDisk)
	if err != nil {
		return err
	}

	// fill in the fields of the passed Chunk with the data from our OnDisk format.
	c.Series = cOnDisk.Series
	c.T0 = cOnDisk.T0
	c.LastTs = cOnDisk.LastTs
	c.NumPoints = cOnDisk.NumPoints
	c.Saved = cOnDisk.Saved

	return nil
}
<commit_msg>fix typo in chunk.go<commit_after>package main

import (
	"bytes"
	"encoding/gob"
	"fmt"

	//"github.com/dgryski/go-tsz"
	"github.com/raintank/go-tsz"
)

// Chunk is a chunk of data. not concurrency safe.
type Chunk struct {
	*tsz.Series
	T0        uint32
	LastTs    uint32
	NumPoints uint32
	Saved     bool
}

func NewChunk(t0 uint32) *Chunk {
	return &Chunk{tsz.New(t0), t0, 0, 0, false}
}

func (c *Chunk) String() string {
	return fmt.Sprintf("<chunk t0 at %s, %d points>", TS(c.T0), c.NumPoints)

}
func (c *Chunk) Push(t uint32, v float64) error {
	if t <= c.LastTs {
		return fmt.Errorf("Can't push points that are older then points already added. t:%d lastTs: %d", t, c.LastTs)
	}
	c.Series.Push(t, v)
	c.NumPoints += 1
	c.LastTs = t
	return nil
}

type chunkOnDisk struct {
	Series    *tsz.Series
	T0        uint32
	LastTs    uint32
	NumPoints uint32
	Saved     bool
}

func (c *Chunk) GobEncode() ([]byte, error) {
	// create an OnDisk format of our data.
	cOnDisk := chunkOnDisk{
		Series:    c.Series,
		T0:        c.T0,
		LastTs:    c.LastTs,
		NumPoints: c.NumPoints,
		Saved:     c.Saved,
	}
	var b bytes.Buffer
	enc := gob.NewEncoder(&b)
	err := enc.Encode(cOnDisk)
	return b.Bytes(), err
}

func (c *Chunk) GobDecode(data []byte) error {
	//decode our data bytes into our onDisk struct
	r := bytes.NewReader(data)
	dec := gob.NewDecoder(r)
	cOnDisk := &chunkOnDisk{}
	err := dec.Decode(cOnDisk)
	if err != nil {
		return err
	}

	// fill in the fields of the passed Chunk with the data from our OnDisk format.
	c.Series = cOnDisk.Series
	c.T0 = cOnDisk.T0
	c.LastTs = cOnDisk.LastTs
	c.NumPoints = cOnDisk.NumPoints
	c.Saved = cOnDisk.Saved

	return nil
}
<|endoftext|>