<commit_before>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package builders

import (
	"fmt"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apiserver/pkg/endpoints/request"
	"k8s.io/apiserver/pkg/registry/generic"
	"k8s.io/apiserver/pkg/registry/generic/registry"
	"k8s.io/apiserver/pkg/registry/rest"
	"k8s.io/client-go/pkg/api"
)

//
// Versioned Kind Builder builds a versioned resource using unversioned strategy
//

// NewApiResource returns a new versionedResourceBuilder for registering endpoints for
// resources that are persisted to storage.
// strategy - unversionedBuilder from calling NewUnversionedXXX()
// new - function for creating new empty VERSIONED instances - e.g. func() runtime.Object { return &Deployment{} }
// newList - function for creating an empty list of VERSIONED instances - e.g. func() runtime.Object { return &DeploymentList{} }
// storeBuilder - builder for creating the store
func NewApiResource(
	unversionedBuilder UnversionedResourceBuilder,
	schemeFns SchemeFns,
	new, newList func() runtime.Object,
	storeBuilder StorageBuilder) *versionedResourceBuilder {

	if storeBuilder == nil {
		storeBuilder = StorageStrategySingleton
	}

	return &versionedResourceBuilder{
		unversionedBuilder, schemeFns, new, newList, storeBuilder, nil, nil,
	}
}

// NewApiResourceWithStorage returns a new versionedResourceBuilder for registering endpoints that
// does not require standard storage (e.g. subresources reuses the storage for the parent resource).
// strategy - unversionedBuilder from calling NewUnversionedXXX()
// new - function for creating new empty VERSIONED instances - e.g. func() runtime.Object { return &Deployment{} }
// storage - storage for manipulating the resource
func NewApiResourceWithStorage(
	unversionedBuilder UnversionedResourceBuilder,
	schemeFns SchemeFns,
	new, newList func() runtime.Object,
	storage rest.Storage) *versionedResourceBuilder {
	v := &versionedResourceBuilder{
		unversionedBuilder, schemeFns, new, newList, nil, storage, nil,
	}
	if new == nil {
		panic(fmt.Errorf("Cannot call NewApiResourceWithStorage with nil new function."))
	}
	if storage == nil {
		panic(fmt.Errorf("Cannot call NewApiResourceWithStorage with nil new storage."))
	}
	return v
}

type versionedResourceBuilder struct {
	Unversioned UnversionedResourceBuilder
	SchemeFns   SchemeFns

	// NewFunc returns an empty unversioned instance of a resource
	NewFunc func() runtime.Object

	// NewListFunc returns and empty unversioned instance of a resource List
	NewListFunc func() runtime.Object

	// Store is used to modify the default storage, mutually exclusive with RESTFunc
	StorageBuilder StorageBuilder

	// REST a rest.Store implementation, mutually exclusive with StoreFunc
	REST rest.Storage

	Storage rest.StandardStorage
}

func (b *versionedResourceBuilder) New() runtime.Object {
	if b.NewFunc == nil {
		return nil
	}
	return b.NewFunc()
}

func (b *versionedResourceBuilder) NewList() runtime.Object {
	if b.NewListFunc == nil {
		return nil
	}
	return b.NewListFunc()
}

type StorageWrapper struct {
	registry.Store
}

func (s StorageWrapper) Create(ctx request.Context, obj runtime.Object) (runtime.Object, error) {
	return s.Store.Create(ctx, obj)
}

func (b *versionedResourceBuilder) Build(
	group string,
	optionsGetter generic.RESTOptionsGetter) rest.StandardStorage {

	// Set a default strategy
	watchCacheSize := 1000
	store := &StorageWrapper{registry.Store{
		Copier:            api.Scheme,
		NewFunc:           b.Unversioned.New,     // Use the unversioned type
		NewListFunc:       b.Unversioned.NewList, // Use the unversioned type
		QualifiedResource: b.getGroupResource(group),
		WatchCacheSize:    &watchCacheSize,
	}}

	// Use default, requires
	options := &generic.StoreOptions{RESTOptions: optionsGetter}

	if b.StorageBuilder != nil {
		// Allow overriding the storage defaults
		b.StorageBuilder.Build(b.StorageBuilder, store, options)
	}

	if err := store.CompleteWithOptions(options); err != nil {
		panic(err) // TODO: Propagate error up
	}
	b.Storage = store
	return store
}

func (b *versionedResourceBuilder) GetStandardStorage() rest.StandardStorage {
	return b.Storage
}

// getGroupResource returns the GroupResource for this Resource and the provided Group
// group is the group the resource belongs to
func (b *versionedResourceBuilder) getGroupResource(group string) schema.GroupResource {
	return schema.GroupResource{group, b.Unversioned.GetName()}

}

// registerEndpoints registers the REST endpoints for this resource in the registry
// group is the group to register the resource under
// optionsGetter is the RESTOptionsGetter provided by a server.Config
// registry is the server.APIGroupInfo VersionedResourcesStorageMap used to register REST endpoints
func (b *versionedResourceBuilder) registerEndpoints(
	group string,
	optionsGetter generic.RESTOptionsGetter,
	registry map[string]rest.Storage) {

	// Register the endpoint
	path := b.Unversioned.GetPath()
	if len(path) > 0 {
		// Subresources appear after the resource
		path = b.Unversioned.GetName() + "/" + path
	} else {
		path = b.Unversioned.GetName()
	}

	if b.REST != nil {
		// Use the REST implementation directly.
		registry[path] = b.REST
	} else {
		// Create a new REST implementation wired to storage.
		registry[path] = b.
			Build(group, optionsGetter)
	}
}
<commit_msg>Revert "Update for compatibility with newest apiserver code"<commit_after>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package builders

import (
	"fmt"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apiserver/pkg/endpoints/request"
	"k8s.io/apiserver/pkg/registry/generic"
	"k8s.io/apiserver/pkg/registry/generic/registry"
	"k8s.io/apiserver/pkg/registry/rest"
	"k8s.io/client-go/pkg/api"
)

//
// Versioned Kind Builder builds a versioned resource using unversioned strategy
//

// NewApiResource returns a new versionedResourceBuilder for registering endpoints for
// resources that are persisted to storage.
// strategy - unversionedBuilder from calling NewUnversionedXXX()
// new - function for creating new empty VERSIONED instances - e.g. func() runtime.Object { return &Deployment{} }
// newList - function for creating an empty list of VERSIONED instances - e.g. func() runtime.Object { return &DeploymentList{} }
// storeBuilder - builder for creating the store
func NewApiResource(
	unversionedBuilder UnversionedResourceBuilder,
	schemeFns SchemeFns,
	new, newList func() runtime.Object,
	storeBuilder StorageBuilder) *versionedResourceBuilder {

	if storeBuilder == nil {
		storeBuilder = StorageStrategySingleton
	}

	return &versionedResourceBuilder{
		unversionedBuilder, schemeFns, new, newList, storeBuilder, nil, nil,
	}
}

// NewApiResourceWithStorage returns a new versionedResourceBuilder for registering endpoints that
// does not require standard storage (e.g. subresources reuses the storage for the parent resource).
// strategy - unversionedBuilder from calling NewUnversionedXXX()
// new - function for creating new empty VERSIONED instances - e.g. func() runtime.Object { return &Deployment{} }
// storage - storage for manipulating the resource
func NewApiResourceWithStorage(
	unversionedBuilder UnversionedResourceBuilder,
	schemeFns SchemeFns,
	new, newList func() runtime.Object,
	storage rest.Storage) *versionedResourceBuilder {
	v := &versionedResourceBuilder{
		unversionedBuilder, schemeFns, new, newList, nil, storage, nil,
	}
	if new == nil {
		panic(fmt.Errorf("Cannot call NewApiResourceWithStorage with nil new function."))
	}
	if storage == nil {
		panic(fmt.Errorf("Cannot call NewApiResourceWithStorage with nil new storage."))
	}
	return v
}

type versionedResourceBuilder struct {
	Unversioned UnversionedResourceBuilder
	SchemeFns   SchemeFns

	// NewFunc returns an empty unversioned instance of a resource
	NewFunc func() runtime.Object

	// NewListFunc returns and empty unversioned instance of a resource List
	NewListFunc func() runtime.Object

	// Store is used to modify the default storage, mutually exclusive with RESTFunc
	StorageBuilder StorageBuilder

	// REST a rest.Store implementation, mutually exclusive with StoreFunc
	REST rest.Storage

	Storage rest.StandardStorage
}

func (b *versionedResourceBuilder) New() runtime.Object {
	if b.NewFunc == nil {
		return nil
	}
	return b.NewFunc()
}

func (b *versionedResourceBuilder) NewList() runtime.Object {
	if b.NewListFunc == nil {
		return nil
	}
	return b.NewListFunc()
}

type StorageWrapper struct {
	registry.Store
}

func (s StorageWrapper) Create(ctx request.Context, obj runtime.Object) (runtime.Object, error) {
	return s.Store.Create(ctx, obj)
}

func (b *versionedResourceBuilder) Build(
	group string,
	optionsGetter generic.RESTOptionsGetter) rest.StandardStorage {

	// Set a default strategy
	store := &StorageWrapper{registry.Store{
		Copier:            api.Scheme,
		NewFunc:           b.Unversioned.New,     // Use the unversioned type
		NewListFunc:       b.Unversioned.NewList, // Use the unversioned type
		QualifiedResource: b.getGroupResource(group),
		WatchCacheSize:    1000,
	}}

	// Use default, requires
	options := &generic.StoreOptions{RESTOptions: optionsGetter}

	if b.StorageBuilder != nil {
		// Allow overriding the storage defaults
		b.StorageBuilder.Build(b.StorageBuilder, store, options)
	}

	if err := store.CompleteWithOptions(options); err != nil {
		panic(err) // TODO: Propagate error up
	}
	b.Storage = store
	return store
}

func (b *versionedResourceBuilder) GetStandardStorage() rest.StandardStorage {
	return b.Storage
}

// getGroupResource returns the GroupResource for this Resource and the provided Group
// group is the group the resource belongs to
func (b *versionedResourceBuilder) getGroupResource(group string) schema.GroupResource {
	return schema.GroupResource{group, b.Unversioned.GetName()}

}

// registerEndpoints registers the REST endpoints for this resource in the registry
// group is the group to register the resource under
// optionsGetter is the RESTOptionsGetter provided by a server.Config
// registry is the server.APIGroupInfo VersionedResourcesStorageMap used to register REST endpoints
func (b *versionedResourceBuilder) registerEndpoints(
	group string,
	optionsGetter generic.RESTOptionsGetter,
	registry map[string]rest.Storage) {

	// Register the endpoint
	path := b.Unversioned.GetPath()
	if len(path) > 0 {
		// Subresources appear after the resource
		path = b.Unversioned.GetName() + "/" + path
	} else {
		path = b.Unversioned.GetName()
	}

	if b.REST != nil {
		// Use the REST implementation directly.
		registry[path] = b.REST
	} else {
		// Create a new REST implementation wired to storage.
		registry[path] = b.
			Build(group, optionsGetter)
	}
}
<|endoftext|>


<commit_before>package acceptance_test

import (
	"fmt"
	"os/exec"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"
)

func startDaemon(args ...string) (*gexec.Session, error) {
	ducatiCmd := exec.Command(ducatidPath, args...)
	return gexec.Start(ducatiCmd, GinkgoWriter, GinkgoWriter)
}

var _ = Describe("Ducati Daemon Flag Validation", func() {
	var (
		address string
		session *gexec.Session
		err     error
	)

	BeforeEach(func() {
		address = fmt.Sprintf("127.0.0.1:%d", 4001+GinkgoParallelNode())
	})

	AfterEach(func() {
		if session != nil {
			session.Kill()
			Eventually(session).Should(gexec.Exit())
		}
	})

	Context("when the listenAddr flag is missing", func() {
		It("fails to start and provides a meaninful error", func() {
			session, err = startDaemon("-localSubnet=192.168.3.0/16", "-overlayNetwork=192.168.0.0/16")
			Expect(err).NotTo(HaveOccurred())

			Eventually(session).Should(gexec.Exit(1))
			Expect(session.Err).To(gbytes.Say(`missing required flag "listenAddr"`))
		})
	})

	Context("when the overlayNetwork flag is missing", func() {
		It("fails to start and provides a meaninful error", func() {
			session, err = startDaemon("-listenAddr", address, "-localSubnet=192.168.3.0/16")
			Expect(err).NotTo(HaveOccurred())

			Eventually(session).Should(gexec.Exit(1))
			Expect(session.Err).To(gbytes.Say(`missing required flag "overlayNetwork"`))
		})
	})

	Context("when the localSubnet flag is missing", func() {
		It("fails to start and provides a meaninful error", func() {
			session, err = startDaemon("-listenAddr", address, "-overlayNetwork=192.168.3.0/16")
			Expect(err).NotTo(HaveOccurred())

			Eventually(session).Should(gexec.Exit(1))
			Expect(session.Err).To(gbytes.Say(`missing required flag "localSubnet"`))
		})
	})

	Context("when the overlayNetwork does not contain localSubnet", func() {
		It("fails to start and provides a meaninful error", func() {
			session, err = startDaemon("-listenAddr", address, "-overlayNetwork=192.168.3.0/24", "-localSubnet=192.168.4.0/24")
			Expect(err).NotTo(HaveOccurred())

			Eventually(session).Should(gexec.Exit(1))
			Expect(session.Err).To(gbytes.Say(`overlay network does not contain local subnet`))
		})
	})

	Context("when localSubnet is not a valid CIDR", func() {
		It("fails to start and provides a meaninful error", func() {
			session, err = startDaemon("-listenAddr", address, "-overlayNetwork=192.168.3.0/24", "-localSubnet=gobbledygook")
			Expect(err).NotTo(HaveOccurred())

			Eventually(session).Should(gexec.Exit(1))
			Expect(session.Err).To(gbytes.Say(`invalid CIDR provided for "localSubnet": gobbledygook`))
		})
	})

	Context("when overlayNetwork is not a valid CIDR", func() {
		It("fails to start and provides a meaninful error", func() {
			session, err = startDaemon("-listenAddr", address, "-overlayNetwork=gobbledygook", "-localSubnet=192.168.1.0/24")
			Expect(err).NotTo(HaveOccurred())

			Eventually(session).Should(gexec.Exit(1))
			Expect(session.Err).To(gbytes.Say(`invalid CIDR provided for "overlayNetwork": gobbledygook`))
		})
	})
})
<commit_msg>Refactor daemon flag errors acceptance test as table test<commit_after>package acceptance_test

import (
	"os/exec"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/ginkgo/extensions/table"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"
)

func startDaemon(args ...string) (*gexec.Session, error) {
	ducatiCmd := exec.Command(ducatidPath, args...)
	return gexec.Start(ducatiCmd, GinkgoWriter, GinkgoWriter)
}

var _ = Describe("Ducati Daemon Flag Validation", func() {
	var (
		session *gexec.Session
		err     error
	)

	AfterEach(func() {
		if session != nil {
			session.Kill()
			Eventually(session).Should(gexec.Exit())
		}
	})

	DescribeTable("flag errors",
		func(expectedError string, flags ...string) {
			session, err = startDaemon(flags...)
			Expect(err).NotTo(HaveOccurred())

			Eventually(session).Should(gexec.Exit(1))
			Expect(session.Err).To(gbytes.Say(expectedError))
		},
		Entry("missing listenAddr", `missing required flag "listenAddr"`,
			"-localSubnet=192.168.3.0/16", "-overlayNetwork=192.168.0.0/16"),

		Entry("missing overlayNetwork flag", `missing required flag "listenAddr"`,
			"-localSubnet=192.168.3.0/16", "-overlayNetwork=192.168.0.0/16"),

		Entry("missing localSubnet flag", `missing required flag "localSubnet"`,
			"-listenAddr=some-listen-address", "-overlayNetwork=192.168.3.0/16"),

		Entry("overlayNetwork does not container localSubnet", `overlay network does not contain local subnet`,
			"-listenAddr=some-listen-address", "-overlayNetwork=192.168.3.0/24", "-localSubnet=192.168.4.0/24"),

		Entry("localSubnet is not a valid CIDR", `invalid CIDR provided for "localSubnet": gobbledygook`,
			"-listenAddr=some-listen-address", "-overlayNetwork=192.168.3.0/24", "-localSubnet=gobbledygook"),

		Entry("overlayNetwork is not a valid CIDR", `invalid CIDR provided for "overlayNetwork": gobbledygook`,
			"-listenAddr=some-listen-address", "-overlayNetwork=gobbledygook", "-localSubnet=192.168.1.0/24"),
	)
})
<|endoftext|>


<commit_before>package main

import (
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/terraform"
)

// Provider returns a terraform.ResourceProvider.
func Provider() terraform.ResourceProvider {
	return &schema.Provider{
		Schema: map[string]*schema.Schema{
			"key": {
				Type:        schema.TypeString,
				Required:    true,
				DefaultFunc: schema.EnvDefaultFunc("GD_KEY", nil),
				Description: "GoDaddy API Key.",
			},

			"secret": {
				Type:        schema.TypeString,
				Required:    true,
				DefaultFunc: schema.EnvDefaultFunc("GD_SECRET", nil),
				Description: "GoDaddy API Secret.",
			},

			"baseurl": &schema.Schema{
				Type:        schema.TypeString,
				Optional:    true,
				Default:     "https://api.ote-godaddy.com",
				Description: "GoDaddy Base Url(defaults to testing).",
			},
		},

		ResourcesMap: map[string]*schema.Resource{
			"godaddy_domain_record": resourceDomainRecord(),
		},

		ConfigureFunc: providerConfigure,
	}
}

func providerConfigure(d *schema.ResourceData) (interface{}, error) {
	config := Config{
		Key:     d.Get("key").(string),
		Secret:  d.Get("secret").(string),
		BaseURL: d.Get("baseurl").(string),
	}

	return config.Client()
}
<commit_msg>correct baseurl for default api url; fixes #1<commit_after>package main

import (
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/terraform"
)

// Provider returns a terraform.ResourceProvider.
func Provider() terraform.ResourceProvider {
	return &schema.Provider{
		Schema: map[string]*schema.Schema{
			"key": {
				Type:        schema.TypeString,
				Required:    true,
				DefaultFunc: schema.EnvDefaultFunc("GD_KEY", nil),
				Description: "GoDaddy API Key.",
			},

			"secret": {
				Type:        schema.TypeString,
				Required:    true,
				DefaultFunc: schema.EnvDefaultFunc("GD_SECRET", nil),
				Description: "GoDaddy API Secret.",
			},

			"baseurl": &schema.Schema{
				Type:        schema.TypeString,
				Optional:    true,
				Default:     "https://api.godaddy.com",
				Description: "GoDaddy Base Url(defaults to testing).",
			},
		},

		ResourcesMap: map[string]*schema.Resource{
			"godaddy_domain_record": resourceDomainRecord(),
		},

		ConfigureFunc: providerConfigure,
	}
}

func providerConfigure(d *schema.ResourceData) (interface{}, error) {
	config := Config{
		Key:     d.Get("key").(string),
		Secret:  d.Get("secret").(string),
		BaseURL: d.Get("baseurl").(string),
	}

	return config.Client()
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"time"

	"github.com/99designs/aws-vault/keyring"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/service/sts"
)

const (
	MaxSessionDuration    = time.Hour * 36
	MinSessionDuration    = time.Minute * 15
	MinAssumeRoleDuration = time.Minute * 15
	MaxAssumeRoleDuration = time.Hour

	DefaultSessionDuration    = time.Hour * 4
	DefaultAssumeRoleDuration = time.Minute * 15
)

type stsClient interface {
	AssumeRole(input *sts.AssumeRoleInput) (*sts.AssumeRoleOutput, error)
	GetSessionToken(input *sts.GetSessionTokenInput) (*sts.GetSessionTokenOutput, error)
}

type VaultOptions struct {
	SessionDuration    time.Duration
	AssumeRoleDuration time.Duration
	ExpiryWindow       time.Duration
	WriteEnv           bool
}

func (o VaultOptions) Validate() error {
	if o.SessionDuration < time.Minute*15 {
		return errors.New("Minimum session duration is 15 minutes")
	} else if o.SessionDuration > time.Hour*36 {
		return errors.New("Maximum session duration is 36 hours")
	}
	return nil
}

func (o VaultOptions) ApplyDefaults() VaultOptions {
	if o.AssumeRoleDuration == 0 {
		o.AssumeRoleDuration = DefaultAssumeRoleDuration
	}
	if o.SessionDuration == 0 {
		o.SessionDuration = DefaultSessionDuration
	}
	return o
}

type VaultProvider struct {
	credentials.Expiry
	VaultOptions
	profile  string
	expires  time.Time
	keyring  keyring.Keyring
	profiles profiles
	session  *sts.Credentials
	client   stsClient
}

func NewVaultProvider(k keyring.Keyring, profile string, opts VaultOptions) (*VaultProvider, error) {
	if err := opts.Validate(); err != nil {
		return nil, err
	}
	profiles, err := parseProfiles()
	if err != nil {
		return nil, err
	}
	return &VaultProvider{
		VaultOptions: opts.ApplyDefaults(),
		keyring:      k,
		profile:      profile,
		profiles:     profiles,
	}, nil
}

func (p *VaultProvider) Retrieve() (credentials.Value, error) {
	creds, err := p.getMasterCreds()
	if err != nil {
		return credentials.Value{}, err
	}

	session, err := p.getCachedSession()
	if err != nil {
		if err == keyring.ErrKeyNotFound {
			log.Println("Session not found in keyring")
		} else {
			log.Println(err)
		}

		session, err = p.getSessionToken(&creds)
		if err != nil {
			return credentials.Value{}, err
		}

		bytes, err := json.Marshal(session)
		if err != nil {
			return credentials.Value{}, err
		}

		log.Printf("Writing session for %s to keyring", p.profile)
		p.keyring.Set(keyring.Item{
			Key:       sessionKey(p.profile),
			Label:     "aws-vault session for " + p.profile,
			Data:      bytes,
			TrustSelf: true,
		})
	}

	log.Printf("Using session, expires in %s", session.Expiration.Sub(time.Now()).String())

	window := p.ExpiryWindow
	if window == 0 {
		window = p.SessionDuration - (p.SessionDuration / 3)
	}

	p.SetExpiration(*session.Expiration, window)
	p.expires = *session.Expiration

	if role, ok := p.profiles[p.profile]["role_arn"]; ok {
		session, err = p.assumeRole(session, role)
		if err != nil {
			return credentials.Value{}, err
		}

		log.Printf("Role token expires in %s", session.Expiration.Sub(time.Now()))
	}

	value := credentials.Value{
		AccessKeyID:     *session.AccessKeyId,
		SecretAccessKey: *session.SecretAccessKey,
		SessionToken:    *session.SessionToken,
	}

	return value, nil
}

func sessionKey(profile string) string {
	return profile + " session"
}

func (p *VaultProvider) getCachedSession() (session sts.Credentials, err error) {
	item, err := p.keyring.Get(sessionKey(p.profile))
	if err != nil {
		return session, err
	}

	if err = json.Unmarshal(item.Data, &session); err != nil {
		return session, err
	}

	if session.Expiration.Before(time.Now()) {
		return session, errors.New("Session is expired")
	}

	return
}

func (p *VaultProvider) getMasterCreds() (credentials.Value, error) {
	source := p.profiles.sourceProfile(p.profile)

	provider := credentials.NewChainCredentials([]credentials.Provider{
		&credentials.EnvProvider{},
		&credentials.SharedCredentialsProvider{Filename: "", Profile: p.profile},
		&KeyringProvider{Keyring: p.keyring, Profile: source},
	})

	return provider.Get()
}

func (p *VaultProvider) getSessionToken(creds *credentials.Value) (sts.Credentials, error) {
	params := &sts.GetSessionTokenInput{
		DurationSeconds: aws.Int64(int64(p.SessionDuration.Seconds())),
	}

	if mfa, ok := p.profiles[p.profile]["mfa_serial"]; ok {
		token, err := prompt(fmt.Sprintf("Enter token for %s: ", mfa))
		if err != nil {
			return sts.Credentials{}, err
		}
		params.SerialNumber = aws.String(mfa)
		params.TokenCode = aws.String(token)
	}

	client := p.client
	if client == nil {
		client = sts.New(&aws.Config{
			Credentials: credentials.NewCredentials(&credentials.StaticProvider{
				Value: *creds,
			}),
		})
	}

	log.Printf("Getting new session token for profile %s", p.profile)
	resp, err := client.GetSessionToken(params)
	if err != nil {
		return sts.Credentials{}, err
	}

	return *resp.Credentials, nil
}

func (p *VaultProvider) assumeRole(session sts.Credentials, roleArn string) (sts.Credentials, error) {
	client := p.client
	if client == nil {
		client = sts.New(&aws.Config{Credentials: credentials.NewStaticCredentials(
			*session.AccessKeyId,
			*session.SecretAccessKey,
			*session.SessionToken,
		)})
	}

	// Try to work out a role name that will hopefully end up unique.
	roleSessionName := fmt.Sprintf("%d", time.Now().UTC().UnixNano())

	input := &sts.AssumeRoleInput{
		RoleArn:         aws.String(roleArn),
		RoleSessionName: aws.String(roleSessionName),
		DurationSeconds: aws.Int64(int64(p.AssumeRoleDuration.Seconds())),
	}

	log.Printf("Assuming role %s, expires in %s", roleArn, p.AssumeRoleDuration.String())
	resp, err := client.AssumeRole(input)
	if err != nil {
		return sts.Credentials{}, err
	}

	return *resp.Credentials, nil
}

type KeyringProvider struct {
	Keyring keyring.Keyring
	Profile string
}

func (p *KeyringProvider) IsExpired() bool {
	return false
}

func (p *KeyringProvider) Retrieve() (val credentials.Value, err error) {
	log.Printf("Looking up keyring for %s", p.Profile)
	item, err := p.Keyring.Get(p.Profile)
	if err != nil {
		return val, err
	}

	err = json.Unmarshal(item.Data, &val)
	return
}

func (p *KeyringProvider) Store(val credentials.Value) error {
	p.Keyring.Remove(sessionKey(p.Profile))

	bytes, err := json.Marshal(val)
	if err != nil {
		return err
	}

	return p.Keyring.Set(keyring.Item{
		Key:  p.Profile,
		Data: bytes,
	})
}

func (p *KeyringProvider) Delete() error {
	p.Keyring.Remove(sessionKey(p.Profile))
	return p.Keyring.Remove(p.Profile)
}

type VaultCredentials struct {
	*credentials.Credentials
	provider *VaultProvider
}

func NewVaultCredentials(k keyring.Keyring, profile string, opts VaultOptions) (*VaultCredentials, error) {
	provider, err := NewVaultProvider(k, profile, opts)
	if err != nil {
		return nil, err
	}

	return &VaultCredentials{credentials.NewCredentials(provider), provider}, nil
}

func (v *VaultCredentials) Expires() time.Time {
	return v.provider.expires
}
<commit_msg>Fix bug where option validation always fails<commit_after>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"time"

	"github.com/99designs/aws-vault/keyring"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/service/sts"
)

const (
	MaxSessionDuration    = time.Hour * 36
	MinSessionDuration    = time.Minute * 15
	MinAssumeRoleDuration = time.Minute * 15
	MaxAssumeRoleDuration = time.Hour

	DefaultSessionDuration    = time.Hour * 4
	DefaultAssumeRoleDuration = time.Minute * 15
)

type stsClient interface {
	AssumeRole(input *sts.AssumeRoleInput) (*sts.AssumeRoleOutput, error)
	GetSessionToken(input *sts.GetSessionTokenInput) (*sts.GetSessionTokenOutput, error)
}

type VaultOptions struct {
	SessionDuration    time.Duration
	AssumeRoleDuration time.Duration
	ExpiryWindow       time.Duration
	WriteEnv           bool
}

func (o VaultOptions) Validate() error {
	if o.SessionDuration < time.Minute*15 {
		return errors.New("Minimum session duration is 15 minutes")
	} else if o.SessionDuration > time.Hour*36 {
		return errors.New("Maximum session duration is 36 hours")
	}
	return nil
}

func (o VaultOptions) ApplyDefaults() VaultOptions {
	if o.AssumeRoleDuration == 0 {
		o.AssumeRoleDuration = DefaultAssumeRoleDuration
	}
	if o.SessionDuration == 0 {
		o.SessionDuration = DefaultSessionDuration
	}
	return o
}

type VaultProvider struct {
	credentials.Expiry
	VaultOptions
	profile  string
	expires  time.Time
	keyring  keyring.Keyring
	profiles profiles
	session  *sts.Credentials
	client   stsClient
}

func NewVaultProvider(k keyring.Keyring, profile string, opts VaultOptions) (*VaultProvider, error) {
	opts = opts.ApplyDefaults()
	if err := opts.Validate(); err != nil {
		return nil, err
	}
	profiles, err := parseProfiles()
	if err != nil {
		return nil, err
	}
	return &VaultProvider{
		VaultOptions: opts,
		keyring:      k,
		profile:      profile,
		profiles:     profiles,
	}, nil
}

func (p *VaultProvider) Retrieve() (credentials.Value, error) {
	creds, err := p.getMasterCreds()
	if err != nil {
		return credentials.Value{}, err
	}

	session, err := p.getCachedSession()
	if err != nil {
		if err == keyring.ErrKeyNotFound {
			log.Println("Session not found in keyring")
		} else {
			log.Println(err)
		}

		session, err = p.getSessionToken(&creds)
		if err != nil {
			return credentials.Value{}, err
		}

		bytes, err := json.Marshal(session)
		if err != nil {
			return credentials.Value{}, err
		}

		log.Printf("Writing session for %s to keyring", p.profile)
		p.keyring.Set(keyring.Item{
			Key:       sessionKey(p.profile),
			Label:     "aws-vault session for " + p.profile,
			Data:      bytes,
			TrustSelf: true,
		})
	}

	log.Printf("Using session, expires in %s", session.Expiration.Sub(time.Now()).String())

	window := p.ExpiryWindow
	if window == 0 {
		window = p.SessionDuration - (p.SessionDuration / 3)
	}

	p.SetExpiration(*session.Expiration, window)
	p.expires = *session.Expiration

	if role, ok := p.profiles[p.profile]["role_arn"]; ok {
		session, err = p.assumeRole(session, role)
		if err != nil {
			return credentials.Value{}, err
		}

		log.Printf("Role token expires in %s", session.Expiration.Sub(time.Now()))
	}

	value := credentials.Value{
		AccessKeyID:     *session.AccessKeyId,
		SecretAccessKey: *session.SecretAccessKey,
		SessionToken:    *session.SessionToken,
	}

	return value, nil
}

func sessionKey(profile string) string {
	return profile + " session"
}

func (p *VaultProvider) getCachedSession() (session sts.Credentials, err error) {
	item, err := p.keyring.Get(sessionKey(p.profile))
	if err != nil {
		return session, err
	}

	if err = json.Unmarshal(item.Data, &session); err != nil {
		return session, err
	}

	if session.Expiration.Before(time.Now()) {
		return session, errors.New("Session is expired")
	}

	return
}

func (p *VaultProvider) getMasterCreds() (credentials.Value, error) {
	source := p.profiles.sourceProfile(p.profile)

	provider := credentials.NewChainCredentials([]credentials.Provider{
		&credentials.EnvProvider{},
		&credentials.SharedCredentialsProvider{Filename: "", Profile: p.profile},
		&KeyringProvider{Keyring: p.keyring, Profile: source},
	})

	return provider.Get()
}

func (p *VaultProvider) getSessionToken(creds *credentials.Value) (sts.Credentials, error) {
	params := &sts.GetSessionTokenInput{
		DurationSeconds: aws.Int64(int64(p.SessionDuration.Seconds())),
	}

	if mfa, ok := p.profiles[p.profile]["mfa_serial"]; ok {
		token, err := prompt(fmt.Sprintf("Enter token for %s: ", mfa))
		if err != nil {
			return sts.Credentials{}, err
		}
		params.SerialNumber = aws.String(mfa)
		params.TokenCode = aws.String(token)
	}

	client := p.client
	if client == nil {
		client = sts.New(&aws.Config{
			Credentials: credentials.NewCredentials(&credentials.StaticProvider{
				Value: *creds,
			}),
		})
	}

	log.Printf("Getting new session token for profile %s", p.profile)
	resp, err := client.GetSessionToken(params)
	if err != nil {
		return sts.Credentials{}, err
	}

	return *resp.Credentials, nil
}

func (p *VaultProvider) assumeRole(session sts.Credentials, roleArn string) (sts.Credentials, error) {
	client := p.client
	if client == nil {
		client = sts.New(&aws.Config{Credentials: credentials.NewStaticCredentials(
			*session.AccessKeyId,
			*session.SecretAccessKey,
			*session.SessionToken,
		)})
	}

	// Try to work out a role name that will hopefully end up unique.
	roleSessionName := fmt.Sprintf("%d", time.Now().UTC().UnixNano())

	input := &sts.AssumeRoleInput{
		RoleArn:         aws.String(roleArn),
		RoleSessionName: aws.String(roleSessionName),
		DurationSeconds: aws.Int64(int64(p.AssumeRoleDuration.Seconds())),
	}

	log.Printf("Assuming role %s, expires in %s", roleArn, p.AssumeRoleDuration.String())
	resp, err := client.AssumeRole(input)
	if err != nil {
		return sts.Credentials{}, err
	}

	return *resp.Credentials, nil
}

type KeyringProvider struct {
	Keyring keyring.Keyring
	Profile string
}

func (p *KeyringProvider) IsExpired() bool {
	return false
}

func (p *KeyringProvider) Retrieve() (val credentials.Value, err error) {
	log.Printf("Looking up keyring for %s", p.Profile)
	item, err := p.Keyring.Get(p.Profile)
	if err != nil {
		return val, err
	}

	err = json.Unmarshal(item.Data, &val)
	return
}

func (p *KeyringProvider) Store(val credentials.Value) error {
	p.Keyring.Remove(sessionKey(p.Profile))

	bytes, err := json.Marshal(val)
	if err != nil {
		return err
	}

	return p.Keyring.Set(keyring.Item{
		Key:  p.Profile,
		Data: bytes,
	})
}

func (p *KeyringProvider) Delete() error {
	p.Keyring.Remove(sessionKey(p.Profile))
	return p.Keyring.Remove(p.Profile)
}

type VaultCredentials struct {
	*credentials.Credentials
	provider *VaultProvider
}

func NewVaultCredentials(k keyring.Keyring, profile string, opts VaultOptions) (*VaultCredentials, error) {
	provider, err := NewVaultProvider(k, profile, opts)
	if err != nil {
		return nil, err
	}

	return &VaultCredentials{credentials.NewCredentials(provider), provider}, nil
}

func (v *VaultCredentials) Expires() time.Time {
	return v.provider.expires
}
<|endoftext|>


<commit_before>package gomniauth

import (
	"github.com/stretchr/gomniauth/common"
	"github.com/stretchr/stew/objects"
	"net/http"
)

type Provider interface {

	// Name is the unique name for this provider.
	Name() string

	// With gets a provider with the specified Config.
	With(common.Config) Provider

	// AuthHandler gets the AuthHandler that handles this provider.
	AuthHandler() AuthHandler

	// BeginAuthURL gets the URL that the client must visit in order
	// to begin the authentication process.
	BeginAuthURL(params objects.Map) (string, error)

	// CompleteAuth takes a map of arguments that are used to
	// complete the authorisation process, completes it, and returns
	// the appropriate common.Credentials.
	CompleteAuth(data objects.Map) (common.Credentials, error)

	// LoadUser uses the specified common.Credentials to access the users profile
	// from the remote provider, and builds the appropriate User object.
	LoadUser(creds common.Credentials) (User, error)

	// GetClient gets an http.Client authenticated with the specified
	// common.Credentials.
	GetClient(creds common.Credentials) (*http.Client, error)
}
<commit_msg>removed With<commit_after>package gomniauth

import (
	"github.com/stretchr/gomniauth/common"
	"github.com/stretchr/stew/objects"
	"net/http"
)

type Provider interface {

	// Name is the unique name for this provider.
	Name() string

	// AuthHandler gets the AuthHandler that handles this provider.
	AuthHandler() AuthHandler

	// BeginAuthURL gets the URL that the client must visit in order
	// to begin the authentication process.
	BeginAuthURL(params objects.Map) (string, error)

	// CompleteAuth takes a map of arguments that are used to
	// complete the authorisation process, completes it, and returns
	// the appropriate common.Credentials.
	CompleteAuth(data objects.Map) (common.Credentials, error)

	// LoadUser uses the specified common.Credentials to access the users profile
	// from the remote provider, and builds the appropriate User object.
	LoadUser(creds common.Credentials) (User, error)

	// GetClient gets an http.Client authenticated with the specified
	// common.Credentials.
	GetClient(creds common.Credentials) (*http.Client, error)
}
<|endoftext|>


<commit_before>package api

import (
	"log"
	"net/http"

	"github.com/labstack/echo"
)

type Application struct {
	ID int `json:"id"`
	Name string `json:"name"`
	AuthorName string `json:"authorName"`
	CallbackURL string `json:"callbackUrl"`
}

type ApplicationTokenResponse struct {
	Status string `json:"status"`
	Token string `json:"token"`
}
type SingleApplicationResponse struct {
	Status string `json:"status"`
	Application Application `json:"application"`
}

func InitApplicationAPI(e *echo.Echo) {
	e.POST("/application/completeAuth", func(c echo.Context) error {
		if GetSessionUserID(&c) == -1 {
			return c.JSON(http.StatusUnauthorized, ErrorResponse{"error", "logged_out"})
		}

		// get the application
		applicationRows, err := DB.Query("SELECT id, name, authorName, callbackUrl FROM applications WHERE clientId = ?", c.FormValue("clientId"))
		if err != nil {
			log.Println("Error while completing application auth: ")
			log.Println(err)
			return c.JSON(http.StatusInternalServerError, StatusResponse{"error"})
		}
		defer applicationRows.Close()

		if !applicationRows.Next() {
			return c.JSON(http.StatusNotFound, ErrorResponse{"error", "not_found"})
		}

		application := Application{-1, "", "", ""}
		applicationRows.Scan(&application.ID, &application.Name, &application.AuthorName, &application.CallbackURL)

		// check if we've already authorized this application
		tokenCheckRows, err := DB.Query("SELECT token FROM application_authorizations WHERE applicationId = ? AND userId = ?", application.ID, GetSessionUserID(&c))
		if err != nil {
			log.Println("Error while completing application auth: ")
			log.Println(err)
			return c.JSON(http.StatusInternalServerError, StatusResponse{"error"})
		}
		defer tokenCheckRows.Close()

		if tokenCheckRows.Next() {
			// if we have, just return that token
			token := ""
			tokenCheckRows.Scan(&token)
			return c.JSON(http.StatusOK, ApplicationTokenResponse{"ok", token})
		}

		// add the new authorization
		token, err := Util_GenerateRandomString(56)
		if err != nil {
			log.Println("Error while generating application token:")
			log.Println(err)
			return c.JSON(http.StatusInternalServerError, StatusResponse{"error"})
		}

		stmt, err := DB.Prepare("INSERT INTO application_authorizations(applicationId, userId, token) VALUES(?, ?, ?)")
		if err != nil {
			log.Println("Error while authorizing application:")
			log.Println(err)
			return c.JSON(http.StatusInternalServerError, StatusResponse{"error"})
		}
		_, err = stmt.Exec(application.ID, GetSessionUserID(&c), token)
		if err != nil {
			log.Println("Error while authorizing application:")
			log.Println(err)
			return c.JSON(http.StatusInternalServerError, StatusResponse{"error"})
		}

		return c.JSON(http.StatusOK, ApplicationTokenResponse{"ok", token})
	})
	e.GET("/application/get/:id", func(c echo.Context) error {
		if GetSessionUserID(&c) == -1 {
			jsonResp := ErrorResponse{"error", "logged_out"}
			return c.JSON(http.StatusUnauthorized, jsonResp)
		}

		rows, err := DB.Query("SELECT id, name, authorName, callbackUrl FROM applications WHERE clientId = ?", c.Param("id"))
		if err != nil {
			log.Println("Error while getting application information: ")
			log.Println(err)
			jsonResp := StatusResponse{"error"}
			return c.JSON(http.StatusInternalServerError, jsonResp)
		}
		defer rows.Close()

		if !rows.Next() {
			jsonResp := ErrorResponse{"error", "not_found"}
			return c.JSON(http.StatusNotFound, jsonResp)
		}

		resp := Application{-1, "", "", ""}
		rows.Scan(&resp.ID, &resp.Name, &resp.AuthorName, &resp.CallbackURL)

		jsonResp := SingleApplicationResponse{"ok", resp}
		return c.JSON(http.StatusOK, jsonResp)
	})
	e.GET("/application/requestAuth/:id", func(c echo.Context) error {
		if GetSessionUserID(&c) == -1 {
			jsonResp := ErrorResponse{"error", "logged_out"}
			return c.JSON(http.StatusUnauthorized, jsonResp)
		}
		return c.Redirect(http.StatusFound, AuthURLBase + "?id=" + c.Param("id"))
	})
}<commit_msg>add endpoint to revoke application access<commit_after>package api

import (
	"log"
	"net/http"

	"github.com/labstack/echo"
)

type Application struct {
	ID int `json:"id"`
	Name string `json:"name"`
	AuthorName string `json:"authorName"`
	CallbackURL string `json:"callbackUrl"`
}
type ApplicationAuthorization struct {
	ID int `json:"id"`
	ApplicationID int `json:"applicationId"`
	Name string `json:"name"`
	AuthorName string `json:"authorName"`
}

type ApplicationTokenResponse struct {
	Status string `json:"status"`
	Token string `json:"token"`
}
type ApplicationAuthorizationsResponse struct {
	Status string `json:"status"`
	Authorizations []ApplicationAuthorization `json:"authorizations"`
}
type SingleApplicationResponse struct {
	Status string `json:"status"`
	Application Application `json:"application"`
}

func InitApplicationAPI(e *echo.Echo) {
	e.POST("/application/completeAuth", func(c echo.Context) error {
		if GetSessionUserID(&c) == -1 {
			return c.JSON(http.StatusUnauthorized, ErrorResponse{"error", "logged_out"})
		}

		// get the application
		applicationRows, err := DB.Query("SELECT id, name, authorName, callbackUrl FROM applications WHERE clientId = ?", c.FormValue("clientId"))
		if err != nil {
			log.Println("Error while completing application auth: ")
			log.Println(err)
			return c.JSON(http.StatusInternalServerError, StatusResponse{"error"})
		}
		defer applicationRows.Close()

		if !applicationRows.Next() {
			return c.JSON(http.StatusNotFound, ErrorResponse{"error", "not_found"})
		}

		application := Application{-1, "", "", ""}
		applicationRows.Scan(&application.ID, &application.Name, &application.AuthorName, &application.CallbackURL)

		// check if we've already authorized this application
		tokenCheckRows, err := DB.Query("SELECT token FROM application_authorizations WHERE applicationId = ? AND userId = ?", application.ID, GetSessionUserID(&c))
		if err != nil {
			log.Println("Error while completing application auth: ")
			log.Println(err)
			return c.JSON(http.StatusInternalServerError, StatusResponse{"error"})
		}
		defer tokenCheckRows.Close()

		if tokenCheckRows.Next() {
			// if we have, just return that token
			token := ""
			tokenCheckRows.Scan(&token)
			return c.JSON(http.StatusOK, ApplicationTokenResponse{"ok", token})
		}

		// add the new authorization
		token, err := Util_GenerateRandomString(56)
		if err != nil {
			log.Println("Error while generating application token:")
			log.Println(err)
			return c.JSON(http.StatusInternalServerError, StatusResponse{"error"})
		}

		stmt, err := DB.Prepare("INSERT INTO application_authorizations(applicationId, userId, token) VALUES(?, ?, ?)")
		if err != nil {
			log.Println("Error while authorizing application:")
			log.Println(err)
			return c.JSON(http.StatusInternalServerError, StatusResponse{"error"})
		}
		_, err = stmt.Exec(application.ID, GetSessionUserID(&c), token)
		if err != nil {
			log.Println("Error while authorizing application:")
			log.Println(err)
			return c.JSON(http.StatusInternalServerError, StatusResponse{"error"})
		}

		return c.JSON(http.StatusOK, ApplicationTokenResponse{"ok", token})
	})
	e.GET("/application/get/:id", func(c echo.Context) error {
		if GetSessionUserID(&c) == -1 {
			jsonResp := ErrorResponse{"error", "logged_out"}
			return c.JSON(http.StatusUnauthorized, jsonResp)
		}

		rows, err := DB.Query("SELECT id, name, authorName, callbackUrl FROM applications WHERE clientId = ?", c.Param("id"))
		if err != nil {
			log.Println("Error while getting application information: ")
			log.Println(err)
			jsonResp := StatusResponse{"error"}
			return c.JSON(http.StatusInternalServerError, jsonResp)
		}
		defer rows.Close()

		if !rows.Next() {
			jsonResp := ErrorResponse{"error", "not_found"}
			return c.JSON(http.StatusNotFound, jsonResp)
		}

		resp := Application{-1, "", "", ""}
		rows.Scan(&resp.ID, &resp.Name, &resp.AuthorName, &resp.CallbackURL)

		jsonResp := SingleApplicationResponse{"ok", resp}
		return c.JSON(http.StatusOK, jsonResp)
	})
	e.GET("/application/getAuthorizations", func(c echo.Context) error {
		if GetSessionUserID(&c) == -1 {
			return c.JSON(http.StatusUnauthorized, ErrorResponse{"error", "logged_out"})
		}
		rows, err := DB.Query("SELECT application_authorizations.id, applications.id, applications.name, applications.authorName FROM application_authorizations INNER JOIN applications ON application_authorizations.applicationId = applications.id WHERE application_authorizations.userId = ?", GetSessionUserID(&c))
		if err != nil {
			log.Println("Error while getting authorizations: ")
			log.Println(err)
			return c.JSON(http.StatusInternalServerError, StatusResponse{"error"})
		}
		defer rows.Close()

		authorizations := []ApplicationAuthorization{}
		for rows.Next() {
			resp := ApplicationAuthorization{-1, -1, "", ""}
			rows.Scan(&resp.ID, &resp.ApplicationID, &resp.Name, &resp.AuthorName)
			authorizations = append(authorizations, resp)
		}
		return c.JSON(http.StatusOK, ApplicationAuthorizationsResponse{"ok", authorizations})
	})
	e.GET("/application/requestAuth/:id", func(c echo.Context) error {
		return c.Redirect(http.StatusFound, AuthURLBase + "?id=" + c.Param("id"))
	})
	e.POST("/application/revokeAuth", func(c echo.Context) error {
		if GetSessionUserID(&c) == -1 {
			return c.JSON(http.StatusUnauthorized, ErrorResponse{"error", "logged_out"})
		}

		// find the authorization
		rows, err := DB.Query("SELECT userId FROM application_authorizations WHERE id = ?", c.FormValue("id"))
		if err != nil {
			log.Println("Error while revoking authorization:")
			log.Println(err)
			return c.JSON(http.StatusInternalServerError, StatusResponse{"error"})
		}
		defer rows.Close()

		if !rows.Next() {
			return c.JSON(http.StatusForbidden, ErrorResponse{"error", "forbidden"})
		}

		userId := -1
		rows.Scan(&userId)

		if GetSessionUserID(&c) != userId {
			return c.JSON(http.StatusForbidden, ErrorResponse{"error", "forbidden"})
		}

		// delete the authorization
		deleteStmt, err := DB.Prepare("DELETE FROM application_authorizations WHERE id = ?")
		if err != nil {
			log.Println("Error while revoking authorization:")
			log.Println(err)
			return c.JSON(http.StatusInternalServerError, StatusResponse{"error"})
		}
		_, err = deleteStmt.Exec(c.FormValue("id"))
		if err != nil {
			log.Println("Error while revoking authorization:")
			log.Println(err)
			return c.JSON(http.StatusInternalServerError, StatusResponse{"error"})
		}

		return c.JSON(http.StatusOK, StatusResponse{"ok"})
	})
}<|endoftext|>


<commit_before>package api

import (
	"testing"
	"time"
)

func TestHealth_Node(t *testing.T) {
	c, s := makeClient(t)
	defer s.stop()

	agent := c.Agent()
	health := c.Health()

	info, err := agent.Self()
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	name := info["Config"]["NodeName"].(string)

	checks, meta, err := health.Node(name, nil)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	if meta.LastIndex == 0 {
		t.Fatalf("bad: %v", meta)
	}
	if len(checks) == 0 {
		t.Fatalf("Bad: %v", checks)
	}
}

func TestHealth_Checks(t *testing.T) {
	c, s := makeClient(t)
	defer s.stop()

	agent := c.Agent()
	health := c.Health()

	// Make a service with a check
	reg := &AgentServiceRegistration{
		Name: "foo",
		Check: &AgentServiceCheck{
			TTL: "15s",
		},
	}
	if err := agent.ServiceRegister(reg); err != nil {
		t.Fatalf("err: %v", err)
	}
	defer agent.ServiceDeregister("foo")

	// Wait for the register...
	time.Sleep(20 * time.Millisecond)

	checks, meta, err := health.Checks("foo", nil)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	if meta.LastIndex == 0 {
		t.Fatalf("bad: %v", meta)
	}
	if len(checks) == 0 {
		t.Fatalf("Bad: %v", checks)
	}
}

func TestHealth_Service(t *testing.T) {
	c, s := makeClient(t)
	defer s.stop()

	health := c.Health()

	// consul service should always exist...
	checks, meta, err := health.Service("consul", "", true, nil)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	if meta.LastIndex == 0 {
		t.Fatalf("bad: %v", meta)
	}
	if len(checks) == 0 {
		t.Fatalf("Bad: %v", checks)
	}
}

func TestHealth_State(t *testing.T) {
	c, s := makeClient(t)
	defer s.stop()

	health := c.Health()

	checks, meta, err := health.State("any", nil)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	if meta.LastIndex == 0 {
		t.Fatalf("bad: %v", meta)
	}
	if len(checks) == 0 {
		t.Fatalf("Bad: %v", checks)
	}
}
<commit_msg>api: use WaitForResult() to improve health tests<commit_after>package api

import (
	"fmt"
	"testing"

	"github.com/hashicorp/consul/testutil"
)

func TestHealth_Node(t *testing.T) {
	c, s := makeClient(t)
	defer s.stop()

	agent := c.Agent()
	health := c.Health()

	info, err := agent.Self()
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	name := info["Config"]["NodeName"].(string)

	checks, meta, err := health.Node(name, nil)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	if meta.LastIndex == 0 {
		t.Fatalf("bad: %v", meta)
	}
	if len(checks) == 0 {
		t.Fatalf("Bad: %v", checks)
	}
}

func TestHealth_Checks(t *testing.T) {
	c, s := makeClient(t)
	defer s.stop()

	agent := c.Agent()
	health := c.Health()

	// Make a service with a check
	reg := &AgentServiceRegistration{
		Name: "foo",
		Check: &AgentServiceCheck{
			TTL: "15s",
		},
	}
	if err := agent.ServiceRegister(reg); err != nil {
		t.Fatalf("err: %v", err)
	}
	defer agent.ServiceDeregister("foo")

	testutil.WaitForResult(func() (bool, error) {
		checks, meta, err := health.Checks("foo", nil)
		if err != nil {
			return false, err
		}
		if meta.LastIndex == 0 {
			return false, fmt.Errorf("bad: %v", meta)
		}
		if len(checks) == 0 {
			return false, fmt.Errorf("Bad: %v", checks)
		}
		return true, nil
	}, func(err error) {
		t.Fatalf("err: %s", err)
	})
}

func TestHealth_Service(t *testing.T) {
	c, s := makeClient(t)
	defer s.stop()

	health := c.Health()

	// consul service should always exist...
	checks, meta, err := health.Service("consul", "", true, nil)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	if meta.LastIndex == 0 {
		t.Fatalf("bad: %v", meta)
	}
	if len(checks) == 0 {
		t.Fatalf("Bad: %v", checks)
	}
}

func TestHealth_State(t *testing.T) {
	c, s := makeClient(t)
	defer s.stop()

	health := c.Health()

	checks, meta, err := health.State("any", nil)
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	if meta.LastIndex == 0 {
		t.Fatalf("bad: %v", meta)
	}
	if len(checks) == 0 {
		t.Fatalf("Bad: %v", checks)
	}
}
<|endoftext|>


<commit_before>package api

import (
	"errors"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/mundipagg/boleto-api/bank"
	"github.com/mundipagg/boleto-api/config"
	"github.com/mundipagg/boleto-api/log"
	"github.com/mundipagg/boleto-api/metrics"
	"github.com/mundipagg/boleto-api/models"
	"github.com/mundipagg/boleto-api/util"
)

// ReturnHeaders 'seta' os headers padrões de resposta
func ReturnHeaders() gin.HandlerFunc {
	return func(c *gin.Context) {
		c.Header("Content-Type", "application/json")
		c.Next()
	}
}

func executionController() gin.HandlerFunc {
	return func(c *gin.Context) {
		if config.IsRunning() {
			c.AbortWithError(500, errors.New("A aplicação está sendo finalizada"))
			return
		}
	}
}

func timingMetrics() gin.HandlerFunc {
	return func(c *gin.Context) {
		start := time.Now()
		c.Next()
		end := time.Now()
		total := end.Sub(start)
		s := float64(total.Seconds())
		metrics.GetTimingMetrics().Push("request-time", s)
	}
}

//ParseBoleto trata a entrada de boleto em todos os requests
func ParseBoleto() gin.HandlerFunc {
	return func(c *gin.Context) {
		businessMetrics := metrics.GetBusinessMetrics()
		boleto := models.BoletoRequest{}
		errBind := c.BindJSON(&boleto)
		if errBind != nil {
			e := models.NewFormatError(errBind.Error())
			checkError(c, e, log.CreateLog())
			businessMetrics.Push("json_error", 1)
			return
		}
		bank, err := bank.Get(boleto)
		if checkError(c, err, log.CreateLog()) {
			c.Set("error", err)
			return
		}
		c.Set("bank", bank)
		d, errFmt := time.Parse("2006-01-02", boleto.Title.ExpireDate)
		boleto.Title.ExpireDateTime = d
		if errFmt != nil {
			e := models.NewFormatError(errFmt.Error())
			checkError(c, e, log.CreateLog())
			businessMetrics.Push(bank.GetBankNameIntegration()+"-bad-request", 1)
			return
		}
		l := log.CreateLog()
		l.NossoNumero = boleto.Title.OurNumber
		l.Operation = "RegisterBoleto"
		l.Recipient = boleto.Recipient.Name
		l.RequestKey = boleto.RequestKey
		l.BankName = bank.GetBankNameIntegration()
		l.IPAddress = c.ClientIP()
		l.RequestApplication(boleto, c.Request.URL.RequestURI(), util.HeaderToMap(c.Request.Header))
		c.Set("boleto", boleto)
		c.Next()
		resp, _ := c.Get("boletoResponse")
		l.ResponseApplication(resp, c.Request.URL.RequestURI())
		tag := bank.GetBankNameIntegration() + "-status"
		businessMetrics.PushAndFlush(tag, c.Writer.Status())
		businessMetrics.PushAndFlush("boleto-total", 1)
	}
}

//GetBoleto metrifica a entrada de GET Boleto
func GetBoleto() gin.HandlerFunc {
	return func(c *gin.Context) {
		businessMetrics := metrics.GetBusinessMetrics()
		fmt := c.Query("fmt")
		businessMetrics.PushAndFlush("boleto-get-"+fmt, 1)
		businessMetrics.PushAndFlush("boleto-get-total", 1)
	}
}
<commit_msg>:art: Altera nome da tag de boleto-total para boleto-register-total<commit_after>package api

import (
	"errors"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/mundipagg/boleto-api/bank"
	"github.com/mundipagg/boleto-api/config"
	"github.com/mundipagg/boleto-api/log"
	"github.com/mundipagg/boleto-api/metrics"
	"github.com/mundipagg/boleto-api/models"
	"github.com/mundipagg/boleto-api/util"
)

// ReturnHeaders 'seta' os headers padrões de resposta
func ReturnHeaders() gin.HandlerFunc {
	return func(c *gin.Context) {
		c.Header("Content-Type", "application/json")
		c.Next()
	}
}

func executionController() gin.HandlerFunc {
	return func(c *gin.Context) {
		if config.IsRunning() {
			c.AbortWithError(500, errors.New("A aplicação está sendo finalizada"))
			return
		}
	}
}

func timingMetrics() gin.HandlerFunc {
	return func(c *gin.Context) {
		start := time.Now()
		c.Next()
		end := time.Now()
		total := end.Sub(start)
		s := float64(total.Seconds())
		metrics.GetTimingMetrics().Push("request-time", s)
	}
}

//ParseBoleto trata a entrada de boleto em todos os requests
func ParseBoleto() gin.HandlerFunc {
	return func(c *gin.Context) {
		businessMetrics := metrics.GetBusinessMetrics()
		boleto := models.BoletoRequest{}
		errBind := c.BindJSON(&boleto)
		if errBind != nil {
			e := models.NewFormatError(errBind.Error())
			checkError(c, e, log.CreateLog())
			businessMetrics.Push("json_error", 1)
			return
		}
		bank, err := bank.Get(boleto)
		if checkError(c, err, log.CreateLog()) {
			c.Set("error", err)
			return
		}
		c.Set("bank", bank)
		d, errFmt := time.Parse("2006-01-02", boleto.Title.ExpireDate)
		boleto.Title.ExpireDateTime = d
		if errFmt != nil {
			e := models.NewFormatError(errFmt.Error())
			checkError(c, e, log.CreateLog())
			businessMetrics.Push(bank.GetBankNameIntegration()+"-bad-request", 1)
			return
		}
		l := log.CreateLog()
		l.NossoNumero = boleto.Title.OurNumber
		l.Operation = "RegisterBoleto"
		l.Recipient = boleto.Recipient.Name
		l.RequestKey = boleto.RequestKey
		l.BankName = bank.GetBankNameIntegration()
		l.IPAddress = c.ClientIP()
		l.RequestApplication(boleto, c.Request.URL.RequestURI(), util.HeaderToMap(c.Request.Header))
		c.Set("boleto", boleto)
		c.Next()
		resp, _ := c.Get("boletoResponse")
		l.ResponseApplication(resp, c.Request.URL.RequestURI())
		tag := bank.GetBankNameIntegration() + "-status"
		businessMetrics.PushAndFlush(tag, c.Writer.Status())
		businessMetrics.PushAndFlush("boleto-register-total", 1)
	}
}

//GetBoleto metrifica a entrada de GET Boleto
func GetBoleto() gin.HandlerFunc {
	return func(c *gin.Context) {
		businessMetrics := metrics.GetBusinessMetrics()
		fmt := c.Query("fmt")
		businessMetrics.PushAndFlush("boleto-get-"+fmt, 1)
		businessMetrics.PushAndFlush("boleto-get-total", 1)
	}
}
<|endoftext|>


<commit_before>package api

import (
	"net/http"
	"testing"
)

// TestExplorerPreset checks that the default configuration for the explorer is
// working correctly.
func TestExplorerPreset(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}
	st, err := createExplorerServerTester("TestExplorerPreset")
	if err != nil {
		t.Fatal(err)
	}
	defer st.server.Close()

	// Try calling a legal endpoint without a user agent.
	err = st.stdGetAPIUA("/explorer", "")
	if err != nil {
		t.Fatal(err)
	}
}

// TestReloading reloads a server and does smoke testing to see that modules
// are still working after reload.
func TestReloading(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}

	// Create a server tester, which will have blocks mined. Then get the
	// reloaded version of the server tester (all persistence files get copied
	// to a new folder, and then the modules are pointed at the new folders
	// during calls to 'New')
	st, err := createServerTester("TestReloading")
	if err != nil {
		t.Fatal(err)
	}
	height := st.server.cs.Height()
	err = st.server.Close()
	if err != nil {
		t.Fatal(err)
	}
	rst, err := st.reloadedServerTester()
	if err != nil {
		t.Fatal(err)
	}
	defer rst.server.Close()
	if st.server.api.cs.Height() != rst.server.api.cs.Height() {
		t.Error("server heights do not match")
	}

	// Mine some blocks on the reloaded server and see if any errors or panics
	// are triggered.
	for i := 0; i < 3; i++ {
		_, err := rst.miner.AddBlock()
		if err != nil {
			t.Fatal(err)
		}
	}
}

// TestAuthenticated tests creating a server that requires authenticated API
// calls, and then makes (un)authenticated API calls to test the
// authentication.
func TestAuthentication(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}

	st, err := createAuthenticatedServerTester("TestAuthentication", "password")
	if err != nil {
		t.Fatal(err)
	}
	defer st.server.Close()

	testGETURL := "http://" + st.server.listener.Addr().String() + "/wallet/seeds"
	testPOSTURL := "http://" + st.server.listener.Addr().String() + "/host/announce"

	// Test that unauthenticated API calls fail.
	// GET
	resp, err := HttpGET(testGETURL)
	if err != nil {
		t.Fatal(err)
	}
	if resp.StatusCode != http.StatusUnauthorized {
		t.Fatal("unauthenticated API call succeeded on a server that requires authentication")
	}
	// POST
	resp, err = HttpPOST(testPOSTURL, "")
	if err != nil {
		t.Fatal(err)
	}
	if resp.StatusCode != http.StatusUnauthorized {
		t.Fatal("unauthenticated API call succeeded on a server that requires authentication")
	}

	// Test that authenticated API calls with the wrong password fail.
	// GET
	resp, err = HttpGETAuthenticated(testGETURL, "wrong password")
	if err != nil {
		t.Fatal(err)
	}
	if resp.StatusCode != http.StatusUnauthorized {
		t.Fatal("authenticated API call succeeded with an incorrect password")
	}
	// POST
	resp, err = HttpPOSTAuthenticated(testPOSTURL, "", "wrong password")
	if err != nil {
		t.Fatal(err)
	}
	if resp.StatusCode != http.StatusUnauthorized {
		t.Fatal("authenticated API call succeeded with an incorrect password")
	}

	// Test that authenticated API calls with the correct password succeed.
	// GET
	resp, err = HttpGETAuthenticated(testGETURL, "password")
	if err != nil {
		t.Fatal(err)
	}
	if non2xx(resp.StatusCode) {
		t.Fatal("authenticated API call failed with the correct password")
	}
	// POST
	resp, err = HttpPOSTAuthenticated(testPOSTURL, "", "password")
	if err != nil {
		t.Fatal(err)
	}
	if non2xx(resp.StatusCode) {
		t.Fatal("authenticated API call failed with the correct password")
	}
}
<commit_msg>removed unused `height` left over from manual merge<commit_after>package api

import (
	"net/http"
	"testing"
)

// TestExplorerPreset checks that the default configuration for the explorer is
// working correctly.
func TestExplorerPreset(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}
	st, err := createExplorerServerTester("TestExplorerPreset")
	if err != nil {
		t.Fatal(err)
	}
	defer st.server.Close()

	// Try calling a legal endpoint without a user agent.
	err = st.stdGetAPIUA("/explorer", "")
	if err != nil {
		t.Fatal(err)
	}
}

// TestReloading reloads a server and does smoke testing to see that modules
// are still working after reload.
func TestReloading(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}

	// Create a server tester, which will have blocks mined. Then get the
	// reloaded version of the server tester (all persistence files get copied
	// to a new folder, and then the modules are pointed at the new folders
	// during calls to 'New')
	st, err := createServerTester("TestReloading")
	if err != nil {
		t.Fatal(err)
	}
	err = st.server.Close()
	if err != nil {
		t.Fatal(err)
	}
	rst, err := st.reloadedServerTester()
	if err != nil {
		t.Fatal(err)
	}
	defer rst.server.Close()
	if st.server.api.cs.Height() != rst.server.api.cs.Height() {
		t.Error("server heights do not match")
	}

	// Mine some blocks on the reloaded server and see if any errors or panics
	// are triggered.
	for i := 0; i < 3; i++ {
		_, err := rst.miner.AddBlock()
		if err != nil {
			t.Fatal(err)
		}
	}
}

// TestAuthenticated tests creating a server that requires authenticated API
// calls, and then makes (un)authenticated API calls to test the
// authentication.
func TestAuthentication(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}

	st, err := createAuthenticatedServerTester("TestAuthentication", "password")
	if err != nil {
		t.Fatal(err)
	}
	defer st.server.Close()

	testGETURL := "http://" + st.server.listener.Addr().String() + "/wallet/seeds"
	testPOSTURL := "http://" + st.server.listener.Addr().String() + "/host/announce"

	// Test that unauthenticated API calls fail.
	// GET
	resp, err := HttpGET(testGETURL)
	if err != nil {
		t.Fatal(err)
	}
	if resp.StatusCode != http.StatusUnauthorized {
		t.Fatal("unauthenticated API call succeeded on a server that requires authentication")
	}
	// POST
	resp, err = HttpPOST(testPOSTURL, "")
	if err != nil {
		t.Fatal(err)
	}
	if resp.StatusCode != http.StatusUnauthorized {
		t.Fatal("unauthenticated API call succeeded on a server that requires authentication")
	}

	// Test that authenticated API calls with the wrong password fail.
	// GET
	resp, err = HttpGETAuthenticated(testGETURL, "wrong password")
	if err != nil {
		t.Fatal(err)
	}
	if resp.StatusCode != http.StatusUnauthorized {
		t.Fatal("authenticated API call succeeded with an incorrect password")
	}
	// POST
	resp, err = HttpPOSTAuthenticated(testPOSTURL, "", "wrong password")
	if err != nil {
		t.Fatal(err)
	}
	if resp.StatusCode != http.StatusUnauthorized {
		t.Fatal("authenticated API call succeeded with an incorrect password")
	}

	// Test that authenticated API calls with the correct password succeed.
	// GET
	resp, err = HttpGETAuthenticated(testGETURL, "password")
	if err != nil {
		t.Fatal(err)
	}
	if non2xx(resp.StatusCode) {
		t.Fatal("authenticated API call failed with the correct password")
	}
	// POST
	resp, err = HttpPOSTAuthenticated(testPOSTURL, "", "password")
	if err != nil {
		t.Fatal(err)
	}
	if non2xx(resp.StatusCode) {
		t.Fatal("authenticated API call failed with the correct password")
	}
}
<|endoftext|>


<commit_before>/*
Licensed to the Apache Software Foundation (ASF) Under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you 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 gremlingo

const (
	baseNamespace         = "org.apache.tinkerpop.gremlin.process.traversal.strategy."
	decorationNamespace   = baseNamespace + "decoration."
	finalizationNamespace = baseNamespace + "finalization."
	optimizationNamespace = baseNamespace + "optimization."
	verificationNamespace = baseNamespace + "verification."
)

// Decoration strategies

func PartitionStrategy(partitionKey, writePartition, readPartitions, includeMetaProperties string) *traversalStrategy {
	config := make(map[string]interface{})
	if partitionKey != "" {
		config["partitionKey"] = partitionKey
	}
	if writePartition != "" {
		config["writePartition"] = writePartition
	}
	if readPartitions != "" {
		config["readPartitions"] = readPartitions
	}
	if includeMetaProperties != "" {
		config["includeMetaProperties"] = includeMetaProperties
	}
	return &traversalStrategy{name: decorationNamespace + "PartitionStrategy", configuration: config}
}

// Verification strategies

func ReadOnlyStrategy() *traversalStrategy {
	return &traversalStrategy{name: verificationNamespace + "ReadOnlyStrategy"}
}

// Optimization strategies

// AdjacentToIncidentStrategy looks for vertex- and value-emitting steps followed by a CountGlobalStep and replaces
// the pattern with an edge- or property-emitting step followed by a CountGlobalStep. Furthermore, if a vertex-
// or value-emitting step is the last step in a .Has(traversal), .And(traversal, ...) or .Or(traversal, ...)
// child traversal, it is replaced by an appropriate edge- or property-emitting step.
// Performing this replacement removes situations where the more expensive trip to an adjacent graph element (e.g.
// the vertex on the other side of an edge) can be satisfied by trips to incident graph elements (e.g. just the edge
// itself).
func AdjacentToIncidentStrategy() *traversalStrategy {
	return &traversalStrategy{name: optimizationNamespace + "AdjacentToIncidentStrategy"}
}

// ByModulatorOptimizationStrategy looks for standard traversals in by-modulators and replaces them with more
// optimized traversals (e.g. TokenTraversal) if possible.
func ByModulatorOptimizationStrategy() *traversalStrategy {
	return &traversalStrategy{name: optimizationNamespace + "ByModulatorOptimizationStrategy"}
}

// CountStrategy optimizes any occurrence of CountGlobalStep followed by an IsStep The idea is to limit
// the number of incoming elements in a way that it's enough for the IsStep to decide whether it evaluates
// true or false. If the traversal already contains a user supplied limit, the strategy won't modify it.
func CountStrategy() *traversalStrategy {
	return &traversalStrategy{name: optimizationNamespace + "CountStrategy"}
}

// EarlyLimitStrategy looks for RangeGlobalSteps that can be moved further left in the traversal and thus be applied
// earlier. It will also try to merge multiple RangeGlobalSteps into one.
// If the logical consequence of one or multiple RangeGlobalSteps is an empty result, the strategy will remove
// as many steps as possible and add a NoneStep instead.
func EarlyLimitStrategy() *traversalStrategy {
	return &traversalStrategy{name: optimizationNamespace + "EarlyLimitStrategy"}
}

// FilterRankingStrategy reorders filter- and order-steps according to their rank. Step ranks are defined within
// the strategy and indicate when it is reasonable for a step to move in front of another. It will also do its best to
// push step labels as far "right" as possible in order to keep traversers as small and bulkable as possible prior to
// the absolute need for path-labeling.
func FilterRankingStrategy() *traversalStrategy {
	return &traversalStrategy{name: optimizationNamespace + "FilterRankingStrategy"}
}

// IdentityRemovalStrategy looks for IdentityStep instances and removes them.
// If the identity step is labeled, its labels are added to the previous step.
// If the identity step is labeled and it's the first step in the traversal, it stays.
func IdentityRemovalStrategy() *traversalStrategy {
	return &traversalStrategy{name: optimizationNamespace + "IdentityRemovalStrategy"}
}

// IncidentToAdjacentStrategy looks for .outE().inV(), .inE().outV() and .bothE().otherV()
// and replaces these step sequences with .out(), .in() or .both() respectively.
// The strategy won't modify the traversal if:
//   the edge step is labeled
//   the traversal contains a path step
//   the traversal contains a lambda step
func IncidentToAdjacentStrategy() *traversalStrategy {
	return &traversalStrategy{name: optimizationNamespace + "IncidentToAdjacentStrategy"}
}

// InlineFilterStrategy analyzes filter-steps with child traversals that themselves are pure filters. If
// the child traversals are pure filters then the wrapping parent filter is not needed and thus, the children
// can be "inlined." Normalizing  pure filters with inlining reduces the number of variations of a filter that
// a graph provider may need to reason about when writing their own strategies. As a result, this strategy helps
// increase the likelihood that a provider's filtering optimization will succeed at re-writing the traversal.
func InlineFilterStrategy() *traversalStrategy {
	return &traversalStrategy{name: optimizationNamespace + "InlineFilterStrategy"}
}

// LazyBarrierStrategy is an OLTP-only strategy that automatically inserts a NoOpBarrierStep after every
// FlatMapStep if neither path-tracking nor partial path-tracking is required, and the next step is not the
// traversal's last step or a Barrier. NoOpBarrierSteps allow traversers to be bulked, thus this strategy
// is meant to reduce memory requirements and improve the overall query performance.
func LazyBarrierStrategy() *traversalStrategy {
	return &traversalStrategy{name: optimizationNamespace + "LazyBarrierStrategy"}
}

// MatchPredicateStrategy will fold any post-where() step that maintains a traversal constraint into
// match(). MatchStep is intelligent with traversal constraint applications and thus, can more
// efficiently use the constraint of WhereTraversalStep or WherePredicateStep.
func MatchPredicateStrategy() *traversalStrategy {
	return &traversalStrategy{name: optimizationNamespace + "MatchPredicateStrategy"}
}

// OrderLimitStrategy is an OLAP strategy that folds a RangeGlobalStep into a preceding
// OrderGlobalStep. This helps to eliminate traversers early in the traversal and can
// significantly reduce the amount of memory required by the OLAP execution engine.
func OrderLimitStrategy() *traversalStrategy {
	return &traversalStrategy{name: optimizationNamespace + "OrderLimitStrategy"}
}

// PathProcessorStrategy  is an OLAP strategy that does its best to turn non-local children in where()
// and select() into local children by inlining components of the non-local child. In this way,
// PathProcessorStrategy helps to ensure that more traversals meet the local child constraint imposed
// on OLAP traversals.
func PathProcessorStrategy() *traversalStrategy {
	return &traversalStrategy{name: optimizationNamespace + "PathProcessorStrategy"}
}

// PathRetractionStrategy will remove paths from the traversers and increase the likelihood of bulking
// as path data is not required after select('b').
func PathRetractionStrategy() *traversalStrategy {
	return &traversalStrategy{name: optimizationNamespace + "PathRetractionStrategy"}
}

// ProductiveByStrategy takes an argument of by() and wraps it CoalesceStep so that the result is either
// the initial Traversal argument or null. In this way, the by() is always "productive". This strategy
// is an "optimization" but it is perhaps more of a "decoration", but it should follow
// ByModulatorOptimizationStrategy which features optimizations relevant to this one.
func ProductiveByStrategy(productiveKeys []string) *traversalStrategy {
	config := make(map[string]interface{})
	config["productiveKeys"] = productiveKeys

	return &traversalStrategy{name: optimizationNamespace + "ProductiveByStrategy", configuration: config}
}

// RepeatUnrollStrategy is an OLTP-only strategy that unrolls any RepeatStep if it uses a constant
// number of loops (times(x)) and doesn't emit intermittent elements. If any of the following 3 steps appears
// within the repeat-traversal, the strategy will not be applied:
//   DedupGlobalStep
//   LoopsStep
//   LambdaHolder
func RepeatUnrollStrategy() *traversalStrategy {
	return &traversalStrategy{name: optimizationNamespace + "RepeatUnrollStrategy"}
}

//

func RemoteStrategy(connection DriverRemoteConnection) *traversalStrategy {
	a := func(g GraphTraversal) {
		result, err := g.getResults()
		if err != nil || result != nil {
			return
		}

		rs, err := connection.submitBytecode(g.bytecode)
		if err != nil {
			return
		}
		g.results = rs
	}

	return &traversalStrategy{name: "RemoteStrategy", apply: a}
}
<commit_msg>Update gremlin-go/driver/strategies.go<commit_after>/*
Licensed to the Apache Software Foundation (ASF) Under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you 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 gremlingo

const (
	baseNamespace         = "org.apache.tinkerpop.gremlin.process.traversal.strategy."
	decorationNamespace   = baseNamespace + "decoration."
	finalizationNamespace = baseNamespace + "finalization."
	optimizationNamespace = baseNamespace + "optimization."
	verificationNamespace = baseNamespace + "verification."
)

// Decoration strategies

func PartitionStrategy(partitionKey, writePartition, readPartitions, includeMetaProperties string) *traversalStrategy {
	config := make(map[string]interface{})
	if partitionKey != "" {
		config["partitionKey"] = partitionKey
	}
	if writePartition != "" {
		config["writePartition"] = writePartition
	}
	if readPartitions != "" {
		config["readPartitions"] = readPartitions
	}
	if includeMetaProperties != "" {
		config["includeMetaProperties"] = includeMetaProperties
	}
	return &traversalStrategy{name: decorationNamespace + "PartitionStrategy", configuration: config}
}

// Verification strategies

func ReadOnlyStrategy() *traversalStrategy {
	return &traversalStrategy{name: verificationNamespace + "ReadOnlyStrategy"}
}

// Optimization strategies

// AdjacentToIncidentStrategy looks for Vertex- and value-emitting steps followed by a CountGlobalStep and replaces
// the pattern with an edge- or property-emitting step followed by a CountGlobalStep. Furthermore, if a vertex-
// or value-emitting step is the last step in a .Has(traversal), .And(traversal, ...) or .Or(traversal, ...)
// child traversal, it is replaced by an appropriate edge- or property-emitting step.
// Performing this replacement removes situations where the more expensive trip to an adjacent graph element (e.g.
// the vertex on the other side of an edge) can be satisfied by trips to incident graph elements (e.g. just the edge
// itself).
func AdjacentToIncidentStrategy() *traversalStrategy {
	return &traversalStrategy{name: optimizationNamespace + "AdjacentToIncidentStrategy"}
}

// ByModulatorOptimizationStrategy looks for standard traversals in by-modulators and replaces them with more
// optimized traversals (e.g. TokenTraversal) if possible.
func ByModulatorOptimizationStrategy() *traversalStrategy {
	return &traversalStrategy{name: optimizationNamespace + "ByModulatorOptimizationStrategy"}
}

// CountStrategy optimizes any occurrence of CountGlobalStep followed by an IsStep The idea is to limit
// the number of incoming elements in a way that it's enough for the IsStep to decide whether it evaluates
// true or false. If the traversal already contains a user supplied limit, the strategy won't modify it.
func CountStrategy() *traversalStrategy {
	return &traversalStrategy{name: optimizationNamespace + "CountStrategy"}
}

// EarlyLimitStrategy looks for RangeGlobalSteps that can be moved further left in the traversal and thus be applied
// earlier. It will also try to merge multiple RangeGlobalSteps into one.
// If the logical consequence of one or multiple RangeGlobalSteps is an empty result, the strategy will remove
// as many steps as possible and add a NoneStep instead.
func EarlyLimitStrategy() *traversalStrategy {
	return &traversalStrategy{name: optimizationNamespace + "EarlyLimitStrategy"}
}

// FilterRankingStrategy reorders filter- and order-steps according to their rank. Step ranks are defined within
// the strategy and indicate when it is reasonable for a step to move in front of another. It will also do its best to
// push step labels as far "right" as possible in order to keep traversers as small and bulkable as possible prior to
// the absolute need for path-labeling.
func FilterRankingStrategy() *traversalStrategy {
	return &traversalStrategy{name: optimizationNamespace + "FilterRankingStrategy"}
}

// IdentityRemovalStrategy looks for IdentityStep instances and removes them.
// If the identity step is labeled, its labels are added to the previous step.
// If the identity step is labeled and it's the first step in the traversal, it stays.
func IdentityRemovalStrategy() *traversalStrategy {
	return &traversalStrategy{name: optimizationNamespace + "IdentityRemovalStrategy"}
}

// IncidentToAdjacentStrategy looks for .outE().inV(), .inE().outV() and .bothE().otherV()
// and replaces these step sequences with .out(), .in() or .both() respectively.
// The strategy won't modify the traversal if:
//   the edge step is labeled
//   the traversal contains a path step
//   the traversal contains a lambda step
func IncidentToAdjacentStrategy() *traversalStrategy {
	return &traversalStrategy{name: optimizationNamespace + "IncidentToAdjacentStrategy"}
}

// InlineFilterStrategy analyzes filter-steps with child traversals that themselves are pure filters. If
// the child traversals are pure filters then the wrapping parent filter is not needed and thus, the children
// can be "inlined." Normalizing  pure filters with inlining reduces the number of variations of a filter that
// a graph provider may need to reason about when writing their own strategies. As a result, this strategy helps
// increase the likelihood that a provider's filtering optimization will succeed at re-writing the traversal.
func InlineFilterStrategy() *traversalStrategy {
	return &traversalStrategy{name: optimizationNamespace + "InlineFilterStrategy"}
}

// LazyBarrierStrategy is an OLTP-only strategy that automatically inserts a NoOpBarrierStep after every
// FlatMapStep if neither path-tracking nor partial path-tracking is required, and the next step is not the
// traversal's last step or a Barrier. NoOpBarrierSteps allow traversers to be bulked, thus this strategy
// is meant to reduce memory requirements and improve the overall query performance.
func LazyBarrierStrategy() *traversalStrategy {
	return &traversalStrategy{name: optimizationNamespace + "LazyBarrierStrategy"}
}

// MatchPredicateStrategy will fold any post-where() step that maintains a traversal constraint into
// match(). MatchStep is intelligent with traversal constraint applications and thus, can more
// efficiently use the constraint of WhereTraversalStep or WherePredicateStep.
func MatchPredicateStrategy() *traversalStrategy {
	return &traversalStrategy{name: optimizationNamespace + "MatchPredicateStrategy"}
}

// OrderLimitStrategy is an OLAP strategy that folds a RangeGlobalStep into a preceding
// OrderGlobalStep. This helps to eliminate traversers early in the traversal and can
// significantly reduce the amount of memory required by the OLAP execution engine.
func OrderLimitStrategy() *traversalStrategy {
	return &traversalStrategy{name: optimizationNamespace + "OrderLimitStrategy"}
}

// PathProcessorStrategy  is an OLAP strategy that does its best to turn non-local children in where()
// and select() into local children by inlining components of the non-local child. In this way,
// PathProcessorStrategy helps to ensure that more traversals meet the local child constraint imposed
// on OLAP traversals.
func PathProcessorStrategy() *traversalStrategy {
	return &traversalStrategy{name: optimizationNamespace + "PathProcessorStrategy"}
}

// PathRetractionStrategy will remove paths from the traversers and increase the likelihood of bulking
// as path data is not required after select('b').
func PathRetractionStrategy() *traversalStrategy {
	return &traversalStrategy{name: optimizationNamespace + "PathRetractionStrategy"}
}

// ProductiveByStrategy takes an argument of by() and wraps it CoalesceStep so that the result is either
// the initial Traversal argument or null. In this way, the by() is always "productive". This strategy
// is an "optimization" but it is perhaps more of a "decoration", but it should follow
// ByModulatorOptimizationStrategy which features optimizations relevant to this one.
func ProductiveByStrategy(productiveKeys []string) *traversalStrategy {
	config := make(map[string]interface{})
	config["productiveKeys"] = productiveKeys

	return &traversalStrategy{name: optimizationNamespace + "ProductiveByStrategy", configuration: config}
}

// RepeatUnrollStrategy is an OLTP-only strategy that unrolls any RepeatStep if it uses a constant
// number of loops (times(x)) and doesn't emit intermittent elements. If any of the following 3 steps appears
// within the repeat-traversal, the strategy will not be applied:
//   DedupGlobalStep
//   LoopsStep
//   LambdaHolder
func RepeatUnrollStrategy() *traversalStrategy {
	return &traversalStrategy{name: optimizationNamespace + "RepeatUnrollStrategy"}
}

//

func RemoteStrategy(connection DriverRemoteConnection) *traversalStrategy {
	a := func(g GraphTraversal) {
		result, err := g.getResults()
		if err != nil || result != nil {
			return
		}

		rs, err := connection.submitBytecode(g.bytecode)
		if err != nil {
			return
		}
		g.results = rs
	}

	return &traversalStrategy{name: "RemoteStrategy", apply: a}
}
<|endoftext|>


<commit_before>package cli

import (
	"bytes"
	"fmt"
    "io"
    "io/ioutil"
    "os"
    "path"
    "testing"
	"github.com/compostware/quokka/services"
)

const (
	inputFileName = "input.txt"
	outputFileName = "output.txt"
	inputText = "turgid existence"
)

var (
	inputData = []byte("turgid existence")
)

func TestForValidInputAndOutputFiles(t *testing.T) {
	dir, err := ioutil.TempDir("", "")
	checkErr(err)
	defer os.RemoveAll(dir)

	inputPath := path.Join(dir, inputFileName)
	outputPath := path.Join(dir, outputFileName)

	err = ioutil.WriteFile(inputPath, inputData, os.ModeTemporary)
	checkErr(err)

	target := createTestCommand()

	args := []string { inputPath, outputPath }

	target.Execute(args)

	outputData, err := ioutil.ReadFile(outputPath)
	checkErr(err)

	fmt.Printf("input: %\n", string(inputData))
	fmt.Printf("output: %\n", string(outputData))

	if bytes.Compare(inputData[:], outputData[:]) != 0 {
		t.Errorf("Input file not correctly written to outputfile")
	}
}

func createTestCommand() *buildCmd {
	cmd := new(buildCmd)
	cmd.builder = createStubService()
	return cmd
}

func createTmpFile() *os.File {
	f, err := ioutil.TempFile("", "")
	if (err != nil) {
		panic(err)
	}
	return f
}

func createStubService() services.BuildService {
	return new(stubBuildService)
}

type stubBuildService struct {

}

func (*stubBuildService) Build(input io.Reader, output io.Writer) {
	// stub services writes read input into output writer
	io.Copy(output, input)
}

func checkErr(err error) {
	if (err != nil) {
		panic(err)
	}
}

<commit_msg>change with file perms to fix travis-ci test error<commit_after>package cli

import (
	"bytes"
	"io"
    "io/ioutil"
    "os"
    "path"
    "testing"
	"github.com/compostware/quokka/services"
)

const (
	inputFileName = "input"
	outputFileName = "output"
	inputText = "turgid existence"
)

var (
	inputData = []byte("turgid existence")
)

func TestForValidInputAndOutputFiles(t *testing.T) {
	dir, err := ioutil.TempDir("", "")
	checkErr(err)
	defer os.RemoveAll(dir)

	inputPath := path.Join(dir, inputFileName)
	outputPath := path.Join(dir, outputFileName)

	err = ioutil.WriteFile(inputPath, inputData, os.ModeTemporary | os.ModePerm)
	checkErr(err)

	target := createTestCommand()

	args := []string { inputPath, outputPath }

	target.Execute(args)

	outputData, err := ioutil.ReadFile(outputPath)
	checkErr(err)

	if bytes.Compare(inputData[:], outputData[:]) != 0 {
		t.Errorf("Input file not correctly written to outputfile")
	}
}

func createTestCommand() *buildCmd {
	cmd := new(buildCmd)
	cmd.builder = createStubService()
	return cmd
}

func createTmpFile() *os.File {
	f, err := ioutil.TempFile("", "")
	if (err != nil) {
		panic(err)
	}
	return f
}

func createStubService() services.BuildService {
	return new(stubBuildService)
}

type stubBuildService struct {

}

func (*stubBuildService) Build(input io.Reader, output io.Writer) {
	// stub services writes read input into output writer
	io.Copy(output, input)
}

func checkErr(err error) {
	if (err != nil) {
		panic(err)
	}
}

<|endoftext|>


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

package cmd

import (
	"fmt"
	"os"

	"github.com/codegangsta/cli"

	"github.com/control-center/serviced/commons/docker"
	"github.com/control-center/serviced/script"
)

// Initializer for serviced metric
func (c *ServicedCli) initScript() {
	c.app.Commands = append(c.app.Commands, cli.Command{
		Name:        "script",
		Usage:       "serviced script",
		Description: "",
		Subcommands: []cli.Command{
			{
				Name:        "parse",
				Usage:       "Parse a script",
				Description: "serviced script parse file ",
				Action:      c.cmdScriptParse,
			},
			{
				Name:        "run",
				Usage:       "Run a script",
				Description: "serviced script run file ",
				Action:      c.cmdScriptRun,
				Flags: []cli.Flag{
					cli.BoolFlag{"no-op, n", "Run through script without modifying system"},
				},
			},
			{
				Name:        "service",
				Usage:       "Run a script with a service as an argument",
				Description: "serviced script SERVICEID file ",
				Action:      c.cmdScriptSvcRun,
				Flags: []cli.Flag{
					cli.BoolFlag{"no-op, n", "Run through script without modifying system"},
				},
			},
		},
	})
}

// cmdScriptSvcRun serviced script <service> filename
func (c *ServicedCli) cmdScriptSvcRun(ctx *cli.Context) {
	args := ctx.Args()
	if len(args) != 2 {
		fmt.Fprintln(os.Stderr, "Incorrect Usage.\n\n")
		c.exit(1)
		return
	}
	svcID := args[0]
	//verify service or translate to ID
	svc, err := c.searchForService(svcID)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		c.exit(1)
		return
	}
	if svc == nil {
		fmt.Fprintf(os.Stderr, "service %s not found\n", svcID)
		c.exit(1)
		return
	}

	fileName := args[1]
	config := &script.Config{
		ServiceID: svc.ID,
	}
	runScript(c, ctx, fileName, config)
}

// cmdScriptRun serviced script run filename
func (c *ServicedCli) cmdScriptRun(ctx *cli.Context) {
	args := ctx.Args()
	if len(args) != 1 {
		fmt.Fprintln(os.Stderr, "Incorrect Usage.\n\n")
		return
	}
	fileName := args[0]
	config := &script.Config{}
	runScript(c, ctx, fileName, config)
}

// cmdScriptRun serviced script run filename
func (c *ServicedCli) cmdScriptParse(ctx *cli.Context) {
	args := ctx.Args()
	if len(args) != 1 {
		fmt.Fprintln(os.Stderr, "Incorrect Usage.\n\n")
		return
	}
	fileName := args[0]
	config := script.Config{}
	err := c.driver.ScriptParse(fileName, &config)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
	}
	return
}

func runScript(c *ServicedCli, ctx *cli.Context, fileName string, config *script.Config) {
	config.NoOp = ctx.Bool("no-op")
	config.DockerRegistry = docker.DEFAULT_REGISTRY
	err := c.driver.ScriptRun(fileName, config)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		c.exit(1)
		return
	}
}
<commit_msg>Cleanup command help on script command<commit_after>// Copyright 2014 The Serviced Authors.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
	"fmt"
	"os"

	"github.com/codegangsta/cli"

	"github.com/control-center/serviced/commons/docker"
	"github.com/control-center/serviced/script"
)

// Initializer for serviced metric
func (c *ServicedCli) initScript() {
	c.app.Commands = append(c.app.Commands, cli.Command{
		Name:        "script",
		Usage:       "serviced script",
		Description: "",
		Subcommands: []cli.Command{
			{
				Name:        "parse",
				Usage:       "Parse a script",
				Description: "serviced script parse FILE",
				Action:      c.cmdScriptParse,
			},
			{
				Name:        "run",
				Usage:       "Run a script",
				Description: "serviced script run FILE [-n]",
				Action:      c.cmdScriptRun,
				Flags: []cli.Flag{
					cli.BoolFlag{"no-op, n", "Run through script without modifying system"},
				},
			},
			{
				Name:        "service",
				Usage:       "Run a script with a service as an argument",
				Description: "serviced script service SERVICEID FILE [-n]",
				Action:      c.cmdScriptSvcRun,
				Flags: []cli.Flag{
					cli.BoolFlag{"no-op, n", "Run through script without modifying system"},
				},
			},
		},
	})
}

// cmdScriptSvcRun serviced script <service> filename
func (c *ServicedCli) cmdScriptSvcRun(ctx *cli.Context) {
	args := ctx.Args()
	if len(args) != 2 {
		fmt.Fprintln(os.Stderr, "Incorrect Usage.\n\n")
		c.exit(1)
		return
	}
	svcID := args[0]
	//verify service or translate to ID
	svc, err := c.searchForService(svcID)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		c.exit(1)
		return
	}
	if svc == nil {
		fmt.Fprintf(os.Stderr, "service %s not found\n", svcID)
		c.exit(1)
		return
	}

	fileName := args[1]
	config := &script.Config{
		ServiceID: svc.ID,
	}
	runScript(c, ctx, fileName, config)
}

// cmdScriptRun serviced script run filename
func (c *ServicedCli) cmdScriptRun(ctx *cli.Context) {
	args := ctx.Args()
	if len(args) != 1 {
		fmt.Fprintln(os.Stderr, "Incorrect Usage.\n\n")
		return
	}
	fileName := args[0]
	config := &script.Config{}
	runScript(c, ctx, fileName, config)
}

// cmdScriptRun serviced script run filename
func (c *ServicedCli) cmdScriptParse(ctx *cli.Context) {
	args := ctx.Args()
	if len(args) != 1 {
		fmt.Fprintln(os.Stderr, "Incorrect Usage.\n\n")
		return
	}
	fileName := args[0]
	config := script.Config{}
	err := c.driver.ScriptParse(fileName, &config)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
	}
	return
}

func runScript(c *ServicedCli, ctx *cli.Context, fileName string, config *script.Config) {
	config.NoOp = ctx.Bool("no-op")
	config.DockerRegistry = docker.DEFAULT_REGISTRY
	err := c.driver.ScriptRun(fileName, config)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		c.exit(1)
		return
	}
}
<|endoftext|>


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

package report

import (
	"errors"

	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

var flags struct {
	queryPath    string
	reportPath   string
	reportFormat string
	bucketName   string
	dirName      string
	listReports  bool
}

func init() {
	viper.AutomaticEnv()

	Cmd.Flags().StringVar(&flags.queryPath, "query-path", "", "Path to directory containing inventory queries")
	Cmd.MarkFlagRequired("query-path")

	Cmd.Flags().StringVar(&flags.reportPath, "report-path", "", "Path to directory to contain report outputs")

	Cmd.Flags().StringVar(&flags.bucketName, "bucket", "", "GCS bucket name for storing inventory (conflicts with --dir-path)")
	Cmd.Flags().StringVar(&flags.dirName, "dir-path", "", "Local directory path for storing inventory (conflicts with --bucket)")

	Cmd.Flags().StringVar(&flags.reportFormat, "format", "", "Format of inventory report outputs, can be json or csv, default is csv")

	Cmd.Flags().BoolVar(&flags.listReports, "list-available-reports", false, "List available inventory report queries")
}

// Cmd represents the base scorecard command
var Cmd = &cobra.Command{
	Use:   "report",
	Short: "Generate inventory reports based on CAI outputs in a directory.",
	Long: `Generate inventory reports for resources in Cloud Asset Inventory (CAI) output files, with reports defined in rego (in 'samplereports' folder).

	Example:
	  cft report --query-path ./path/to/cloud-foundation-toolkit/cli/samplereports \
		--dir-path ./path/to/cai-export-directory \
		--report-path ./path/to/report-output-directory \
	`,

	Args: cobra.NoArgs,
	PreRunE: func(c *cobra.Command, args []string) error {
		if !flags.listReports {
			if flags.reportPath == "" {
				return errors.New("missing required argument --report-path")
			}
			if (flags.bucketName == "" && flags.dirName == "") ||
				(flags.bucketName != "" && flags.dirName != "") {
				return errors.New("Either bucket or dir-path should be set")
			}
		}
		return nil
	},
	RunE: func(cmd *cobra.Command, args []string) error {
		if !flags.listReports {
			err := GenerateReports(flags.dirName, flags.queryPath, flags.reportPath, flags.reportFormat)
			if err != nil {
				return err
			}
		} else {
			err := ListAvailableReports(flags.queryPath)
			if err != nil {
				return err
			}
		}
		return nil
	},
}
<commit_msg>use viper to manage default for report-format param<commit_after>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package report

import (
	"errors"

	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

var flags struct {
	queryPath    string
	reportPath   string
	reportFormat string
	bucketName   string
	dirName      string
	listReports  bool
}

func init() {
	viper.AutomaticEnv()

	Cmd.Flags().StringVar(&flags.queryPath, "query-path", "", "Path to directory containing inventory queries")
	Cmd.MarkFlagRequired("query-path")

	Cmd.Flags().StringVar(&flags.reportPath, "report-path", "", "Path to directory to contain report outputs")

	Cmd.Flags().StringVar(&flags.bucketName, "bucket", "", "GCS bucket name for storing inventory (conflicts with --dir-path)")
	Cmd.Flags().StringVar(&flags.dirName, "dir-path", "", "Local directory path for storing inventory (conflicts with --bucket)")

	Cmd.Flags().StringVar(&flags.reportFormat, "report-format", "", "Format of inventory report outputs, can be json or csv, default is csv")
	viper.SetDefault("report-format", "csv")
	viper.BindPFlag("report-format", Cmd.Flags().Lookup("report-format"))

	Cmd.Flags().BoolVar(&flags.listReports, "list-available-reports", false, "List available inventory report queries")
}

// Cmd represents the base scorecard command
var Cmd = &cobra.Command{
	Use:   "report",
	Short: "Generate inventory reports based on CAI outputs in a directory.",
	Long: `Generate inventory reports for resources in Cloud Asset Inventory (CAI) output files, with reports defined in rego (in 'samplereports' folder).

	Example:
	  cft report --query-path ./path/to/cloud-foundation-toolkit/cli/samplereports \
		--dir-path ./path/to/cai-export-directory \
		--report-path ./path/to/report-output-directory \
	`,

	Args: cobra.NoArgs,
	PreRunE: func(c *cobra.Command, args []string) error {
		if !flags.listReports {
			if flags.reportPath == "" {
				return errors.New("missing required argument --report-path")
			}
			if (flags.bucketName == "" && flags.dirName == "") ||
				(flags.bucketName != "" && flags.dirName != "") {
				return errors.New("Either bucket or dir-path should be set")
			}
		}
		return nil
	},
	RunE: func(cmd *cobra.Command, args []string) error {
		if !flags.listReports {
			err := GenerateReports(flags.dirName, flags.queryPath, flags.reportPath, viper.GetString("report-format"))
			if err != nil {
				return err
			}
		} else {
			err := ListAvailableReports(flags.queryPath)
			if err != nil {
				return err
			}
		}
		return nil
	},
}
<|endoftext|>