<commit_before>package upspin

// A UserName is just a string representing a user.
// It is given a unique type so the API is clear.
// Example: gopher@google.com
type UserName string

// A PathName is just a string representing a full path name.
// It is given a unique type so the API is clear.
// Example: gopher@google.com/burrow/hoard
type PathName string

// Transport identifies the type of access required to reach the data, that is, the
// realm in which the network address within a Location is to be interpreted.
type Transport uint8

const (
	// InProcess indicates that contents are located in the current process,
	// typically in memory.
	InProcess Transport = iota

	// GCP indicates a Google Cloud Store instance.
	GCP

	// HTTP is a URL-encoded address.
	HTTP
)

// A Location identifies where a piece of data is stored and how to retrieve it.
type Location struct {
	// Endpoint identifies the machine or service where the data resides.
	Endpoint Endpoint

	// Reference is the key that will retrieve the data from the endpoint.
	Reference Reference
}

// An Endpoint identifies an instance of a service, encompassing an address
// such as a domain name and information (the Transport) about how to interpret
// that address.
type Endpoint struct {
	// Transport specifies how the network address is to be interpreted,
	// for instance that it is the URL of an HTTP service.
	Transport Transport

	// NetAddr returns the (typically) network address of the data.
	NetAddr NetAddr
}

// A NetAddr is the network address of service. It is interpreted by Access's
// Dial method to connect to the service.
type NetAddr string

// A Reference is the key to find a piece of data in a given Store. It is decoupled
// from the address of the Store itself, but contains a unique identifier key
// such as a hash of the contents and a Packing defining how to unpack it.
type Reference struct {
	// Key identifies the data within the Store.
	Key string

	// Packing identifies how to unpack the original data using this Reference.
	Packing Packing
}

// A Packing identifies the technique for turning the data pointed to by
// a Reference into the user's data. This may involve checksum verification,
// decrypting, signature checking, or nothing at all.
// Secondary data such as encryption keys may be required to implement
// the packing. That data appears in the API as arguments and struct fields
// called packdata.
type Packing uint8

// Packer provides the implementation of a Packing. The pack package binds
// Packing values to the concrete implementations of this interface.
type Packer interface {
	// Packing returns the integer identifier of this Packing algorithm.
	Packing() Packing

	// Pack takes cleartext data, metadata and path name and
	// stores the ciphertext encoding in the supplied slice.
	// The ciphertext and cleartext slices must not overlap.
	// Pack might update the metadata.
	// The slice must be large enough; the PackLen method may be used to
	// find a suitable allocation size.
	// The returned count is the length of the ciphertext.
	Pack(ciphertext, cleartext []byte, meta *Metadata, name PathName) (int, error)

	// Unpack takes ciphertext data and packing metadata and stores the
	// cleartext version in the supplied slice, which must be large enough.
	// The ciphertext and cleartext slices must not overlap.
	// Unpack might update the metadata.
	// It returns the path name and the number of bytes written to the slice.
	// The returned name will be empty if the ciphertext does not contain one.
	Unpack(cleartext, ciphertext []byte, meta *Metadata, name PathName) (int, error)

	// PackLen returns an upper bound on the number of bytes required
	// to store the cleartext after packing. It might update the metadata.
	// Returns -1 if there is an error.
	PackLen(cleartext []byte, meta *Metadata, name PathName) int

	// UnpackLen returns an upper bound on the number of bytes required
	// to store the unpacked cleartext. It might update the metadata.
	// Returns -1 if there is an error.
	UnpackLen(ciphertext []byte, meta *Metadata) int
}

const (
	// The DebugPack packing is available for use in tests for any purpose.
	// It is never used in production.
	DebugPack Packing = iota

	// PlainPack is the trivial, no-op packing. Bytes are copied untouched.
	PlainPack

	// EEp256Pack packing stores AES-encrypted data.
	// The associated metadata has an ECDSA signature and ECDH-wrapped keys.
	EEp256Pack
)

// User service.

// The User interface provides access to public information about users.
type User interface {
	Access

	// Lookup returns a list (slice) of Endpoints of Directory services that may
	// hold the root directory for the named user. Those earlier in the
	// list are better places to look.
	Lookup(userName UserName) ([]Endpoint, error)
}

// Directory service.

// The Directory service manages the name space for one or more users.
type Directory interface {
	Access

	// Lookup returns the directory entry for the named file.
	Lookup(name PathName) (*DirEntry, error)

	// Put stores the data at the given name and associates packdata with it.
	// If something is already stored with that name, the new data and
	// packdata replace the old.
	Put(name PathName, data []byte, packdata []byte) (Location, error)

	// MakeDirectory creates a directory with the given name, which
	// must not already exist. All but the last element of the path name
	// must already exist and be directories.
	// TODO: Make multiple elems?
	MakeDirectory(dirName PathName) (Location, error)

	// Glob matches the pattern against the file names of the full rooted tree.
	// That is, the pattern must look like a full path name, but elements of the
	// path may contain metacharacters. Matching is done using Go's path.Match
	// elementwise. The user name must be present in the pattern and is treated as
	// a literal even if it contains metacharacters.
	// The Metadata contains no key information.
	Glob(pattern string) ([]*DirEntry, error)
}

// DirEntry represents the directory information for a file.
type DirEntry struct {
	Name     PathName // The full path name of the file.
	Location Location // The location of the file.
	Metadata Metadata
}

// Metadata stores (among other things) the keys that enable the
// file to be decrypted by the appropriate recipient.
type Metadata struct {
	IsDir    bool   // The file is a directory.
	Sequence int64  // The sequence (version) number of the item.
	PackData []byte // Packing-specific metadata stored in directory.
}

// Store service.

// The Store service saves and retrieves data without interpretation.
type Store interface {
	Access

	// Get attempts to retrieve the data identified by the key.
	// Three things might happen:
	// 1. The data is in this Store. It is returned. The Location slice
	// and error are nil.
	// 2. The data is not in this Store, but may be in one or more
	// other locations known to the store. The slice of Locations
	// is returned. The data slice and error are nil.
	// 3. An error occurs. The data and Location slices are nil
	// and the error describes the problem.
	Get(key string) ([]byte, []Location, error)

	// Put puts the data into the store and returns the key
	// to be used to retrieve it.
	Put(data []byte) (string, error)

	// Delete permanently removes all storage space associated
	// with key. After a successful Delete, calls to Get with the
	// same key will fail. If a key is not found, an error is
	// returned.
	Delete(key string) error

	// Endpoint returns the network endpoint of the server.
	Endpoint() Endpoint
}

// Client API.

// The Client interface provides a higher-level API suitable for applications
// that wish to access Upspin's name space.
type Client interface {
	// Get returns the clear, decrypted data stored under the given name.
	// It is intended only for special purposes, since it will allocate memory
	// for the entire "blob" to return. Most access will use the file-like
	// API below.
	Get(name PathName) ([]byte, error)

	// Put stores the data at the given name. If something is already
	// stored with that name, it is replaced with the new data.
	// Like Get, it is not the usual access method. The file-like API
	// is preferred.
	Put(name PathName, data []byte) (Location, error)

	// MakeDirectory creates a directory with the given name, which
	// must not already exist. All but the last element of the path name
	// must already exist and be directories.
	// TODO: Make multiple elems?
	MakeDirectory(dirName PathName) (Location, error)

	// File-like methods similar to Go's os.File API.
	// The name, however, is a fully-qualified upspin PathName.
	// TODO: Should there be a concept of current directory and
	// local names?
	Create(name PathName) (File, error)
	Open(name PathName) (File, error)
}

// The File interface has semantics and API that parallels a subset
// of Go's os.File's. The main semantic difference, besides the limited
// method set, is that a Read will only return once the entire contents
// have been decrypted and verified.
type File interface {
	// Close releases the resources. For a writable file, it also
	// writes the accumulated data in a Store server. After a
	// Close, successful or not, all methods of File except Name
	// will fail.
	Close() error

	// Name returns the full path name of the File.
	Name() PathName

	// Read, ReadAt, Write, WriteAt and Seek implement
	// the standard Go interfaces io.Reader, etc.
	// Because of the nature of upsin storage, the entire
	// item might need to be read into memory by the
	// implementation before Read can return any data.
	// Similarly, Write might accumulate all data and only
	// flush to storage once Close is called.
	Read(b []byte) (n int, err error)
	ReadAt(b []byte, off int64) (n int, err error)
	Write(b []byte) (n int, err error)
	WriteAt(b []byte, off int64) (n int, err error)
	Seek(offset int64, whence int) (ret int64, err error)
}

// ClientContext contains information such as the user's keys and
// preferred User, Directory, and Store servers.
type ClientContext struct {
	// The name of the user requesting access.
	UserName UserName

	// PrivateKey holds the user's private cryptographic keys.
	// The public key is accessible through the data held here.
	PrivateKey interface{}

	// Packing is the default Packing to use when creating new data items.
	// It may be overridden by circumstances such as preferences related
	// to the directory.
	Packing Packing

	// User is the User service to contact when evaluating names.
	User User

	// Directory is the Directory in which to place new data items,
	// usually the location of the user's root.
	Directory Directory

	// Store is the Store in which to place new data items.
	Store Store
}

// Access defines how to connect and authenticate to a server. Each
// service type (User, Directory, Store) implements the methods of
// the Access interface. These methods are not used directly by
// clients. Instead, clients should use the various Bind methods of
// the Upspin "access" package to connect to services.
type Access interface {
	// Dial connects to the service and performs any needed authentication.
	Dial(*ClientContext, Endpoint) (interface{}, error)

	// ServerUserName returns the authenticated user name of the server.
	// If there is no authenticated name an empty string is returned.
	// TODO(p): Should I distinguish a server which didn't pass authentication
	// from one which has no user name?
	ServerUserName() string
}
<commit_msg>upspin: clarify behavior of Put<commit_after>package upspin

// A UserName is just a string representing a user.
// It is given a unique type so the API is clear.
// Example: gopher@google.com
type UserName string

// A PathName is just a string representing a full path name.
// It is given a unique type so the API is clear.
// Example: gopher@google.com/burrow/hoard
type PathName string

// Transport identifies the type of access required to reach the data, that is, the
// realm in which the network address within a Location is to be interpreted.
type Transport uint8

const (
	// InProcess indicates that contents are located in the current process,
	// typically in memory.
	InProcess Transport = iota

	// GCP indicates a Google Cloud Store instance.
	GCP

	// HTTP is a URL-encoded address.
	HTTP
)

// A Location identifies where a piece of data is stored and how to retrieve it.
type Location struct {
	// Endpoint identifies the machine or service where the data resides.
	Endpoint Endpoint

	// Reference is the key that will retrieve the data from the endpoint.
	Reference Reference
}

// An Endpoint identifies an instance of a service, encompassing an address
// such as a domain name and information (the Transport) about how to interpret
// that address.
type Endpoint struct {
	// Transport specifies how the network address is to be interpreted,
	// for instance that it is the URL of an HTTP service.
	Transport Transport

	// NetAddr returns the (typically) network address of the data.
	NetAddr NetAddr
}

// A NetAddr is the network address of service. It is interpreted by Access's
// Dial method to connect to the service.
type NetAddr string

// A Reference is the key to find a piece of data in a given Store. It is decoupled
// from the address of the Store itself, but contains a unique identifier key
// such as a hash of the contents and a Packing defining how to unpack it.
type Reference struct {
	// Key identifies the data within the Store.
	Key string

	// Packing identifies how to unpack the original data using this Reference.
	Packing Packing
}

// A Packing identifies the technique for turning the data pointed to by
// a Reference into the user's data. This may involve checksum verification,
// decrypting, signature checking, or nothing at all.
// Secondary data such as encryption keys may be required to implement
// the packing. That data appears in the API as arguments and struct fields
// called packdata.
type Packing uint8

// Packer provides the implementation of a Packing. The pack package binds
// Packing values to the concrete implementations of this interface.
type Packer interface {
	// Packing returns the integer identifier of this Packing algorithm.
	Packing() Packing

	// Pack takes cleartext data, metadata and path name and
	// stores the ciphertext encoding in the supplied slice.
	// The ciphertext and cleartext slices must not overlap.
	// Pack might update the metadata.
	// The slice must be large enough; the PackLen method may be used to
	// find a suitable allocation size.
	// The returned count is the length of the ciphertext.
	Pack(ciphertext, cleartext []byte, meta *Metadata, name PathName) (int, error)

	// Unpack takes ciphertext data and packing metadata and stores the
	// cleartext version in the supplied slice, which must be large enough.
	// The ciphertext and cleartext slices must not overlap.
	// Unpack might update the metadata.
	// It returns the path name and the number of bytes written to the slice.
	// The returned name will be empty if the ciphertext does not contain one.
	Unpack(cleartext, ciphertext []byte, meta *Metadata, name PathName) (int, error)

	// PackLen returns an upper bound on the number of bytes required
	// to store the cleartext after packing. It might update the metadata.
	// Returns -1 if there is an error.
	PackLen(cleartext []byte, meta *Metadata, name PathName) int

	// UnpackLen returns an upper bound on the number of bytes required
	// to store the unpacked cleartext. It might update the metadata.
	// Returns -1 if there is an error.
	UnpackLen(ciphertext []byte, meta *Metadata) int
}

const (
	// The DebugPack packing is available for use in tests for any purpose.
	// It is never used in production.
	DebugPack Packing = iota

	// PlainPack is the trivial, no-op packing. Bytes are copied untouched.
	PlainPack

	// EEp256Pack packing stores AES-encrypted data.
	// The associated metadata has an ECDSA signature and ECDH-wrapped keys.
	EEp256Pack
)

// User service.

// The User interface provides access to public information about users.
type User interface {
	Access

	// Lookup returns a list (slice) of Endpoints of Directory services that may
	// hold the root directory for the named user. Those earlier in the
	// list are better places to look.
	Lookup(userName UserName) ([]Endpoint, error)
}

// Directory service.

// The Directory service manages the name space for one or more users.
type Directory interface {
	Access

	// Lookup returns the directory entry for the named file.
	Lookup(name PathName) (*DirEntry, error)

	// Put stores the data at the given path and associates packdata with it.
	// All but the last element of the path name must already exist and be
	// directories. The final element, if it exists, must not be a directory.
	// If something is already stored under the path, the new data and
	// packdata replace the old.
	Put(path PathName, data []byte, packdata []byte) (Location, error)

	// MakeDirectory creates a directory with the given name, which
	// must not already exist. All but the last element of the path name
	// must already exist and be directories.
	// TODO: Make multiple elems?
	MakeDirectory(dirName PathName) (Location, error)

	// Glob matches the pattern against the file names of the full rooted tree.
	// That is, the pattern must look like a full path name, but elements of the
	// path may contain metacharacters. Matching is done using Go's path.Match
	// elementwise. The user name must be present in the pattern and is treated as
	// a literal even if it contains metacharacters.
	// The Metadata contains no key information.
	Glob(pattern string) ([]*DirEntry, error)
}

// DirEntry represents the directory information for a file.
type DirEntry struct {
	Name     PathName // The full path name of the file.
	Location Location // The location of the file.
	Metadata Metadata
}

// Metadata stores (among other things) the keys that enable the
// file to be decrypted by the appropriate recipient.
type Metadata struct {
	IsDir    bool   // The file is a directory.
	Sequence int64  // The sequence (version) number of the item.
	PackData []byte // Packing-specific metadata stored in directory.
}

// Store service.

// The Store service saves and retrieves data without interpretation.
type Store interface {
	Access

	// Get attempts to retrieve the data identified by the key.
	// Three things might happen:
	// 1. The data is in this Store. It is returned. The Location slice
	// and error are nil.
	// 2. The data is not in this Store, but may be in one or more
	// other locations known to the store. The slice of Locations
	// is returned. The data slice and error are nil.
	// 3. An error occurs. The data and Location slices are nil
	// and the error describes the problem.
	Get(key string) ([]byte, []Location, error)

	// Put puts the data into the store and returns the key
	// to be used to retrieve it.
	Put(data []byte) (string, error)

	// Delete permanently removes all storage space associated
	// with key. After a successful Delete, calls to Get with the
	// same key will fail. If a key is not found, an error is
	// returned.
	Delete(key string) error

	// Endpoint returns the network endpoint of the server.
	Endpoint() Endpoint
}

// Client API.

// The Client interface provides a higher-level API suitable for applications
// that wish to access Upspin's name space.
type Client interface {
	// Get returns the clear, decrypted data stored under the given name.
	// It is intended only for special purposes, since it will allocate memory
	// for the entire "blob" to return. Most access will use the file-like
	// API below.
	Get(name PathName) ([]byte, error)

	// Put stores the data at the given name. If something is already
	// stored with that name, it is replaced with the new data.
	// Like Get, it is not the usual access method. The file-like API
	// is preferred.
	Put(name PathName, data []byte) (Location, error)

	// MakeDirectory creates a directory with the given name, which
	// must not already exist. All but the last element of the path name
	// must already exist and be directories.
	// TODO: Make multiple elems?
	MakeDirectory(dirName PathName) (Location, error)

	// File-like methods similar to Go's os.File API.
	// The name, however, is a fully-qualified upspin PathName.
	// TODO: Should there be a concept of current directory and
	// local names?
	Create(name PathName) (File, error)
	Open(name PathName) (File, error)
}

// The File interface has semantics and API that parallels a subset
// of Go's os.File's. The main semantic difference, besides the limited
// method set, is that a Read will only return once the entire contents
// have been decrypted and verified.
type File interface {
	// Close releases the resources. For a writable file, it also
	// writes the accumulated data in a Store server. After a
	// Close, successful or not, all methods of File except Name
	// will fail.
	Close() error

	// Name returns the full path name of the File.
	Name() PathName

	// Read, ReadAt, Write, WriteAt and Seek implement
	// the standard Go interfaces io.Reader, etc.
	// Because of the nature of upsin storage, the entire
	// item might need to be read into memory by the
	// implementation before Read can return any data.
	// Similarly, Write might accumulate all data and only
	// flush to storage once Close is called.
	Read(b []byte) (n int, err error)
	ReadAt(b []byte, off int64) (n int, err error)
	Write(b []byte) (n int, err error)
	WriteAt(b []byte, off int64) (n int, err error)
	Seek(offset int64, whence int) (ret int64, err error)
}

// ClientContext contains information such as the user's keys and
// preferred User, Directory, and Store servers.
type ClientContext struct {
	// The name of the user requesting access.
	UserName UserName

	// PrivateKey holds the user's private cryptographic keys.
	// The public key is accessible through the data held here.
	PrivateKey interface{}

	// Packing is the default Packing to use when creating new data items.
	// It may be overridden by circumstances such as preferences related
	// to the directory.
	Packing Packing

	// User is the User service to contact when evaluating names.
	User User

	// Directory is the Directory in which to place new data items,
	// usually the location of the user's root.
	Directory Directory

	// Store is the Store in which to place new data items.
	Store Store
}

// Access defines how to connect and authenticate to a server. Each
// service type (User, Directory, Store) implements the methods of
// the Access interface. These methods are not used directly by
// clients. Instead, clients should use the various Bind methods of
// the Upspin "access" package to connect to services.
type Access interface {
	// Dial connects to the service and performs any needed authentication.
	Dial(*ClientContext, Endpoint) (interface{}, error)

	// ServerUserName returns the authenticated user name of the server.
	// If there is no authenticated name an empty string is returned.
	// TODO(p): Should I distinguish a server which didn't pass authentication
	// from one which has no user name?
	ServerUserName() string
}
<|endoftext|>


<commit_before>package isolated

import (
	"code.cloudfoundry.org/cli/integration/helpers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
)

var _ = Describe("set-space-role command", func() {
	Describe("help", func() {
		When("--help flag is set", func() {
			It("Displays command usage to output", func() {
				session := helpers.CF("set-space-role", "--help")
				Eventually(session).Should(Say("NAME:"))
				Eventually(session).Should(Say("set-space-role - Assign a space role to a user"))
				Eventually(session).Should(Say("USAGE:"))
				Eventually(session).Should(Say("cf set-space-role USERNAME ORG SPACE ROLE"))
				Eventually(session).Should(Say("ROLES:"))
				Eventually(session).Should(Say("'SpaceManager' - Invite and manage users, and enable features for a given space"))
				Eventually(session).Should(Say("'SpaceDeveloper' - Create and manage apps and services, and see logs and reports"))
				Eventually(session).Should(Say("'SpaceAuditor' - View logs, reports, and settings on this space"))
				Eventually(session).Should(Say("SEE ALSO:"))
				Eventually(session).Should(Say("space-users"))
				Eventually(session).Should(Exit(0))
			})
		})
	})

	When("the org, space, and user all exist", func() {
		var (
			username  string
			orgName   string
			spaceName string
		)

		BeforeEach(func() {
			helpers.LoginCF()
			orgName = helpers.NewOrgName()
			spaceName = helpers.NewSpaceName()
			helpers.CreateOrgAndSpace(orgName, spaceName)
			username, _ = helpers.CreateUser()
		})

		It("sets the space role for the user", func() {
			session := helpers.CF("set-space-role", username, orgName, spaceName, "SpaceAuditor")
			Eventually(session).Should(Say("Assigning role RoleSpaceAuditor to user %s in org %s / space %s as admin...", username, orgName, spaceName))
			Eventually(session).Should(Say("OK"))
			Eventually(session).Should(Exit(0))
		})

		When("the user already has the desired role", func() {
			BeforeEach(func() {
				session := helpers.CF("set-space-role", username, orgName, spaceName, "SpaceAuditor")
				Eventually(session).Should(Say("Assigning role RoleSpaceAuditor to user %s in org %s / space %s as admin...", username, orgName, spaceName))
				Eventually(session).Should(Exit(0))
			})

			It("is idempotent", func() {
				session := helpers.CF("set-space-role", username, orgName, spaceName, "SpaceAuditor")
				Eventually(session).Should(Say("Assigning role RoleSpaceAuditor to user %s in org %s / space %s as admin...", username, orgName, spaceName))
				Eventually(session).Should(Exit(0))
			})
		})
	})
})
<commit_msg>Change SpaceAuditor to SpaceDeveloper<commit_after>package isolated

import (
	"code.cloudfoundry.org/cli/integration/helpers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
)

var _ = Describe("set-space-role command", func() {
	Describe("help", func() {
		When("--help flag is set", func() {
			It("Displays command usage to output", func() {
				session := helpers.CF("set-space-role", "--help")
				Eventually(session).Should(Say("NAME:"))
				Eventually(session).Should(Say("set-space-role - Assign a space role to a user"))
				Eventually(session).Should(Say("USAGE:"))
				Eventually(session).Should(Say("cf set-space-role USERNAME ORG SPACE ROLE"))
				Eventually(session).Should(Say("ROLES:"))
				Eventually(session).Should(Say("'SpaceManager' - Invite and manage users, and enable features for a given space"))
				Eventually(session).Should(Say("'SpaceDeveloper' - Create and manage apps and services, and see logs and reports"))
				Eventually(session).Should(Say("'SpaceAuditor' - View logs, reports, and settings on this space"))
				Eventually(session).Should(Say("SEE ALSO:"))
				Eventually(session).Should(Say("space-users"))
				Eventually(session).Should(Exit(0))
			})
		})
	})

	When("the org, space, and user all exist", func() {
		var (
			username  string
			orgName   string
			spaceName string
		)

		BeforeEach(func() {
			helpers.LoginCF()
			orgName = helpers.NewOrgName()
			spaceName = helpers.NewSpaceName()
			helpers.CreateOrgAndSpace(orgName, spaceName)
			username, _ = helpers.CreateUser()
		})

		It("sets the space role for the user", func() {
			session := helpers.CF("set-space-role", username, orgName, spaceName, "SpaceAuditor")
			Eventually(session).Should(Say("Assigning role RoleSpaceAuditor to user %s in org %s / space %s as admin...", username, orgName, spaceName))
			Eventually(session).Should(Say("OK"))
			Eventually(session).Should(Exit(0))
		})

		When("the user already has the desired role", func() {
			BeforeEach(func() {
				session := helpers.CF("set-space-role", username, orgName, spaceName, "SpaceDeveloper")
				Eventually(session).Should(Say("Assigning role RoleSpaceDeveloper to user %s in org %s / space %s as admin...", username, orgName, spaceName))
				Eventually(session).Should(Exit(0))
			})

			It("is idempotent", func() {
				session := helpers.CF("set-space-role", username, orgName, spaceName, "SpaceDeveloper")
				Eventually(session).Should(Say("Assigning role RoleSpaceDeveloper to user %s in org %s / space %s as admin...", username, orgName, spaceName))
				Eventually(session).Should(Exit(0))
			})
		})
	})
})
<|endoftext|>


<commit_before>// +build windows

/*
   Copyright The containerd 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 lcow

import (
	"context"
	"io"
	"os"
	"path"
	"time"

	"github.com/Microsoft/hcsshim/ext4/tar2ext4"
	"github.com/containerd/containerd/archive/compression"
	"github.com/containerd/containerd/content"
	"github.com/containerd/containerd/diff"
	"github.com/containerd/containerd/errdefs"
	"github.com/containerd/containerd/images"
	"github.com/containerd/containerd/log"
	"github.com/containerd/containerd/metadata"
	"github.com/containerd/containerd/mount"
	"github.com/containerd/containerd/plugin"
	digest "github.com/opencontainers/go-digest"
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

const (
	// maxLcowVhdSizeGB is the max size in GB of any layer
	maxLcowVhdSizeGB = 128 * 1024 * 1024 * 1024
)

func init() {
	plugin.Register(&plugin.Registration{
		Type: plugin.DiffPlugin,
		ID:   "windows-lcow",
		Requires: []plugin.Type{
			plugin.MetadataPlugin,
		},
		InitFn: func(ic *plugin.InitContext) (interface{}, error) {
			md, err := ic.Get(plugin.MetadataPlugin)
			if err != nil {
				return nil, err
			}

			ic.Meta.Platforms = append(ic.Meta.Platforms, ocispec.Platform{
				OS:           "linux",
				Architecture: "amd64",
			})
			return NewWindowsLcowDiff(md.(*metadata.DB).ContentStore())
		},
	})
}

// CompareApplier handles both comparison and
// application of layer diffs.
type CompareApplier interface {
	diff.Applier
	diff.Comparer
}

// windowsLcowDiff does filesystem comparison and application
// for Windows specific Linux layer diffs.
type windowsLcowDiff struct {
	store content.Store
}

var emptyDesc = ocispec.Descriptor{}

// NewWindowsLcowDiff is the Windows LCOW container layer implementation
// for comparing and applying Linux filesystem layers on Windows
func NewWindowsLcowDiff(store content.Store) (CompareApplier, error) {
	return windowsLcowDiff{
		store: store,
	}, nil
}

// Apply applies the content associated with the provided digests onto the
// provided mounts. Archive content will be extracted and decompressed if
// necessary.
func (s windowsLcowDiff) Apply(ctx context.Context, desc ocispec.Descriptor, mounts []mount.Mount) (d ocispec.Descriptor, err error) {
	t1 := time.Now()
	defer func() {
		if err == nil {
			log.G(ctx).WithFields(logrus.Fields{
				"d":     time.Since(t1),
				"dgst":  desc.Digest,
				"size":  desc.Size,
				"media": desc.MediaType,
			}).Debugf("diff applied")
		}
	}()

	layer, _, err := mountsToLayerAndParents(mounts)
	if err != nil {
		return emptyDesc, err
	}

	isCompressed, err := images.IsCompressedDiff(ctx, desc.MediaType)
	if err != nil {
		return emptyDesc, errors.Wrapf(errdefs.ErrNotImplemented, "unsupported diff media type: %v", desc.MediaType)
	}

	ra, err := s.store.ReaderAt(ctx, desc)
	if err != nil {
		return emptyDesc, errors.Wrap(err, "failed to get reader from content store")
	}
	defer ra.Close()
	rdr := content.NewReader(ra)
	if isCompressed {
		ds, err := compression.DecompressStream(rdr)
		if err != nil {
			return emptyDesc, err
		}
		defer ds.Close()
		rdr = ds
	}
	// Calculate the Digest as we go
	digester := digest.Canonical.Digester()
	rc := &readCounter{
		r: io.TeeReader(rdr, digester.Hash()),
	}

	layerPath := path.Join(layer, "layer.vhd")
	outFile, err := os.Create(layerPath)
	if err != nil {
		return emptyDesc, err
	}
	defer outFile.Close()
	defer func() {
		if err != nil {
			outFile.Close()
			os.Remove(layerPath)
		}
	}()

	err = tar2ext4.Convert(rc, outFile, tar2ext4.ConvertWhiteout, tar2ext4.AppendVhdFooter, tar2ext4.MaximumDiskSize(maxLcowVhdSizeGB))
	if err != nil {
		return emptyDesc, errors.Wrapf(err, "failed to convert tar to ext4 vhd")
	}

	return ocispec.Descriptor{
		MediaType: ocispec.MediaTypeImageLayer,
		Size:      rc.c,
		Digest:    digester.Digest(),
	}, nil
}

// Compare creates a diff between the given mounts and uploads the result
// to the content store.
func (s windowsLcowDiff) Compare(ctx context.Context, lower, upper []mount.Mount, opts ...diff.Opt) (d ocispec.Descriptor, err error) {
	return emptyDesc, errdefs.ErrNotImplemented
}

type readCounter struct {
	r io.Reader
	c int64
}

func (rc *readCounter) Read(p []byte) (n int, err error) {
	n, err = rc.r.Read(p)
	rc.c += int64(n)
	return
}

func mountsToLayerAndParents(mounts []mount.Mount) (string, []string, error) {
	if len(mounts) != 1 {
		return "", nil, errors.Wrap(errdefs.ErrInvalidArgument, "number of mounts should always be 1 for Windows lcow-layers")
	}
	mnt := mounts[0]
	if mnt.Type != "lcow-layer" {
		return "", nil, errors.Wrap(errdefs.ErrInvalidArgument, "mount layer type must be lcow-layer")
	}

	parentLayerPaths, err := mnt.GetParentPaths()
	if err != nil {
		return "", nil, err
	}

	return mnt.Source, parentLayerPaths, nil
}
<commit_msg>Update Windows lcow differ to set NT VIRTUAL MACHINE\Virtual Machines SID<commit_after>// +build windows

/*
   Copyright The containerd 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 lcow

import (
	"context"
	"io"
	"os"
	"path"
	"time"

	"github.com/Microsoft/go-winio/pkg/security"
	"github.com/Microsoft/hcsshim/ext4/tar2ext4"
	"github.com/containerd/containerd/archive/compression"
	"github.com/containerd/containerd/content"
	"github.com/containerd/containerd/diff"
	"github.com/containerd/containerd/errdefs"
	"github.com/containerd/containerd/images"
	"github.com/containerd/containerd/log"
	"github.com/containerd/containerd/metadata"
	"github.com/containerd/containerd/mount"
	"github.com/containerd/containerd/plugin"
	digest "github.com/opencontainers/go-digest"
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

const (
	// maxLcowVhdSizeGB is the max size in GB of any layer
	maxLcowVhdSizeGB = 128 * 1024 * 1024 * 1024
)

func init() {
	plugin.Register(&plugin.Registration{
		Type: plugin.DiffPlugin,
		ID:   "windows-lcow",
		Requires: []plugin.Type{
			plugin.MetadataPlugin,
		},
		InitFn: func(ic *plugin.InitContext) (interface{}, error) {
			md, err := ic.Get(plugin.MetadataPlugin)
			if err != nil {
				return nil, err
			}

			ic.Meta.Platforms = append(ic.Meta.Platforms, ocispec.Platform{
				OS:           "linux",
				Architecture: "amd64",
			})
			return NewWindowsLcowDiff(md.(*metadata.DB).ContentStore())
		},
	})
}

// CompareApplier handles both comparison and
// application of layer diffs.
type CompareApplier interface {
	diff.Applier
	diff.Comparer
}

// windowsLcowDiff does filesystem comparison and application
// for Windows specific Linux layer diffs.
type windowsLcowDiff struct {
	store content.Store
}

var emptyDesc = ocispec.Descriptor{}

// NewWindowsLcowDiff is the Windows LCOW container layer implementation
// for comparing and applying Linux filesystem layers on Windows
func NewWindowsLcowDiff(store content.Store) (CompareApplier, error) {
	return windowsLcowDiff{
		store: store,
	}, nil
}

// Apply applies the content associated with the provided digests onto the
// provided mounts. Archive content will be extracted and decompressed if
// necessary.
func (s windowsLcowDiff) Apply(ctx context.Context, desc ocispec.Descriptor, mounts []mount.Mount) (d ocispec.Descriptor, err error) {
	t1 := time.Now()
	defer func() {
		if err == nil {
			log.G(ctx).WithFields(logrus.Fields{
				"d":     time.Since(t1),
				"dgst":  desc.Digest,
				"size":  desc.Size,
				"media": desc.MediaType,
			}).Debugf("diff applied")
		}
	}()

	layer, _, err := mountsToLayerAndParents(mounts)
	if err != nil {
		return emptyDesc, err
	}

	isCompressed, err := images.IsCompressedDiff(ctx, desc.MediaType)
	if err != nil {
		return emptyDesc, errors.Wrapf(errdefs.ErrNotImplemented, "unsupported diff media type: %v", desc.MediaType)
	}

	ra, err := s.store.ReaderAt(ctx, desc)
	if err != nil {
		return emptyDesc, errors.Wrap(err, "failed to get reader from content store")
	}
	defer ra.Close()
	rdr := content.NewReader(ra)
	if isCompressed {
		ds, err := compression.DecompressStream(rdr)
		if err != nil {
			return emptyDesc, err
		}
		defer ds.Close()
		rdr = ds
	}
	// Calculate the Digest as we go
	digester := digest.Canonical.Digester()
	rc := &readCounter{
		r: io.TeeReader(rdr, digester.Hash()),
	}

	layerPath := path.Join(layer, "layer.vhd")
	outFile, err := os.Create(layerPath)
	if err != nil {
		return emptyDesc, err
	}
	defer func() {
		if err != nil {
			outFile.Close()
			os.Remove(layerPath)
		}
	}()

	err = tar2ext4.Convert(rc, outFile, tar2ext4.ConvertWhiteout, tar2ext4.AppendVhdFooter, tar2ext4.MaximumDiskSize(maxLcowVhdSizeGB))
	if err != nil {
		return emptyDesc, errors.Wrapf(err, "failed to convert tar to ext4 vhd")
	}
	outFile.Close()

	err = security.GrantVmGroupAccess(layerPath)
	if err != nil {
		return emptyDesc, errors.Wrapf(err, "failed GrantVmGroupAccess on layer vhd: %v", layerPath)
	}

	return ocispec.Descriptor{
		MediaType: ocispec.MediaTypeImageLayer,
		Size:      rc.c,
		Digest:    digester.Digest(),
	}, nil
}

// Compare creates a diff between the given mounts and uploads the result
// to the content store.
func (s windowsLcowDiff) Compare(ctx context.Context, lower, upper []mount.Mount, opts ...diff.Opt) (d ocispec.Descriptor, err error) {
	return emptyDesc, errdefs.ErrNotImplemented
}

type readCounter struct {
	r io.Reader
	c int64
}

func (rc *readCounter) Read(p []byte) (n int, err error) {
	n, err = rc.r.Read(p)
	rc.c += int64(n)
	return
}

func mountsToLayerAndParents(mounts []mount.Mount) (string, []string, error) {
	if len(mounts) != 1 {
		return "", nil, errors.Wrap(errdefs.ErrInvalidArgument, "number of mounts should always be 1 for Windows lcow-layers")
	}
	mnt := mounts[0]
	if mnt.Type != "lcow-layer" {
		return "", nil, errors.Wrap(errdefs.ErrInvalidArgument, "mount layer type must be lcow-layer")
	}

	parentLayerPaths, err := mnt.GetParentPaths()
	if err != nil {
		return "", nil, err
	}

	return mnt.Source, parentLayerPaths, nil
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"testing"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/ses"
	"github.com/hashicorp/terraform-plugin-sdk/helper/acctest"
	"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
	"github.com/hashicorp/terraform-plugin-sdk/terraform"
)

func TestAccAWSSESIdentityPolicy_basic(t *testing.T) {
	domain := fmt.Sprintf(
		"%s.terraformtesting.com.",
		acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum))
	resourceName := "aws_ses_identity_policy.test"

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAwsSESIdentityPolicyDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAWSSESIdentityPolicyConfigIdentityDomain(domain),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAwsSESIdentityPolicyExists(resourceName),
				),
			},
			{
				ResourceName:      resourceName,
				ImportState:       true,
				ImportStateVerify: true,
			},
		},
	})
}

func TestAccAWSSESIdentityPolicy_Identity_Email(t *testing.T) {
	email := fmt.Sprintf(
		"%s@terraformtesting.com",
		acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum))
	resourceName := "aws_ses_identity_policy.test"

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAwsSESIdentityPolicyDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAWSSESIdentityPolicyConfigIdentityEmail(email),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAwsSESIdentityPolicyExists(resourceName),
				),
			},
			{
				ResourceName:      resourceName,
				ImportState:       true,
				ImportStateVerify: true,
			},
		},
	})
}

func TestAccAWSSESIdentityPolicy_Policy(t *testing.T) {
	domain := fmt.Sprintf(
		"%s.terraformtesting.com.",
		acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum))
	resourceName := "aws_ses_identity_policy.test"

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAwsSESIdentityPolicyDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAWSSESIdentityPolicyConfigPolicy1(domain),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAwsSESIdentityPolicyExists(resourceName),
				),
			},
			{
				Config: testAccAWSSESIdentityPolicyConfigPolicy2(domain),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAwsSESIdentityPolicyExists(resourceName),
				),
			},
			{
				ResourceName:      resourceName,
				ImportState:       true,
				ImportStateVerify: true,
			},
		},
	})
}

func testAccCheckAwsSESIdentityPolicyDestroy(s *terraform.State) error {
	conn := testAccProvider.Meta().(*AWSClient).sesconn

	for _, rs := range s.RootModule().Resources {
		if rs.Type != "aws_ses_identity_policy" {
			continue
		}

		identityARN, policyName, err := resourceAwsSesIdentityPolicyParseID(rs.Primary.ID)
		if err != nil {
			return err
		}

		input := &ses.GetIdentityPoliciesInput{
			Identity:    aws.String(identityARN),
			PolicyNames: aws.StringSlice([]string{policyName}),
		}

		output, err := conn.GetIdentityPolicies(input)

		if err != nil {
			return err
		}

		if output != nil && len(output.Policies) > 0 && aws.StringValue(output.Policies[policyName]) != "" {
			return fmt.Errorf("SES Identity (%s) Policy (%s) still exists", identityARN, policyName)
		}
	}

	return nil
}

func testAccCheckAwsSESIdentityPolicyExists(resourceName string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[resourceName]
		if !ok {
			return fmt.Errorf("SES Identity Policy not found: %s", resourceName)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("SES Identity Policy ID not set")
		}

		conn := testAccProvider.Meta().(*AWSClient).sesconn

		identityARN, policyName, err := resourceAwsSesIdentityPolicyParseID(rs.Primary.ID)
		if err != nil {
			return err
		}

		input := &ses.GetIdentityPoliciesInput{
			Identity:    aws.String(identityARN),
			PolicyNames: aws.StringSlice([]string{policyName}),
		}

		output, err := conn.GetIdentityPolicies(input)

		if err != nil {
			return err
		}

		if output == nil || len(output.Policies) == 0 {
			return fmt.Errorf("SES Identity (%s) Policy (%s) not found", identityARN, policyName)
		}

		return nil
	}
}

func testAccAWSSESIdentityPolicyConfigIdentityDomain(domain string) string {
	return fmt.Sprintf(`
data "aws_iam_policy_document" "test" {
  statement {
    actions   = ["SES:SendEmail", "SES:SendRawEmail"]
    resources = ["${aws_ses_domain_identity.test.arn}"]

    principals {
      identifiers = ["*"]
      type        = "AWS"
    }
  }
}

resource "aws_ses_domain_identity" "test" {
  domain = %[1]q
}

resource "aws_ses_identity_policy" "test" {
  identity = "${aws_ses_domain_identity.test.arn}"
  name     = "test"
  policy   = "${data.aws_iam_policy_document.test.json}"
}
`, domain)
}

func testAccAWSSESIdentityPolicyConfigIdentityEmail(email string) string {
	return fmt.Sprintf(`
data "aws_iam_policy_document" "test" {
  statement {
    actions   = ["SES:SendEmail", "SES:SendRawEmail"]
    resources = ["${aws_ses_email_identity.test.arn}"]

    principals {
      identifiers = ["*"]
      type        = "AWS"
    }
  }
}

resource "aws_ses_email_identity" "test" {
  email = %[1]q
}

resource "aws_ses_identity_policy" "test" {
  identity = "${aws_ses_email_identity.test.email}"
  name     = "test"
  policy   = "${data.aws_iam_policy_document.test.json}"
}
`, email)
}

func testAccAWSSESIdentityPolicyConfigPolicy1(domain string) string {
	return fmt.Sprintf(`
data "aws_iam_policy_document" "test" {
  statement {
    actions   = ["SES:SendEmail", "SES:SendRawEmail"]
    resources = ["${aws_ses_domain_identity.test.arn}"]

    principals {
      identifiers = ["*"]
      type        = "AWS"
    }
  }
}

resource "aws_ses_domain_identity" "test" {
  domain = %[1]q
}

resource "aws_ses_identity_policy" "test" {
  identity = "${aws_ses_domain_identity.test.arn}"
  name     = "test"
  policy   = "${data.aws_iam_policy_document.test.json}"
}
`, domain)
}

func testAccAWSSESIdentityPolicyConfigPolicy2(domain string) string {
	return fmt.Sprintf(`
data "aws_caller_identity" "current" {}

data "aws_iam_policy_document" "test" {
  statement {
    actions   = ["SES:SendEmail", "SES:SendRawEmail"]
    resources = ["${aws_ses_domain_identity.test.arn}"]

    principals {
      identifiers = ["${data.aws_caller_identity.current.account_id}"]
      type        = "AWS"
    }
  }
}

resource "aws_ses_domain_identity" "test" {
  domain = %[1]q
}

resource "aws_ses_identity_policy" "test" {
  identity = "${aws_ses_domain_identity.test.arn}"
  name     = "test"
  policy   = "${data.aws_iam_policy_document.test.json}"
}
`, domain)
}
<commit_msg>tests/resource/aws_ses_identity_policy: Fix TestAccAWSSESIdentityPolicy_* tests (#14524)<commit_after>package aws

import (
	"fmt"
	"testing"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/ses"
	"github.com/hashicorp/terraform-plugin-sdk/helper/acctest"
	"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
	"github.com/hashicorp/terraform-plugin-sdk/terraform"
)

func TestAccAWSSESIdentityPolicy_basic(t *testing.T) {
	domain := fmt.Sprintf(
		"%s.terraformtesting.com",
		acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum))
	resourceName := "aws_ses_identity_policy.test"

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAwsSESIdentityPolicyDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAWSSESIdentityPolicyConfigIdentityDomain(domain),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAwsSESIdentityPolicyExists(resourceName),
				),
			},
			{
				ResourceName:      resourceName,
				ImportState:       true,
				ImportStateVerify: true,
			},
		},
	})
}

func TestAccAWSSESIdentityPolicy_Identity_Email(t *testing.T) {
	email := fmt.Sprintf(
		"%s@terraformtesting.com",
		acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum))
	resourceName := "aws_ses_identity_policy.test"

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAwsSESIdentityPolicyDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAWSSESIdentityPolicyConfigIdentityEmail(email),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAwsSESIdentityPolicyExists(resourceName),
				),
			},
			{
				ResourceName:      resourceName,
				ImportState:       true,
				ImportStateVerify: true,
			},
		},
	})
}

func TestAccAWSSESIdentityPolicy_Policy(t *testing.T) {
	domain := fmt.Sprintf(
		"%s.terraformtesting.com",
		acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum))
	resourceName := "aws_ses_identity_policy.test"

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAwsSESIdentityPolicyDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAWSSESIdentityPolicyConfigPolicy1(domain),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAwsSESIdentityPolicyExists(resourceName),
				),
			},
			{
				Config: testAccAWSSESIdentityPolicyConfigPolicy2(domain),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAwsSESIdentityPolicyExists(resourceName),
				),
			},
			{
				ResourceName:      resourceName,
				ImportState:       true,
				ImportStateVerify: true,
			},
		},
	})
}

func testAccCheckAwsSESIdentityPolicyDestroy(s *terraform.State) error {
	conn := testAccProvider.Meta().(*AWSClient).sesconn

	for _, rs := range s.RootModule().Resources {
		if rs.Type != "aws_ses_identity_policy" {
			continue
		}

		identityARN, policyName, err := resourceAwsSesIdentityPolicyParseID(rs.Primary.ID)
		if err != nil {
			return err
		}

		input := &ses.GetIdentityPoliciesInput{
			Identity:    aws.String(identityARN),
			PolicyNames: aws.StringSlice([]string{policyName}),
		}

		output, err := conn.GetIdentityPolicies(input)

		if err != nil {
			return err
		}

		if output != nil && len(output.Policies) > 0 && aws.StringValue(output.Policies[policyName]) != "" {
			return fmt.Errorf("SES Identity (%s) Policy (%s) still exists", identityARN, policyName)
		}
	}

	return nil
}

func testAccCheckAwsSESIdentityPolicyExists(resourceName string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[resourceName]
		if !ok {
			return fmt.Errorf("SES Identity Policy not found: %s", resourceName)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("SES Identity Policy ID not set")
		}

		conn := testAccProvider.Meta().(*AWSClient).sesconn

		identityARN, policyName, err := resourceAwsSesIdentityPolicyParseID(rs.Primary.ID)
		if err != nil {
			return err
		}

		input := &ses.GetIdentityPoliciesInput{
			Identity:    aws.String(identityARN),
			PolicyNames: aws.StringSlice([]string{policyName}),
		}

		output, err := conn.GetIdentityPolicies(input)

		if err != nil {
			return err
		}

		if output == nil || len(output.Policies) == 0 {
			return fmt.Errorf("SES Identity (%s) Policy (%s) not found", identityARN, policyName)
		}

		return nil
	}
}

func testAccAWSSESIdentityPolicyConfigIdentityDomain(domain string) string {
	return fmt.Sprintf(`
data "aws_iam_policy_document" "test" {
  statement {
    actions   = ["SES:SendEmail", "SES:SendRawEmail"]
    resources = ["${aws_ses_domain_identity.test.arn}"]

    principals {
      identifiers = ["*"]
      type        = "AWS"
    }
  }
}

resource "aws_ses_domain_identity" "test" {
  domain = %[1]q
}

resource "aws_ses_identity_policy" "test" {
  identity = "${aws_ses_domain_identity.test.arn}"
  name     = "test"
  policy   = "${data.aws_iam_policy_document.test.json}"
}
`, domain)
}

func testAccAWSSESIdentityPolicyConfigIdentityEmail(email string) string {
	return fmt.Sprintf(`
data "aws_iam_policy_document" "test" {
  statement {
    actions   = ["SES:SendEmail", "SES:SendRawEmail"]
    resources = ["${aws_ses_email_identity.test.arn}"]

    principals {
      identifiers = ["*"]
      type        = "AWS"
    }
  }
}

resource "aws_ses_email_identity" "test" {
  email = %[1]q
}

resource "aws_ses_identity_policy" "test" {
  identity = "${aws_ses_email_identity.test.email}"
  name     = "test"
  policy   = "${data.aws_iam_policy_document.test.json}"
}
`, email)
}

func testAccAWSSESIdentityPolicyConfigPolicy1(domain string) string {
	return fmt.Sprintf(`
data "aws_iam_policy_document" "test" {
  statement {
    actions   = ["SES:SendEmail", "SES:SendRawEmail"]
    resources = ["${aws_ses_domain_identity.test.arn}"]

    principals {
      identifiers = ["*"]
      type        = "AWS"
    }
  }
}

resource "aws_ses_domain_identity" "test" {
  domain = %[1]q
}

resource "aws_ses_identity_policy" "test" {
  identity = "${aws_ses_domain_identity.test.arn}"
  name     = "test"
  policy   = "${data.aws_iam_policy_document.test.json}"
}
`, domain)
}

func testAccAWSSESIdentityPolicyConfigPolicy2(domain string) string {
	return fmt.Sprintf(`
data "aws_caller_identity" "current" {}

data "aws_iam_policy_document" "test" {
  statement {
    actions   = ["SES:SendEmail", "SES:SendRawEmail"]
    resources = ["${aws_ses_domain_identity.test.arn}"]

    principals {
      identifiers = ["${data.aws_caller_identity.current.account_id}"]
      type        = "AWS"
    }
  }
}

resource "aws_ses_domain_identity" "test" {
  domain = %[1]q
}

resource "aws_ses_identity_policy" "test" {
  identity = "${aws_ses_domain_identity.test.arn}"
  name     = "test"
  policy   = "${data.aws_iam_policy_document.test.json}"
}
`, domain)
}
<|endoftext|>


<commit_before>package util

import (
  "crypto/sha256"
  "io"
  "os"
)

func Checksum(path string) ([]byte, error) {
  var result []byte
  file, err := os.Open(path)

  if err != nil {
    return result, err
  }

  defer file.Close()

  hash := sha256.New()

  if _, err := io.Copy(hash, file); err != nil {
    return result, err
  }

  return hash.Sum(result), nil
}
<commit_msg>Fixed checksum creater<commit_after>package util

import (
	"crypto/sha256"
	"encoding/hex"
	"io"
	"os"
)

func Checksum(path string) (string, error) {
	file, err := os.Open(path)

	if err != nil {
		return "", err
	}

	defer file.Close()

	hash := sha256.New()

	if _, err := io.Copy(hash, file); err != nil {
		return "", err
	}

	return hex.EncodeToString(hash.Sum(nil)), nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"github.com/THUNDERGROOVE/stats-bot/db"
	"log"
	"text/template"

	"strings"
)

var searchTmpl *template.Template

func init() {
	log.Println("Registering blacklist commands")
	searchTmpl = parseTemplate("search.tmpl")

	RegisterCommand("reportpsn", cmdReportPSN, CMD_DEV)
	RegisterCommand("searchreport", cmdSearchReports, CMD_DEV)
}

func cmdSearchReports(ctx *Context) {
	args := strings.Split(ctx.Ev.Text, " ")
	search := args[1]

	reports := []*db.Report{}
	g := map[string]interface{}{}

	db.DB.Where("name like ?", fmt.Sprintf("%%%v%%", search)).Find(&reports)
	g["Reports"] = reports
	buf := bytes.NewBufferString("")
	searchTmpl.Execute(buf, g)
	ctx.Respond(buf.String())
}

func cmdReportPSN(ctx *Context) {
	args := strings.Split(ctx.Ev.Text, " ")
	if len(args) < 3 {
		ctx.Respond("report <name> <psn> <additional information>")
	}
	name := args[1]
	psn := args[2]

	info := strings.Join(args[len(args)-3:], " ")

	// Lookup Character to know what region they play on

	char, err := Census.GetCharacterByName(name)

	if err != nil {
		err = nil
		char, err = CensusEU.GetCharacterByName(name)
		if err != nil {
			ctx.Respond("That name didn't exist in either US or EU")
			return
		}
	} else {
		_, err := CensusEU.GetCharacterByName(name)
		if err == nil {
			ctx.Respond("The given character name matches on US and EU")
		}
	}
	db.NewReport(ctx.Ev.Name, char.Name.First, psn, info, char.Parent)
	ctx.Respond(fmt.Sprintf("Reported: %v for %v.", char.Name.First, info))
}

func cmdIsAdmin(ctx *Context) {
	if isAdmin(ctx) {
		ctx.Respond("You are an admin")
	} else {
		ctx.Respond("You are not an admin")
	}
}

func isAdmin(ctx *Context) bool {
	u, err := ctx.Bot.GetUserInfo(ctx.Ev.Username)
	if err != nil {
		return false
	}
	return u.IsAdmin
}
<commit_msg>!report now<commit_after>package main

import (
	"bytes"
	"fmt"
	"log"
	"strings"
	"text/template"

	"github.com/THUNDERGROOVE/stats-bot/db"
)

var searchTmpl *template.Template

func init() {
	log.Println("Registering blacklist commands")
	searchTmpl = parseTemplate("search.tmpl")

	RegisterCommand("reportpsn", cmdReportPSN, CMD_DEV)
	RegisterCommand("report", cmdReport, CMD_DEV)
	RegisterCommand("searchreport", cmdSearchReports, CMD_DEV)
	RegisterCommand("isadmin", cmdIsAdmin, CMD_READY)
}

func cmdReport(ctx *Context) {
	args := strings.Split(ctx.Ev.Text, " ")
	if len(args) < 2 {
		ctx.Respond("report <name> <additional information>")
	}
	name := args[1]

	info := strings.Join(args[len(args)-2:], " ")

	// Lookup Character to know what region they play on

	// TODO: Refactor this with PSN version
	char, err := Census.GetCharacterByName(name)

	if err != nil {
		err = nil
		char, err = CensusEU.GetCharacterByName(name)
		if err != nil {
			ctx.Respond("That name didn't exist in either US or EU")
			return
		}
	} else {
		_, err := CensusEU.GetCharacterByName(name)
		if err == nil {
			ctx.Respond("The given character name matches on US and EU")
		}
	}
	db.NewReport(ctx.Ev.Name, char.Name.First, "not specified", info, char.Parent)
	ctx.Respond(fmt.Sprintf("Reported: %v for %v.", char.Name.First, info))

}

func cmdSearchReports(ctx *Context) {
	args := strings.Split(ctx.Ev.Text, " ")
	search := args[1]

	reports := []*db.Report{}
	g := map[string]interface{}{}

	db.DB.Where("name like ?", fmt.Sprintf("%%%v%%", search)).Find(&reports)
	g["Reports"] = reports

	buf := bytes.NewBufferString("")
	searchTmpl.Execute(buf, g)
	ctx.Respond(buf.String())
}

func cmdReportPSN(ctx *Context) {
	args := strings.Split(ctx.Ev.Text, " ")
	if len(args) < 3 {
		ctx.Respond("report <name> <psn> <additional information>")
	}
	name := args[1]
	psn := args[2]

	info := strings.Join(args[len(args)-3:], " ")

	// Lookup Character to know what region they play on

	char, err := Census.GetCharacterByName(name)

	if err != nil {
		err = nil
		char, err = CensusEU.GetCharacterByName(name)
		if err != nil {
			ctx.Respond("That name didn't exist in either US or EU")
			return
		}
	} else {
		_, err := CensusEU.GetCharacterByName(name)
		if err == nil {
			ctx.Respond("The given character name matches on US and EU")
		}
	}
	db.NewReport(ctx.Ev.Name, char.Name.First, psn, info, char.Parent)
	ctx.Respond(fmt.Sprintf("Reported: %v for %v.", char.Name.First, info))
}

func cmdIsAdmin(ctx *Context) {
	if isAdmin(ctx) {
		ctx.Respond("You are an admin")
	} else {
		ctx.Respond("You are not an admin")
	}
}

func isAdmin(ctx *Context) bool {
	u, err := ctx.Bot.GetUserInfo(ctx.Ev.Username)
	if err != nil {
		return false
	}
	return u.IsAdmin
}
<|endoftext|>


<commit_before>package util

import (
	"fmt"
)

type Packed64SingleBlock struct {
	PackedIntsReaderImpl
	get    func(index int32) int64
	blocks []int64
}

func (p *Packed64SingleBlock) Get(index int32) int64 {
	return p.get(index)
}

func newPacked64SingleBlockFromInput(in *DataInput, valueCount int32, bitsPerValue uint32) (reader *Packed64SingleBlock, err error) {
	reader = newPacked64SingleBlockBy(valueCount, bitsPerValue)
	for i, _ := range reader.blocks {
		reader.blocks[i], err = in.ReadLong()
		if err == nil {
			return reader, nil
		}
	}
	return &reader, nil
}

func newPacked64SingleBlockBy(valueCount int32, bitsPerValue uint32) (reader Packed64SingleBlock, err error) {
	switch bitsPerValue {
	case 1:
		return newPacked64SingleBlock1(valueCount)
	case 2:
		return newPacked64SingleBlock2(valueCount)
	case 3:
		return newPacked64SingleBlock3(valueCount)
	case 4:
		return newPacked64SingleBlock4(valueCount)
	case 5:
		return newPacked64SingleBlock5(valueCount)
	case 6:
		return newPacked64SingleBlock6(valueCount)
	case 7:
		return newPacked64SingleBlock7(valueCount)
	case 8:
		return newPacked64SingleBlock8(valueCount)
	case 9:
		return newPacked64SingleBlock9(valueCount)
	case 10:
		return newPacked64SingleBlock10(valueCount)
	case 12:
		return newPacked64SingleBlock12(valueCount)
	case 16:
		return newPacked64SingleBlock16(valueCount)
	case 21:
		return newPacked64SingleBlock21(valueCount)
	case 32:
		return newPacked64SingleBlock32(valueCount)
	default:
		panic(fmt.Sprintf("Unsuppoted number of bits per value: %v", bitsPerValue))
	}
}

func newPacked64SingleBlock1(valueCount int32) Packed64SingleBlock {
	ans := newPacked64SingleBlock(valueCount, 1)
	ans.get = func(index int32) int64 {
		o := uint32(index) >> 6
		b := index & 63
		shift := b << 0
		return int64(uint64(ans.blocks[o])>>shift) & 1
	}
	ans.set = func(index int32, value int64) {
		o := uint32(index) >> 6
		b := index & 63
		shift := b << 0
		ans.blocks[o] = (ans.blocks[o] & ^(int64(1) << shift)) | (value << shift)
	}
	return ans
}

func newPacked64SingleBlock2(valueCount int32) Packed64SingleBlock {
	ans := newPacked64SingleBlock(valueCount, 2)
	ans.get = func(index int32) int64 {
		o := uint32(index) >> 5
		b := index & 31
		shift := b << 1
		return int64(uint64(ans.blocks[o])>>shift) & 3
	}
	ans.set = func(index int32, value int64) {
		o := uint32(index) >> 5
		b := index & 31
		shift := b << 1
		ans.blocks[o] = (ans.blocks[o] & ^(int64(3) << shift)) | (value << shift)
	}
	return ans
}

func newPacked64SingleBlock3(valueCount int32) Packed64SingleBlock {
	ans := newPacked64SingleBlock(valueCount, 3)
	ans.get = func(index int32) int64 {
		o := index / 21
		b := index % 21
		shift := b * 3
		return int64(uint64(ans.blocks[o])>>shift) & 7
	}
	ans.set = func(index int32, value int64) {
		o := index / 21
		b := index % 21
		shift := b * 3
		ans.blocks[o] = (ans.blocks[o] & ^(int64(7) << shift)) | (value << shift)
	}
	return ans
}

func newPacked64SingleBlock4(valueCount int32) Packed64SingleBlock {
	ans := newPacked64SingleBlock(valueCount, 4)
	ans.get = func(index int32) int64 {
		o := uint32(index) >> 4
		b := index & 15
		shift := b << 2
		return int64(uint64(ans.blocks[o])>>shift) & 15
	}
	ans.set = func(index int32, value int64) {
		o := uint32(index) >> 4
		b := index & 15
		shift := b << 2
		ans.blocks[o] = (ans.blocks[o] & ^(int64(15) << shift)) | (value << shift)
	}
	return ans
}

func newPacked64SingleBlock5(valueCount int32) Packed64SingleBlock {
	ans := newPacked64SingleBlock(valueCount, 5)
	ans.get = func(index int32) int64 {
		o := index / 12
		b := index % 12
		shift := b * 5
		return int64(uint64(ans.blocks[o])>>shift) & 31
	}
	ans.set = func(index int32, value int64) {
		o := index / 12
		b := index % 12
		shift := b * 5
		ans.blocks[o] = (ans.blocks[o] & ^(int64(31) << shift)) | (value << shift)
	}
	return ans
}

func newPacked64SingleBlock6(valueCount int32) Packed64SingleBlock {
	ans := newPacked64SingleBlock(valueCount, 6)
	ans.get = func(index int32) int64 {
		o := index / 10
		b := index % 10
		shift := b * 6
		return int64(uint64(ans.blocks[o])>>shift) & 63
	}
	ans.set = func(index int32, value int64) {
		o := index / 10
		b := index % 10
		shift := b * 6
		ans.blocks[o] = (ans.blocks[o] & ^(int64(63) << shift)) | (value << shift)
	}
	return ans
}

func newPacked64SingleBlock7(valueCount int32) Packed64SingleBlock {
	ans := newPacked64SingleBlock(valueCount, 7)
	ans.get = func(index int32) int64 {
		o := index / 9
		b := index % 9
		shift := b * 7
		return int64(uint64(ans.blocks[o])>>shift) & 127
	}
	ans.set = func(index int32, value int64) {
		o := index / 9
		b := index % 9
		shift := b * 7
		ans.blocks[o] = (ans.blocks[o] & ^(int64(127) << shift)) | (value << shift)
	}
	return ans
}

func newPacked64SingleBlock8(valueCount int32) Packed64SingleBlock {
	ans := newPacked64SingleBlock(valueCount, 8)
	ans.get = func(index int32) int64 {
		o := uint32(index) >> 3
		b := index & 7
		shift := b << 3
		return int64(uint64(ans.blocks[o])>>shift) & 255
	}
	ans.set = func(index int32, value int64) {
		o := uint32(index) >> 3
		b := index & 7
		shift := b << 3
		ans.blocks[o] = (ans.blocks[o] & ^(int64(255) << shift)) | (value << shift)
	}
	return ans
}

func newPacked64SingleBlock9(valueCount int32) Packed64SingleBlock {
	ans := newPacked64SingleBlock(valueCount, 9)
	ans.get = func(index int32) int64 {
		o := index / 7
		b := index % 7
		shift := b * 9
		return int64(uint64(ans.blocks[o])>>shift) & 511
	}
	ans.set = func(index int32, value int64) {
		o := index / 7
		b := index % 7
		shift := b * 9
		ans.blocks[o] = (ans.blocks[o] & ^(int64(511) << shift)) | (value << shift)
	}
	return ans
}

func newPacked64SingleBlock10(valueCount int32) Packed64SingleBlock {
	ans := newPacked64SingleBlock(valueCount, 10)
	ans.get = func(index int32) int64 {
		o := index / 6
		b := index % 6
		shift := b * 10
		return int64(uint64(ans.blocks[o])>>shift) & 1023
	}
	ans.set = func(index int32, value int64) {
		o := index / 6
		b := index % 6
		shift := b * 10
		ans.blocks[o] = (ans.blocks[o] & ^(int64(1023) << shift)) | (value << shift)
	}
	return ans
}
func newPacked64SingleBlock12(valueCount int32) Packed64SingleBlock {
	ans := newPacked64SingleBlock(valueCount, 12)
	ans.get = func(index int32) int64 {
		o := index / 5
		b := index % 5
		shift := b * 12
		return int64(uint64(ans.blocks[o])>>shift) & 4095
	}
	ans.set = func(index int32, value int64) {
		o := index / 5
		b := index % 5
		shift := b * 12
		ans.blocks[o] = (ans.blocks[o] & ^(int64(4095) << shift)) | (value << shift)
	}
	return ans
}

func newPacked64SingleBlock16(valueCount int32) Packed64SingleBlock {
	ans := newPacked64SingleBlock(valueCount, 16)
	ans.get = func(index int32) int64 {
		o := uint32(index) >> 2
		b := index & 3
		shift := b << 4
		return int64(uint64(ans.blocks[o])>>shift) & 65535
	}
	ans.set = func(index int32, value int64) {
		o := uint32(index) >> 2
		b := index & 3
		shift := b << 4
		ans.blocks[o] = (ans.blocks[o] & ^(int64(65335) << shift)) | (value << shift)
	}
	return ans
}

func newPacked64SingleBlock21(valueCount int32) Packed64SingleBlock {
	ans := newPacked64SingleBlock(valueCount, 21)
	ans.get = func(index int32) int64 {
		o := index / 3
		b := index % 3
		shift := b * 21
		return int64(uint64(ans.blocks[o])>>shift) & 2097151
	}
	ans.set = func(index int32, value int64) {
		o := index / 3
		b := index % 3
		shift := b * 21
		ans.blocks[o] = (ans.blocks[o] & ^(int64(2097151) << shift)) | (value << shift)
	}
	return ans
}

func newPacked64SingleBlock32(valueCount int32) Packed64SingleBlock {
	ans := newPacked64SingleBlock(valueCount, 32)
	ans.get = func(index int32) int64 {
		o := uint32(index) >> 1
		b := index & 1
		shift := b << 5
		return int64(uint64(ans.blocks[o])>>shift) & 4294967295
	}
	ans.set = func(index int32, value int64) {
		o := uint32(index) >> 1
		b := index & 1
		shift := b << 5
		ans.blocks[o] = (ans.blocks[o] & ^(int64(4294967295) << shift)) | (value << shift)
	}
	return ans
}
<commit_msg>fix compile error<commit_after>package util

import (
	"fmt"
)

type Packed64SingleBlock struct {
	PackedIntsReaderImpl
	get    func(index int32) int64
	blocks []int64
}

func (p *Packed64SingleBlock) Get(index int32) int64 {
	return p.get(index)
}

func newPacked64SingleBlock(valueCount int32, bitsPerValue uint32) Packed64SingleBlock {
	// assert isSupported(bitsPerValue)
	valuesPerBlock := int32(64 / bitsPerValue)
	ans := Packed64SingleBlock{blocks: make([]int64, requiredCapacity(valueCount, valuesPerBlock))}
	ans.PackedIntsReaderImpl = newPackedIntsReaderImpl(valueCount, bitsPerValue)
	return ans
}

func requiredCapacity(valueCount, valuesPerBlock int32) int32 {
	fit := (valueCount % valuesPerBlock) != 0
	ans := valueCount / valuesPerBlock
	if fit {
		ans++
	}
	return ans
}

func newPacked64SingleBlockFromInput(in *DataInput, valueCount int32, bitsPerValue uint32) (reader PackedIntsReader, err error) {
	ans := newPacked64SingleBlockBy(valueCount, bitsPerValue)
	for i, _ := range ans.blocks {
		if ans.blocks[i], err = in.ReadLong(); err != nil {
			break
		}
	}
	return &ans, err
}

func newPacked64SingleBlockBy(valueCount int32, bitsPerValue uint32) Packed64SingleBlock {
	switch bitsPerValue {
	case 1:
		return newPacked64SingleBlock1(valueCount)
	case 2:
		return newPacked64SingleBlock2(valueCount)
	case 3:
		return newPacked64SingleBlock3(valueCount)
	case 4:
		return newPacked64SingleBlock4(valueCount)
	case 5:
		return newPacked64SingleBlock5(valueCount)
	case 6:
		return newPacked64SingleBlock6(valueCount)
	case 7:
		return newPacked64SingleBlock7(valueCount)
	case 8:
		return newPacked64SingleBlock8(valueCount)
	case 9:
		return newPacked64SingleBlock9(valueCount)
	case 10:
		return newPacked64SingleBlock10(valueCount)
	case 12:
		return newPacked64SingleBlock12(valueCount)
	case 16:
		return newPacked64SingleBlock16(valueCount)
	case 21:
		return newPacked64SingleBlock21(valueCount)
	case 32:
		return newPacked64SingleBlock32(valueCount)
	default:
		panic(fmt.Sprintf("Unsuppoted number of bits per value: %v", bitsPerValue))
	}
}

func newPacked64SingleBlock1(valueCount int32) Packed64SingleBlock {
	ans := newPacked64SingleBlock(valueCount, 1)
	ans.get = func(index int32) int64 {
		o := uint32(index) >> 6
		b := index & 63
		shift := b << 0
		return int64(uint64(ans.blocks[o])>>shift) & 1
	}
	ans.set = func(index int32, value int64) {
		o := uint32(index) >> 6
		b := index & 63
		shift := b << 0
		ans.blocks[o] = (ans.blocks[o] & ^(int64(1) << shift)) | (value << shift)
	}
	return ans
}

func newPacked64SingleBlock2(valueCount int32) Packed64SingleBlock {
	ans := newPacked64SingleBlock(valueCount, 2)
	ans.get = func(index int32) int64 {
		o := uint32(index) >> 5
		b := index & 31
		shift := b << 1
		return int64(uint64(ans.blocks[o])>>shift) & 3
	}
	ans.set = func(index int32, value int64) {
		o := uint32(index) >> 5
		b := index & 31
		shift := b << 1
		ans.blocks[o] = (ans.blocks[o] & ^(int64(3) << shift)) | (value << shift)
	}
	return ans
}

func newPacked64SingleBlock3(valueCount int32) Packed64SingleBlock {
	ans := newPacked64SingleBlock(valueCount, 3)
	ans.get = func(index int32) int64 {
		o := index / 21
		b := index % 21
		shift := b * 3
		return int64(uint64(ans.blocks[o])>>shift) & 7
	}
	ans.set = func(index int32, value int64) {
		o := index / 21
		b := index % 21
		shift := b * 3
		ans.blocks[o] = (ans.blocks[o] & ^(int64(7) << shift)) | (value << shift)
	}
	return ans
}

func newPacked64SingleBlock4(valueCount int32) Packed64SingleBlock {
	ans := newPacked64SingleBlock(valueCount, 4)
	ans.get = func(index int32) int64 {
		o := uint32(index) >> 4
		b := index & 15
		shift := b << 2
		return int64(uint64(ans.blocks[o])>>shift) & 15
	}
	ans.set = func(index int32, value int64) {
		o := uint32(index) >> 4
		b := index & 15
		shift := b << 2
		ans.blocks[o] = (ans.blocks[o] & ^(int64(15) << shift)) | (value << shift)
	}
	return ans
}

func newPacked64SingleBlock5(valueCount int32) Packed64SingleBlock {
	ans := newPacked64SingleBlock(valueCount, 5)
	ans.get = func(index int32) int64 {
		o := index / 12
		b := index % 12
		shift := b * 5
		return int64(uint64(ans.blocks[o])>>shift) & 31
	}
	ans.set = func(index int32, value int64) {
		o := index / 12
		b := index % 12
		shift := b * 5
		ans.blocks[o] = (ans.blocks[o] & ^(int64(31) << shift)) | (value << shift)
	}
	return ans
}

func newPacked64SingleBlock6(valueCount int32) Packed64SingleBlock {
	ans := newPacked64SingleBlock(valueCount, 6)
	ans.get = func(index int32) int64 {
		o := index / 10
		b := index % 10
		shift := b * 6
		return int64(uint64(ans.blocks[o])>>shift) & 63
	}
	ans.set = func(index int32, value int64) {
		o := index / 10
		b := index % 10
		shift := b * 6
		ans.blocks[o] = (ans.blocks[o] & ^(int64(63) << shift)) | (value << shift)
	}
	return ans
}

func newPacked64SingleBlock7(valueCount int32) Packed64SingleBlock {
	ans := newPacked64SingleBlock(valueCount, 7)
	ans.get = func(index int32) int64 {
		o := index / 9
		b := index % 9
		shift := b * 7
		return int64(uint64(ans.blocks[o])>>shift) & 127
	}
	ans.set = func(index int32, value int64) {
		o := index / 9
		b := index % 9
		shift := b * 7
		ans.blocks[o] = (ans.blocks[o] & ^(int64(127) << shift)) | (value << shift)
	}
	return ans
}

func newPacked64SingleBlock8(valueCount int32) Packed64SingleBlock {
	ans := newPacked64SingleBlock(valueCount, 8)
	ans.get = func(index int32) int64 {
		o := uint32(index) >> 3
		b := index & 7
		shift := b << 3
		return int64(uint64(ans.blocks[o])>>shift) & 255
	}
	ans.set = func(index int32, value int64) {
		o := uint32(index) >> 3
		b := index & 7
		shift := b << 3
		ans.blocks[o] = (ans.blocks[o] & ^(int64(255) << shift)) | (value << shift)
	}
	return ans
}

func newPacked64SingleBlock9(valueCount int32) Packed64SingleBlock {
	ans := newPacked64SingleBlock(valueCount, 9)
	ans.get = func(index int32) int64 {
		o := index / 7
		b := index % 7
		shift := b * 9
		return int64(uint64(ans.blocks[o])>>shift) & 511
	}
	ans.set = func(index int32, value int64) {
		o := index / 7
		b := index % 7
		shift := b * 9
		ans.blocks[o] = (ans.blocks[o] & ^(int64(511) << shift)) | (value << shift)
	}
	return ans
}

func newPacked64SingleBlock10(valueCount int32) Packed64SingleBlock {
	ans := newPacked64SingleBlock(valueCount, 10)
	ans.get = func(index int32) int64 {
		o := index / 6
		b := index % 6
		shift := b * 10
		return int64(uint64(ans.blocks[o])>>shift) & 1023
	}
	ans.set = func(index int32, value int64) {
		o := index / 6
		b := index % 6
		shift := b * 10
		ans.blocks[o] = (ans.blocks[o] & ^(int64(1023) << shift)) | (value << shift)
	}
	return ans
}
func newPacked64SingleBlock12(valueCount int32) Packed64SingleBlock {
	ans := newPacked64SingleBlock(valueCount, 12)
	ans.get = func(index int32) int64 {
		o := index / 5
		b := index % 5
		shift := b * 12
		return int64(uint64(ans.blocks[o])>>shift) & 4095
	}
	ans.set = func(index int32, value int64) {
		o := index / 5
		b := index % 5
		shift := b * 12
		ans.blocks[o] = (ans.blocks[o] & ^(int64(4095) << shift)) | (value << shift)
	}
	return ans
}

func newPacked64SingleBlock16(valueCount int32) Packed64SingleBlock {
	ans := newPacked64SingleBlock(valueCount, 16)
	ans.get = func(index int32) int64 {
		o := uint32(index) >> 2
		b := index & 3
		shift := b << 4
		return int64(uint64(ans.blocks[o])>>shift) & 65535
	}
	ans.set = func(index int32, value int64) {
		o := uint32(index) >> 2
		b := index & 3
		shift := b << 4
		ans.blocks[o] = (ans.blocks[o] & ^(int64(65335) << shift)) | (value << shift)
	}
	return ans
}

func newPacked64SingleBlock21(valueCount int32) Packed64SingleBlock {
	ans := newPacked64SingleBlock(valueCount, 21)
	ans.get = func(index int32) int64 {
		o := index / 3
		b := index % 3
		shift := b * 21
		return int64(uint64(ans.blocks[o])>>shift) & 2097151
	}
	ans.set = func(index int32, value int64) {
		o := index / 3
		b := index % 3
		shift := b * 21
		ans.blocks[o] = (ans.blocks[o] & ^(int64(2097151) << shift)) | (value << shift)
	}
	return ans
}

func newPacked64SingleBlock32(valueCount int32) Packed64SingleBlock {
	ans := newPacked64SingleBlock(valueCount, 32)
	ans.get = func(index int32) int64 {
		o := uint32(index) >> 1
		b := index & 1
		shift := b << 5
		return int64(uint64(ans.blocks[o])>>shift) & 4294967295
	}
	ans.set = func(index int32, value int64) {
		o := uint32(index) >> 1
		b := index & 1
		shift := b << 5
		ans.blocks[o] = (ans.blocks[o] & ^(int64(4294967295) << shift)) | (value << shift)
	}
	return ans
}
<|endoftext|>


<commit_before>package util

import (
	"fmt"
	"regexp"

	"github.com/prometheus/common/model"
)

var validLabelRE = regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_]*$`)

// ValidateSample returns an err if the sample is invalid
func ValidateSample(s *model.Sample) error {
	for k, _ := range s.Metric {
		if !validLabelRE.MatchString(string(k)) {
			return fmt.Errorf("invalid label: %s", k)
		}
	}
	return nil
}
<commit_msg>Make it lint...<commit_after>package util

import (
	"fmt"
	"regexp"

	"github.com/prometheus/common/model"
)

var validLabelRE = regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_]*$`)

// ValidateSample returns an err if the sample is invalid
func ValidateSample(s *model.Sample) error {
	for k := range s.Metric {
		if !validLabelRE.MatchString(string(k)) {
			return fmt.Errorf("invalid label: %s", k)
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package remote

import (
	"github.com/AsynkronIT/protoactor-go/actor"
	"github.com/AsynkronIT/protoactor-go/log"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"io"
)

func endpointWriterProducer(remote *Remote, address string, config *Config) actor.Producer {
	return func() actor.Actor {
		return &endpointWriter{
			address: address,
			config:  config,
			remote:  remote,
		}
	}
}

type endpointWriter struct {
	config              *Config
	address             string
	conn                *grpc.ClientConn
	stream              Remoting_ReceiveClient
	defaultSerializerId int32
	remote              *Remote
}

func (state *endpointWriter) initialize() error {
	err := state.initializeInternal()
	if err != nil {
		plog.Error("EndpointWriter failed to connect", log.String("address", state.address), log.Error(err))
		return err
	}
	return nil
}

func (state *endpointWriter) initializeInternal() error {
	plog.Info("Started EndpointWriter. connecting", log.String("address", state.address))
	conn, err := grpc.Dial(state.address, state.config.DialOptions...)
	if err != nil {
		plog.Info("EndpointWriter connect failed", log.String("address", state.address), log.Error(err))
		return err
	}
	state.conn = conn
	c := NewRemotingClient(conn)
	resp, err := c.Connect(context.Background(), &ConnectRequest{})
	if err != nil {
		plog.Info("EndpointWriter connect failed", log.String("address", state.address), log.Error(err))
		return err
	}
	state.defaultSerializerId = resp.DefaultSerializerId

	//	log.Printf("Getting stream from address %v", state.address)
	stream, err := c.Receive(context.Background(), state.config.CallOptions...)
	if err != nil {
		plog.Info("EndpointWriter connect failed", log.String("address", state.address), log.Error(err))
		return err
	}
	go func() {
		for {
			_, err := stream.Recv()
			if err == io.EOF {
				plog.Debug("EndpointWriter stream completed", log.String("address", state.address))
				break
			} else if err != nil {
				plog.Error("EndpointWriter lost connection", log.String("address", state.address), log.Error(err))

				// notify that the endpoint terminated
				terminated := &EndpointTerminatedEvent{
					Address: state.address,
				}
				state.remote.actorSystem.EventStream.Publish(terminated)
				break
			} else {
				plog.Info("EndpointWriter remote disconnected", log.String("address", state.address))
				// notify that the endpoint terminated
				terminated := &EndpointTerminatedEvent{
					Address: state.address,
				}
				state.remote.actorSystem.EventStream.Publish(terminated)
			}
		}
	}()

	plog.Info("EndpointWriter connected", log.String("address", state.address))
	connected := &EndpointConnectedEvent{Address: state.address}
	state.remote.actorSystem.EventStream.Publish(connected)
	state.stream = stream
	return nil
}

func (state *endpointWriter) sendEnvelopes(msg []interface{}, ctx actor.Context) {
	envelopes := make([]*MessageEnvelope, len(msg))

	// type name uniqueness map name string to type index
	typeNames := make(map[string]int32)
	typeNamesArr := make([]string, 0)
	targetNames := make(map[string]int32)
	targetNamesArr := make([]string, 0)
	var header *MessageHeader
	var typeID int32
	var targetID int32
	var serializerID int32
	for i, tmp := range msg {

		switch unwrapped := tmp.(type) {
		case *EndpointTerminatedEvent, EndpointTerminatedEvent:
			plog.Debug("Handling array wrapped terminate event", log.String("address", state.address), log.Object("msg", unwrapped))
			ctx.Stop(ctx.Self())
			return
		}
		rd := tmp.(*remoteDeliver)

		if rd.serializerID == -1 {
			serializerID = state.defaultSerializerId
		} else {
			serializerID = rd.serializerID
		}

		if rd.header == nil || rd.header.Length() == 0 {
			header = nil
		} else {
			header = &MessageHeader{rd.header.ToMap()}
		}

		bytes, typeName, err := Serialize(rd.message, serializerID)
		if err != nil {
			panic(err)
		}
		typeID, typeNamesArr = addToLookup(typeNames, typeName, typeNamesArr)
		targetID, targetNamesArr = addToLookup(targetNames, rd.target.Id, targetNamesArr)

		envelopes[i] = &MessageEnvelope{
			MessageHeader: header,
			MessageData:   bytes,
			Sender:        rd.sender,
			Target:        targetID,
			TypeId:        typeID,
			SerializerId:  serializerID,
		}
	}

	batch := &MessageBatch{
		TypeNames:   typeNamesArr,
		TargetNames: targetNamesArr,
		Envelopes:   envelopes,
	}
	err := state.stream.Send(batch)

	if err != nil {
		ctx.Stash()
		plog.Debug("gRPC Failed to send", log.String("address", state.address), log.Error(err))
		panic("restart it")
	}
}

func addToLookup(m map[string]int32, name string, a []string) (int32, []string) {
	max := int32(len(m))
	id, ok := m[name]
	if !ok {
		m[name] = max
		id = max
		a = append(a, name)
	}
	return id, a
}

func (state *endpointWriter) Receive(ctx actor.Context) {
	switch msg := ctx.Message().(type) {
	case *actor.Started:
		err := state.initialize()
		if err != nil {
			plog.Error("Endpoint could not reach endpoint address - killing endpoint actor",
				log.Error(err),
				log.String("actorId", ctx.Self().GetId()),
				log.String("actorAddress", ctx.Self().GetAddress()))
			ctx.Stop(ctx.Self())
		}
	case *actor.Stopped:
		if state.stream != nil {
			err := state.stream.CloseSend()
			if err != nil {
				plog.Error("EndpointWriter error when closing the stream", log.Error(err))
			}
		}
	case *actor.Restarting:
		if state.stream != nil {
			err := state.stream.CloseSend()
			if err != nil {
				plog.Error("EndpointWriter error when closing the stream", log.Error(err))
			}
		}
	case *EndpointTerminatedEvent:
		ctx.Stop(ctx.Self())
	case []interface{}:
		state.sendEnvelopes(msg, ctx)
	case actor.SystemMessage, actor.AutoReceiveMessage:
		// ignore
	default:
		plog.Error("EndpointWriter received unknown message", log.String("address", state.address), log.TypeOf("type", msg), log.Message(msg))
	}
}
<commit_msg>Revert "Endpoint actor now doesn't crashloop"<commit_after>package remote

import (
	io "io"
	"time"

	"github.com/AsynkronIT/protoactor-go/actor"
	"github.com/AsynkronIT/protoactor-go/log"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
)

func endpointWriterProducer(remote *Remote, address string, config *Config) actor.Producer {
	return func() actor.Actor {
		return &endpointWriter{
			address: address,
			config:  config,
			remote:  remote,
		}
	}
}

type endpointWriter struct {
	config              *Config
	address             string
	conn                *grpc.ClientConn
	stream              Remoting_ReceiveClient
	defaultSerializerId int32
	remote              *Remote
}

func (state *endpointWriter) initialize() {
	err := state.initializeInternal()
	if err != nil {
		plog.Error("EndpointWriter failed to connect", log.String("address", state.address), log.Error(err))
		// Wait 2 seconds to restart and retry
		// Replace with Exponential Backoff
		time.Sleep(2 * time.Second)
		panic(err)
	}
}

func (state *endpointWriter) initializeInternal() error {
	plog.Info("Started EndpointWriter. connecting", log.String("address", state.address))
	conn, err := grpc.Dial(state.address, state.config.DialOptions...)
	if err != nil {
		plog.Info("EndpointWriter connect failed", log.String("address", state.address), log.Error(err))
		return err
	}
	state.conn = conn
	c := NewRemotingClient(conn)
	resp, err := c.Connect(context.Background(), &ConnectRequest{})
	if err != nil {
		plog.Info("EndpointWriter connect failed", log.String("address", state.address), log.Error(err))
		return err
	}
	state.defaultSerializerId = resp.DefaultSerializerId

	//	log.Printf("Getting stream from address %v", state.address)
	stream, err := c.Receive(context.Background(), state.config.CallOptions...)
	if err != nil {
		plog.Info("EndpointWriter connect failed", log.String("address", state.address), log.Error(err))
		return err
	}
	go func() {
		for {
			_, err := stream.Recv()
			if err == io.EOF {
				plog.Debug("EndpointWriter stream completed", log.String("address", state.address))
				break
			} else if err != nil {
				plog.Error("EndpointWriter lost connection", log.String("address", state.address), log.Error(err))

				// notify that the endpoint terminated
				terminated := &EndpointTerminatedEvent{
					Address: state.address,
				}
				state.remote.actorSystem.EventStream.Publish(terminated)
				break
			} else {
				plog.Info("EndpointWriter remote disconnected", log.String("address", state.address))
				// notify that the endpoint terminated
				terminated := &EndpointTerminatedEvent{
					Address: state.address,
				}
				state.remote.actorSystem.EventStream.Publish(terminated)
			}
		}
	}()

	plog.Info("EndpointWriter connected", log.String("address", state.address))
	connected := &EndpointConnectedEvent{Address: state.address}
	state.remote.actorSystem.EventStream.Publish(connected)
	state.stream = stream
	return nil
}

func (state *endpointWriter) sendEnvelopes(msg []interface{}, ctx actor.Context) {
	envelopes := make([]*MessageEnvelope, len(msg))

	// type name uniqueness map name string to type index
	typeNames := make(map[string]int32)
	typeNamesArr := make([]string, 0)
	targetNames := make(map[string]int32)
	targetNamesArr := make([]string, 0)
	var header *MessageHeader
	var typeID int32
	var targetID int32
	var serializerID int32
	for i, tmp := range msg {

		switch unwrapped := tmp.(type) {
		case *EndpointTerminatedEvent, EndpointTerminatedEvent:
			plog.Debug("Handling array wrapped terminate event", log.String("address", state.address), log.Object("msg", unwrapped))
			ctx.Stop(ctx.Self())
			return
		}
		rd := tmp.(*remoteDeliver)

		if rd.serializerID == -1 {
			serializerID = state.defaultSerializerId
		} else {
			serializerID = rd.serializerID
		}

		if rd.header == nil || rd.header.Length() == 0 {
			header = nil
		} else {
			header = &MessageHeader{rd.header.ToMap()}
		}

		bytes, typeName, err := Serialize(rd.message, serializerID)
		if err != nil {
			panic(err)
		}
		typeID, typeNamesArr = addToLookup(typeNames, typeName, typeNamesArr)
		targetID, targetNamesArr = addToLookup(targetNames, rd.target.Id, targetNamesArr)

		envelopes[i] = &MessageEnvelope{
			MessageHeader: header,
			MessageData:   bytes,
			Sender:        rd.sender,
			Target:        targetID,
			TypeId:        typeID,
			SerializerId:  serializerID,
		}
	}

	batch := &MessageBatch{
		TypeNames:   typeNamesArr,
		TargetNames: targetNamesArr,
		Envelopes:   envelopes,
	}
	err := state.stream.Send(batch)

	if err != nil {
		ctx.Stash()
		plog.Debug("gRPC Failed to send", log.String("address", state.address), log.Error(err))
		panic("restart it")
	}
}

func addToLookup(m map[string]int32, name string, a []string) (int32, []string) {
	max := int32(len(m))
	id, ok := m[name]
	if !ok {
		m[name] = max
		id = max
		a = append(a, name)
	}
	return id, a
}

func (state *endpointWriter) Receive(ctx actor.Context) {
	switch msg := ctx.Message().(type) {
	case *actor.Started:
		state.initialize()
	case *actor.Stopped:
		if state.stream != nil {
			err := state.stream.CloseSend()
			if err != nil {
				plog.Error("EndpointWriter error when closing the stream", log.Error(err))
			}
		}
	case *actor.Restarting:
		if state.stream != nil {
			err := state.stream.CloseSend()
			if err != nil {
				plog.Error("EndpointWriter error when closing the stream", log.Error(err))
			}
		}
	case *EndpointTerminatedEvent:
		ctx.Stop(ctx.Self())
	case []interface{}:
		state.sendEnvelopes(msg, ctx)
	case actor.SystemMessage, actor.AutoReceiveMessage:
		// ignore
	default:
		plog.Error("EndpointWriter received unknown message", log.String("address", state.address), log.TypeOf("type", msg), log.Message(msg))
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/base64"
	"flag"
	"fmt"
	"io"
	"koding/virt"
	"net/http"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"time"

	"koding/migrators/useroverlay/token"

	"github.com/gorilla/mux"
	"github.com/koding/logging"
	"labix.org/v2/mgo/bson"
)

var (
	log      = logging.NewLogger("useroverlay")
	mode     = flag.String("mode", "serve", "mode can be serve or token")
	certFile = flag.String("cert", "certs/user_file_exporter_self_signed_cert.pem", "TLS cert file")
	keyFile  = flag.String("key", "certs/user_file_exporter_self_signed_key.pem", "TLS key file")
	vm       = flag.String("vm", "", "the vm id")
	username = flag.String("username", "", "the username")
)

func main() {
	flag.Parse()
	switch *mode {
	case "serve":
		serve()
	case "token":
		createToken()
	}
}

func serve() {
	r := mux.NewRouter()
	r.HandleFunc("/export-files", exportFiles).Methods("POST")
	http.Handle("/", basicAuth(r))
	if err := http.ListenAndServeTLS(":3000", *certFile, *keyFile, nil); err != nil {
		log.Error(err.Error())
	}
}

func basicAuth(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if ok, err := checkAuth(w, r); !ok {
			if err != nil {
				log.Error(err.Error())
			}
			respond(w, 403, "Access denied")
			return
		}
		next.ServeHTTP(w, r)
	})
}

func checkAuth(w http.ResponseWriter, r *http.Request) (bool, error) {
	auth := r.Header.Get("Authorization")
	s := strings.SplitN(auth, " ", 2)
	if len(s) != 2 {
		return false, fmt.Errorf("Invalid authorization header: '%v'", auth)
	}

	b, err := base64.StdEncoding.DecodeString(s[1])
	if err != nil {
		return false, err
	}

	pair := strings.SplitN(string(b), ":", 2)
	if len(pair) != 2 {
		return false, fmt.Errorf("Invalid authorization header: '%v'", auth)
	}

	// validate the password:
	if pair[1] == token.StringToken(pair[0], r.PostFormValue("vm")) {
		return true, nil
	}
	return false, nil
}

func exportFiles(w http.ResponseWriter, r *http.Request) {
	vm, status, message, err := validateRequest(w, r)
	if err != nil {
		log.Error(err.Error())
	}

	if status != 200 {
		respond(w, status, message)
		return
	}
	if err := vm.LockRBD(); err != nil {
		respond(w, 412, "RBD cannot be locked")
	}
	defer func() {
		if err := vm.UnlockRBD(); err != nil {
			log.Error(err.Error())
		}
	}()
	archive, err := exportUserFiles(vm)
	if err != nil {
		respond(w, 500, err.Error())
		return
	}
	w.Header().Set("Content-type", "application/octet-stream")
	if _, err := io.Copy(w, archive); err != nil {
		log.Error(err.Error())
	}
}

func validateRequest(w http.ResponseWriter, r *http.Request) (*virt.VM, int, string, error) {
	id := r.PostFormValue("vm")
	if !bson.IsObjectIdHex(id) {
		return nil, 400, "Bad input", nil
	}
	vm := &virt.VM{Id: bson.ObjectIdHex(id)}

	exists, err := vm.ExistsRBD()
	if err != nil {
		return vm, 500, "Internal error", err
	}
	if !exists {
		return vm, 404, "Not found", nil
	}
	return vm, 200, "", nil
}

func exportUserFiles(vm *virt.VM) (io.Reader, error) {
	// map the RBD:
	if out, err := exec.Command("/usr/bin/rbd", "map", "--pool", virt.VMPool, "--image", vm.String()).CombinedOutput(); err != nil {
		return nil, commandError("rbd map failed.", err, out)
	}
	defer func() {
		if out, err := exec.Command("/usr/bin/rbd", "unmap", "/dev/rbd/"+virt.VMPool+"/"+vm.String()).CombinedOutput(); err != nil {
			log.Error(commandError("rbd unmap failed.", err, out).Error())
		}
	}()
	// generate a timestamp for uniqueness:
	timestamp := strconv.FormatInt(time.Now().Local().Unix(), 10)
	baseName := "export-" + vm.String() + "-" + timestamp
	dirName := "/tmp/" + baseName
	archiveName := dirName + ".tgz"
	// make a blank directory to export to:
	if err := os.Mkdir(dirName, os.ModeDir); err != nil {
		return nil, err
	}
	defer func() {
		// remove the working directory:
		if err := os.RemoveAll(dirName); err != nil {
			log.Error(err.Error())
		}
	}()
	// mount the rbd over an empty rootfs:
	if out, err := exec.Command("/bin/mount", "-o", "ro", "-t", "ext4", "/dev/rbd/vms/"+vm.String(), dirName).CombinedOutput(); err != nil {
		return nil, commandError("mount failed.", err, out)
	}
	defer func() {
		// unmount the rbd:
		if out, err := exec.Command("/bin/umount", dirName).CombinedOutput(); err != nil {
			log.Error(commandError("umount failed.", err, out).Error())
		}
	}()
	// tar the resulting directory structure:
	if out, err := exec.Command("/bin/tar", "--directory", "/tmp", "-czf", archiveName, baseName).CombinedOutput(); err != nil {
		return nil, commandError("tar failed.", err, out)
	}
	defer func() {
		// remove the archive:
		if err := os.Remove(archiveName); err != nil {
			log.Error(err.Error())
		}
	}()

	return os.Open(archiveName)
}

func respond(w http.ResponseWriter, code int, body string) {
	w.WriteHeader(code)
	io.WriteString(w, body)
}

func commandError(message string, err error, out []byte) error {
	return fmt.Errorf("%s\n%s\n%s", message, err.Error(), string(out))
}

func createToken() {
	fmt.Println(token.StringToken(*username, *vm))
}
<commit_msg>useroverlay: don't leak error messages<commit_after>package main

import (
	"encoding/base64"
	"flag"
	"fmt"
	"io"
	"koding/virt"
	"net/http"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"time"

	"koding/migrators/useroverlay/token"

	"github.com/gorilla/mux"
	"github.com/koding/logging"
	"labix.org/v2/mgo/bson"
)

var (
	log      = logging.NewLogger("useroverlay")
	mode     = flag.String("mode", "serve", "mode can be serve or token")
	certFile = flag.String("cert", "certs/user_file_exporter_self_signed_cert.pem", "TLS cert file")
	keyFile  = flag.String("key", "certs/user_file_exporter_self_signed_key.pem", "TLS key file")
	vm       = flag.String("vm", "", "the vm id")
	username = flag.String("username", "", "the username")
)

func main() {
	flag.Parse()
	switch *mode {
	case "serve":
		serve()
	case "token":
		createToken()
	}
}

func serve() {
	r := mux.NewRouter()
	r.HandleFunc("/export-files", exportFiles).Methods("POST")
	http.Handle("/", basicAuth(r))
	if err := http.ListenAndServeTLS(":3000", *certFile, *keyFile, nil); err != nil {
		log.Error(err.Error())
	}
}

func basicAuth(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if ok, err := checkAuth(w, r); !ok {
			if err != nil {
				log.Error(err.Error())
			}
			respond(w, 403, "Access denied")
			return
		}
		next.ServeHTTP(w, r)
	})
}

func checkAuth(w http.ResponseWriter, r *http.Request) (bool, error) {
	auth := r.Header.Get("Authorization")
	s := strings.SplitN(auth, " ", 2)
	if len(s) != 2 {
		return false, fmt.Errorf("Invalid authorization header: '%v'", auth)
	}

	b, err := base64.StdEncoding.DecodeString(s[1])
	if err != nil {
		return false, err
	}

	pair := strings.SplitN(string(b), ":", 2)
	if len(pair) != 2 {
		return false, fmt.Errorf("Invalid authorization header: '%v'", auth)
	}

	// validate the password:
	if pair[1] == token.StringToken(pair[0], r.PostFormValue("vm")) {
		return true, nil
	}
	return false, nil
}

func exportFiles(w http.ResponseWriter, r *http.Request) {
	vm, status, message, err := validateRequest(w, r)
	if err != nil {
		log.Error(err.Error())
	}

	if status != 200 {
		respond(w, status, message)
		return
	}
	if err := vm.LockRBD(); err != nil {
		respond(w, 412, "RBD cannot be locked")
	}
	defer func() {
		if err := vm.UnlockRBD(); err != nil {
			log.Error(err.Error())
		}
	}()
	archive, err := exportUserFiles(vm)
	if err != nil {
		respond(w, 500, err.Error())
		return
	}
	w.Header().Set("Content-type", "application/octet-stream")
	if _, err := io.Copy(w, archive); err != nil {
		log.Error(err.Error())
	}
}

func validateRequest(w http.ResponseWriter, r *http.Request) (*virt.VM, int, string, error) {
	id := r.PostFormValue("vm")
	if !bson.IsObjectIdHex(id) {
		return nil, 400, "Bad input", nil
	}
	vm := &virt.VM{Id: bson.ObjectIdHex(id)}

	exists, err := vm.ExistsRBD()
	if err != nil {
		return vm, 500, "Internal error", err
	}
	if !exists {
		return vm, 404, "Not found", nil
	}
	return vm, 200, "", nil
}

func exportUserFiles(vm *virt.VM) (io.Reader, error) {
	// map the RBD:
	if out, err := exec.Command("/usr/bin/rbd", "map", "--pool", virt.VMPool, "--image", vm.String()).CombinedOutput(); err != nil {
		return nil, commandError("rbd map failed.", err, out)
	}
	defer func() {
		if out, err := exec.Command("/usr/bin/rbd", "unmap", "/dev/rbd/"+virt.VMPool+"/"+vm.String()).CombinedOutput(); err != nil {
			log.Error(commandError("rbd unmap failed.", err, out).Error())
		}
	}()
	// generate a timestamp for uniqueness:
	timestamp := strconv.FormatInt(time.Now().Local().Unix(), 10)
	baseName := "export-" + vm.String() + "-" + timestamp
	dirName := "/tmp/" + baseName
	archiveName := dirName + ".tgz"
	// make a blank directory to export to:
	if err := os.Mkdir(dirName, os.ModeDir); err != nil {
		return nil, err
	}
	defer func() {
		// remove the working directory:
		if err := os.RemoveAll(dirName); err != nil {
			log.Error(err.Error())
		}
	}()
	// mount the rbd over an empty rootfs:
	if out, err := exec.Command("/bin/mount", "-o", "ro", "-t", "ext4", "/dev/rbd/vms/"+vm.String(), dirName).CombinedOutput(); err != nil {
		return nil, commandError("mount failed.", err, out)
	}
	defer func() {
		// unmount the rbd:
		if out, err := exec.Command("/bin/umount", dirName).CombinedOutput(); err != nil {
			log.Error(commandError("umount failed.", err, out).Error())
		}
	}()
	// tar the resulting directory structure:
	if out, err := exec.Command("/bin/tar", "--directory", "/tmp", "-czf", archiveName, baseName).CombinedOutput(); err != nil {
		return nil, commandError("tar failed.", err, out)
	}
	defer func() {
		// remove the archive:
		if err := os.Remove(archiveName); err != nil {
			log.Error(err.Error())
		}
	}()

	return os.Open(archiveName)
}

func respond(w http.ResponseWriter, code int, body string) {
	log.Error("server error: '%s' (%d)", body, code)
	w.WriteHeader(500)
	io.WriteString(w, "server error")
}

func commandError(message string, err error, out []byte) error {
	return fmt.Errorf("%s\n%s\n%s", message, err.Error(), string(out))
}

func createToken() {
	fmt.Println(token.StringToken(*username, *vm))
}
<|endoftext|>