<commit_before>package flags

import (
	"testing"
	"time"
)

func expectConvert(t *testing.T, o *Option, expected string) {
	s, err := convertToString(o.value, o.tag)

	if err != nil {
		t.Errorf("Unexpected error: %v", err)
		return
	}

	assertString(t, s, expected)
}

func TestConvertToString(t *testing.T) {
	d, _ := time.ParseDuration("1h2m4s")

	var opts = struct {
		String string `long:"string"`

		Int   int   `long:"int"`
		Int8  int8  `long:"int8"`
		Int16 int16 `long:"int16"`
		Int32 int32 `long:"int32"`
		Int64 int64 `long:"int64"`

		Uint   uint   `long:"uint"`
		Uint8  uint8  `long:"uint8"`
		Uint16 uint16 `long:"uint16"`
		Uint32 uint32 `long:"uint32"`
		Uint64 uint64 `long:"uint64"`

		Float32 float32 `long:"float32"`
		Float64 float64 `long:"float64"`

		Duration time.Duration `long:"duration"`

		Bool bool `long:"bool"`

		IntSlice    []int           `long:"int-slice"`
		IntFloatMap map[int]float64 `long:"int-float-map"`

		PtrBool   *bool       `long:"ptr-bool"`
		Interface interface{} `long:"interface"`

		Int32Base  int32  `long:"int32-base" base:"16"`
		Uint32Base uint32 `long:"uint32-base" base:"16"`
	}{
		"string",

		-2,
		-1,
		0,
		1,
		2,

		1,
		2,
		3,
		4,
		5,

		1.2,
		-3.4,

		d,
		true,

		[]int{-3, 4, -2},
		map[int]float64{-2: 4.5, -3: 0.1},

		new(bool),
		float32(5.2),

		-5823,
		4232,
	}

	p := NewNamedParser("test", Default)
	grp, _ := p.AddGroup("test group", "", &opts)

	expects := []string{
		"string",
		"-2",
		"-1",
		"0",
		"1",
		"2",

		"1",
		"2",
		"3",
		"4",
		"5",

		"1.2",
		"-3.4",

		"1h2m4s",
		"true",

		"[-3, 4, -2]",
		"{-2:4.5, -3:0.1}",

		"false",
		"5.2",

		"-16bf",
		"1088",
	}

	for i, v := range grp.Options() {
		expectConvert(t, v, expects[i])
	}
}

func TestConvertToStringInvalidIntBase(t *testing.T) {
	var opts = struct {
		Int int `long:"int" base:"no"`
	}{
		2,
	}

	p := NewNamedParser("test", Default)
	grp, _ := p.AddGroup("test group", "", &opts)
	o := grp.Options()[0]

	_, err := convertToString(o.value, o.tag)

	if err != nil {
		err = newErrorf(ErrMarshal, "%v", err)
	}

	assertError(t, err, ErrMarshal, "strconv.ParseInt: parsing \"no\": invalid syntax")
}

func TestConvertToStringInvalidUintBase(t *testing.T) {
	var opts = struct {
		Uint uint `long:"uint" base:"no"`
	}{
		2,
	}

	p := NewNamedParser("test", Default)
	grp, _ := p.AddGroup("test group", "", &opts)
	o := grp.Options()[0]

	_, err := convertToString(o.value, o.tag)

	if err != nil {
		err = newErrorf(ErrMarshal, "%v", err)
	}

	assertError(t, err, ErrMarshal, "strconv.ParseInt: parsing \"no\": invalid syntax")
}

func TestWrapText(t *testing.T) {
	s := "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."

	got := wrapText(s, 60, "      ")
	expected := `Lorem ipsum dolor sit amet, consectetur adipisicing elit,
      sed do eiusmod tempor incididunt ut labore et dolore magna
      aliqua. Ut enim ad minim veniam, quis nostrud exercitation
      ullamco laboris nisi ut aliquip ex ea commodo consequat.
      Duis aute irure dolor in reprehenderit in voluptate velit
      esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
      occaecat cupidatat non proident, sunt in culpa qui officia
      deserunt mollit anim id est laborum.`

	if got != expected {
		ret, err := helpDiff(got, expected)

		if err != nil {
			t.Errorf("Unexpected wrapped text, expected:\n\n%s\n\nbut got\n\n%s", expected, got)
		} else {
			t.Errorf("Unexpected wrapped text:\n\n%s", ret)
		}
	}
}
<commit_msg>Cannot rely on order of map elements<commit_after>package flags

import (
	"testing"
	"time"
)

func expectConvert(t *testing.T, o *Option, expected string) {
	s, err := convertToString(o.value, o.tag)

	if err != nil {
		t.Errorf("Unexpected error: %v", err)
		return
	}

	assertString(t, s, expected)
}

func TestConvertToString(t *testing.T) {
	d, _ := time.ParseDuration("1h2m4s")

	var opts = struct {
		String string `long:"string"`

		Int   int   `long:"int"`
		Int8  int8  `long:"int8"`
		Int16 int16 `long:"int16"`
		Int32 int32 `long:"int32"`
		Int64 int64 `long:"int64"`

		Uint   uint   `long:"uint"`
		Uint8  uint8  `long:"uint8"`
		Uint16 uint16 `long:"uint16"`
		Uint32 uint32 `long:"uint32"`
		Uint64 uint64 `long:"uint64"`

		Float32 float32 `long:"float32"`
		Float64 float64 `long:"float64"`

		Duration time.Duration `long:"duration"`

		Bool bool `long:"bool"`

		IntSlice    []int           `long:"int-slice"`
		IntFloatMap map[int]float64 `long:"int-float-map"`

		PtrBool   *bool       `long:"ptr-bool"`
		Interface interface{} `long:"interface"`

		Int32Base  int32  `long:"int32-base" base:"16"`
		Uint32Base uint32 `long:"uint32-base" base:"16"`
	}{
		"string",

		-2,
		-1,
		0,
		1,
		2,

		1,
		2,
		3,
		4,
		5,

		1.2,
		-3.4,

		d,
		true,

		[]int{-3, 4, -2},
		map[int]float64{-2: 4.5},

		new(bool),
		float32(5.2),

		-5823,
		4232,
	}

	p := NewNamedParser("test", Default)
	grp, _ := p.AddGroup("test group", "", &opts)

	expects := []string{
		"string",
		"-2",
		"-1",
		"0",
		"1",
		"2",

		"1",
		"2",
		"3",
		"4",
		"5",

		"1.2",
		"-3.4",

		"1h2m4s",
		"true",

		"[-3, 4, -2]",
		"{-2:4.5}",

		"false",
		"5.2",

		"-16bf",
		"1088",
	}

	for i, v := range grp.Options() {
		expectConvert(t, v, expects[i])
	}
}

func TestConvertToStringInvalidIntBase(t *testing.T) {
	var opts = struct {
		Int int `long:"int" base:"no"`
	}{
		2,
	}

	p := NewNamedParser("test", Default)
	grp, _ := p.AddGroup("test group", "", &opts)
	o := grp.Options()[0]

	_, err := convertToString(o.value, o.tag)

	if err != nil {
		err = newErrorf(ErrMarshal, "%v", err)
	}

	assertError(t, err, ErrMarshal, "strconv.ParseInt: parsing \"no\": invalid syntax")
}

func TestConvertToStringInvalidUintBase(t *testing.T) {
	var opts = struct {
		Uint uint `long:"uint" base:"no"`
	}{
		2,
	}

	p := NewNamedParser("test", Default)
	grp, _ := p.AddGroup("test group", "", &opts)
	o := grp.Options()[0]

	_, err := convertToString(o.value, o.tag)

	if err != nil {
		err = newErrorf(ErrMarshal, "%v", err)
	}

	assertError(t, err, ErrMarshal, "strconv.ParseInt: parsing \"no\": invalid syntax")
}

func TestWrapText(t *testing.T) {
	s := "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."

	got := wrapText(s, 60, "      ")
	expected := `Lorem ipsum dolor sit amet, consectetur adipisicing elit,
      sed do eiusmod tempor incididunt ut labore et dolore magna
      aliqua. Ut enim ad minim veniam, quis nostrud exercitation
      ullamco laboris nisi ut aliquip ex ea commodo consequat.
      Duis aute irure dolor in reprehenderit in voluptate velit
      esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
      occaecat cupidatat non proident, sunt in culpa qui officia
      deserunt mollit anim id est laborum.`

	if got != expected {
		ret, err := helpDiff(got, expected)

		if err != nil {
			t.Errorf("Unexpected wrapped text, expected:\n\n%s\n\nbut got\n\n%s", expected, got)
		} else {
			t.Errorf("Unexpected wrapped text:\n\n%s", ret)
		}
	}
}
<|endoftext|>


<commit_before>package body

import (
	"encoding/json"
	"errors"
	"io"
	"net/http"

	"github.com/AlexanderChen1989/xrest"

	"golang.org/x/net/context"
)

type body struct {
	onError func(r *http.Request, err error)
	next    xrest.Handler
}

type readCloser struct {
	rc  io.ReadCloser
	bp  *body
	buf buffer
}

func newBody(onError func(r *http.Request, err error)) *body {
	return &body{onError: onError}
}

// New create new body plug
func New(onError func(r *http.Request, err error)) xrest.Plugger {
	return newBody(onError)
}

// ErrBodyNotPlugged body plug not plugged
var ErrBodyNotPlugged = errors.New("body not plugged")

// DecodeJSON decode json to interface from body
func DecodeJSON(ctx context.Context, v interface{}) error {
	data, ok := FetchBody(ctx)

	if !ok {
		return ErrBodyNotPlugged
	}

	return json.Unmarshal(data, v)
}

var ctxBodyKey uint8

// FetchBody fetch request body from context
func FetchBody(ctx context.Context) ([]byte, bool) {
	body, ok := ctx.Value(&ctxBodyKey).(buffer)
	return []byte(body), ok
}

func (bp *body) Plug(h xrest.Handler) xrest.Handler {
	bp.next = h
	return bp
}

func (bp *body) ServeHTTP(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	if _, ok := FetchBody(ctx); !ok {
		buf := getBuffer()
		defer buf.free()

		if _, err := io.Copy(&buf, r.Body); err != nil {
			if bp.onError != nil {
				bp.onError(r, err)
			}
		} else {
			ctx = context.WithValue(ctx, &ctxBodyKey, buf)
		}
	}

	bp.next.ServeHTTP(ctx, w, r)
	return
}
<commit_msg>deprecate body plug<commit_after>package body

import (
	"encoding/json"
	"errors"
	"io"
	"log"
	"net/http"

	"github.com/AlexanderChen1989/xrest"

	"golang.org/x/net/context"
)

func init() {
	log.Println("This plug is deprecated. Please use mapstruct plug.")
}

type body struct {
	onError func(r *http.Request, err error)
	next    xrest.Handler
}

type readCloser struct {
	rc  io.ReadCloser
	bp  *body
	buf buffer
}

func newBody(onError func(r *http.Request, err error)) *body {
	return &body{onError: onError}
}

// New create new body plug
func New(onError func(r *http.Request, err error)) xrest.Plugger {
	return newBody(onError)
}

// ErrBodyNotPlugged body plug not plugged
var ErrBodyNotPlugged = errors.New("body not plugged")

// DecodeJSON decode json to interface from body
func DecodeJSON(ctx context.Context, v interface{}) error {
	data, ok := FetchBody(ctx)

	if !ok {
		return ErrBodyNotPlugged
	}

	return json.Unmarshal(data, v)
}

var ctxBodyKey uint8

// FetchBody fetch request body from context
func FetchBody(ctx context.Context) ([]byte, bool) {
	body, ok := ctx.Value(&ctxBodyKey).(buffer)
	return []byte(body), ok
}

func (bp *body) Plug(h xrest.Handler) xrest.Handler {
	bp.next = h
	return bp
}

func (bp *body) ServeHTTP(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	if _, ok := FetchBody(ctx); !ok {
		buf := getBuffer()
		defer buf.free()

		if _, err := io.Copy(&buf, r.Body); err != nil {
			if bp.onError != nil {
				bp.onError(r, err)
			}
		} else {
			ctx = context.WithValue(ctx, &ctxBodyKey, buf)
		}
	}

	bp.next.ServeHTTP(ctx, w, r)
	return
}
<|endoftext|>


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

package cloud

import (
	"fmt"

	"github.com/juju/cmd"
	"github.com/juju/errors"
	"github.com/juju/utils/set"
	"launchpad.net/gnuflag"

	jujucloud "github.com/juju/juju/cloud"
	"github.com/juju/juju/environs"
	"github.com/juju/juju/jujuclient"
)

type detectCredentialsCommand struct {
	cmd.CommandBase
	out cmd.Output

	store jujuclient.CredentialStore

	// Replace, if true, existing credential information is overwritten.
	Replace bool

	// The cloud for which to load credentials.
	CloudName string
}

var detectCredentialsDoc = `
The autoload-credentials command looks for well known locations for supported clouds and
loads any credentials and default regions found into the Juju credentials store and makes
these available when bootstrapping new controllers.

The resulting credentials may be viewed with juju list-credentials.

The clouds for which credentials may be autoloaded are:

AWS
  Credentials and regions are located in:
    1. On Linux, $HOME/.aws/credentials and $HOME/.aws/config
    2. Environment variables AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY

GCE
  Credentials are located in:
    1. A JSON file whose path is specified by the GOOGLE_APPLICATION_CREDENTIALS environment variable
    2. A JSON file in a knowm location eg on Linux $HOME/.config/gcloud/application_default_credentials.json
  Default region is specified by the CLOUDSDK_COMPUTE_REGION environment variable.

OpenStack (see below)
  Credentials are located in:
    1. On Linux, $HOME/.novarc
    2. Environment variables OS_USERNAME, OS_PASSWORD, OS_TENANT_NAME

Some standard credentials locations may apply for more than one cloud. For example, there may be more than one
OpenStack cloud defined. In such cases, the cloud name may be specified and only credentials for that cloud are
searched, and when found, applied to that cloud specifically.

If the detected credentials contain labeled credential values which already exist, the --replace option
may be used to force the overwrite of any existing values. The --replace option is also used to specify
that any default region value is overwritten.

Example:
   juju autoload-credentials
   juju autoload-credentials rackspace
   juju autoload-credentials --replace

See Also:
   juju list-credentials
   juju add-credentials
`

// NewDetectCredentialsCommand returns a command to add credential information to credentials.yaml.
func NewDetectCredentialsCommand() cmd.Command {
	return &detectCredentialsCommand{
		store: jujuclient.NewFileCredentialStore(),
	}
}

func (c *detectCredentialsCommand) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "autoload-credentials",
		Purpose: "looks for cloud credentials and caches those for use by Juju when bootstrapping",
		Args:    "[<cloud-name>]",
		Doc:     detectCredentialsDoc,
	}
}

func (c *detectCredentialsCommand) SetFlags(f *gnuflag.FlagSet) {
	f.BoolVar(&c.Replace, "replace", false, "overwrite any existing credential information")
}

func (c *detectCredentialsCommand) Init(args []string) (err error) {
	if len(args) > 1 {
		return errors.New("Usage: juju autoload-credentials [--replace] [<cloud-name>]")
	}
	if len(args) == 1 {
		c.CloudName = args[0]
	}
	return nil
}

// TODO(wallyworld) - temporary only, we'll add prompting as per spec and this will go away
// unambiguousClouds represents those clouds for which we will detect credentials
// without user disambiguation.
var unambiguousClouds = []string{"aws", "azure", "google", "joyent", "cloudsigma"}

func (c *detectCredentialsCommand) Run(ctxt *cmd.Context) error {
	ctxt.Verbosef("Looking for cloud and credential information locally...")
	clouds, _, err := jujucloud.PublicCloudMetadata(jujucloud.JujuPublicCloudsPath())
	if err != nil {
		return err
	}
	personalClouds, err := jujucloud.PersonalCloudMetadata()
	if err != nil {
		return err
	}
	for k, v := range personalClouds {
		clouds[k] = v
	}
	okClouds := set.NewStrings(unambiguousClouds...)
	for cloudName, cloud := range clouds {
		if c.CloudName != "" && c.CloudName != cloudName {
			continue
		} else if c.CloudName == "" && !okClouds.Contains(cloudName) {
			continue
		}
		provider, err := environs.Provider(cloud.Type)
		if err != nil {
			// Should never happen but it will on go 1.2
			// because lxd provider is not built.
			logger.Warningf("cloud %q not available on this platform", cloud.Type)
			continue
		}
		if detectCredentials, ok := provider.(environs.ProviderCredentials); ok {
			detected, err := detectCredentials.DetectCredentials()
			if err != nil && !errors.IsNotFound(err) {
				logger.Warningf("could not detect credentials for %q: %v", cloudName, err)
				continue
			}
			if errors.IsNotFound(err) || len(detected.AuthCredentials) == 0 {
				continue
			}
			credentials, err := c.store.CredentialForCloud(cloudName)
			if err != nil && !errors.IsNotFound(err) {
				return errors.Trace(err)
			}
			if !c.Replace && err == nil {
				existingCredNames := set.NewStrings()
				for n := range credentials.AuthCredentials {
					existingCredNames.Add(n)
				}
				newCredNames := set.NewStrings()
				for n, cred := range detected.AuthCredentials {
					if cred.AuthType() == jujucloud.EmptyAuthType {
						continue
					}
					newCredNames.Add(credentialLabel(n))
				}
				wouldBeOverwriten := existingCredNames.Intersection(newCredNames)
				if !wouldBeOverwriten.IsEmpty() {
					fmt.Fprintf(ctxt.Stdout,
						"Detected credentials %v would overwrite existing credentials for cloud %s.\nUse the --replace option.\n",
						wouldBeOverwriten.Values(), cloudName)
					return nil
				}
			}
			for name := range detected.AuthCredentials {
				credName := credentialLabel(name)
				fmt.Fprintf(ctxt.Stdout, "%s cloud credential %q found\n", cloudName, credName)
			}
			if credentials == nil {
				credentials = detected
			} else {
				for name, cred := range detected.AuthCredentials {
					credName := credentialLabel(name)
					credentials.AuthCredentials[credName] = cred
				}
			}
			if (c.Replace || credentials.DefaultRegion == "") && detected.DefaultRegion != "" {
				credentials.DefaultRegion = detected.DefaultRegion
			}
			if err := c.store.UpdateCredential(cloudName, *credentials); err != nil {
				return errors.Annotatef(err, "cannot add credentials for cloud %q", cloudName)
			}
		}
	}
	return nil
}

func credentialLabel(name string) string {
	if name != "" {
		return name
	}
	return "default"
}
<commit_msg>Disallow credentials with empty names<commit_after>// Copyright 2016 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package cloud

import (
	"fmt"

	"github.com/juju/cmd"
	"github.com/juju/errors"
	"github.com/juju/utils/set"
	"launchpad.net/gnuflag"

	jujucloud "github.com/juju/juju/cloud"
	"github.com/juju/juju/environs"
	"github.com/juju/juju/jujuclient"
)

type detectCredentialsCommand struct {
	cmd.CommandBase
	out cmd.Output

	store jujuclient.CredentialStore

	// Replace, if true, existing credential information is overwritten.
	Replace bool

	// The cloud for which to load credentials.
	CloudName string
}

var detectCredentialsDoc = `
The autoload-credentials command looks for well known locations for supported clouds and
loads any credentials and default regions found into the Juju credentials store and makes
these available when bootstrapping new controllers.

The resulting credentials may be viewed with juju list-credentials.

The clouds for which credentials may be autoloaded are:

AWS
  Credentials and regions are located in:
    1. On Linux, $HOME/.aws/credentials and $HOME/.aws/config
    2. Environment variables AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY

GCE
  Credentials are located in:
    1. A JSON file whose path is specified by the GOOGLE_APPLICATION_CREDENTIALS environment variable
    2. A JSON file in a knowm location eg on Linux $HOME/.config/gcloud/application_default_credentials.json
  Default region is specified by the CLOUDSDK_COMPUTE_REGION environment variable.

OpenStack (see below)
  Credentials are located in:
    1. On Linux, $HOME/.novarc
    2. Environment variables OS_USERNAME, OS_PASSWORD, OS_TENANT_NAME

Some standard credentials locations may apply for more than one cloud. For example, there may be more than one
OpenStack cloud defined. In such cases, the cloud name may be specified and only credentials for that cloud are
searched, and when found, applied to that cloud specifically.

If the detected credentials contain labeled credential values which already exist, the --replace option
may be used to force the overwrite of any existing values. The --replace option is also used to specify
that any default region value is overwritten.

Example:
   juju autoload-credentials
   juju autoload-credentials rackspace
   juju autoload-credentials --replace

See Also:
   juju list-credentials
   juju add-credentials
`

// NewDetectCredentialsCommand returns a command to add credential information to credentials.yaml.
func NewDetectCredentialsCommand() cmd.Command {
	return &detectCredentialsCommand{
		store: jujuclient.NewFileCredentialStore(),
	}
}

func (c *detectCredentialsCommand) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "autoload-credentials",
		Purpose: "looks for cloud credentials and caches those for use by Juju when bootstrapping",
		Args:    "[<cloud-name>]",
		Doc:     detectCredentialsDoc,
	}
}

func (c *detectCredentialsCommand) SetFlags(f *gnuflag.FlagSet) {
	f.BoolVar(&c.Replace, "replace", false, "overwrite any existing credential information")
}

func (c *detectCredentialsCommand) Init(args []string) (err error) {
	if len(args) > 1 {
		return errors.New("Usage: juju autoload-credentials [--replace] [<cloud-name>]")
	}
	if len(args) == 1 {
		c.CloudName = args[0]
	}
	return nil
}

// TODO(wallyworld) - temporary only, we'll add prompting as per spec and this will go away
// unambiguousClouds represents those clouds for which we will detect credentials
// without user disambiguation.
var unambiguousClouds = []string{"aws", "azure", "google", "joyent", "cloudsigma"}

func (c *detectCredentialsCommand) Run(ctxt *cmd.Context) error {
	ctxt.Verbosef("Looking for cloud and credential information locally...")
	clouds, _, err := jujucloud.PublicCloudMetadata(jujucloud.JujuPublicCloudsPath())
	if err != nil {
		return err
	}
	personalClouds, err := jujucloud.PersonalCloudMetadata()
	if err != nil {
		return err
	}
	for k, v := range personalClouds {
		clouds[k] = v
	}
	okClouds := set.NewStrings(unambiguousClouds...)
	for cloudName, cloud := range clouds {
		if c.CloudName != "" && c.CloudName != cloudName {
			continue
		} else if c.CloudName == "" && !okClouds.Contains(cloudName) {
			continue
		}
		provider, err := environs.Provider(cloud.Type)
		if err != nil {
			// Should never happen but it will on go 1.2
			// because lxd provider is not built.
			logger.Warningf("cloud %q not available on this platform", cloud.Type)
			continue
		}
		if detectCredentials, ok := provider.(environs.ProviderCredentials); ok {
			detected, err := detectCredentials.DetectCredentials()
			if err != nil && !errors.IsNotFound(err) {
				logger.Warningf("could not detect credentials for %q: %v", cloudName, err)
				continue
			}
			if errors.IsNotFound(err) || len(detected.AuthCredentials) == 0 {
				continue
			}
			credentials, err := c.store.CredentialForCloud(cloudName)
			if err != nil && !errors.IsNotFound(err) {
				return errors.Trace(err)
			}
			if !c.Replace && err == nil {
				existingCredNames := set.NewStrings()
				for name := range credentials.AuthCredentials {
					existingCredNames.Add(name)
				}
				newCredNames := set.NewStrings()
				for n, cred := range detected.AuthCredentials {
					if n == "" || cred.AuthType() == jujucloud.EmptyAuthType {
						continue
					}
					newCredNames.Add(n)
				}
				wouldBeOverwriten := existingCredNames.Intersection(newCredNames)
				if !wouldBeOverwriten.IsEmpty() {
					fmt.Fprintf(ctxt.Stdout,
						"Detected credentials %v would overwrite existing credentials for cloud %s.\nUse the --replace option.\n",
						wouldBeOverwriten.Values(), cloudName)
					return nil
				}
			}
			for name := range detected.AuthCredentials {
				if name == "" {
					logger.Warningf("ignoring unnamed credential for clous %s", cloudName)
					continue
				}
				fmt.Fprintf(ctxt.Stdout, "%s cloud credential %q found\n", cloudName, name)
			}
			if credentials == nil {
				credentials = detected
			} else {
				for name, cred := range detected.AuthCredentials {
					if name == "" {
						continue
					}
					credentials.AuthCredentials[name] = cred
				}
			}
			if (c.Replace || credentials.DefaultRegion == "") && detected.DefaultRegion != "" {
				credentials.DefaultRegion = detected.DefaultRegion
			}
			if err := c.store.UpdateCredential(cloudName, *credentials); err != nil {
				return errors.Annotatef(err, "cannot add credentials for cloud %q", cloudName)
			}
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package metadata

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"reflect"
	"strings"
	"sync"
	"time"

	"github.com/StackExchange/scollector/opentsdb"
	"github.com/StackExchange/scollector/util"
	"github.com/StackExchange/slog"
)

type RateType int

const (
	Unknown RateType = iota
	Gauge
	Counter
	Rate
)

type Unit int

const (
	None Unit = iota
	Byte
)

type Metakey struct {
	Metric string
	Tags   string
	Name   string
}

func (m Metakey) TagSet() opentsdb.TagSet {
	tags, err := opentsdb.ParseTags(m.Tags)
	if err != nil {
		return nil
	}
	return tags
}

var (
	metadata     = make(map[Metakey]interface{})
	metalock     sync.Mutex
	metainterval = time.Second * 2
	metahost     string
	metafuncs    []func()
)

func AddMeta(metric string, tags opentsdb.TagSet, name string, value interface{}, setHost bool) {
	if tags == nil {
		tags = make(opentsdb.TagSet)
	}
	if _, present := tags["host"]; setHost && !present {
		tags["host"] = util.Hostname
	}
	ts := tags.Tags()
	metalock.Lock()
	defer metalock.Unlock()
	prev, present := metadata[Metakey{metric, ts, name}]
	if !reflect.DeepEqual(prev, value) && present {
		slog.Infof("metadata changed for %s/%s/%s: %v to %v", metric, ts, name, prev, value)
	}
	metadata[Metakey{metric, ts, name}] = value
}

func Init(host string) {
	metahost = host
	go collectMetadata()
}

func collectMetadata() {
	for _ = range time.Tick(metainterval) {
		for _, f := range metafuncs {
			f()
		}
		sendMetadata()
	}
}

func init() {
	metafuncs = append(metafuncs, collectMetadataOmreport)
}

func collectMetadataOmreport() {
	util.ReadCommand(func(line string) {
		fields := strings.Split(line, ";")
		if len(fields) != 2 {
			return
		}
		switch fields[0] {
		case "Chassis Service Tag":
			AddMeta("", nil, "svctag", fields[1], true)
		case "Chassis Model":
			AddMeta("", nil, "model", fields[1], true)
		}
	}, "omreport", "chassis", "info", "-fmt", "ssv")
}

type Metasend struct {
	Metric string `json:",omitempty"`
	Tags   string `json:",omitempty"`
	Name   string `json:",omitempty"`
	Value  interface{}
}

func sendMetadata() {
	metalock.Lock()
	if len(metadata) == 0 {
		metalock.Unlock()
		return
	}
	ms := make([]Metasend, len(metadata))
	i := 0
	for k, v := range metadata {
		ms[i] = Metasend{
			Metric: k.Metric,
			Tags:   k.Tags,
			Name:   k.Name,
			Value:  v,
		}
		i++
	}
	metalock.Unlock()
	b, err := json.MarshalIndent(&ms, "", "  ")
	if err != nil {
		slog.Error(err)
		return
	}
	resp, err := http.Post(fmt.Sprintf("http://%s/api/metadata/put", metahost), "application/json", bytes.NewBuffer(b))
	if err != nil {
		slog.Error(err)
		return
	}
	if resp.StatusCode != 204 {
		slog.Error("bad metadata return:", resp.Status)
		return
	}
}
<commit_msg>cmd/scollector: Send metadata each hour<commit_after>package metadata

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"reflect"
	"strings"
	"sync"
	"time"

	"github.com/StackExchange/scollector/opentsdb"
	"github.com/StackExchange/scollector/util"
	"github.com/StackExchange/slog"
)

type RateType int

const (
	Unknown RateType = iota
	Gauge
	Counter
	Rate
)

type Unit int

const (
	None Unit = iota
	Byte
)

type Metakey struct {
	Metric string
	Tags   string
	Name   string
}

func (m Metakey) TagSet() opentsdb.TagSet {
	tags, err := opentsdb.ParseTags(m.Tags)
	if err != nil {
		return nil
	}
	return tags
}

var (
	metadata  = make(map[Metakey]interface{})
	metalock  sync.Mutex
	metahost  string
	metafuncs []func()
)

func AddMeta(metric string, tags opentsdb.TagSet, name string, value interface{}, setHost bool) {
	if tags == nil {
		tags = make(opentsdb.TagSet)
	}
	if _, present := tags["host"]; setHost && !present {
		tags["host"] = util.Hostname
	}
	ts := tags.Tags()
	metalock.Lock()
	defer metalock.Unlock()
	prev, present := metadata[Metakey{metric, ts, name}]
	if !reflect.DeepEqual(prev, value) && present {
		slog.Infof("metadata changed for %s/%s/%s: %v to %v", metric, ts, name, prev, value)
	}
	metadata[Metakey{metric, ts, name}] = value
}

func Init(host string) {
	metahost = host
	go collectMetadata()
}

func collectMetadata() {
	// Wait a bit to seed metric unit data.
	time.Sleep(time.Second * 5)
	for {
		for _, f := range metafuncs {
			f()
		}
		sendMetadata()
		time.Sleep(time.Hour)
	}
}

func init() {
	metafuncs = append(metafuncs, collectMetadataOmreport)
}

func collectMetadataOmreport() {
	util.ReadCommand(func(line string) {
		fields := strings.Split(line, ";")
		if len(fields) != 2 {
			return
		}
		switch fields[0] {
		case "Chassis Service Tag":
			AddMeta("", nil, "svctag", fields[1], true)
		case "Chassis Model":
			AddMeta("", nil, "model", fields[1], true)
		}
	}, "omreport", "chassis", "info", "-fmt", "ssv")
}

type Metasend struct {
	Metric string `json:",omitempty"`
	Tags   string `json:",omitempty"`
	Name   string `json:",omitempty"`
	Value  interface{}
}

func sendMetadata() {
	metalock.Lock()
	if len(metadata) == 0 {
		metalock.Unlock()
		return
	}
	ms := make([]Metasend, len(metadata))
	i := 0
	for k, v := range metadata {
		ms[i] = Metasend{
			Metric: k.Metric,
			Tags:   k.Tags,
			Name:   k.Name,
			Value:  v,
		}
		i++
	}
	metalock.Unlock()
	b, err := json.MarshalIndent(&ms, "", "  ")
	if err != nil {
		slog.Error(err)
		return
	}
	resp, err := http.Post(fmt.Sprintf("http://%s/api/metadata/put", metahost), "application/json", bytes.NewBuffer(b))
	if err != nil {
		slog.Error(err)
		return
	}
	if resp.StatusCode != 204 {
		slog.Error("bad metadata return:", resp.Status)
		return
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"os"

	"github.com/anacrolix/envpprof"
	"github.com/anacrolix/tagflag"
	"github.com/anacrolix/torrent/metainfo"
	"github.com/bradfitz/iter"
)

var flags struct {
	JustName    bool
	PieceHashes bool
	Files       bool
	tagflag.StartPos
}

func processReader(r io.Reader) error {
	metainfo, err := metainfo.Load(r)
	if err != nil {
		return err
	}
	info, err := metainfo.UnmarshalInfo()
	if err != nil {
		return fmt.Errorf("error unmarshalling info: %s", err)
	}
	if flags.JustName {
		fmt.Printf("%s\n", info.Name)
		return nil
	}
	d := map[string]interface{}{
		"Name":         info.Name,
		"NumPieces":    info.NumPieces(),
		"PieceLength":  info.PieceLength,
		"InfoHash":     metainfo.HashInfoBytes().HexString(),
		"NumFiles":     len(info.UpvertedFiles()),
		"TotalLength":  info.TotalLength(),
		"Announce":     metainfo.Announce,
		"AnnounceList": metainfo.AnnounceList,
		"UrlList":      metainfo.UrlList,
	}
	if flags.Files {
		d["Files"] = info.Files
	}
	if flags.PieceHashes {
		d["PieceHashes"] = func() (ret []string) {
			for i := range iter.N(info.NumPieces()) {
				ret = append(ret, hex.EncodeToString(info.Pieces[i*20:(i+1)*20]))
			}
			return
		}()
	}
	b, _ := json.MarshalIndent(d, "", "  ")
	_, err = os.Stdout.Write(b)
	return err
}

func main() {
	defer envpprof.Stop()
	tagflag.Parse(&flags)
	err := processReader(bufio.NewReader(os.Stdin))
	if err != nil {
		log.Fatal(err)
	}
	if !flags.JustName {
		os.Stdout.WriteString("\n")
	}
}
<commit_msg>cmd/torrent-metainfo-pprint: Fix -files for single-file torrents<commit_after>package main

import (
	"bufio"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"os"

	"github.com/anacrolix/envpprof"
	"github.com/anacrolix/tagflag"
	"github.com/anacrolix/torrent/metainfo"
	"github.com/bradfitz/iter"
)

var flags struct {
	JustName    bool
	PieceHashes bool
	Files       bool
	tagflag.StartPos
}

func processReader(r io.Reader) error {
	metainfo, err := metainfo.Load(r)
	if err != nil {
		return err
	}
	info, err := metainfo.UnmarshalInfo()
	if err != nil {
		return fmt.Errorf("error unmarshalling info: %s", err)
	}
	if flags.JustName {
		fmt.Printf("%s\n", info.Name)
		return nil
	}
	d := map[string]interface{}{
		"Name":         info.Name,
		"NumPieces":    info.NumPieces(),
		"PieceLength":  info.PieceLength,
		"InfoHash":     metainfo.HashInfoBytes().HexString(),
		"NumFiles":     len(info.UpvertedFiles()),
		"TotalLength":  info.TotalLength(),
		"Announce":     metainfo.Announce,
		"AnnounceList": metainfo.AnnounceList,
		"UrlList":      metainfo.UrlList,
	}
	if flags.Files {
		d["Files"] = info.UpvertedFiles()
	}
	if flags.PieceHashes {
		d["PieceHashes"] = func() (ret []string) {
			for i := range iter.N(info.NumPieces()) {
				ret = append(ret, hex.EncodeToString(info.Pieces[i*20:(i+1)*20]))
			}
			return
		}()
	}
	b, _ := json.MarshalIndent(d, "", "  ")
	_, err = os.Stdout.Write(b)
	return err
}

func main() {
	defer envpprof.Stop()
	tagflag.Parse(&flags)
	err := processReader(bufio.NewReader(os.Stdin))
	if err != nil {
		log.Fatal(err)
	}
	if !flags.JustName {
		os.Stdout.WriteString("\n")
	}
}
<|endoftext|>


<commit_before>/*
 * 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 (
	"bytes"
	"context"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	exec "github.com/mesos/mesos-go/executor"
	mesos "github.com/mesos/mesos-go/mesosproto"
	log "github.com/sirupsen/logrus"

	"github.com/paypal/dce-go/config"
	"github.com/paypal/dce-go/dce/monitor"
	"github.com/paypal/dce-go/plugin"
	_ "github.com/paypal/dce-go/plugin/example"
	_ "github.com/paypal/dce-go/plugin/general"
	"github.com/paypal/dce-go/types"
	"github.com/paypal/dce-go/utils"
	fileUtils "github.com/paypal/dce-go/utils/file"
	"github.com/paypal/dce-go/utils/pod"
	"github.com/paypal/dce-go/utils/wait"
)

var logger *log.Entry
var extpoints []plugin.ComposePlugin

type dockerComposeExecutor struct {
	tasksLaunched int
}

func newDockerComposeExecutor() *dockerComposeExecutor {
	return &dockerComposeExecutor{tasksLaunched: 0}
}

func (exec *dockerComposeExecutor) Registered(driver exec.ExecutorDriver, execInfo *mesos.ExecutorInfo, fwinfo *mesos.FrameworkInfo, slaveInfo *mesos.SlaveInfo) {
	fmt.Println("====================Mesos Registered====================")
	fmt.Println("Mesos Register : Registered Executor on slave ", slaveInfo.GetHostname())
	pod.ComposeExcutorDriver = driver
}

func (exec *dockerComposeExecutor) Reregistered(driver exec.ExecutorDriver, slaveInfo *mesos.SlaveInfo) {
	fmt.Println("====================Mesos Reregistered====================")
	fmt.Println("Mesos Re-registered Re-registered : Executor on slave ", slaveInfo.GetHostname())
}

func (exec *dockerComposeExecutor) Disconnected(exec.ExecutorDriver) {
	fmt.Println("====================Mesos Disconnected====================")
	fmt.Println("Mesos Disconnected : Mesos Executordisconnected.")
}

func (exec *dockerComposeExecutor) LaunchTask(driver exec.ExecutorDriver, taskInfo *mesos.TaskInfo) {
	fmt.Println("====================Mesos LaunchTask====================")
	pod.ComposeExcutorDriver = driver

	log.Infof("Task DataByte: %v", taskInfo.Data)
	n := len(taskInfo.Data)
	log.Infof("Task Data: %v",string(taskInfo.Data[:n]))
	var taskData map[string]interface{}
	if err := json.Unmarshal(taskInfo.Data,&taskData); err != nil{
		log.Infof("Task Data: Can not read task data %v",err)
	}else{
		log.Infof("Task Data: %v", taskData)
	}
	task, err := json.Marshal(taskInfo)
	if err != nil {
		log.Println("Error marshalling taskInfo", err.Error())
	}
	buf := new(bytes.Buffer)
	json.Indent(buf, task, "", " ")
	fmt.Println("taskInfo : ", buf)

	isService := pod.IsService(taskInfo)
	fmt.Printf("task is service: %v\n", isService)
	config.GetConfig().Set(types.IS_SERVICE, isService)

	logger = log.WithFields(log.Fields{
		"requuid":   pod.GetLabel("requuid", taskInfo),
		"tenant":    pod.GetLabel("tenant", taskInfo),
		"namespace": pod.GetLabel("namespace", taskInfo),
		"pool":      pod.GetLabel("pool", taskInfo),
	})

	pod.ComposeTaskInfo = taskInfo
	executorId := taskInfo.GetExecutor().GetExecutorId().GetValue()

	// Update pod status to STARTING
	pod.SetPodStatus(types.POD_STARTING)

	// Update mesos state TO STARTING
	pod.SendMesosStatus(driver, taskInfo.GetTaskId(), mesos.TaskState_TASK_STARTING.Enum())

	// Get required compose file list
	pod.ComposeFiles, _ = fileUtils.GetFiles(taskInfo)

	// Generate app folder to keep temp files
	err = fileUtils.GenerateAppFolder()
	if err != nil {
		logger.Errorln("Error creating app folder")
	}

	// Create context with timeout
	// Wait for pod launching until timeout
	var ctx context.Context
	var cancel context.CancelFunc
	ctx = context.Background()
	ctx, cancel = context.WithTimeout(ctx, config.GetLaunchTimeout()*time.Millisecond)
	go pod.WaitOnPod(&ctx)

	// Get order of plugins from config or mesos labels
	pluginOrder, err := fileUtils.GetPluginOrder(taskInfo)
	if err != nil {
		logger.Println("Plugin order missing in mesos label, trying to get it from config")
		pluginOrder = strings.Split(config.GetConfigSection("plugins")[types.PLUGIN_ORDER], ",")
	}
	pod.PluginOrder = pluginOrder
	logger.Println("PluginOrder : ", pluginOrder)

	// Select plugin extension points from plugin pools
	extpoints = plugin.GetOrderedExtpoints(pluginOrder)

	// Executing PreLaunchTask in order
	_, err = utils.PluginPanicHandler(utils.ConditionFunc(func() (string, error) {
		for i, ext := range extpoints {
			if ext == nil {
				logger.Errorln("Error getting plugins from plugin registration pools")
				return "", errors.New("plugin is nil")
			}
			err = ext.PreLaunchTask(&ctx, &pod.ComposeFiles, executorId, taskInfo)
			if err != nil {
				logger.Errorf("Error executing PreLaunchTask of plugin : %v\n", err)
				return "", err
			}
			if config.EnableComposeTrace() {
				fileUtils.DumpPluginModifiedComposeFiles(ctx, pluginOrder[i], i)
			}
		}
		return "", err
	}))
	if err != nil {
		pod.SetPodStatus(types.POD_FAILED)
		cancel()
		pod.SendMesosStatus(driver, taskInfo.GetTaskId(), mesos.TaskState_TASK_FAILED.Enum())
		return
	}

	// Service list from all compose files
	podServices := getServices(ctx)
	logger.Printf("pod service list: %v", podServices)

	// Write updated compose files into pod folder
	err = fileUtils.WriteChangeToFiles(ctx)
	if err != nil {
		logger.Errorf("Failure writing updated compose files : %v", err)
		pod.SetPodStatus(types.POD_FAILED)
		cancel()
		pod.SendMesosStatus(driver, taskInfo.GetTaskId(), mesos.TaskState_TASK_FAILED.Enum())
	}

	// Pulling image and launch pod
	replyPodStatus := pullAndLaunchPod()

	logger.Printf("Pod status returned by pullAndLaunchPod : %v", replyPodStatus)

	// Take an action depends on different status
	switch replyPodStatus {
	case types.POD_FAILED:
		cancel()
		pod.SendPodStatus(types.POD_FAILED)

	case types.POD_PULL_FAILED:
		cancel()
		pod.SendPodStatus(types.POD_PULL_FAILED)

	case types.POD_STARTING:
		// Initial health check
		res, err := initHealthCheck(podServices)
		if err != nil || res == types.POD_FAILED {
			cancel()
			pod.SendPodStatus(types.POD_FAILED)
		}

		// Temp status keeps the pod status returned by PostLaunchTask
		tempStatus, err := utils.PluginPanicHandler(utils.ConditionFunc(func() (string, error) {
			var tempStatus string
			for _, ext := range extpoints {
				logger.Println("Executing post launch task plugin")

				tempStatus, err = ext.PostLaunchTask(&ctx, pod.ComposeFiles, taskInfo)
				if err != nil {
					logger.Errorf("Error executing PostLaunchTask : %v", err)
				}
				logger.Printf("Get pod status : %s returned by PostLaunchTask", tempStatus)

				if tempStatus == types.POD_FAILED {
					return tempStatus, nil
				}
			}
			return tempStatus, nil
		}))
		if err != nil {
			logger.Errorf("Error executing PostLaunchTask : %v", err)
		}
		if tempStatus == types.POD_FAILED {
			cancel()
			pod.SendPodStatus(types.POD_FAILED)
		}

		if res == types.POD_RUNNING {
			cancel()
			if pod.GetPodStatus() != types.POD_RUNNING {
				pod.SendPodStatus(types.POD_RUNNING)
				go monitor.MonitorPoller()
			}
		}

		//For adhoc job, send finished to mesos if job already finished during init health check
		if res == types.POD_FINISHED {
			cancel()
			pod.SendPodStatus(types.POD_FINISHED)
		}

	default:
		logger.Printf("default: Unknown status -- %s from pullAndLaunchPod ", replyPodStatus)

	}

	logger.Println("====================Mesos LaunchTask Returned====================")
}

func (exec *dockerComposeExecutor) KillTask(driver exec.ExecutorDriver, taskId *mesos.TaskID) {
	log.Println("====================Mesos KillTask====================")

	logKill := log.WithFields(log.Fields{
		"taskId": taskId,
	})

	status := pod.GetPodStatus()
	switch status {
	case types.POD_FAILED:
		logKill.Printf("Mesos Kill Task : Current task status is %s , ignore killTask", status)

	case types.POD_RUNNING:
		logKill.Printf("Mesos Kill Task : Current task status is %s , continue killTask", status)
		pod.SetPodStatus(types.POD_KILLED)

		err := pod.StopPod(pod.ComposeFiles)
		if err != nil {
			logKill.Errorf("Error cleaning up pod : %v", err.Error())
		}

		err = pod.SendMesosStatus(driver, taskId, mesos.TaskState_TASK_KILLED.Enum())
		if err != nil {
			logKill.Errorf("Error during kill Task : %v", err.Error())
		}

		log.Println("====================Stop ExecutorDriver====================")
		time.Sleep(200 * time.Millisecond)
		driver.Stop()

	}

	logKill.Println("====================Mesos KillTask Stopped====================")
}

func (exec *dockerComposeExecutor) FrameworkMessage(driver exec.ExecutorDriver, msg string) {
	fmt.Printf("Got framework message: %v\n", msg)
}

func (exec *dockerComposeExecutor) Shutdown(driver exec.ExecutorDriver) {
	// Execute shutdown plugin extensions in order
	for _, ext := range extpoints {
		ext.Shutdown(pod.ComposeExcutorDriver)
	}
	fmt.Println("====================Stop ExecutorDriver====================")
	driver.Stop()
}

func (exec *dockerComposeExecutor) Error(driver exec.ExecutorDriver, err string) {
	fmt.Printf("Got error message : %v\n", err)
}

func pullAndLaunchPod() string {
	logger.Println("====================Pod Pull And Launch====================")

	if !config.SkipPullImages() {
		err := wait.PollRetry(config.GetPullRetryCount(), time.Duration(config.GetPollInterval())*time.Millisecond, wait.ConditionFunc(func() (string, error) {
			return "", pod.PullImage(pod.ComposeFiles)
		}))

		if err != nil {
			logger.Printf("POD_IMAGE_PULL_FAILED -- %v", err)
			return types.POD_PULL_FAILED
		}
	}

	return pod.LaunchPod(pod.ComposeFiles)
}

func initHealthCheck(podServices map[string]bool) (string, error) {
	res, err := wait.WaitUntil(config.GetLaunchTimeout()*time.Millisecond, wait.ConditionCHFunc(func(healthCheckReply chan string) {
		pod.HealthCheck(pod.ComposeFiles, podServices, healthCheckReply)
	}))

	if err != nil {
		log.Printf("POD_INIT_HEALTH_CHECK_TIMEOUT -- %v", err)
		return types.POD_FAILED, err
	}
	return res, err
}

func getServices(ctx context.Context) map[string]bool {
	podService := make(map[string]bool)
	filesMap := ctx.Value(types.SERVICE_DETAIL).(types.ServiceDetail)

	for _, file := range pod.ComposeFiles {
		servMap := filesMap[file][types.SERVICES].(map[interface{}]interface{})

		for serviceName := range servMap {
			podService[serviceName.(string)] = true
		}
	}
	return podService
}

func init() {
	flag.Parse()
	log.SetOutput(os.Stdout)

	// Set log to debug level when trace mode is turned on
	if config.EnableDebugMode() {
		log.SetLevel(log.DebugLevel)
	} else {
		log.SetLevel(log.InfoLevel)
	}
}

func main() {
	fmt.Println("====================Genesis Executor (Go)====================")

	sig := make(chan os.Signal, 1)
	signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL, syscall.SIGUSR1)
	go func() {
		for {
			sig := <-sig
			fmt.Printf("Received signal %s\n", sig.String())
			if sig == syscall.SIGUSR1 {
				switchDebugMode()
			}
		}
	}()

	dConfig := exec.DriverConfig{
		Executor: newDockerComposeExecutor(),
	}

	driver, err := exec.NewMesosExecutorDriver(dConfig)
	if err != nil {
		fmt.Errorf("Unable to create a ExecutorDriver : %v\n", err.Error())
	}

	_, err = driver.Start()
	if err != nil {
		fmt.Errorf("Got error: %v\n", err.Error())
		return
	}

	fmt.Println("Executor : Executor process has started and running.")
	driver.Join()

}

func switchDebugMode() {
	if config.EnableDebugMode() {
		config.GetConfig().Set(config.DEBUG_MODE, false)
		log.Println("###Turn off debug mode###")
		log.SetLevel(log.InfoLevel)
	} else {
		config.GetConfig().Set(config.DEBUG_MODE, true)
		log.Println("###Turn on debug mode###")
		log.SetLevel(log.DebugLevel)
	}
}
<commit_msg>removed data<commit_after>/*
 * 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 (
	"bytes"
	"context"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	exec "github.com/mesos/mesos-go/executor"
	mesos "github.com/mesos/mesos-go/mesosproto"
	log "github.com/sirupsen/logrus"

	"github.com/paypal/dce-go/config"
	"github.com/paypal/dce-go/dce/monitor"
	"github.com/paypal/dce-go/plugin"
	_ "github.com/paypal/dce-go/plugin/example"
	_ "github.com/paypal/dce-go/plugin/general"
	"github.com/paypal/dce-go/types"
	"github.com/paypal/dce-go/utils"
	fileUtils "github.com/paypal/dce-go/utils/file"
	"github.com/paypal/dce-go/utils/pod"
	"github.com/paypal/dce-go/utils/wait"
)

var logger *log.Entry
var extpoints []plugin.ComposePlugin

type dockerComposeExecutor struct {
	tasksLaunched int
}

func newDockerComposeExecutor() *dockerComposeExecutor {
	return &dockerComposeExecutor{tasksLaunched: 0}
}

func (exec *dockerComposeExecutor) Registered(driver exec.ExecutorDriver, execInfo *mesos.ExecutorInfo, fwinfo *mesos.FrameworkInfo, slaveInfo *mesos.SlaveInfo) {
	fmt.Println("====================Mesos Registered====================")
	fmt.Println("Mesos Register : Registered Executor on slave ", slaveInfo.GetHostname())
	pod.ComposeExcutorDriver = driver
}

func (exec *dockerComposeExecutor) Reregistered(driver exec.ExecutorDriver, slaveInfo *mesos.SlaveInfo) {
	fmt.Println("====================Mesos Reregistered====================")
	fmt.Println("Mesos Re-registered Re-registered : Executor on slave ", slaveInfo.GetHostname())
}

func (exec *dockerComposeExecutor) Disconnected(exec.ExecutorDriver) {
	fmt.Println("====================Mesos Disconnected====================")
	fmt.Println("Mesos Disconnected : Mesos Executordisconnected.")
}

func (exec *dockerComposeExecutor) LaunchTask(driver exec.ExecutorDriver, taskInfo *mesos.TaskInfo) {
	fmt.Println("====================Mesos LaunchTask====================")
	pod.ComposeExcutorDriver = driver

	task, err := json.Marshal(taskInfo)
	if err != nil {
		log.Println("Error marshalling taskInfo", err.Error())
	}
	buf := new(bytes.Buffer)
	json.Indent(buf, task, "", " ")
	fmt.Println("taskInfo : ", buf)

	isService := pod.IsService(taskInfo)
	fmt.Printf("task is service: %v\n", isService)
	config.GetConfig().Set(types.IS_SERVICE, isService)

	logger = log.WithFields(log.Fields{
		"requuid":   pod.GetLabel("requuid", taskInfo),
		"tenant":    pod.GetLabel("tenant", taskInfo),
		"namespace": pod.GetLabel("namespace", taskInfo),
		"pool":      pod.GetLabel("pool", taskInfo),
	})

	pod.ComposeTaskInfo = taskInfo
	executorId := taskInfo.GetExecutor().GetExecutorId().GetValue()

	// Update pod status to STARTING
	pod.SetPodStatus(types.POD_STARTING)

	// Update mesos state TO STARTING
	pod.SendMesosStatus(driver, taskInfo.GetTaskId(), mesos.TaskState_TASK_STARTING.Enum())

	// Get required compose file list
	pod.ComposeFiles, _ = fileUtils.GetFiles(taskInfo)

	// Generate app folder to keep temp files
	err = fileUtils.GenerateAppFolder()
	if err != nil {
		logger.Errorln("Error creating app folder")
	}

	// Create context with timeout
	// Wait for pod launching until timeout
	var ctx context.Context
	var cancel context.CancelFunc
	ctx = context.Background()
	ctx, cancel = context.WithTimeout(ctx, config.GetLaunchTimeout()*time.Millisecond)
	go pod.WaitOnPod(&ctx)

	// Get order of plugins from config or mesos labels
	pluginOrder, err := fileUtils.GetPluginOrder(taskInfo)
	if err != nil {
		logger.Println("Plugin order missing in mesos label, trying to get it from config")
		pluginOrder = strings.Split(config.GetConfigSection("plugins")[types.PLUGIN_ORDER], ",")
	}
	pod.PluginOrder = pluginOrder
	logger.Println("PluginOrder : ", pluginOrder)

	// Select plugin extension points from plugin pools
	extpoints = plugin.GetOrderedExtpoints(pluginOrder)

	// Executing PreLaunchTask in order
	_, err = utils.PluginPanicHandler(utils.ConditionFunc(func() (string, error) {
		for i, ext := range extpoints {
			if ext == nil {
				logger.Errorln("Error getting plugins from plugin registration pools")
				return "", errors.New("plugin is nil")
			}
			err = ext.PreLaunchTask(&ctx, &pod.ComposeFiles, executorId, taskInfo)
			if err != nil {
				logger.Errorf("Error executing PreLaunchTask of plugin : %v\n", err)
				return "", err
			}
			if config.EnableComposeTrace() {
				fileUtils.DumpPluginModifiedComposeFiles(ctx, pluginOrder[i], i)
			}
		}
		return "", err
	}))
	if err != nil {
		pod.SetPodStatus(types.POD_FAILED)
		cancel()
		pod.SendMesosStatus(driver, taskInfo.GetTaskId(), mesos.TaskState_TASK_FAILED.Enum())
		return
	}

	// Service list from all compose files
	podServices := getServices(ctx)
	logger.Printf("pod service list: %v", podServices)

	// Write updated compose files into pod folder
	err = fileUtils.WriteChangeToFiles(ctx)
	if err != nil {
		logger.Errorf("Failure writing updated compose files : %v", err)
		pod.SetPodStatus(types.POD_FAILED)
		cancel()
		pod.SendMesosStatus(driver, taskInfo.GetTaskId(), mesos.TaskState_TASK_FAILED.Enum())
	}

	// Pulling image and launch pod
	replyPodStatus := pullAndLaunchPod()

	logger.Printf("Pod status returned by pullAndLaunchPod : %v", replyPodStatus)

	// Take an action depends on different status
	switch replyPodStatus {
	case types.POD_FAILED:
		cancel()
		pod.SendPodStatus(types.POD_FAILED)

	case types.POD_PULL_FAILED:
		cancel()
		pod.SendPodStatus(types.POD_PULL_FAILED)

	case types.POD_STARTING:
		// Initial health check
		res, err := initHealthCheck(podServices)
		if err != nil || res == types.POD_FAILED {
			cancel()
			pod.SendPodStatus(types.POD_FAILED)
		}

		// Temp status keeps the pod status returned by PostLaunchTask
		tempStatus, err := utils.PluginPanicHandler(utils.ConditionFunc(func() (string, error) {
			var tempStatus string
			for _, ext := range extpoints {
				logger.Println("Executing post launch task plugin")

				tempStatus, err = ext.PostLaunchTask(&ctx, pod.ComposeFiles, taskInfo)
				if err != nil {
					logger.Errorf("Error executing PostLaunchTask : %v", err)
				}
				logger.Printf("Get pod status : %s returned by PostLaunchTask", tempStatus)

				if tempStatus == types.POD_FAILED {
					return tempStatus, nil
				}
			}
			return tempStatus, nil
		}))
		if err != nil {
			logger.Errorf("Error executing PostLaunchTask : %v", err)
		}
		if tempStatus == types.POD_FAILED {
			cancel()
			pod.SendPodStatus(types.POD_FAILED)
		}

		if res == types.POD_RUNNING {
			cancel()
			if pod.GetPodStatus() != types.POD_RUNNING {
				pod.SendPodStatus(types.POD_RUNNING)
				go monitor.MonitorPoller()
			}
		}

		//For adhoc job, send finished to mesos if job already finished during init health check
		if res == types.POD_FINISHED {
			cancel()
			pod.SendPodStatus(types.POD_FINISHED)
		}

	default:
		logger.Printf("default: Unknown status -- %s from pullAndLaunchPod ", replyPodStatus)

	}

	logger.Println("====================Mesos LaunchTask Returned====================")
}

func (exec *dockerComposeExecutor) KillTask(driver exec.ExecutorDriver, taskId *mesos.TaskID) {
	log.Println("====================Mesos KillTask====================")

	logKill := log.WithFields(log.Fields{
		"taskId": taskId,
	})

	status := pod.GetPodStatus()
	switch status {
	case types.POD_FAILED:
		logKill.Printf("Mesos Kill Task : Current task status is %s , ignore killTask", status)

	case types.POD_RUNNING:
		logKill.Printf("Mesos Kill Task : Current task status is %s , continue killTask", status)
		pod.SetPodStatus(types.POD_KILLED)

		err := pod.StopPod(pod.ComposeFiles)
		if err != nil {
			logKill.Errorf("Error cleaning up pod : %v", err.Error())
		}

		err = pod.SendMesosStatus(driver, taskId, mesos.TaskState_TASK_KILLED.Enum())
		if err != nil {
			logKill.Errorf("Error during kill Task : %v", err.Error())
		}

		log.Println("====================Stop ExecutorDriver====================")
		time.Sleep(200 * time.Millisecond)
		driver.Stop()

	}

	logKill.Println("====================Mesos KillTask Stopped====================")
}

func (exec *dockerComposeExecutor) FrameworkMessage(driver exec.ExecutorDriver, msg string) {
	fmt.Printf("Got framework message: %v\n", msg)
}

func (exec *dockerComposeExecutor) Shutdown(driver exec.ExecutorDriver) {
	// Execute shutdown plugin extensions in order
	for _, ext := range extpoints {
		ext.Shutdown(pod.ComposeExcutorDriver)
	}
	fmt.Println("====================Stop ExecutorDriver====================")
	driver.Stop()
}

func (exec *dockerComposeExecutor) Error(driver exec.ExecutorDriver, err string) {
	fmt.Printf("Got error message : %v\n", err)
}

func pullAndLaunchPod() string {
	logger.Println("====================Pod Pull And Launch====================")

	if !config.SkipPullImages() {
		err := wait.PollRetry(config.GetPullRetryCount(), time.Duration(config.GetPollInterval())*time.Millisecond, wait.ConditionFunc(func() (string, error) {
			return "", pod.PullImage(pod.ComposeFiles)
		}))

		if err != nil {
			logger.Printf("POD_IMAGE_PULL_FAILED -- %v", err)
			return types.POD_PULL_FAILED
		}
	}

	return pod.LaunchPod(pod.ComposeFiles)
}

func initHealthCheck(podServices map[string]bool) (string, error) {
	res, err := wait.WaitUntil(config.GetLaunchTimeout()*time.Millisecond, wait.ConditionCHFunc(func(healthCheckReply chan string) {
		pod.HealthCheck(pod.ComposeFiles, podServices, healthCheckReply)
	}))

	if err != nil {
		log.Printf("POD_INIT_HEALTH_CHECK_TIMEOUT -- %v", err)
		return types.POD_FAILED, err
	}
	return res, err
}

func getServices(ctx context.Context) map[string]bool {
	podService := make(map[string]bool)
	filesMap := ctx.Value(types.SERVICE_DETAIL).(types.ServiceDetail)

	for _, file := range pod.ComposeFiles {
		servMap := filesMap[file][types.SERVICES].(map[interface{}]interface{})

		for serviceName := range servMap {
			podService[serviceName.(string)] = true
		}
	}
	return podService
}

func init() {
	flag.Parse()
	log.SetOutput(os.Stdout)

	// Set log to debug level when trace mode is turned on
	if config.EnableDebugMode() {
		log.SetLevel(log.DebugLevel)
	} else {
		log.SetLevel(log.InfoLevel)
	}
}

func main() {
	fmt.Println("====================Genesis Executor (Go)====================")

	sig := make(chan os.Signal, 1)
	signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL, syscall.SIGUSR1)
	go func() {
		for {
			sig := <-sig
			fmt.Printf("Received signal %s\n", sig.String())
			if sig == syscall.SIGUSR1 {
				switchDebugMode()
			}
		}
	}()

	dConfig := exec.DriverConfig{
		Executor: newDockerComposeExecutor(),
	}

	driver, err := exec.NewMesosExecutorDriver(dConfig)
	if err != nil {
		fmt.Errorf("Unable to create a ExecutorDriver : %v\n", err.Error())
	}

	_, err = driver.Start()
	if err != nil {
		fmt.Errorf("Got error: %v\n", err.Error())
		return
	}

	fmt.Println("Executor : Executor process has started and running.")
	driver.Join()

}

func switchDebugMode() {
	if config.EnableDebugMode() {
		config.GetConfig().Set(config.DEBUG_MODE, false)
		log.Println("###Turn off debug mode###")
		log.SetLevel(log.InfoLevel)
	} else {
		config.GetConfig().Set(config.DEBUG_MODE, true)
		log.Println("###Turn on debug mode###")
		log.SetLevel(log.DebugLevel)
	}
}
<|endoftext|>


<commit_before><commit_msg>Do not store a list of watchers<commit_after><|endoftext|>


<commit_before>/*
                       WARNING WARNING WARNING

                Attention all potential contributors

   This testfile is not in the best state. We've been slowly transitioning
   from the built in "testing" package to using Ginkgo. As you can see, we've
   changed the format, but a lot of the setup, test body, descriptions, etc
   are either hardcoded, completely lacking, or misleading.

   For example:

   Describe("Testing with ginkgo"...)      // This is not a great description
   It("TestDoesSoemthing"...)              // This is a horrible description

   Describe("create-user command"...       // Describe the actual object under test
   It("creates a user when provided ..."   // this is more descriptive

   For good examples of writing Ginkgo tests for the cli, refer to

   src/github.com/cloudfoundry/cli/cf/commands/application/delete_app_test.go
   src/github.com/cloudfoundry/cli/cf/terminal/ui_test.go
   src/github.com/cloudfoundry/loggregator_consumer/consumer_test.go
*/

package organization_test

import (
	. "github.com/cloudfoundry/cli/cf/commands/organization"
	"github.com/cloudfoundry/cli/cf/configuration"
	"github.com/cloudfoundry/cli/cf/models"
	testapi "github.com/cloudfoundry/cli/testhelpers/api"
	testcmd "github.com/cloudfoundry/cli/testhelpers/commands"
	testconfig "github.com/cloudfoundry/cli/testhelpers/configuration"
	testreq "github.com/cloudfoundry/cli/testhelpers/requirements"
	testterm "github.com/cloudfoundry/cli/testhelpers/terminal"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	. "github.com/cloudfoundry/cli/testhelpers/matchers"
)

func callCreateOrg(args []string, requirementsFactory *testreq.FakeReqFactory, orgRepo *testapi.FakeOrgRepository) (fakeUI *testterm.FakeUI) {
	fakeUI = new(testterm.FakeUI)

	space := models.SpaceFields{}
	space.Name = "my-space"

	organization := models.OrganizationFields{}
	organization.Name = "my-org"

	token := configuration.TokenInfo{Username: "my-user"}
	config := testconfig.NewRepositoryWithAccessToken(token)
	config.SetSpaceFields(space)
	config.SetOrganizationFields(organization)

	cmd := NewCreateOrg(fakeUI, config, orgRepo)

	testcmd.RunCommand(cmd, args, requirementsFactory)
	return
}

var _ = Describe("Testing with ginkgo", func() {
	It("TestCreateOrgFailsWithUsage", func() {
		orgRepo := &testapi.FakeOrgRepository{}
		requirementsFactory := &testreq.FakeReqFactory{LoginSuccess: true}

		ui := callCreateOrg([]string{}, requirementsFactory, orgRepo)
		Expect(ui.FailedWithUsage).To(BeTrue())

		ui = callCreateOrg([]string{"my-org"}, requirementsFactory, orgRepo)
		Expect(ui.FailedWithUsage).To(BeFalse())
	})

	It("TestCreateOrgRequirements", func() {
		orgRepo := &testapi.FakeOrgRepository{}

		requirementsFactory := &testreq.FakeReqFactory{LoginSuccess: true}
		callCreateOrg([]string{"my-org"}, requirementsFactory, orgRepo)
		Expect(testcmd.CommandDidPassRequirements).To(BeTrue())

		requirementsFactory = &testreq.FakeReqFactory{LoginSuccess: false}
		callCreateOrg([]string{"my-org"}, requirementsFactory, orgRepo)
		Expect(testcmd.CommandDidPassRequirements).To(BeFalse())
	})

	It("TestCreateOrg", func() {
		orgRepo := &testapi.FakeOrgRepository{}
		requirementsFactory := &testreq.FakeReqFactory{LoginSuccess: true}
		ui := callCreateOrg([]string{"my-org"}, requirementsFactory, orgRepo)

		Expect(ui.Outputs).To(ContainSubstrings(
			[]string{"Creating org", "my-org", "my-user"},
			[]string{"OK"},
		))
		Expect(orgRepo.CreateName).To(Equal("my-org"))
	})

	It("TestCreateOrgWhenAlreadyExists", func() {
		orgRepo := &testapi.FakeOrgRepository{CreateOrgExists: true}
		requirementsFactory := &testreq.FakeReqFactory{LoginSuccess: true}
		ui := callCreateOrg([]string{"my-org"}, requirementsFactory, orgRepo)

		Expect(ui.Outputs).To(ContainSubstrings(
			[]string{"Creating org", "my-org"},
			[]string{"OK"},
			[]string{"my-org", "already exists"},
		))
	})
})
<commit_msg>Cleanup create-org tests<commit_after>package organization_test

import (
	"github.com/cloudfoundry/cli/cf/configuration"
	testapi "github.com/cloudfoundry/cli/testhelpers/api"
	testcmd "github.com/cloudfoundry/cli/testhelpers/commands"
	testconfig "github.com/cloudfoundry/cli/testhelpers/configuration"
	testreq "github.com/cloudfoundry/cli/testhelpers/requirements"
	testterm "github.com/cloudfoundry/cli/testhelpers/terminal"

	. "github.com/cloudfoundry/cli/cf/commands/organization"
	. "github.com/cloudfoundry/cli/testhelpers/matchers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("create-org command", func() {
	var (
		config              configuration.ReadWriter
		ui                  *testterm.FakeUI
		requirementsFactory *testreq.FakeReqFactory
		orgRepo             *testapi.FakeOrgRepository
	)

	BeforeEach(func() {
		ui = &testterm.FakeUI{}
		config = testconfig.NewRepositoryWithDefaults()
		requirementsFactory = &testreq.FakeReqFactory{}
		orgRepo = &testapi.FakeOrgRepository{}
	})

	runCommand := func(args ...string) {
		testcmd.RunCommand(NewCreateOrg(ui, config, orgRepo), args, requirementsFactory)
	}

	Describe("requirements", func() {
		It("fails with usage when not provided exactly one arg", func() {
			requirementsFactory.LoginSuccess = true
			runCommand()
			Expect(ui.FailedWithUsage).To(BeTrue())
		})

		It("fails when not logged in", func() {
			runCommand("my-org")
			Expect(testcmd.CommandDidPassRequirements).To(BeFalse())
		})
	})

	Context("when logged in and provided the name of an org to create", func() {
		BeforeEach(func() {
			requirementsFactory.LoginSuccess = true
		})

		It("creates an org", func() {
			runCommand("my-org")

			Expect(ui.Outputs).To(ContainSubstrings(
				[]string{"Creating org", "my-org", "my-user"},
				[]string{"OK"},
			))
			Expect(orgRepo.CreateName).To(Equal("my-org"))
		})

		It("fails and warns the user when the org already exists", func() {
			orgRepo.CreateOrgExists = true
			runCommand("my-org")

			Expect(ui.Outputs).To(ContainSubstrings(
				[]string{"Creating org", "my-org"},
				[]string{"OK"},
				[]string{"my-org", "already exists"},
			))
		})
	})
})
<|endoftext|>


<commit_before>package organization_test

import (
	"github.com/cloudfoundry/cli/cf/errors"
	"github.com/cloudfoundry/cli/cf/models"

	test_quota "github.com/cloudFoundry/cli/cf/api/quotas/fakes"
	test_org "github.com/cloudfoundry/cli/cf/api/organizations/fakes"
	"github.com/cloudfoundry/cli/cf/configuration"
	testcmd "github.com/cloudfoundry/cli/testhelpers/commands"
	testconfig "github.com/cloudfoundry/cli/testhelpers/configuration"
	testreq "github.com/cloudfoundry/cli/testhelpers/requirements"
	testterm "github.com/cloudfoundry/cli/testhelpers/terminal"

	. "github.com/cloudfoundry/cli/cf/commands/organization"
	. "github.com/cloudfoundry/cli/testhelpers/matchers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("create-org command", func() {
	var (
		config              configuration.ReadWriter
		ui                  *testterm.FakeUI
		requirementsFactory *testreq.FakeReqFactory
		orgRepo             *test_org.FakeOrganizationRepository
		quotaRepo           *test_quota.FakeQuotaRepository
	)

	BeforeEach(func() {
		ui = &testterm.FakeUI{}
		config = testconfig.NewRepositoryWithDefaults()
		requirementsFactory = &testreq.FakeReqFactory{}
		orgRepo = &test_org.FakeOrganizationRepository{}
		quotaRepo = &test_quota.FakeQuotaRepository{}
	})

	runCommand := func(args ...string) {
		testcmd.RunCommand(NewCreateOrg(ui, config, orgRepo, quotaRepo), args, requirementsFactory)
	}

	Describe("requirements", func() {
		It("fails with usage when not provided exactly one arg", func() {
			requirementsFactory.LoginSuccess = true
			runCommand()
			Expect(ui.FailedWithUsage).To(BeTrue())
		})

		It("fails when not logged in", func() {
			runCommand("my-org")
			Expect(testcmd.CommandDidPassRequirements).To(BeFalse())
		})
	})

	Context("when logged in and provided the name of an org to create", func() {
		BeforeEach(func() {
			orgRepo.CreateReturns(nil)
			requirementsFactory.LoginSuccess = true
		})

		It("creates an org", func() {
			runCommand("my-org")

			Expect(ui.Outputs).To(ContainSubstrings(
				[]string{"Creating org", "my-org", "my-user"},
				[]string{"OK"},
			))
			Expect(orgRepo.CreateArgsForCall(0).Name).To(Equal("my-org"))
		})

		It("fails and warns the user when the org already exists", func() {
			err := errors.NewHttpError(400, errors.ORG_EXISTS, "org already exists")
			orgRepo.CreateReturns(err)
			runCommand("my-org")

			Expect(ui.Outputs).To(ContainSubstrings(
				[]string{"Creating org", "my-org"},
				[]string{"OK"},
				[]string{"my-org", "already exists"},
			))
		})

		Context("when allowing a non-defualt quota", func() {
			var (
				quota models.QuotaFields
			)

			BeforeEach(func() {
				quota = models.QuotaFields{
					Name: "non-default-quota",
					Guid: "non-default-quota-guid",
				}
			})

			It("creates an org with a non-default quota", func() {
				quotaRepo.FindByNameReturns(quota, nil)
				runCommand("-q", "non-default-quota", "my-org")

				Expect(quotaRepo.FindByNameArgsForCall(0)).To(Equal("non-default-quota"))
				Expect(orgRepo.CreateArgsForCall(0).QuotaDefinition.Guid).To(Equal("non-default-quota-guid"))
				Expect(ui.Outputs).To(ContainSubstrings(
					[]string{"Creating org", "my-org"},
					[]string{"OK"},
				))
			})

			It("fails and warns the user when the quota cannot be found", func() {
				quotaRepo.FindByNameReturns(models.QuotaFields{}, errors.New("Could not find quota"))
				runCommand("-q", "non-default-quota", "my-org")

				Expect(ui.Outputs).To(ContainSubstrings(
					[]string{"Creating org", "my-org"},
					[]string{"Could not find quota"},
				))
			})
		})
	})
})
<commit_msg>Fix capitAliZation ErrOr<commit_after>package organization_test

import (
	"github.com/cloudfoundry/cli/cf/errors"
	"github.com/cloudfoundry/cli/cf/models"

	test_quota "github.com/cloudfoundry/cli/cf/api/quotas/fakes"
	test_org "github.com/cloudfoundry/cli/cf/api/organizations/fakes"
	"github.com/cloudfoundry/cli/cf/configuration"
	testcmd "github.com/cloudfoundry/cli/testhelpers/commands"
	testconfig "github.com/cloudfoundry/cli/testhelpers/configuration"
	testreq "github.com/cloudfoundry/cli/testhelpers/requirements"
	testterm "github.com/cloudfoundry/cli/testhelpers/terminal"

	. "github.com/cloudfoundry/cli/cf/commands/organization"
	. "github.com/cloudfoundry/cli/testhelpers/matchers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("create-org command", func() {
	var (
		config              configuration.ReadWriter
		ui                  *testterm.FakeUI
		requirementsFactory *testreq.FakeReqFactory
		orgRepo             *test_org.FakeOrganizationRepository
		quotaRepo           *test_quota.FakeQuotaRepository
	)

	BeforeEach(func() {
		ui = &testterm.FakeUI{}
		config = testconfig.NewRepositoryWithDefaults()
		requirementsFactory = &testreq.FakeReqFactory{}
		orgRepo = &test_org.FakeOrganizationRepository{}
		quotaRepo = &test_quota.FakeQuotaRepository{}
	})

	runCommand := func(args ...string) {
		testcmd.RunCommand(NewCreateOrg(ui, config, orgRepo, quotaRepo), args, requirementsFactory)
	}

	Describe("requirements", func() {
		It("fails with usage when not provided exactly one arg", func() {
			requirementsFactory.LoginSuccess = true
			runCommand()
			Expect(ui.FailedWithUsage).To(BeTrue())
		})

		It("fails when not logged in", func() {
			runCommand("my-org")
			Expect(testcmd.CommandDidPassRequirements).To(BeFalse())
		})
	})

	Context("when logged in and provided the name of an org to create", func() {
		BeforeEach(func() {
			orgRepo.CreateReturns(nil)
			requirementsFactory.LoginSuccess = true
		})

		It("creates an org", func() {
			runCommand("my-org")

			Expect(ui.Outputs).To(ContainSubstrings(
				[]string{"Creating org", "my-org", "my-user"},
				[]string{"OK"},
			))
			Expect(orgRepo.CreateArgsForCall(0).Name).To(Equal("my-org"))
		})

		It("fails and warns the user when the org already exists", func() {
			err := errors.NewHttpError(400, errors.ORG_EXISTS, "org already exists")
			orgRepo.CreateReturns(err)
			runCommand("my-org")

			Expect(ui.Outputs).To(ContainSubstrings(
				[]string{"Creating org", "my-org"},
				[]string{"OK"},
				[]string{"my-org", "already exists"},
			))
		})

		Context("when allowing a non-defualt quota", func() {
			var (
				quota models.QuotaFields
			)

			BeforeEach(func() {
				quota = models.QuotaFields{
					Name: "non-default-quota",
					Guid: "non-default-quota-guid",
				}
			})

			It("creates an org with a non-default quota", func() {
				quotaRepo.FindByNameReturns(quota, nil)
				runCommand("-q", "non-default-quota", "my-org")

				Expect(quotaRepo.FindByNameArgsForCall(0)).To(Equal("non-default-quota"))
				Expect(orgRepo.CreateArgsForCall(0).QuotaDefinition.Guid).To(Equal("non-default-quota-guid"))
				Expect(ui.Outputs).To(ContainSubstrings(
					[]string{"Creating org", "my-org"},
					[]string{"OK"},
				))
			})

			It("fails and warns the user when the quota cannot be found", func() {
				quotaRepo.FindByNameReturns(models.QuotaFields{}, errors.New("Could not find quota"))
				runCommand("-q", "non-default-quota", "my-org")

				Expect(ui.Outputs).To(ContainSubstrings(
					[]string{"Creating org", "my-org"},
					[]string{"Could not find quota"},
				))
			})
		})
	})
})
<|endoftext|>


<commit_before>// Copyright (c) 2016-2017 Pani Networks
// 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 idring

import (
	"math"
	"sync"
	"testing"
)

func TestInvert(t *testing.T) {
	var err error
	var id uint64
	idRing := NewIDRing(1, 5, &sync.Mutex{})

	invert := idRing.Invert()
	if len(invert.Ranges) != 0 {
		t.Errorf("Expected empty array for an inversion of an original ring, got %s", invert)
	}

	for i := 0; i < 5; i++ {
		id, err = idRing.GetID()
		if err != nil {
			t.Fatal(err)
		}
		t.Logf("TestInvert: Got %d", id)
	}

	invert = idRing.Invert()
	if len(invert.Ranges) != 1 {
		t.Errorf("Expected a single range for inversion of a filled up ring, got %s", invert)
	}

}

func TestClear(t *testing.T) {
	var err error
	var id uint64
	idRing := NewIDRing(1, math.MaxUint64, &sync.Mutex{})
	// First ID given out should be 1
	id, err = idRing.GetID()
	if err != nil {
		t.Fatalf("Unexpected error %s", err)
	}
	if id != 1 {
		t.Fatalf("Expected 1, got %d", id)
	}
	id, err = idRing.GetID()
	if err != nil {
		t.Fatalf("Unexpected error %s", err)
	}
	if id != 2 {
		t.Fatalf("Expected 2, got %d", id)
	}
	idRing.Clear()

	id, err = idRing.GetID()
	if err != nil {
		t.Fatalf("Unexpected error %s", err)
	}
	//Now we should get one again
	if id != 1 {
		t.Fatalf("Expected 1, got %d", id)
	}
	id, err = idRing.GetID()
	if err != nil {
		t.Fatalf("Unexpected error %s", err)
	}
}

func TestAllocation(t *testing.T) {
	var err error
	var id uint64
	idRing := NewIDRing(1, math.MaxUint64, &sync.Mutex{})

	// 1. Test invert
	invert := idRing.Invert()
	if len(invert.Ranges) != 0 {
		t.Errorf("Expected empty array for an inversion of an original ring, got %s", invert)
	}

	// 2. Test allocation
	// First ID given out should be 1
	id, err = idRing.GetID()
	if err != nil {
		t.Fatalf("Unexpected error %s", err)
	}
	if id != 1 {
		t.Fatalf("Expected 1, got %d", id)
	}

	// IDs should be given out sequentially, let's try getting up to a 100 of them.
	for i := 2; i < 100; i++ {
		id, err := idRing.GetID()
		if err != nil {
			t.Fatalf("Unexpected error %s", err)
		}
		if id != uint64(i) {
			t.Fatalf("Expected %d, got %d", i, id)
		}
	}

	// 3. Test invert again.
	invert = idRing.Invert()
	if len(invert.Ranges) != 1 {
		t.Fatalf("Expected a single range for an inversion, got %s", invert)
	}
	if invert.Ranges[0].Min != 1 || invert.Ranges[0].Max != 99 {
		t.Fatalf("Expected 1:100, got %d:%d", invert.Ranges[0].Min, invert.Ranges[0].Max)
	}

	// 4. Test reclaiming.
	// 500 should be an error, because that ID was never given out.
	err = idRing.ReclaimID(500)
	if err == nil {
		t.Fatalf("Successfully reclaimed 500 into %s, expected error", idRing)
	}

	// All of these should be successful - we are reclaiming all the IDs
	// we got earlier.
	for i := 1; i < 100; i++ {
		err := idRing.ReclaimID(uint64(i))
		if err != nil {
			t.Fatalf("Unexpected error %s", err)
		}
	}
	// We have reclaimed all so now we should have ring from 1 to MaxInt again
	if len(idRing.Ranges) != 1 {
		t.Fatalf("Expected len(idRing.Ranges) to be 1, got %d", len(idRing.Ranges))
	}
	if idRing.Ranges[0].Min != 1 {
		t.Fatalf("Expected idRing.Ranges[0].Min to be 1, got %d", idRing.Ranges[0].Min)
	}
	if idRing.Ranges[0].Max != math.MaxUint64 {
		t.Fatalf("Expected idRing.Ranges[0].Max to be MaxUint64, got %d", idRing.Ranges[0].Max)
	}
}
<commit_msg>(fix) idring_test.go:78:2: this value of id is never used (SA4006)<commit_after>// Copyright (c) 2016-2017 Pani Networks
// 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 idring

import (
	"math"
	"sync"
	"testing"
)

func TestInvert(t *testing.T) {
	var err error
	var id uint64
	idRing := NewIDRing(1, 5, &sync.Mutex{})

	invert := idRing.Invert()
	if len(invert.Ranges) != 0 {
		t.Errorf("Expected empty array for an inversion of an original ring, got %s", invert)
	}

	for i := 0; i < 5; i++ {
		id, err = idRing.GetID()
		if err != nil {
			t.Fatal(err)
		}
		t.Logf("TestInvert: Got %d", id)
	}

	invert = idRing.Invert()
	if len(invert.Ranges) != 1 {
		t.Errorf("Expected a single range for inversion of a filled up ring, got %s", invert)
	}

}

func TestClear(t *testing.T) {
	var err error
	var id uint64
	idRing := NewIDRing(1, math.MaxUint64, &sync.Mutex{})
	// First ID given out should be 1
	id, err = idRing.GetID()
	if err != nil {
		t.Fatalf("Unexpected error %s", err)
	}
	if id != 1 {
		t.Fatalf("Expected 1, got %d", id)
	}
	id, err = idRing.GetID()
	if err != nil {
		t.Fatalf("Unexpected error %s", err)
	}
	if id != 2 {
		t.Fatalf("Expected 2, got %d", id)
	}
	idRing.Clear()

	id, err = idRing.GetID()
	if err != nil {
		t.Fatalf("Unexpected error %s", err)
	}
	//Now we should get one again
	if id != 1 {
		t.Fatalf("Expected 1, got %d", id)
	}
	id, err = idRing.GetID()
	if err != nil {
		t.Fatalf("Unexpected error %s", err)
	}
	if id != 2 {
		t.Fatalf("Expected 2, got %d", id)
	}
}

func TestAllocation(t *testing.T) {
	var err error
	var id uint64
	idRing := NewIDRing(1, math.MaxUint64, &sync.Mutex{})

	// 1. Test invert
	invert := idRing.Invert()
	if len(invert.Ranges) != 0 {
		t.Errorf("Expected empty array for an inversion of an original ring, got %s", invert)
	}

	// 2. Test allocation
	// First ID given out should be 1
	id, err = idRing.GetID()
	if err != nil {
		t.Fatalf("Unexpected error %s", err)
	}
	if id != 1 {
		t.Fatalf("Expected 1, got %d", id)
	}

	// IDs should be given out sequentially, let's try getting up to a 100 of them.
	for i := 2; i < 100; i++ {
		id, err := idRing.GetID()
		if err != nil {
			t.Fatalf("Unexpected error %s", err)
		}
		if id != uint64(i) {
			t.Fatalf("Expected %d, got %d", i, id)
		}
	}

	// 3. Test invert again.
	invert = idRing.Invert()
	if len(invert.Ranges) != 1 {
		t.Fatalf("Expected a single range for an inversion, got %s", invert)
	}
	if invert.Ranges[0].Min != 1 || invert.Ranges[0].Max != 99 {
		t.Fatalf("Expected 1:100, got %d:%d", invert.Ranges[0].Min, invert.Ranges[0].Max)
	}

	// 4. Test reclaiming.
	// 500 should be an error, because that ID was never given out.
	err = idRing.ReclaimID(500)
	if err == nil {
		t.Fatalf("Successfully reclaimed 500 into %s, expected error", idRing)
	}

	// All of these should be successful - we are reclaiming all the IDs
	// we got earlier.
	for i := 1; i < 100; i++ {
		err := idRing.ReclaimID(uint64(i))
		if err != nil {
			t.Fatalf("Unexpected error %s", err)
		}
	}
	// We have reclaimed all so now we should have ring from 1 to MaxInt again
	if len(idRing.Ranges) != 1 {
		t.Fatalf("Expected len(idRing.Ranges) to be 1, got %d", len(idRing.Ranges))
	}
	if idRing.Ranges[0].Min != 1 {
		t.Fatalf("Expected idRing.Ranges[0].Min to be 1, got %d", idRing.Ranges[0].Min)
	}
	if idRing.Ranges[0].Max != math.MaxUint64 {
		t.Fatalf("Expected idRing.Ranges[0].Max to be MaxUint64, got %d", idRing.Ranges[0].Max)
	}
}
<|endoftext|>


<commit_before>package sql

import (
	"io/ioutil"
	"os"
	"path"
	"testing"

	_ "github.com/mattn/go-sqlite3"
	"github.com/stretchr/testify/assert"
)

var store Store

func (s *Store) init() (dirName string, err error) {

	dirName, err = ioutil.TempDir("", "piken")
	if err != nil {
		return "", err
	}

	databaseName := path.Join(dirName, "piken.sqlite3")

	if err := s.Open(databaseName); err != nil {
		return "", err
	}

	return dirName, nil
}

// Insert some data for testing.
func (s *Store) fixture() {
	s.db.Exec(`INSERT INTO unicode_data (codepoint, name, category)
		VALUES ('1F60E', 'SMILING FACE WITH SUNGLASSES', 'So')`)
	s.db.Exec(`INSERT INTO unicode_data (codepoint, name, category)
		VALUES ('1F602', 'FACE WITH TEARS OF JOY', 'So')`)
	s.db.Exec(`INSERT INTO unicode_data (codepoint, name, category)
		VALUES ('1F4D7', 'GREEN BOOK', 'So')`)
}

func TestSearch(t *testing.T) {

	dirName, err := store.init()
	if err != nil {
		assert.Error(t, err)
	}
	defer os.RemoveAll(dirName)
	defer store.Close()

	store.fixture()

	data, err := store.SearchUnicode("cat")
	if err != nil {
		assert.Error(t, err)
	}
	assert.Equal(t, data, []UnicodeData(nil))

	data, err = store.SearchUnicode("book")
	if err != nil {
		assert.Error(t, err)
	}
	assert.Equal(t, len(data), 1)
	assert.Equal(t, data[0].CodePoint, "1F4D7")
	assert.Equal(t, data[0].Name, "GREEN BOOK")
	assert.Equal(t, data[0].Category, "So")

	// Search is case insensitive
	data, err = store.SearchUnicode("fAcE")
	if err != nil {
		assert.Error(t, err)
	}
	assert.Equal(t, len(data), 2)
	assert.Equal(t, data[0].CodePoint, "1F60E")
	assert.Equal(t, data[0].Name, "SMILING FACE WITH SUNGLASSES")
	assert.Equal(t, data[0].Category, "So")
	assert.Equal(t, data[1].CodePoint, "1F602")
	assert.Equal(t, data[1].Name, "FACE WITH TEARS OF JOY")
	assert.Equal(t, data[1].Category, "So")

	data, err = store.SearchUnicode("face NOT sunglasses")
	if err != nil {
		assert.Error(t, err)
	}
	assert.Equal(t, len(data), 1)
	assert.Equal(t, data[0].CodePoint, "1F602")
	assert.Equal(t, data[0].Name, "FACE WITH TEARS OF JOY")
	assert.Equal(t, data[0].Category, "So")
}
<commit_msg>Add tests for last update check<commit_after>package sql

import (
	"io/ioutil"
	"os"
	"path"
	"testing"
	"time"

	_ "github.com/mattn/go-sqlite3"
	"github.com/stretchr/testify/assert"
)

var store Store

func (s *Store) init() (dirName string, err error) {

	dirName, err = ioutil.TempDir("", "piken")
	if err != nil {
		return "", err
	}

	databaseName := path.Join(dirName, "piken.sqlite3")

	if err := s.Open(databaseName); err != nil {
		return "", err
	}

	return dirName, nil
}

// Insert some data for testing.
func (s *Store) fixture() {
	s.db.Exec(`INSERT INTO unicode_data (codepoint, name, category)
		VALUES ('1F60E', 'SMILING FACE WITH SUNGLASSES', 'So')`)
	s.db.Exec(`INSERT INTO unicode_data (codepoint, name, category)
		VALUES ('1F602', 'FACE WITH TEARS OF JOY', 'So')`)
	s.db.Exec(`INSERT INTO unicode_data (codepoint, name, category)
		VALUES ('1F4D7', 'GREEN BOOK', 'So')`)
}

func TestSearch(t *testing.T) {

	dirName, err := store.init()
	if err != nil {
		assert.Error(t, err)
	}
	defer os.RemoveAll(dirName)
	defer store.Close()

	store.fixture()

	data, err := store.SearchUnicode("cat")
	if err != nil {
		assert.Error(t, err)
	}
	assert.Equal(t, data, []UnicodeData(nil))

	data, err = store.SearchUnicode("book")
	if err != nil {
		assert.Error(t, err)
	}
	assert.Equal(t, len(data), 1)
	assert.Equal(t, data[0].CodePoint, "1F4D7")
	assert.Equal(t, data[0].Name, "GREEN BOOK")
	assert.Equal(t, data[0].Category, "So")

	// Search is case insensitive
	data, err = store.SearchUnicode("fAcE")
	if err != nil {
		assert.Error(t, err)
	}
	assert.Equal(t, len(data), 2)
	assert.Equal(t, data[0].CodePoint, "1F60E")
	assert.Equal(t, data[0].Name, "SMILING FACE WITH SUNGLASSES")
	assert.Equal(t, data[0].Category, "So")
	assert.Equal(t, data[1].CodePoint, "1F602")
	assert.Equal(t, data[1].Name, "FACE WITH TEARS OF JOY")
	assert.Equal(t, data[1].Category, "So")

	data, err = store.SearchUnicode("face NOT sunglasses")
	if err != nil {
		assert.Error(t, err)
	}
	assert.Equal(t, len(data), 1)
	assert.Equal(t, data[0].CodePoint, "1F602")
	assert.Equal(t, data[0].Name, "FACE WITH TEARS OF JOY")
	assert.Equal(t, data[0].Category, "So")
}

func TestLastUpdate(t *testing.T) {
	dirName, err := store.init()
	if err != nil {
		assert.Error(t, err)
	}
	defer os.RemoveAll(dirName)
	defer store.Close()

	updateTime, err := store.GetLastUpdate("test.txt")
	if err != nil {
		assert.Error(t, err)
	}
	assert.Equal(t, updateTime, time.Unix(0, 0))

	testTime, _ := time.Parse("2006-Jan-02", "1993-Jan-25")
	if err := store.CreateLastUpdate("test.txt", testTime); err != nil {
		assert.Error(t, err)
	}
	updateTime, err = store.GetLastUpdate("test.txt")
	assert.Equal(t, updateTime, testTime)

}
<|endoftext|>


<commit_before>package models

import (
	"fmt"
)

// Asset represents a file within a space. An asset can be any kind of file: an
// image, a video, an audio file, a PDF or any other filetype. Assets are
// usually attached to entries through links.
//
// Assets can optionally be localized by providing separate files for each
// locale. Those assets which are not localized simply provide a single file
// under the default locale.
type Asset struct {
	System `json:"sys"`
	Fields AssetFields `json:"fields,omitempty"`
}

// AssetFields contains all asset information.
type AssetFields struct {
	Title map[string]string    `json:"title,omitempty"`
	File  map[string]AssetData `json:"file,omitempty"`
}

// AssetData contains all asset information
type AssetData struct {
	MIMEType string      `json:"contentType"`
	Name     string      `json:"fileName"`
	URL      string      `json:"url,omitempty"`
	Upload   string      `json:"upload,omitempty"`
	Detail   AssetDetail `json:"details,omitempty"`
}

// Validate will validate the Asset to ensure all necessary fields are present.
func (a *Asset) Validate() error {
	if a.System.ID == "" {
		fmt.Println("system ID is empty!")
		return fmt.Errorf("Asset validation failed. System.ID cannot be empty!")
	}

	if a.System.Space == nil {
		return fmt.Errorf("Asset validation failed. System.Space.ID cannot be empty!")
	}

	return nil
}

// Link represents a link to the Entry and implements the Linkable interface
func (a *Asset) Link() map[string]map[string]interface{} {
	return map[string]map[string]interface{}{
		"sys": map[string]interface{}{
			"id":       a.ID,
			"linkType": "Asset",
			"type":     LinkType,
		},
	}
}

type ImageDetail struct {
	Width  int `json:"width"`
	Height int `json:"height"`
}

type AssetDetail struct {
	Image ImageDetail `json:"image,omitempty"`
	Size  int         `json:"size"`
}

// File represents all asset data prior to upload
type File struct {
	SpaceID string `json:"-"`

	Fields FileFields `json:"fields"`
}

type FileFields struct {
	Title map[string]string   `json:"title"`
	File  map[string]FileData `json:"file"`
}

// FileData contains all file information
type FileData struct {
	MIMEType string `json:"contentType"`
	Name     string `json:"fileName,omitempty"`
	URL      string `json:"upload,omitempty"`
}

func (f *File) Validate() error {
	if f.SpaceID == "" {
		return fmt.Errorf("Filed validation failed. SpaceID cannot be empty!")
	}

	if f.Fields.File == nil || len(f.Fields.File) == 0 {
		return fmt.Errorf("Filed validation failed. Fields.File cannot be empty!")
	}

	if f.Fields.Title == nil || len(f.Fields.Title) == 0 {
		return fmt.Errorf("Filed validation failed. Fields.Title cannot be empty!")
	}

	for _, data := range f.Fields.File {
		if data.Name == "" {
			return fmt.Errorf("Filed validation failed. FileData.Name cannot be empty. FileData: %v", data)
		} else if data.MIMEType == "" {
			return fmt.Errorf("Filed validation failed. FileData.MIMEType cannot be empty. FileData: %v", data)
		} else if data.URL == "" {
			return fmt.Errorf("Filed validation failed. FileData.URL cannot be empty. FileData: %v", data)
		}
	}

	return nil
}
<commit_msg>Making AssetDetail a pointer<commit_after>package models

import (
	"fmt"
)

// Asset represents a file within a space. An asset can be any kind of file: an
// image, a video, an audio file, a PDF or any other filetype. Assets are
// usually attached to entries through links.
//
// Assets can optionally be localized by providing separate files for each
// locale. Those assets which are not localized simply provide a single file
// under the default locale.
type Asset struct {
	System `json:"sys"`
	Fields AssetFields `json:"fields,omitempty"`
}

// AssetFields contains all asset information.
type AssetFields struct {
	Title map[string]string    `json:"title,omitempty"`
	File  map[string]AssetData `json:"file,omitempty"`
}

// AssetData contains all asset information
type AssetData struct {
	MIMEType string       `json:"contentType"`
	Name     string       `json:"fileName"`
	URL      string       `json:"url,omitempty"`
	Upload   string       `json:"upload,omitempty"`
	Detail   *AssetDetail `json:"details,omitempty"`
}

// Validate will validate the Asset to ensure all necessary fields are present.
func (a *Asset) Validate() error {
	if a.System.ID == "" {
		fmt.Println("system ID is empty!")
		return fmt.Errorf("Asset validation failed. System.ID cannot be empty!")
	}

	if a.System.Space == nil {
		return fmt.Errorf("Asset validation failed. System.Space.ID cannot be empty!")
	}

	return nil
}

// Link represents a link to the Entry and implements the Linkable interface
func (a *Asset) Link() map[string]map[string]interface{} {
	return map[string]map[string]interface{}{
		"sys": map[string]interface{}{
			"id":       a.ID,
			"linkType": "Asset",
			"type":     LinkType,
		},
	}
}

type ImageDetail struct {
	Width  int `json:"width"`
	Height int `json:"height"`
}

type AssetDetail struct {
	Image *ImageDetail `json:"image,omitempty"`
	Size  int          `json:"size"`
}

// File represents all asset data prior to upload
type File struct {
	SpaceID string `json:"-"`

	Fields FileFields `json:"fields"`
}

type FileFields struct {
	Title map[string]string   `json:"title"`
	File  map[string]FileData `json:"file"`
}

// FileData contains all file information
type FileData struct {
	MIMEType string `json:"contentType"`
	Name     string `json:"fileName,omitempty"`
	URL      string `json:"upload,omitempty"`
}

func (f *File) Validate() error {
	if f.SpaceID == "" {
		return fmt.Errorf("Filed validation failed. SpaceID cannot be empty!")
	}

	if f.Fields.File == nil || len(f.Fields.File) == 0 {
		return fmt.Errorf("Filed validation failed. Fields.File cannot be empty!")
	}

	if f.Fields.Title == nil || len(f.Fields.Title) == 0 {
		return fmt.Errorf("Filed validation failed. Fields.Title cannot be empty!")
	}

	for _, data := range f.Fields.File {
		if data.Name == "" {
			return fmt.Errorf("Filed validation failed. FileData.Name cannot be empty. FileData: %v", data)
		} else if data.MIMEType == "" {
			return fmt.Errorf("Filed validation failed. FileData.MIMEType cannot be empty. FileData: %v", data)
		} else if data.URL == "" {
			return fmt.Errorf("Filed validation failed. FileData.URL cannot be empty. FileData: %v", data)
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package brightbox

import (
	"time"
)

// DatabaseServer represents a database server.
// https://api.gb1.brightbox.com/1.0/#database_server
type DatabaseServer struct {
	Id                 string
	Name               string
	Description        string
	Status             string
	Account            Account
	DatabaseEngine     string             `json:"database_engine"`
	DatabaseVersion    string             `json:"database_version"`
	AdminUsername      string             `json:"admin_username"`
	AdminPassword      string             `json:"admin_password"`
	CreatedAt          *time.Time         `json:"created_at"`
	UpdatedAt          *time.Time         `json:"updated_at"`
	DeletedAt          *time.Time         `json:"deleted_at"`
	AllowAccess        []string           `json:"allow_access"`
	MaintenanceWeekday int                `json:"maintenance_weekday"`
	MaintenanceHour    int                `json:"maintenance_hour"`
	SnapshotsSchedule  string             `json:"snapshots_schedule"`
	CloudIPs           []CloudIP          `json:"cloud_ips"`
	DatabaseServerType DatabaseServerType `json:"database_server_type"`
	Locked             bool
	Zone               Zone
}

// DatabaseServerOptions is used in conjunction with CreateDatabaseServer and
// UpdateDatabaseServer to create and update database servers.
type DatabaseServerOptions struct {
	Id                 string   `json:"-"`
	Name               *string  `json:"name,omitempty"`
	Description        *string  `json:"description,omitempty"`
	Engine             string   `json:"engine,omitempty"`
	Version            string   `json:"version,omitempty"`
	AllowAccess        []string `json:"allow_access,omitempty"`
	Snapshot           string   `json:"snapshot,omitempty"`
	Zone               string   `json:"zone,omitempty"`
	DatabaseType       string   `json:"database_type,omitempty"`
	MaintenanceWeekday *int     `json:"maintenance_weekday,omitempty"`
	MaintenanceHour    *int     `json:"maintenance_hour,omitempty"`
	SnapshotsSchedule  *string  `json:"snapshots_schedule,omitempty"`
}

// DatabaseServers retrieves a list of all database servers
func (c *Client) DatabaseServers() ([]DatabaseServer, error) {
	var dbs []DatabaseServer
	_, err := c.MakeApiRequest("GET", "/1.0/database_servers", nil, &dbs)
	if err != nil {
		return nil, err
	}
	return dbs, err
}

// DatabaseServer retrieves a detailed view of one database server
func (c *Client) DatabaseServer(identifier string) (*DatabaseServer, error) {
	dbs := new(DatabaseServer)
	_, err := c.MakeApiRequest("GET", "/1.0/database_servers/"+identifier, nil, dbs)
	if err != nil {
		return nil, err
	}
	return dbs, err
}

// CreateDatabaseServer creates a new database server.
//
// It takes a DatabaseServerOptions struct for specifying name and other
// attributes. Not all attributes can be specified at create time
// (such as Id, which is allocated for you)
func (c *Client) CreateDatabaseServer(options *DatabaseServerOptions) (*DatabaseServer, error) {
	dbs := new(DatabaseServer)
	_, err := c.MakeApiRequest("POST", "/1.0/database_servers", options, &dbs)
	if err != nil {
		return nil, err
	}
	return dbs, nil
}

// UpdateDatabaseServer updates an existing database server.
//
// It takes a DatabaseServerOptions struct for specifying Id, name and other
// attributes. Not all attributes can be specified at update time.
func (c *Client) UpdateDatabaseServer(options *DatabaseServerOptions) (*DatabaseServer, error) {
	dbs := new(DatabaseServer)
	_, err := c.MakeApiRequest("PUT", "/1.0/database_servers/"+options.Id, options, &dbs)
	if err != nil {
		return nil, err
	}
	return dbs, nil
}

// DestroyDatabaseServer issues a request to deletes an existing database server
func (c *Client) DestroyDatabaseServer(identifier string) error {
	_, err := c.MakeApiRequest("DELETE", "/1.0/database_servers/"+identifier, nil, nil)
	return err
}

// SnapshotDatabaseServer requests a snapshot of an existing database server.
func (c *Client) SnapshotDatabaseServer(identifier string) (*DatabaseSnapshot, error) {
	dbs := new(DatabaseServer)
	res, err := c.MakeApiRequest("POST", "/1.0/database_servers/"+identifier+"/snapshot", nil, &dbs)
	if err != nil {
		return nil, err
	}
	snapID := getLinkRel(res.Header.Get("Link"), "dbi", "snapshot")
	if snapID != nil {
		snap := new(DatabaseSnapshot)
		snap.Id = *snapID
		return snap, nil
	}
	return nil, nil
}

// ResetPasswordForDatabaseServer requests a snapshot of an existing database server.
func (c *Client) ResetPasswordForDatabaseServer(identifier string) (*DatabaseServer, error) {
	dbs := new(DatabaseServer)
	_, err := c.MakeApiRequest("POST", "/1.0/database_servers/"+identifier+"/reset_password", nil, &dbs)
	if err != nil {
		return nil, err
	}
	return dbs, nil
}
<commit_msg>Add snapshot schedule time to database server<commit_after>package brightbox

import (
	"time"
)

// DatabaseServer represents a database server.
// https://api.gb1.brightbox.com/1.0/#database_server
type DatabaseServer struct {
	Id                      string
	Name                    string
	Description             string
	Status                  string
	Account                 Account
	DatabaseEngine          string             `json:"database_engine"`
	DatabaseVersion         string             `json:"database_version"`
	AdminUsername           string             `json:"admin_username"`
	AdminPassword           string             `json:"admin_password"`
	CreatedAt               *time.Time         `json:"created_at"`
	UpdatedAt               *time.Time         `json:"updated_at"`
	DeletedAt               *time.Time         `json:"deleted_at"`
	SnapshotsScheduleNextAt *time.Time         `json:"snapshots_schedule_next_at"`
	AllowAccess             []string           `json:"allow_access"`
	MaintenanceWeekday      int                `json:"maintenance_weekday"`
	MaintenanceHour         int                `json:"maintenance_hour"`
	SnapshotsSchedule       string             `json:"snapshots_schedule"`
	CloudIPs                []CloudIP          `json:"cloud_ips"`
	DatabaseServerType      DatabaseServerType `json:"database_server_type"`
	Locked                  bool
	Zone                    Zone
}

// DatabaseServerOptions is used in conjunction with CreateDatabaseServer and
// UpdateDatabaseServer to create and update database servers.
type DatabaseServerOptions struct {
	Id                 string   `json:"-"`
	Name               *string  `json:"name,omitempty"`
	Description        *string  `json:"description,omitempty"`
	Engine             string   `json:"engine,omitempty"`
	Version            string   `json:"version,omitempty"`
	AllowAccess        []string `json:"allow_access,omitempty"`
	Snapshot           string   `json:"snapshot,omitempty"`
	Zone               string   `json:"zone,omitempty"`
	DatabaseType       string   `json:"database_type,omitempty"`
	MaintenanceWeekday *int     `json:"maintenance_weekday,omitempty"`
	MaintenanceHour    *int     `json:"maintenance_hour,omitempty"`
	SnapshotsSchedule  *string  `json:"snapshots_schedule,omitempty"`
}

// DatabaseServers retrieves a list of all database servers
func (c *Client) DatabaseServers() ([]DatabaseServer, error) {
	var dbs []DatabaseServer
	_, err := c.MakeApiRequest("GET", "/1.0/database_servers", nil, &dbs)
	if err != nil {
		return nil, err
	}
	return dbs, err
}

// DatabaseServer retrieves a detailed view of one database server
func (c *Client) DatabaseServer(identifier string) (*DatabaseServer, error) {
	dbs := new(DatabaseServer)
	_, err := c.MakeApiRequest("GET", "/1.0/database_servers/"+identifier, nil, dbs)
	if err != nil {
		return nil, err
	}
	return dbs, err
}

// CreateDatabaseServer creates a new database server.
//
// It takes a DatabaseServerOptions struct for specifying name and other
// attributes. Not all attributes can be specified at create time
// (such as Id, which is allocated for you)
func (c *Client) CreateDatabaseServer(options *DatabaseServerOptions) (*DatabaseServer, error) {
	dbs := new(DatabaseServer)
	_, err := c.MakeApiRequest("POST", "/1.0/database_servers", options, &dbs)
	if err != nil {
		return nil, err
	}
	return dbs, nil
}

// UpdateDatabaseServer updates an existing database server.
//
// It takes a DatabaseServerOptions struct for specifying Id, name and other
// attributes. Not all attributes can be specified at update time.
func (c *Client) UpdateDatabaseServer(options *DatabaseServerOptions) (*DatabaseServer, error) {
	dbs := new(DatabaseServer)
	_, err := c.MakeApiRequest("PUT", "/1.0/database_servers/"+options.Id, options, &dbs)
	if err != nil {
		return nil, err
	}
	return dbs, nil
}

// DestroyDatabaseServer issues a request to deletes an existing database server
func (c *Client) DestroyDatabaseServer(identifier string) error {
	_, err := c.MakeApiRequest("DELETE", "/1.0/database_servers/"+identifier, nil, nil)
	return err
}

// SnapshotDatabaseServer requests a snapshot of an existing database server.
func (c *Client) SnapshotDatabaseServer(identifier string) (*DatabaseSnapshot, error) {
	dbs := new(DatabaseServer)
	res, err := c.MakeApiRequest("POST", "/1.0/database_servers/"+identifier+"/snapshot", nil, &dbs)
	if err != nil {
		return nil, err
	}
	snapID := getLinkRel(res.Header.Get("Link"), "dbi", "snapshot")
	if snapID != nil {
		snap := new(DatabaseSnapshot)
		snap.Id = *snapID
		return snap, nil
	}
	return nil, nil
}

// ResetPasswordForDatabaseServer requests a snapshot of an existing database server.
func (c *Client) ResetPasswordForDatabaseServer(identifier string) (*DatabaseServer, error) {
	dbs := new(DatabaseServer)
	_, err := c.MakeApiRequest("POST", "/1.0/database_servers/"+identifier+"/reset_password", nil, &dbs)
	if err != nil {
		return nil, err
	}
	return dbs, nil
}
<|endoftext|>