<commit_before>package dockerregistry

import (
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"path"
	"strings"

	"github.com/fsouza/go-dockerclient"
	"github.com/golang/glog"

	imageapi "github.com/openshift/origin/pkg/image/api"
)

// Client includes methods for accessing a Docker registry by name.
type Client interface {
	// Connect to a Docker registry by name. Pass "" for the Docker Hub
	Connect(registry string, allowInsecure bool) (Connection, error)
}

// Connection allows you to retrieve data from a Docker V1 registry.
type Connection interface {
	// ImageTags will return a map of the tags for the image by namespace (if not
	// specified, will be "library") and name.
	ImageTags(namespace, name string) (map[string]string, error)
	// ImageByID will return the requested image by namespace (if not specified,
	// will be "library"), name, and ID.
	ImageByID(namespace, name, id string) (*docker.Image, error)
	// ImageByTag will return the requested image by namespace (if not specified,
	// will be "library"), name, and tag (if not specified, "latest").
	ImageByTag(namespace, name, tag string) (*docker.Image, error)
}

// NewClient returns a client object which allows public access to
// a Docker registry.
// TODO: accept a docker auth config
func NewClient() Client {
	return &client{
		connections: make(map[string]*connection),
	}
}

// client implements the Client interface
type client struct {
	connections map[string]*connection
}

// Connect accepts the name of a registry in the common form Docker provides and will
// create a connection to the registry. Callers may provide a host, a host:port, or
// a fully qualified URL. When not providing a URL, the default scheme will be "https"
func (c *client) Connect(name string, allowInsecure bool) (Connection, error) {
	target, err := normalizeRegistryName(name)
	if err != nil {
		return nil, err
	}
	prefix := target.String()
	if conn, ok := c.connections[prefix]; ok && conn.allowInsecure == allowInsecure {
		return conn, nil
	}
	conn := newConnection(*target, allowInsecure)
	c.connections[prefix] = conn
	return conn, nil
}

func normalizeRegistryName(name string) (*url.URL, error) {
	prefix := name
	if len(prefix) == 0 {
		prefix = "index.docker.io"
	}
	hadPrefix := false
	switch {
	case strings.HasPrefix(prefix, "http://"), strings.HasPrefix(prefix, "https://"):
		hadPrefix = true
	default:
		prefix = "https://" + prefix
	}

	target, err := url.Parse(prefix)
	if err != nil {
		return nil, fmt.Errorf("the registry name cannot be made into a valid url: %v", err)
	}

	if host, port, err := net.SplitHostPort(target.Host); err == nil {
		if host == "docker.io" {
			host = "index.docker.io"
		}
		if hadPrefix {
			switch {
			case port == "443" && target.Scheme == "https":
				target.Host = host
			case port == "80" && target.Scheme == "http":
				target.Host = host
			}
		}
	} else {
		if target.Host == "docker.io" {
			target.Host = "index.docker.io"
		}
	}
	return target, nil
}

func convertConnectionError(registry string, err error) error {
	switch {
	case strings.Contains(err.Error(), "connection refused"):
		return errRegistryNotFound{registry}
	default:
		return err
	}
}

type connection struct {
	client *http.Client
	url    url.URL
	cached map[string]*repository

	allowInsecure bool
}

func newConnection(url url.URL, allowInsecure bool) *connection {
	client := http.DefaultClient
	if allowInsecure {
		tr := &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}
		client = &http.Client{Transport: tr}
	}
	return &connection{
		url:    url,
		client: client,
		cached: make(map[string]*repository),

		allowInsecure: allowInsecure,
	}
}

type repository struct {
	name     string
	endpoint url.URL
	token    string
}

// ImageTags returns the tags for the named Docker image repository.
func (c *connection) ImageTags(namespace, name string) (map[string]string, error) {
	if len(namespace) == 0 {
		namespace = "library"
	}
	if len(name) == 0 {
		return nil, fmt.Errorf("image name must be specified")
	}

	repo, err := c.getCachedRepository(fmt.Sprintf("%s/%s", namespace, name))
	if err != nil {
		return nil, err
	}

	return c.getTags(repo)
}

// ImageByID returns the specified image within the named Docker image repository
func (c *connection) ImageByID(namespace, name, imageID string) (*docker.Image, error) {
	if len(namespace) == 0 {
		namespace = "library"
	}
	if len(name) == 0 {
		return nil, fmt.Errorf("image name must be specified")
	}

	repo, err := c.getCachedRepository(fmt.Sprintf("%s/%s", namespace, name))
	if err != nil {
		return nil, err
	}

	return c.getImage(repo, imageID, "")
}

// ImageByTag returns the specified image within the named Docker image repository
func (c *connection) ImageByTag(namespace, name, tag string) (*docker.Image, error) {
	if len(namespace) == 0 {
		namespace = "library"
	}
	if len(name) == 0 {
		return nil, fmt.Errorf("image name must be specified")
	}
	searchTag := tag
	if len(searchTag) == 0 {
		searchTag = imageapi.DefaultImageTag
	}

	repo, err := c.getCachedRepository(fmt.Sprintf("%s/%s", namespace, name))
	if err != nil {
		return nil, err
	}

	imageID, err := c.getTag(repo, searchTag, tag)
	if err != nil {
		return nil, err
	}

	return c.getImage(repo, imageID, tag)
}

func (c *connection) getCachedRepository(name string) (*repository, error) {
	if cached, ok := c.cached[name]; ok {
		return cached, nil
	}
	repo, err := c.getRepository(name)
	if err != nil {
		return nil, err
	}
	c.cached[name] = repo
	return repo, nil
}

func (c *connection) getRepository(name string) (*repository, error) {
	glog.V(4).Infof("Getting repository %s from %s", name, c.url)
	base := c.url
	base.Path = path.Join(base.Path, fmt.Sprintf("/v1/repositories/%s/images", name))
	req, err := http.NewRequest("GET", base.String(), nil)
	if err != nil {
		return nil, fmt.Errorf("error creating request: %v", err)
	}
	req.Header.Add("X-Docker-Token", "true")
	resp, err := c.client.Do(req)
	if err != nil {
		// if we tried https and were rejected, try http
		if c.url.Scheme == "https" && c.allowInsecure {
			glog.V(4).Infof("Failed to get https, trying http: %v", err)
			c.url.Scheme = "http"
			return c.getRepository(name)
		}
		return nil, convertConnectionError(c.url.String(), fmt.Errorf("error getting X-Docker-Token from %s: %v", name, err))
	}

	// if we were redirected, update the base urls
	c.url.Scheme = resp.Request.URL.Scheme
	c.url.Host = resp.Request.URL.Host

	switch code := resp.StatusCode; {
	case code == http.StatusNotFound:
		return nil, errRepositoryNotFound{name}
	case code >= 300 || resp.StatusCode < 200:
		return nil, fmt.Errorf("error retrieving repository: server returned %d", resp.StatusCode)
	}
	// TODO: select a random endpoint
	return &repository{
		name:     name,
		endpoint: url.URL{Scheme: c.url.Scheme, Host: resp.Header.Get("X-Docker-Endpoints")},
		token:    resp.Header.Get("X-Docker-Token"),
	}, nil
}

func (c *connection) getTags(repo *repository) (map[string]string, error) {
	endpoint := repo.endpoint
	endpoint.Path = path.Join(endpoint.Path, fmt.Sprintf("/v1/repositories/%s/tags", repo.name))
	req, err := http.NewRequest("GET", endpoint.String(), nil)
	if err != nil {
		return nil, fmt.Errorf("error creating request: %v", err)
	}
	req.Header.Add("Authorization", "Token "+repo.token)
	resp, err := c.client.Do(req)
	if err != nil {
		return nil, convertConnectionError(c.url.String(), fmt.Errorf("error getting image tags for %s: %v", repo.name, err))
	}
	switch code := resp.StatusCode; {
	case code == http.StatusNotFound:
		return nil, errRepositoryNotFound{repo.name}
	case code >= 300 || resp.StatusCode < 200:
		return nil, fmt.Errorf("error retrieving tags: server returned %d", resp.StatusCode)
	}
	tags := make(map[string]string)
	if err := json.NewDecoder(resp.Body).Decode(&tags); err != nil {
		return nil, fmt.Errorf("error decoding image %s tags: %v", repo.name, err)
	}
	return tags, nil
}

func (c *connection) getTag(repo *repository, tag, userTag string) (string, error) {
	endpoint := repo.endpoint
	endpoint.Path = path.Join(endpoint.Path, fmt.Sprintf("/v1/repositories/%s/tags/%s", repo.name, tag))
	req, err := http.NewRequest("GET", endpoint.String(), nil)
	if err != nil {
		return "", fmt.Errorf("error creating request: %v", err)
	}
	req.Header.Add("Authorization", "Token "+repo.token)
	resp, err := c.client.Do(req)
	if err != nil {
		return "", convertConnectionError(c.url.String(), fmt.Errorf("error getting image id for %s:%s: %v", repo.name, tag, err))
	}
	switch code := resp.StatusCode; {
	case code == http.StatusNotFound:
		return "", errTagNotFound{len(userTag) == 0, tag, repo.name}
	case code >= 300 || resp.StatusCode < 200:
		return "", fmt.Errorf("error retrieving tag: server returned %d", resp.StatusCode)
	}
	var imageID string
	if err := json.NewDecoder(resp.Body).Decode(&imageID); err != nil {
		return "", fmt.Errorf("error decoding image id: %v", err)
	}
	return imageID, nil
}

func (c *connection) getImage(repo *repository, image, userTag string) (*docker.Image, error) {
	endpoint := repo.endpoint
	endpoint.Path = path.Join(endpoint.Path, fmt.Sprintf("/v1/images/%s/json", image))
	req, err := http.NewRequest("GET", endpoint.String(), nil)
	if err != nil {
		return nil, fmt.Errorf("error creating request: %v", err)
	}
	req.Header.Add("Authorization", "Token "+repo.token)
	resp, err := c.client.Do(req)
	if err != nil {
		return nil, convertConnectionError(c.url.String(), fmt.Errorf("error getting json for image %q: %v", image, err))
	}
	switch code := resp.StatusCode; {
	case code == http.StatusNotFound:
		return nil, NewImageNotFoundError(repo.name, image, userTag)
	case code >= 300 || resp.StatusCode < 200:
		return nil, fmt.Errorf("error retrieving image %s: server returned %d", req.URL, resp.StatusCode)
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("can't read image body from %s: %v", req.URL, err)
	}
	return unmarshalDockerImage(body)
}

type errTagNotFound struct {
	wasDefault bool
	tag        string
	repository string
}

func (e errTagNotFound) Error() string {
	if e.wasDefault {
		return fmt.Sprintf("the default tag %q has not been set on repository %q", e.tag, e.repository)
	}
	return fmt.Sprintf("tag %q has not been set on repository %q", e.tag, e.repository)
}

type errRepositoryNotFound struct {
	repository string
}

func (e errRepositoryNotFound) Error() string {
	return fmt.Sprintf("the repository %q was not found", e.repository)
}

type errImageNotFound struct {
	tag        string
	image      string
	repository string
}

func NewImageNotFoundError(repository, image, tag string) error {
	return errImageNotFound{tag, image, repository}
}

func (e errImageNotFound) Error() string {
	if len(e.tag) == 0 {
		return fmt.Sprintf("the image %q in repository %q was not found and may have been deleted", e.image, e.repository)
	}
	return fmt.Sprintf("the image %q in repository %q with tag %q was not found and may have been deleted", e.image, e.repository, e.tag)
}

type errRegistryNotFound struct {
	registry string
}

func (e errRegistryNotFound) Error() string {
	return fmt.Sprintf("the registry %q could not be reached", e.registry)
}

func IsRegistryNotFound(err error) bool {
	_, ok := err.(errRegistryNotFound)
	return ok
}

func IsRepositoryNotFound(err error) bool {
	_, ok := err.(errRepositoryNotFound)
	return ok
}

func IsImageNotFound(err error) bool {
	_, ok := err.(errImageNotFound)
	return ok
}

func IsTagNotFound(err error) bool {
	_, ok := err.(errTagNotFound)
	return ok
}

func IsNotFound(err error) bool {
	return IsRegistryNotFound(err) || IsRepositoryNotFound(err) || IsImageNotFound(err) || IsTagNotFound(err)
}

func unmarshalDockerImage(body []byte) (*docker.Image, error) {
	var imagePre012 docker.ImagePre012
	if err := json.Unmarshal(body, &imagePre012); err != nil {
		return nil, err
	}

	return &docker.Image{
		ID:              imagePre012.ID,
		Parent:          imagePre012.Parent,
		Comment:         imagePre012.Comment,
		Created:         imagePre012.Created,
		Container:       imagePre012.Container,
		ContainerConfig: imagePre012.ContainerConfig,
		DockerVersion:   imagePre012.DockerVersion,
		Author:          imagePre012.Author,
		Config:          imagePre012.Config,
		Architecture:    imagePre012.Architecture,
		Size:            imagePre012.Size,
	}, nil
}
<commit_msg>Set http.Transport to get proxy from environment<commit_after>package dockerregistry

import (
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"path"
	"strings"

	"github.com/fsouza/go-dockerclient"
	"github.com/golang/glog"

	imageapi "github.com/openshift/origin/pkg/image/api"
)

// Client includes methods for accessing a Docker registry by name.
type Client interface {
	// Connect to a Docker registry by name. Pass "" for the Docker Hub
	Connect(registry string, allowInsecure bool) (Connection, error)
}

// Connection allows you to retrieve data from a Docker V1 registry.
type Connection interface {
	// ImageTags will return a map of the tags for the image by namespace (if not
	// specified, will be "library") and name.
	ImageTags(namespace, name string) (map[string]string, error)
	// ImageByID will return the requested image by namespace (if not specified,
	// will be "library"), name, and ID.
	ImageByID(namespace, name, id string) (*docker.Image, error)
	// ImageByTag will return the requested image by namespace (if not specified,
	// will be "library"), name, and tag (if not specified, "latest").
	ImageByTag(namespace, name, tag string) (*docker.Image, error)
}

// NewClient returns a client object which allows public access to
// a Docker registry.
// TODO: accept a docker auth config
func NewClient() Client {
	return &client{
		connections: make(map[string]*connection),
	}
}

// client implements the Client interface
type client struct {
	connections map[string]*connection
}

// Connect accepts the name of a registry in the common form Docker provides and will
// create a connection to the registry. Callers may provide a host, a host:port, or
// a fully qualified URL. When not providing a URL, the default scheme will be "https"
func (c *client) Connect(name string, allowInsecure bool) (Connection, error) {
	target, err := normalizeRegistryName(name)
	if err != nil {
		return nil, err
	}
	prefix := target.String()
	if conn, ok := c.connections[prefix]; ok && conn.allowInsecure == allowInsecure {
		return conn, nil
	}
	conn := newConnection(*target, allowInsecure)
	c.connections[prefix] = conn
	return conn, nil
}

func normalizeRegistryName(name string) (*url.URL, error) {
	prefix := name
	if len(prefix) == 0 {
		prefix = "index.docker.io"
	}
	hadPrefix := false
	switch {
	case strings.HasPrefix(prefix, "http://"), strings.HasPrefix(prefix, "https://"):
		hadPrefix = true
	default:
		prefix = "https://" + prefix
	}

	target, err := url.Parse(prefix)
	if err != nil {
		return nil, fmt.Errorf("the registry name cannot be made into a valid url: %v", err)
	}

	if host, port, err := net.SplitHostPort(target.Host); err == nil {
		if host == "docker.io" {
			host = "index.docker.io"
		}
		if hadPrefix {
			switch {
			case port == "443" && target.Scheme == "https":
				target.Host = host
			case port == "80" && target.Scheme == "http":
				target.Host = host
			}
		}
	} else {
		if target.Host == "docker.io" {
			target.Host = "index.docker.io"
		}
	}
	return target, nil
}

func convertConnectionError(registry string, err error) error {
	switch {
	case strings.Contains(err.Error(), "connection refused"):
		return errRegistryNotFound{registry}
	default:
		return err
	}
}

type connection struct {
	client *http.Client
	url    url.URL
	cached map[string]*repository

	allowInsecure bool
}

func newConnection(url url.URL, allowInsecure bool) *connection {
	client := http.DefaultClient
	if allowInsecure {
		tr := &http.Transport{
			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
			Proxy:           http.ProxyFromEnvironment,
		}
		client = &http.Client{Transport: tr}
	}
	return &connection{
		url:    url,
		client: client,
		cached: make(map[string]*repository),

		allowInsecure: allowInsecure,
	}
}

type repository struct {
	name     string
	endpoint url.URL
	token    string
}

// ImageTags returns the tags for the named Docker image repository.
func (c *connection) ImageTags(namespace, name string) (map[string]string, error) {
	if len(namespace) == 0 {
		namespace = "library"
	}
	if len(name) == 0 {
		return nil, fmt.Errorf("image name must be specified")
	}

	repo, err := c.getCachedRepository(fmt.Sprintf("%s/%s", namespace, name))
	if err != nil {
		return nil, err
	}

	return c.getTags(repo)
}

// ImageByID returns the specified image within the named Docker image repository
func (c *connection) ImageByID(namespace, name, imageID string) (*docker.Image, error) {
	if len(namespace) == 0 {
		namespace = "library"
	}
	if len(name) == 0 {
		return nil, fmt.Errorf("image name must be specified")
	}

	repo, err := c.getCachedRepository(fmt.Sprintf("%s/%s", namespace, name))
	if err != nil {
		return nil, err
	}

	return c.getImage(repo, imageID, "")
}

// ImageByTag returns the specified image within the named Docker image repository
func (c *connection) ImageByTag(namespace, name, tag string) (*docker.Image, error) {
	if len(namespace) == 0 {
		namespace = "library"
	}
	if len(name) == 0 {
		return nil, fmt.Errorf("image name must be specified")
	}
	searchTag := tag
	if len(searchTag) == 0 {
		searchTag = imageapi.DefaultImageTag
	}

	repo, err := c.getCachedRepository(fmt.Sprintf("%s/%s", namespace, name))
	if err != nil {
		return nil, err
	}

	imageID, err := c.getTag(repo, searchTag, tag)
	if err != nil {
		return nil, err
	}

	return c.getImage(repo, imageID, tag)
}

func (c *connection) getCachedRepository(name string) (*repository, error) {
	if cached, ok := c.cached[name]; ok {
		return cached, nil
	}
	repo, err := c.getRepository(name)
	if err != nil {
		return nil, err
	}
	c.cached[name] = repo
	return repo, nil
}

func (c *connection) getRepository(name string) (*repository, error) {
	glog.V(4).Infof("Getting repository %s from %s", name, c.url)
	base := c.url
	base.Path = path.Join(base.Path, fmt.Sprintf("/v1/repositories/%s/images", name))
	req, err := http.NewRequest("GET", base.String(), nil)
	if err != nil {
		return nil, fmt.Errorf("error creating request: %v", err)
	}
	req.Header.Add("X-Docker-Token", "true")
	resp, err := c.client.Do(req)
	if err != nil {
		// if we tried https and were rejected, try http
		if c.url.Scheme == "https" && c.allowInsecure {
			glog.V(4).Infof("Failed to get https, trying http: %v", err)
			c.url.Scheme = "http"
			return c.getRepository(name)
		}
		return nil, convertConnectionError(c.url.String(), fmt.Errorf("error getting X-Docker-Token from %s: %v", name, err))
	}

	// if we were redirected, update the base urls
	c.url.Scheme = resp.Request.URL.Scheme
	c.url.Host = resp.Request.URL.Host

	switch code := resp.StatusCode; {
	case code == http.StatusNotFound:
		return nil, errRepositoryNotFound{name}
	case code >= 300 || resp.StatusCode < 200:
		return nil, fmt.Errorf("error retrieving repository: server returned %d", resp.StatusCode)
	}
	// TODO: select a random endpoint
	return &repository{
		name:     name,
		endpoint: url.URL{Scheme: c.url.Scheme, Host: resp.Header.Get("X-Docker-Endpoints")},
		token:    resp.Header.Get("X-Docker-Token"),
	}, nil
}

func (c *connection) getTags(repo *repository) (map[string]string, error) {
	endpoint := repo.endpoint
	endpoint.Path = path.Join(endpoint.Path, fmt.Sprintf("/v1/repositories/%s/tags", repo.name))
	req, err := http.NewRequest("GET", endpoint.String(), nil)
	if err != nil {
		return nil, fmt.Errorf("error creating request: %v", err)
	}
	req.Header.Add("Authorization", "Token "+repo.token)
	resp, err := c.client.Do(req)
	if err != nil {
		return nil, convertConnectionError(c.url.String(), fmt.Errorf("error getting image tags for %s: %v", repo.name, err))
	}
	switch code := resp.StatusCode; {
	case code == http.StatusNotFound:
		return nil, errRepositoryNotFound{repo.name}
	case code >= 300 || resp.StatusCode < 200:
		return nil, fmt.Errorf("error retrieving tags: server returned %d", resp.StatusCode)
	}
	tags := make(map[string]string)
	if err := json.NewDecoder(resp.Body).Decode(&tags); err != nil {
		return nil, fmt.Errorf("error decoding image %s tags: %v", repo.name, err)
	}
	return tags, nil
}

func (c *connection) getTag(repo *repository, tag, userTag string) (string, error) {
	endpoint := repo.endpoint
	endpoint.Path = path.Join(endpoint.Path, fmt.Sprintf("/v1/repositories/%s/tags/%s", repo.name, tag))
	req, err := http.NewRequest("GET", endpoint.String(), nil)
	if err != nil {
		return "", fmt.Errorf("error creating request: %v", err)
	}
	req.Header.Add("Authorization", "Token "+repo.token)
	resp, err := c.client.Do(req)
	if err != nil {
		return "", convertConnectionError(c.url.String(), fmt.Errorf("error getting image id for %s:%s: %v", repo.name, tag, err))
	}
	switch code := resp.StatusCode; {
	case code == http.StatusNotFound:
		return "", errTagNotFound{len(userTag) == 0, tag, repo.name}
	case code >= 300 || resp.StatusCode < 200:
		return "", fmt.Errorf("error retrieving tag: server returned %d", resp.StatusCode)
	}
	var imageID string
	if err := json.NewDecoder(resp.Body).Decode(&imageID); err != nil {
		return "", fmt.Errorf("error decoding image id: %v", err)
	}
	return imageID, nil
}

func (c *connection) getImage(repo *repository, image, userTag string) (*docker.Image, error) {
	endpoint := repo.endpoint
	endpoint.Path = path.Join(endpoint.Path, fmt.Sprintf("/v1/images/%s/json", image))
	req, err := http.NewRequest("GET", endpoint.String(), nil)
	if err != nil {
		return nil, fmt.Errorf("error creating request: %v", err)
	}
	req.Header.Add("Authorization", "Token "+repo.token)
	resp, err := c.client.Do(req)
	if err != nil {
		return nil, convertConnectionError(c.url.String(), fmt.Errorf("error getting json for image %q: %v", image, err))
	}
	switch code := resp.StatusCode; {
	case code == http.StatusNotFound:
		return nil, NewImageNotFoundError(repo.name, image, userTag)
	case code >= 300 || resp.StatusCode < 200:
		return nil, fmt.Errorf("error retrieving image %s: server returned %d", req.URL, resp.StatusCode)
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("can't read image body from %s: %v", req.URL, err)
	}
	return unmarshalDockerImage(body)
}

type errTagNotFound struct {
	wasDefault bool
	tag        string
	repository string
}

func (e errTagNotFound) Error() string {
	if e.wasDefault {
		return fmt.Sprintf("the default tag %q has not been set on repository %q", e.tag, e.repository)
	}
	return fmt.Sprintf("tag %q has not been set on repository %q", e.tag, e.repository)
}

type errRepositoryNotFound struct {
	repository string
}

func (e errRepositoryNotFound) Error() string {
	return fmt.Sprintf("the repository %q was not found", e.repository)
}

type errImageNotFound struct {
	tag        string
	image      string
	repository string
}

func NewImageNotFoundError(repository, image, tag string) error {
	return errImageNotFound{tag, image, repository}
}

func (e errImageNotFound) Error() string {
	if len(e.tag) == 0 {
		return fmt.Sprintf("the image %q in repository %q was not found and may have been deleted", e.image, e.repository)
	}
	return fmt.Sprintf("the image %q in repository %q with tag %q was not found and may have been deleted", e.image, e.repository, e.tag)
}

type errRegistryNotFound struct {
	registry string
}

func (e errRegistryNotFound) Error() string {
	return fmt.Sprintf("the registry %q could not be reached", e.registry)
}

func IsRegistryNotFound(err error) bool {
	_, ok := err.(errRegistryNotFound)
	return ok
}

func IsRepositoryNotFound(err error) bool {
	_, ok := err.(errRepositoryNotFound)
	return ok
}

func IsImageNotFound(err error) bool {
	_, ok := err.(errImageNotFound)
	return ok
}

func IsTagNotFound(err error) bool {
	_, ok := err.(errTagNotFound)
	return ok
}

func IsNotFound(err error) bool {
	return IsRegistryNotFound(err) || IsRepositoryNotFound(err) || IsImageNotFound(err) || IsTagNotFound(err)
}

func unmarshalDockerImage(body []byte) (*docker.Image, error) {
	var imagePre012 docker.ImagePre012
	if err := json.Unmarshal(body, &imagePre012); err != nil {
		return nil, err
	}

	return &docker.Image{
		ID:              imagePre012.ID,
		Parent:          imagePre012.Parent,
		Comment:         imagePre012.Comment,
		Created:         imagePre012.Created,
		Container:       imagePre012.Container,
		ContainerConfig: imagePre012.ContainerConfig,
		DockerVersion:   imagePre012.DockerVersion,
		Author:          imagePre012.Author,
		Config:          imagePre012.Config,
		Architecture:    imagePre012.Architecture,
		Size:            imagePre012.Size,
	}, nil
}
<|endoftext|>


<commit_before>package wikifier

import (
	"regexp"
	"strconv"
	"strings"
)

var externalImageRegex = regexp.MustCompile(`^(.+)://`)

type imageBlock struct {
	file, path, alt, link, lastName string
	align, float, author, license   string
	widthString, heightString       string
	width, height                   int
	parseFailed, useJS              bool
	*Map
}

type imagebox struct {
	*imageBlock
}

// new image{}
func newImageBlock(name string, b *parserBlock) block {
	return &imageBlock{Map: newMapBlock("", b).(*Map)}
}

// new imagebox{}
func newImagebox(name string, b *parserBlock) block {
	return &imagebox{newImageBlock(name, b).(*imageBlock)}
}

// image{} or imagebox{} parse
func (image *imageBlock) parse(page *Page) {
	image.Map.parse(page)
	var w, h int

	// fetch string values from map
	image.file = image.getString("file")
	image.alt = image.getString("alt")
	image.link = image.getString("link")
	image.align = image.getString("align")
	image.float = image.getString("float")
	image.author = image.getString("author")
	image.license = image.getString("license")

	// fetch dimensions
	image.width = image.getPx("width")
	image.height = image.getPx("height")

	// compatibility
	if image.align == "" {
		image.align = image.getString("float")
	}

	// determine alt text
	if image.alt == "" {
		image.alt = image.file
	}

	// no dimensions. if it's an inbox we can guess it
	if image.width == 0 && image.height == 0 && image.parentBlock().blockType() == "infobox" {
		image.width = 270
	}

	// no file - this is mandatory
	if image.file == "" {
		image.warn(image.openPos, "No file specified for image")
		image.parseFailed = true
		return
	}

	split := strings.Split(image.file, "/")
	image.path = image.file
	image.lastName = split[len(split)-1]

	// ##############
	// ### SIZING ###
	// ##############

	sizeMethod := strings.ToLower(page.Opt.Image.SizeMethod)

	if externalImageRegex.MatchString(image.file) {
		// if the file is an absolute URL, we cannot size the image
		// do nothing

	} else if image.width != 0 && image.height != 0 {
		// both dimensions were given, so we need to do no sizing.
		// FIXME: this forces the full size image instead of generating in the
		// given dimensions

		w = image.width
		h = image.height

	} else if sizeMethod == "javascript" {
		// use javascript image sizing
		//
		// uses full-size images directly and uses javascript to size imageboxes
		// - voids the validity as XHTML 1.0 Strict
		// - causes slight flash on page load when images are scaled

		// inject javascript resizer if no width is given
		if image.width == 0 {
			image.useJS = true
		}

		// width and height dummies will be overriden by JavaScript
		if image.width == 0 {
			w = 200
		} else {
			w = image.width
		}
		h = image.height

		// path is file relative to image root (full size image)
		image.path = page.Opt.Root.Image + "/" + image.file

	} else if sizeMethod == "server" {
		// use server-size image sizing
		//
		// - maintains XHTML 1.0 Strict validity
		// - eliminates flash on page load
		// - faster page load (since image files are smaller)
		// - require read access to local image directory

		// this must be provided by wiki
		if page.Opt.Image.Sizer == nil {
			image.warn(image.openPos, "image.sizer required with image.size_method 'server'")
			image.parseFailed = true
			return
		}

		// path is as returned by the function that sizes the image
		image.path = page.Opt.Image.Sizer(
			image.file,
			w,
			h,
			page,
		)

		// remember that we use this image in these dimensions on this page
		page.images[image.file] = append(page.images[image.file], []int{w, h})
	}

	// convert dimensions to string
	if w == 0 {
		image.widthString = "auto"
	} else {
		image.widthString = strconv.Itoa(w) + "px"
	}
	if h == 0 {
		image.heightString = "auto"
	} else {
		image.heightString = strconv.Itoa(h) + "px"
	}
}

// image{} html
func (image *imageBlock) html(page *Page, el element) {
	image.imageHTML(false, page, el)
}

// imagebox{} html
func (image *imagebox) html(page *Page, el element) {
	image.imageHTML(true, page, el)
}

// image{} or imagebox{} html
func (image *imageBlock) imageHTML(isBox bool, page *Page, el element) {
	image.Map.html(page, el)

	// image parse failed, so no need to waste any time here
	if image.parseFailed {
		return
	}

	// add the appropriate float class
	if isBox {
		if image.float == "" {
			image.float = "right"
		}
		el.addClass("imagebox-" + image.float)
	} else if image.float != "" {
		el.addClass("image-" + image.float)
	}

	// retina
	// FIXME: if true -> if the image is not full-size
	srcset := ""
	if true && len(page.Opt.Image.Retina) != 0 {

		// find image name and extension
		imageName, ext := image.path, ""
		if lastDot := strings.LastIndexByte(image.path, '.'); lastDot != -1 {
			ext = image.path[:lastDot]
			imageName = image.path[lastDot+1:]
		}

		// rewrite a.jpg to a@2x.jpg
		scales := make([]string, len(page.Opt.Image.Retina))
		for i, scale := range page.Opt.Image.Retina {
			scales[i] = imageName + "@" + strconv.Itoa(scale) + "x." + ext
		}

		srcset = strings.Join(scales, ", ")
	}

	// determine link
	linkTarget := ""
	if image.link == "none" {
		// we're asked not to link to the image
		image.link = ""

	} else if image.link != "" {
		// link to something else
		// TODO: parse the link
		linkTarget = "_blank"
	} else {
		// link to the image

		image.link = image.path
	}

	// ############
	// ### HTML ###
	// ############

	// create an anchor for the link if there is one

	// this is just an image, no imagebox
	if !isBox {

		// put in link if there is one
		divOrA := el
		if image.link != "" {
			a := el.createChild("a", "image-a")
			a.setAttr("href", image.link)
			a.setAttr("target", linkTarget)
			divOrA = a
		}

		// create img with parent as either a or div
		img := divOrA.createChild("img", "image-img")
		img.setMeta("nonContainer", true)
		img.setAttr("src", image.path)
		img.setAttr("alt", image.alt)
		img.setAttr("srcset", srcset)

		return
	}

	// create inner box with width restriction
	inner := el.createChild("div", "imagebox-inner")
	inner.setStyle("width", strconv.Itoa(image.width)+"px")

	// put in link if there is one
	divOrA := inner
	if image.link != "" {
		a := inner.createChild("a", "image-a")
		a.setAttr("href", image.link)
		a.setAttr("target", linkTarget)
		divOrA = a
	}

	// create img with parent as either a or div
	img := divOrA.createChild("img", "imagebox-img")
	img.setMeta("nonContainer", true)
	img.setAttr("src", image.path)
	img.setAttr("alt", image.alt)
	img.setAttr("srcset", srcset)

	// insert javascript if using browser sizing
	if page.Opt.Image.SizeMethod == "javascript" {
		img.setAttr("onload", "quiki.imageResize(this);")
	}

	// description. we have to extract this here instead of in parse()
	// because at the time of parse() its text is not yet formatted
	if desc, _ := image.Get("description"); desc != nil {
		inner.createChild(
			"div", "imagebox-description",
		).createChild(
			"div", "imagebox-description-inner",
		).add(desc)
	}
}

// FIXME: use position of the key
func (image *imageBlock) getString(key string) string {
	s, err := image.GetStr(key)
	if err != nil {
		image.warn(image.openPos, key+": "+err.Error())
		return ""
	}
	return s
}

// FIXME: use position of the key
func (image *imageBlock) getPx(key string) int {
	s, err := image.GetStr(key)
	if err != nil {
		image.warn(image.openPos, key+": "+err.Error())
		return 0
	}
	if s == "" {
		return 0
	}
	i, err := strconv.Atoi(strings.TrimSuffix(s, "px"))
	if err != nil {
		image.warn(image.openPos, key+": "+err.Error())
		return 0
	}
	return i
}
<commit_msg>desc = description<commit_after>package wikifier

import (
	"regexp"
	"strconv"
	"strings"
)

var externalImageRegex = regexp.MustCompile(`^(.+)://`)

type imageBlock struct {
	file, path, alt, link, lastName string
	align, float, author, license   string
	widthString, heightString       string
	width, height                   int
	parseFailed, useJS              bool
	*Map
}

type imagebox struct {
	*imageBlock
}

// new image{}
func newImageBlock(name string, b *parserBlock) block {
	return &imageBlock{Map: newMapBlock("", b).(*Map)}
}

// new imagebox{}
func newImagebox(name string, b *parserBlock) block {
	return &imagebox{newImageBlock(name, b).(*imageBlock)}
}

// image{} or imagebox{} parse
func (image *imageBlock) parse(page *Page) {
	image.Map.parse(page)
	var w, h int

	// fetch string values from map
	image.file = image.getString("file")
	image.alt = image.getString("alt")
	image.link = image.getString("link")
	image.align = image.getString("align")
	image.float = image.getString("float")
	image.author = image.getString("author")
	image.license = image.getString("license")

	// fetch dimensions
	image.width = image.getPx("width")
	image.height = image.getPx("height")

	// compatibility
	if image.align == "" {
		image.align = image.getString("float")
	}

	// determine alt text
	if image.alt == "" {
		image.alt = image.file
	}

	// no dimensions. if it's an inbox we can guess it
	if image.width == 0 && image.height == 0 && image.parentBlock().blockType() == "infobox" {
		image.width = 270
	}

	// no file - this is mandatory
	if image.file == "" {
		image.warn(image.openPos, "No file specified for image")
		image.parseFailed = true
		return
	}

	split := strings.Split(image.file, "/")
	image.path = image.file
	image.lastName = split[len(split)-1]

	// ##############
	// ### SIZING ###
	// ##############

	sizeMethod := strings.ToLower(page.Opt.Image.SizeMethod)

	if externalImageRegex.MatchString(image.file) {
		// if the file is an absolute URL, we cannot size the image
		// do nothing

	} else if image.width != 0 && image.height != 0 {
		// both dimensions were given, so we need to do no sizing.
		// FIXME: this forces the full size image instead of generating in the
		// given dimensions

		w = image.width
		h = image.height

	} else if sizeMethod == "javascript" {
		// use javascript image sizing
		//
		// uses full-size images directly and uses javascript to size imageboxes
		// - voids the validity as XHTML 1.0 Strict
		// - causes slight flash on page load when images are scaled

		// inject javascript resizer if no width is given
		if image.width == 0 {
			image.useJS = true
		}

		// width and height dummies will be overriden by JavaScript
		if image.width == 0 {
			w = 200
		} else {
			w = image.width
		}
		h = image.height

		// path is file relative to image root (full size image)
		image.path = page.Opt.Root.Image + "/" + image.file

	} else if sizeMethod == "server" {
		// use server-size image sizing
		//
		// - maintains XHTML 1.0 Strict validity
		// - eliminates flash on page load
		// - faster page load (since image files are smaller)
		// - require read access to local image directory

		// this must be provided by wiki
		if page.Opt.Image.Sizer == nil {
			image.warn(image.openPos, "image.sizer required with image.size_method 'server'")
			image.parseFailed = true
			return
		}

		// path is as returned by the function that sizes the image
		image.path = page.Opt.Image.Sizer(
			image.file,
			w,
			h,
			page,
		)

		// remember that we use this image in these dimensions on this page
		page.images[image.file] = append(page.images[image.file], []int{w, h})
	}

	// convert dimensions to string
	if w == 0 {
		image.widthString = "auto"
	} else {
		image.widthString = strconv.Itoa(w) + "px"
	}
	if h == 0 {
		image.heightString = "auto"
	} else {
		image.heightString = strconv.Itoa(h) + "px"
	}
}

// image{} html
func (image *imageBlock) html(page *Page, el element) {
	image.imageHTML(false, page, el)
}

// imagebox{} html
func (image *imagebox) html(page *Page, el element) {
	image.imageHTML(true, page, el)
}

// image{} or imagebox{} html
func (image *imageBlock) imageHTML(isBox bool, page *Page, el element) {
	image.Map.html(page, el)

	// image parse failed, so no need to waste any time here
	if image.parseFailed {
		return
	}

	// add the appropriate float class
	if isBox {
		if image.float == "" {
			image.float = "right"
		}
		el.addClass("imagebox-" + image.float)
	} else if image.float != "" {
		el.addClass("image-" + image.float)
	}

	// retina
	// FIXME: if true -> if the image is not full-size
	srcset := ""
	if true && len(page.Opt.Image.Retina) != 0 {

		// find image name and extension
		imageName, ext := image.path, ""
		if lastDot := strings.LastIndexByte(image.path, '.'); lastDot != -1 {
			ext = image.path[:lastDot]
			imageName = image.path[lastDot+1:]
		}

		// rewrite a.jpg to a@2x.jpg
		scales := make([]string, len(page.Opt.Image.Retina))
		for i, scale := range page.Opt.Image.Retina {
			scales[i] = imageName + "@" + strconv.Itoa(scale) + "x." + ext
		}

		srcset = strings.Join(scales, ", ")
	}

	// determine link
	linkTarget := ""
	if image.link == "none" {
		// we're asked not to link to the image
		image.link = ""

	} else if image.link != "" {
		// link to something else
		// TODO: parse the link
		linkTarget = "_blank"
	} else {
		// link to the image

		image.link = image.path
	}

	// ############
	// ### HTML ###
	// ############

	// create an anchor for the link if there is one

	// this is just an image, no imagebox
	if !isBox {

		// put in link if there is one
		divOrA := el
		if image.link != "" {
			a := el.createChild("a", "image-a")
			a.setAttr("href", image.link)
			a.setAttr("target", linkTarget)
			divOrA = a
		}

		// create img with parent as either a or div
		img := divOrA.createChild("img", "image-img")
		img.setMeta("nonContainer", true)
		img.setAttr("src", image.path)
		img.setAttr("alt", image.alt)
		img.setAttr("srcset", srcset)

		return
	}

	// create inner box with width restriction
	inner := el.createChild("div", "imagebox-inner")
	inner.setStyle("width", strconv.Itoa(image.width)+"px")

	// put in link if there is one
	divOrA := inner
	if image.link != "" {
		a := inner.createChild("a", "image-a")
		a.setAttr("href", image.link)
		a.setAttr("target", linkTarget)
		divOrA = a
	}

	// create img with parent as either a or div
	img := divOrA.createChild("img", "imagebox-img")
	img.setMeta("nonContainer", true)
	img.setAttr("src", image.path)
	img.setAttr("alt", image.alt)
	img.setAttr("srcset", srcset)

	// insert javascript if using browser sizing
	if page.Opt.Image.SizeMethod == "javascript" {
		img.setAttr("onload", "quiki.imageResize(this);")
	}

	// description. we have to extract this here instead of in parse()
	// because at the time of parse() its text is not yet formatted
	desc, _ := image.Get("description")
	if desc == nil {
		desc, _ = image.Get("desc")
	}
	if desc != nil {
		inner.createChild(
			"div", "imagebox-description",
		).createChild(
			"div", "imagebox-description-inner",
		).add(desc)
	}
}

// FIXME: use position of the key
func (image *imageBlock) getString(key string) string {
	s, err := image.GetStr(key)
	if err != nil {
		image.warn(image.openPos, key+": "+err.Error())
		return ""
	}
	return s
}

// FIXME: use position of the key
func (image *imageBlock) getPx(key string) int {
	s, err := image.GetStr(key)
	if err != nil {
		image.warn(image.openPos, key+": "+err.Error())
		return 0
	}
	if s == "" {
		return 0
	}
	i, err := strconv.Atoi(strings.TrimSuffix(s, "px"))
	if err != nil {
		image.warn(image.openPos, key+": "+err.Error())
		return 0
	}
	return i
}
<|endoftext|>


<commit_before>package crypto

import "fmt"
import "github.com/chris-wood/spud/messages"
import "github.com/chris-wood/spud/messages/validation"
import "github.com/chris-wood/spud/stack/codec"
import "github.com/chris-wood/spud/stack/crypto/processor"

type CryptoComponent struct {
    ingress chan messages.Message
    egress chan messages.Message

    cryptoProcessor processor.CryptoProcessor
    codecComponent codec.CodecComponent
}

func NewCryptoComponent(cryptoProcessor processor.CryptoProcessor, codecComponent codec.CodecComponent) CryptoComponent {
    egress := make(chan messages.Message)
    ingress := make(chan messages.Message)

    return CryptoComponent{ingress: ingress, egress: egress, cryptoProcessor: cryptoProcessor, codecComponent: codecComponent}
}

func (c CryptoComponent) ProcessEgressMessages() {
    for ;; {
        msg := <- c.egress
        fmt.Println("Passing down: " + msg.Identifier())

        // 0. Look up the processor based on the message and then extract its validation algorithm
        // XXX: apply the LPM filter for the right processor here
        va := c.cryptoProcessor.ProcessorDetails()

        // 1. Add the validation algorithm information
        msg.SetValidationAlgorithm(va)

        // 2. Compute the signature
        signature, err := c.cryptoProcessor.Sign(msg)

        // 3. Append the signature
        if err != nil {
            vp := validation.NewValidationPayload(signature)
            msg.SetValidationPayload(vp)
        }

        c.codecComponent.Enqueue(msg)
    }
}

func (c CryptoComponent) ProcessIngressMessages() {
    for ;; {
        msg := c.codecComponent.Dequeue()

        fmt.Println("Passing up: " + msg.Identifier())

        // 1. Hash the sensitive region
        // XXX

        // 2. Verify the signature
        // XXX

        // 3. If valid, enqueue upstream
        c.ingress <- msg

        // 4. Else, request whatever is needed to verify the signature and keep going
    }
}

func (c CryptoComponent) Enqueue(msg messages.Message) {
    c.egress <- msg
}

func (c CryptoComponent) Dequeue() messages.Message {
    msg := <-c.ingress
    return msg
}
<commit_msg>Sign and verify loop<commit_after>package crypto

import "fmt"
import "github.com/chris-wood/spud/messages"
import "github.com/chris-wood/spud/messages/validation"
import "github.com/chris-wood/spud/stack/codec"
import "github.com/chris-wood/spud/stack/crypto/processor"

type CryptoComponent struct {
    ingress chan messages.Message
    egress chan messages.Message

    pendingMap map[string]messages.Message

    cryptoProcessor processor.CryptoProcessor
    codecComponent codec.CodecComponent
}

func NewCryptoComponent(cryptoProcessor processor.CryptoProcessor, codecComponent codec.CodecComponent) CryptoComponent {
    egress := make(chan messages.Message)
    ingress := make(chan messages.Message)

    return CryptoComponent{ingress: ingress, egress: egress, cryptoProcessor: cryptoProcessor, codecComponent: codecComponent, pendingMap: make(map[string]messages.Message)}
}

func addAuthenticator(msg messages.Message, proc processor.CryptoProcessor) (messages.Message, error) {
    va := proc.ProcessorDetails()
    msg.SetValidationAlgorithm(va)
    signature, err := proc.Sign(msg)
    if err != nil {
        vp := validation.NewValidationPayload(signature)
        msg.SetValidationPayload(vp)
    }

    return msg, err
}

func verifyAuthenticator(request, response messages.Message, crypto processor.CryptoProcessor) (bool, error) {
    return false, nil
}

func (c CryptoComponent) ProcessEgressMessages() {
    for ;; {
        msg := <- c.egress
        fmt.Println("Passing down: " + msg.Identifier())

        // Look up the processor based on the message
        // XXX: apply the LPM filter for the right processor here
        msg, err := addAuthenticator(msg, c.cryptoProcessor)
        if err != nil {
            fmt.Println(err.Error())
        }
        if msg.IsRequest() {
            c.pendingMap[msg.Identifier()] = msg
        }

        c.codecComponent.Enqueue(msg)
    }
}

func (c CryptoComponent) ProcessIngressMessages() {
    for ;; {
        msg := c.codecComponent.Dequeue()
        fmt.Println("Passing up: " + msg.Identifier())

        // XXX: fix this logic
        if !msg.IsRequest() {
            request, ok := c.pendingMap[msg.Identifier()]
            if ok {
                success, err := verifyAuthenticator(request, msg, c.cryptoProcessor)
                if err != nil {
                    if success {
                        fmt.Println("valid!")
                    }
                }
            } else {
                fmt.Println("Drop the message: " + msg.Identifier())
            }
        }

        // 3. If valid, enqueue upstream
        c.ingress <- msg

        // 4. Else, request whatever is needed to verify the signature and keep going
    }
}

func (c CryptoComponent) Enqueue(msg messages.Message) {
    c.egress <- msg
}

func (c CryptoComponent) Dequeue() messages.Message {
    msg := <-c.ingress
    return msg
}
<|endoftext|>


<commit_before>package zfs_test

import (
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"syscall"
	"testing"
	"time"

	"github.com/mistifyio/mistify/acomm"
	"github.com/mistifyio/mistify/provider"
	zfsp "github.com/mistifyio/mistify/providers/zfs"
	"github.com/spf13/pflag"
	"github.com/spf13/viper"
	"github.com/stretchr/testify/suite"
)

var (
	eagain       = syscall.EAGAIN.Error()
	ebadf        = syscall.EBADF.Error()
	ebusy        = syscall.EBUSY.Error()
	eexist       = syscall.EEXIST.Error()
	einval       = syscall.EINVAL.Error()
	enametoolong = syscall.ENAMETOOLONG.Error()
	enoent       = syscall.ENOENT.Error()
	epipe        = syscall.EPIPE.Error()
	exdev        = syscall.EXDEV.Error()

	longName = strings.Repeat("z", 257)
)

type zfs struct {
	suite.Suite
	pool    string
	files   []string
	dir     string
	config  *provider.Config
	tracker *acomm.Tracker
	zfs     *zfsp.ZFS
}

func TestZFS(t *testing.T) {
	suite.Run(t, new(zfs))
}

type props map[string]interface{}

func command(name string, arg ...string) *exec.Cmd {
	cmd := exec.Command(name, arg...)
	cmd.Stderr = os.Stderr
	return cmd
}

func (s *zfs) zfsSetup(pool string) {
	s.pool = pool
	files := make([]string, 5)
	for i := range files {
		f, err := ioutil.TempFile(s.dir, "zpool-img")
		if err != nil {
			panic(err)
		}
		files[i] = f.Name()
		_ = f.Close()
	}
	s.files = files

	script := []byte(`
    set -e
    pool=` + s.pool + `
    zpool list $pool &>/dev/null && zpool destroy $pool
    files=(` + strings.Join(files, " ") + `)
    for f in ${files[*]}; do
        truncate -s1G $f
    done
    zpool create $pool ${files[*]}

	zfs create $pool/fs
	zfs create $pool/fs/1snap
	zfs snapshot $pool/fs/1snap@snap

	zfs create $pool/fs/3snap
	zfs snapshot $pool/fs/3snap@snap1
	zfs snapshot $pool/fs/3snap@snap2
	zfs snapshot $pool/fs/3snap@snap3

	zfs create $pool/fs/hold_snap
	zfs snapshot $pool/fs/hold_snap@snap
	zfs hold hold $pool/fs/hold_snap@snap

	zfs create $pool/fs/unmounted
	zfs unmount $pool/fs/unmounted

	zfs create $pool/fs/unmounted_children
	zfs create $pool/fs/unmounted_children/1
	zfs create $pool/fs/unmounted_children/2
	zfs unmount $pool/fs/unmounted_children

	zfs snapshot $pool/fs@snap_with_clone
	zfs clone $pool/fs@snap_with_clone $pool/fs_clone
	zfs unmount $pool/fs_clone

	zfs create $pool/vol
	zfs create -V 8192 $pool/vol/1snap
	zfs snapshot $pool/vol/1snap@snap

	exit 0
    `)

	cmd := command("sudo", "bash", "-c", string(script))

	stdin, err := cmd.StdinPipe()
	s.Require().NoError(err)
	go func() {
		_, err := stdin.Write([]byte(script))
		s.Require().NoError(err)
	}()

	s.Require().NoError(cmd.Run())
}

func (s *zfs) zfsTearDown() {
	err := command("sudo", "zpool", "destroy", s.pool).Run()
	for i := range s.files {
		_ = os.Remove(s.files[i])
	}
	s.Require().NoError(err)
}

func unmount(ds string) error {
	return command("sudo", "zfs", "unmount", ds).Run()
}

func unhold(tag, snapshot string) error {
	return command("sudo", "zfs", "release", tag, snapshot).Run()
}

func (s *zfs) SetupSuite() {
	dir, err := ioutil.TempDir("", "zfs-provider-test-")
	s.Require().NoError(err)
	s.dir = dir

	v := viper.New()
	flagset := pflag.NewFlagSet("go-zfs", pflag.PanicOnError)
	config := provider.NewConfig(flagset, v)
	s.Require().NoError(flagset.Parse([]string{}))
	v.Set("service_name", "zfs-provider-test")
	v.Set("socket_dir", s.dir)
	v.Set("coordinator_url", "unix:///tmp/foobar")
	v.Set("log_level", "fatal")
	s.Require().NoError(config.LoadConfig())
	s.Require().NoError(config.SetupLogging())
	s.config = config

	tracker, err := acomm.NewTracker(filepath.Join(s.dir, "tracker.sock"), nil, 5*time.Second)
	s.Require().NoError(err)
	s.Require().NoError(tracker.Start())
	s.tracker = tracker

	s.zfs = zfsp.New(config, tracker)
}

func (s *zfs) SetupTest() {
	s.zfsSetup("zfs-provider-test")
}

func (s *zfs) TearDownTest() {
	s.zfsTearDown()
}

func (s *zfs) TearDownSuite() {
	s.tracker.Stop()
	_ = os.RemoveAll(s.dir)
}
<commit_msg>Add ZFS Provider RegisterTasks and Dataset Mountpoint tests<commit_after>package zfs_test

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"syscall"
	"testing"
	"time"

	"github.com/mistifyio/gozfs"
	"github.com/mistifyio/mistify/acomm"
	"github.com/mistifyio/mistify/provider"
	zfsp "github.com/mistifyio/mistify/providers/zfs"
	"github.com/spf13/pflag"
	"github.com/spf13/viper"
	"github.com/stretchr/testify/suite"
)

var (
	eagain       = syscall.EAGAIN.Error()
	ebadf        = syscall.EBADF.Error()
	ebusy        = syscall.EBUSY.Error()
	eexist       = syscall.EEXIST.Error()
	einval       = syscall.EINVAL.Error()
	enametoolong = syscall.ENAMETOOLONG.Error()
	enoent       = syscall.ENOENT.Error()
	epipe        = syscall.EPIPE.Error()
	exdev        = syscall.EXDEV.Error()

	longName = strings.Repeat("z", 257)
)

type zfs struct {
	suite.Suite
	pool    string
	files   []string
	dir     string
	config  *provider.Config
	tracker *acomm.Tracker
	zfs     *zfsp.ZFS
}

func TestZFS(t *testing.T) {
	suite.Run(t, new(zfs))
}

type props map[string]interface{}

func command(name string, arg ...string) *exec.Cmd {
	cmd := exec.Command(name, arg...)
	cmd.Stderr = os.Stderr
	return cmd
}

func (s *zfs) zfsSetup(pool string) {
	s.pool = pool
	files := make([]string, 5)
	for i := range files {
		f, err := ioutil.TempFile(s.dir, "zpool-img")
		if err != nil {
			panic(err)
		}
		files[i] = f.Name()
		_ = f.Close()
	}
	s.files = files

	script := []byte(`
    set -e
    pool=` + s.pool + `
    zpool list $pool &>/dev/null && zpool destroy $pool
    files=(` + strings.Join(files, " ") + `)
    for f in ${files[*]}; do
        truncate -s1G $f
    done
    zpool create $pool ${files[*]}

	zfs create $pool/fs
	zfs create $pool/fs/1snap
	zfs snapshot $pool/fs/1snap@snap

	zfs create $pool/fs/3snap
	zfs snapshot $pool/fs/3snap@snap1
	zfs snapshot $pool/fs/3snap@snap2
	zfs snapshot $pool/fs/3snap@snap3

	zfs create $pool/fs/hold_snap
	zfs snapshot $pool/fs/hold_snap@snap
	zfs hold hold $pool/fs/hold_snap@snap

	zfs create $pool/fs/unmounted
	zfs unmount $pool/fs/unmounted

	zfs create $pool/fs/unmounted_children
	zfs create $pool/fs/unmounted_children/1
	zfs create $pool/fs/unmounted_children/2
	zfs unmount $pool/fs/unmounted_children

	zfs snapshot $pool/fs@snap_with_clone
	zfs clone $pool/fs@snap_with_clone $pool/fs_clone
	zfs unmount $pool/fs_clone

	zfs create $pool/vol
	zfs create -V 8192 $pool/vol/1snap
	zfs snapshot $pool/vol/1snap@snap

	exit 0
    `)

	cmd := command("sudo", "bash", "-c", string(script))

	stdin, err := cmd.StdinPipe()
	s.Require().NoError(err)
	go func() {
		_, err := stdin.Write([]byte(script))
		s.Require().NoError(err)
	}()

	s.Require().NoError(cmd.Run())
}

func (s *zfs) zfsTearDown() {
	err := command("sudo", "zpool", "destroy", s.pool).Run()
	for i := range s.files {
		_ = os.Remove(s.files[i])
	}
	s.Require().NoError(err)
}

func unmount(ds string) error {
	return command("sudo", "zfs", "unmount", ds).Run()
}

func unhold(tag, snapshot string) error {
	return command("sudo", "zfs", "release", tag, snapshot).Run()
}

func (s *zfs) SetupSuite() {
	dir, err := ioutil.TempDir("", "zfs-provider-test-")
	s.Require().NoError(err)
	s.dir = dir

	v := viper.New()
	flagset := pflag.NewFlagSet("go-zfs", pflag.PanicOnError)
	config := provider.NewConfig(flagset, v)
	s.Require().NoError(flagset.Parse([]string{}))
	v.Set("service_name", "zfs-provider-test")
	v.Set("socket_dir", s.dir)
	v.Set("coordinator_url", "unix:///tmp/foobar")
	v.Set("log_level", "fatal")
	s.Require().NoError(config.LoadConfig())
	s.Require().NoError(config.SetupLogging())
	s.config = config

	tracker, err := acomm.NewTracker(filepath.Join(s.dir, "tracker.sock"), nil, 5*time.Second)
	s.Require().NoError(err)
	s.Require().NoError(tracker.Start())
	s.tracker = tracker

	s.zfs = zfsp.New(config, tracker)
}

func (s *zfs) SetupTest() {
	s.zfsSetup("zfs-provider-test")
}

func (s *zfs) TearDownTest() {
	s.zfsTearDown()
}

func (s *zfs) TearDownSuite() {
	s.tracker.Stop()
	_ = os.RemoveAll(s.dir)
}

func (s *zfs) TestDatasetMoutpoint() {
	tests := []struct {
		name             string
		mountpointSource string
		mountpoint       string
		result           string
	}{
		{"foo", "", "", "foo"},
		{"foo", "foo", "bar", "bar"},
		{"foo/bar", "foo", "baz", "baz/bar"},
	}

	for _, test := range tests {
		testS := fmt.Sprintf("%+v", test)
		ds := &zfsp.Dataset{
			Name: test.name,
			Properties: &gozfs.DatasetProperties{
				MountpointSource: test.mountpointSource,
				Mountpoint:       test.mountpoint,
			},
		}

		s.Equal(test.result, ds.Mountpoint(), testS)
	}
}

func (s *zfs) TestRegisterTasks() {
	server, err := provider.NewServer(s.config)
	s.Require().NoError(err)

	s.zfs.RegisterTasks(server)

	s.True(len(server.RegisteredTasks()) > 0)
}
<|endoftext|>


<commit_before>package operate

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

	humanize "github.com/dustin/go-humanize"
	"github.com/itchio/butler/cmd/sizeof"
	"github.com/itchio/butler/cmd/wipe"
	"github.com/itchio/wharf/state"

	"github.com/go-errors/errors"
	"github.com/itchio/butler/buse"
)

func CleanDownloadsSearch(params *buse.CleanDownloadsSearchParams, consumer *state.Consumer) (*buse.CleanDownloadsSearchResult, error) {
	// struct{} trick to use map as a set with 0-sized values
	whitemap := make(map[string]struct{})
	for _, whitelistPath := range params.Whitelist {
		whitemap[whitelistPath] = struct{}{}
	}

	var entries []*buse.CleanDownloadsEntry

	for _, root := range params.Roots {
		folders, err := ioutil.ReadDir(root)
		if err != nil {
			return nil, errors.Wrap(err, 0)
		}

		for _, folder := range folders {
			base := filepath.Base(folder.Name())
			absoluteFolderPath := filepath.Join(root, base)

			if _, ok := whitemap[base]; ok {
				// don't even consider it
				consumer.Debugf("Ignoring whitelisted (%s)")
				continue
			}

			// ey that's a candidate!
			folderSize, err := sizeof.Do(absoluteFolderPath)
			if err != nil {
				consumer.Warnf("Could not determine folder size: %s", err.Error())
			}

			entries = append(entries, &buse.CleanDownloadsEntry{
				Path: absoluteFolderPath,
				Size: folderSize,
			})
		}
	}

	res := &buse.CleanDownloadsSearchResult{
		Entries: entries,
	}
	return res, nil
}

func CleanDownloadsApply(params *buse.CleanDownloadsApplyParams, consumer *state.Consumer) (*buse.CleanDownloadsApplyResult, error) {
	for _, entry := range params.Entries {
		consumer.Infof("Wiping (%s) - %s", entry.Path, humanize.IBytes(uint64(entry.Size)))
		err := wipe.Do(consumer, entry.Path)
		if err != nil {
			consumer.Warnf("Could not wipe (%s): %s", entry.Path, err.Error())
		}
	}

	res := &buse.CleanDownloadsApplyResult{}
	return res, nil
}
<commit_msg>cleandownloads: gracefully skip folders we can't scan<commit_after>package operate

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

	humanize "github.com/dustin/go-humanize"
	"github.com/itchio/butler/cmd/sizeof"
	"github.com/itchio/butler/cmd/wipe"
	"github.com/itchio/wharf/state"

	"github.com/itchio/butler/buse"
)

func CleanDownloadsSearch(params *buse.CleanDownloadsSearchParams, consumer *state.Consumer) (*buse.CleanDownloadsSearchResult, error) {
	// struct{} trick to use map as a set with 0-sized values
	whitemap := make(map[string]struct{})
	for _, whitelistPath := range params.Whitelist {
		whitemap[whitelistPath] = struct{}{}
	}

	var entries []*buse.CleanDownloadsEntry

	for _, root := range params.Roots {
		folders, err := ioutil.ReadDir(root)
		if err != nil {
			if os.IsNotExist(err) {
				// good, nothing to clean!
				continue
			} else {
				consumer.Warnf("Cannot scan root (%s): %s", root, err.Error())
				continue
			}
		}

		for _, folder := range folders {
			base := filepath.Base(folder.Name())
			absoluteFolderPath := filepath.Join(root, base)

			if _, ok := whitemap[base]; ok {
				// don't even consider it
				consumer.Debugf("Ignoring whitelisted (%s)")
				continue
			}

			// ey that's a candidate!
			folderSize, err := sizeof.Do(absoluteFolderPath)
			if err != nil {
				consumer.Warnf("Could not determine folder size: %s", err.Error())
			}

			entries = append(entries, &buse.CleanDownloadsEntry{
				Path: absoluteFolderPath,
				Size: folderSize,
			})
		}
	}

	res := &buse.CleanDownloadsSearchResult{
		Entries: entries,
	}
	return res, nil
}

func CleanDownloadsApply(params *buse.CleanDownloadsApplyParams, consumer *state.Consumer) (*buse.CleanDownloadsApplyResult, error) {
	for _, entry := range params.Entries {
		consumer.Infof("Wiping (%s) - %s", entry.Path, humanize.IBytes(uint64(entry.Size)))
		err := wipe.Do(consumer, entry.Path)
		if err != nil {
			consumer.Warnf("Could not wipe (%s): %s", entry.Path, err.Error())
		}
	}

	res := &buse.CleanDownloadsApplyResult{}
	return res, nil
}
<|endoftext|>


<commit_before>package dns

import (
	"os"
	"io"
	"big"
	"strconv"
	"crypto/rsa"
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
)

// Empty interface that is used as a wrapper around all possible
// private key implementations from the crypto package.
type PrivateKey interface{}

// Generate a key of the given bit size.
// The public part is put inside the DNSKEY record.
// The Algorithm in the key must be set as this will define
// what kind of DNSKEY will be generated.
// For ECDSA the algorithms implies a keysize, in that case
// bits should be zero.
func (r *RR_DNSKEY) Generate(bits int) (PrivateKey, os.Error) {
	switch r.Algorithm {
	case RSAMD5, RSASHA1, RSASHA256:
		if bits < 512 || bits > 4096 {
			return nil, ErrKeySize
		}
	case RSASHA512:
		if bits < 1024 || bits > 4096 {
			return nil, ErrKeySize
		}
	case ECDSAP256SHA256:
		if bits != 256 {
			return nil, ErrKeySize
		}
	case ECDSAP384SHA384:
		if bits != 384 {
			return nil, ErrKeySize
		}
	}

	switch r.Algorithm {
	case RSAMD5, RSASHA1, RSASHA256, RSASHA512:
		priv, err := rsa.GenerateKey(rand.Reader, bits)
		if err != nil {
			return nil, err
		}
		r.setPublicKeyRSA(priv.PublicKey.E, priv.PublicKey.N)
		return priv, nil
	case ECDSAP256SHA256, ECDSAP384SHA384:
		var c *elliptic.Curve
		switch r.Algorithm {
		case ECDSAP256SHA256:
			c = elliptic.P256()
		case ECDSAP384SHA384:
			c = elliptic.P384()
		}
		priv, err := ecdsa.GenerateKey(c, rand.Reader)
		if err != nil {
			return nil, err
		}
		r.setPublicKeyCurve(priv.PublicKey.X, priv.PublicKey.Y)
		return priv, nil
	default:
		return nil, ErrAlg
	}
	return nil, nil // Dummy return
}

// Convert a PrivateKey to a string. This
// string has the same format as the private-key-file of BIND9 (Private-key-format: v1.3).
// It needs some info from the key (hashing, keytag), so its a method of the RR_DNSKEY.
func (r *RR_DNSKEY) PrivateKeyString(p PrivateKey) (s string) {
	switch t := p.(type) {
	case *rsa.PrivateKey:
		algorithm := strconv.Itoa(int(r.Algorithm)) + " (" + alg_str[r.Algorithm] + ")"
		modulus := unpackBase64(t.PublicKey.N.Bytes())
		e := big.NewInt(int64(t.PublicKey.E))
		publicExponent := unpackBase64(e.Bytes())
		privateExponent := unpackBase64(t.D.Bytes())
		prime1 := unpackBase64(t.Primes[0].Bytes())
		prime2 := unpackBase64(t.Primes[1].Bytes())
		// Calculate Exponent1/2 and Coefficient as per: http://en.wikipedia.org/wiki/RSA#Using_the_Chinese_remainder_algorithm
		// and from: http://code.google.com/p/go/issues/detail?id=987
		one := big.NewInt(1)
		minusone := big.NewInt(-1)
		p_1 := big.NewInt(0).Sub(t.Primes[0], one)
		q_1 := big.NewInt(0).Sub(t.Primes[1], one)
		exp1 := big.NewInt(0).Mod(t.D, p_1)
		exp2 := big.NewInt(0).Mod(t.D, q_1)
		coeff := big.NewInt(0).Exp(t.Primes[1], minusone, t.Primes[0])

		exponent1 := unpackBase64(exp1.Bytes())
		exponent2 := unpackBase64(exp2.Bytes())
		coefficient := unpackBase64(coeff.Bytes())

		s = "Private-key-format: v1.3\n" +
			"Algorithm: " + algorithm + "\n" +
			"Modules: " + modulus + "\n" +
			"PublicExponent: " + publicExponent + "\n" +
			"PrivateExponent: " + privateExponent + "\n" +
			"Prime1: " + prime1 + "\n" +
			"Prime2: " + prime2 + "\n" +
			"Exponent1: " + exponent1 + "\n" +
			"Exponent2: " + exponent2 + "\n" +
			"Coefficient: " + coefficient + "\n"
	case *ecdsa.PrivateKey:
		//
	}
	return
}

func (k *RR_DNSKEY) Read(q io.Reader) os.Error {
	p := NewParser(q)
	r, err := p.RR()
	if err != nil {
		return err
	}
	if _, ok := r.(*RR_DNSKEY); !ok {
		panic("did not read a DNSKEY")
	}
	k.Hdr = r.(*RR_DNSKEY).Hdr
	k.Flags = r.(*RR_DNSKEY).Flags
	k.Protocol = r.(*RR_DNSKEY).Protocol
	k.Algorithm = r.(*RR_DNSKEY).Algorithm
	k.PublicKey = r.(*RR_DNSKEY).PublicKey
	return nil
}

func (k *RR_DNSKEY) ReadPrivateKey(q io.Reader) (PrivateKey, os.Error) {
	p := NewParser(q)
	kv, _ := p.PrivateKey()
	if _, ok := kv["private-key-format"]; !ok {
		return nil, ErrPrivKey
	}
	if kv["private-key-format"] != "v1.2" && kv["private-key-format"] != "v1.3" {
		return nil, ErrPrivKey
	}
	switch kv["algorithm"] {
	case "RSAMD5", "RSASHA1", "RSASHA256", "RSASHA512":
		return k.readPrivateKeyRSA(kv)
	case "ECDSAP256SHA256", "ECDSAP384SHA384":
		return k.readPrivateKeyECDSA(kv)
	}
	return nil, ErrPrivKey
}

// Read a private key (file) string and create a public key. Return the private key.
func (k *RR_DNSKEY) readPrivateKeyRSA(kv map[string]string) (PrivateKey, os.Error) {
	p := new(rsa.PrivateKey)
	p.Primes = []*big.Int{nil, nil}
	for k, v := range kv {
		switch k {
		case "modulus", "publicexponent", "privateexponent", "prime1", "prime2":
			v1, err := packBase64([]byte(v))
			if err != nil {
				return nil, err
			}
			switch k {
			case "modulus":
				p.PublicKey.N = big.NewInt(0)
				p.PublicKey.N.SetBytes(v1)
			case "publicexponent":
				i := big.NewInt(0)
				i.SetBytes(v1)
				p.PublicKey.E = int(i.Int64()) // int64 should be large enough
			case "privateexponent":
				p.D = big.NewInt(0)
				p.D.SetBytes(v1)
			case "prime1":
				p.Primes[0] = big.NewInt(0)
				p.Primes[0].SetBytes(v1)
			case "prime2":
				p.Primes[1] = big.NewInt(0)
				p.Primes[1].SetBytes(v1)
			}
		case "exponent1", "exponent2", "coefficient":
			// not used in Go (yet)
		case "created", "publish", "activate":
			// not used in Go (yet)
		}
	}
	return p, nil
}

func (k *RR_DNSKEY) readPrivateKeyECDSA(kv map[string]string) (PrivateKey, os.Error) {
	p := new(ecdsa.PrivateKey)
	p.D = big.NewInt(0)
	// Need to check if we have everything
	for k, v := range kv {
		switch k {
		case "privatekey:":
			v1, err := packBase64([]byte(v))
			if err != nil {
				return nil, err
			}
			p.D.SetBytes(v1)
		case "created:", "publish:", "activate:":
			/* not used in Go (yet) */
		}
	}
	return p, nil
}
<commit_msg>no panic in the lib<commit_after>package dns

import (
	"os"
	"io"
	"big"
	"strconv"
	"crypto/rsa"
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
)

// Empty interface that is used as a wrapper around all possible
// private key implementations from the crypto package.
type PrivateKey interface{}

// Generate a key of the given bit size.
// The public part is put inside the DNSKEY record.
// The Algorithm in the key must be set as this will define
// what kind of DNSKEY will be generated.
// For ECDSA the algorithms implies a keysize, in that case
// bits should be zero.
func (r *RR_DNSKEY) Generate(bits int) (PrivateKey, os.Error) {
	switch r.Algorithm {
	case RSAMD5, RSASHA1, RSASHA256:
		if bits < 512 || bits > 4096 {
			return nil, ErrKeySize
		}
	case RSASHA512:
		if bits < 1024 || bits > 4096 {
			return nil, ErrKeySize
		}
	case ECDSAP256SHA256:
		if bits != 256 {
			return nil, ErrKeySize
		}
	case ECDSAP384SHA384:
		if bits != 384 {
			return nil, ErrKeySize
		}
	}

	switch r.Algorithm {
	case RSAMD5, RSASHA1, RSASHA256, RSASHA512:
		priv, err := rsa.GenerateKey(rand.Reader, bits)
		if err != nil {
			return nil, err
		}
		r.setPublicKeyRSA(priv.PublicKey.E, priv.PublicKey.N)
		return priv, nil
	case ECDSAP256SHA256, ECDSAP384SHA384:
		var c *elliptic.Curve
		switch r.Algorithm {
		case ECDSAP256SHA256:
			c = elliptic.P256()
		case ECDSAP384SHA384:
			c = elliptic.P384()
		}
		priv, err := ecdsa.GenerateKey(c, rand.Reader)
		if err != nil {
			return nil, err
		}
		r.setPublicKeyCurve(priv.PublicKey.X, priv.PublicKey.Y)
		return priv, nil
	default:
		return nil, ErrAlg
	}
	return nil, nil // Dummy return
}

// Convert a PrivateKey to a string. This
// string has the same format as the private-key-file of BIND9 (Private-key-format: v1.3).
// It needs some info from the key (hashing, keytag), so its a method of the RR_DNSKEY.
func (r *RR_DNSKEY) PrivateKeyString(p PrivateKey) (s string) {
	switch t := p.(type) {
	case *rsa.PrivateKey:
		algorithm := strconv.Itoa(int(r.Algorithm)) + " (" + alg_str[r.Algorithm] + ")"
		modulus := unpackBase64(t.PublicKey.N.Bytes())
		e := big.NewInt(int64(t.PublicKey.E))
		publicExponent := unpackBase64(e.Bytes())
		privateExponent := unpackBase64(t.D.Bytes())
		prime1 := unpackBase64(t.Primes[0].Bytes())
		prime2 := unpackBase64(t.Primes[1].Bytes())
		// Calculate Exponent1/2 and Coefficient as per: http://en.wikipedia.org/wiki/RSA#Using_the_Chinese_remainder_algorithm
		// and from: http://code.google.com/p/go/issues/detail?id=987
		one := big.NewInt(1)
		minusone := big.NewInt(-1)
		p_1 := big.NewInt(0).Sub(t.Primes[0], one)
		q_1 := big.NewInt(0).Sub(t.Primes[1], one)
		exp1 := big.NewInt(0).Mod(t.D, p_1)
		exp2 := big.NewInt(0).Mod(t.D, q_1)
		coeff := big.NewInt(0).Exp(t.Primes[1], minusone, t.Primes[0])

		exponent1 := unpackBase64(exp1.Bytes())
		exponent2 := unpackBase64(exp2.Bytes())
		coefficient := unpackBase64(coeff.Bytes())

		s = "Private-key-format: v1.3\n" +
			"Algorithm: " + algorithm + "\n" +
			"Modules: " + modulus + "\n" +
			"PublicExponent: " + publicExponent + "\n" +
			"PrivateExponent: " + privateExponent + "\n" +
			"Prime1: " + prime1 + "\n" +
			"Prime2: " + prime2 + "\n" +
			"Exponent1: " + exponent1 + "\n" +
			"Exponent2: " + exponent2 + "\n" +
			"Coefficient: " + coefficient + "\n"
	case *ecdsa.PrivateKey:
		//
	}
	return
}

func (k *RR_DNSKEY) Read(q io.Reader) os.Error {
	p := NewParser(q)
	r, err := p.RR()
	if err != nil {
		return err
	}
	if _, ok := r.(*RR_DNSKEY); !ok {
		return ErrKey
	}
	k.Hdr = r.(*RR_DNSKEY).Hdr
	k.Flags = r.(*RR_DNSKEY).Flags
	k.Protocol = r.(*RR_DNSKEY).Protocol
	k.Algorithm = r.(*RR_DNSKEY).Algorithm
	k.PublicKey = r.(*RR_DNSKEY).PublicKey
	return nil
}

func (k *RR_DNSKEY) ReadPrivateKey(q io.Reader) (PrivateKey, os.Error) {
	p := NewParser(q)
	kv, _ := p.PrivateKey()
	if _, ok := kv["private-key-format"]; !ok {
		return nil, ErrPrivKey
	}
	if kv["private-key-format"] != "v1.2" && kv["private-key-format"] != "v1.3" {
		return nil, ErrPrivKey
	}
	switch kv["algorithm"] {
	case "RSAMD5", "RSASHA1", "RSASHA256", "RSASHA512":
		return k.readPrivateKeyRSA(kv)
	case "ECDSAP256SHA256", "ECDSAP384SHA384":
		return k.readPrivateKeyECDSA(kv)
	}
	return nil, ErrPrivKey
}

// Read a private key (file) string and create a public key. Return the private key.
func (k *RR_DNSKEY) readPrivateKeyRSA(kv map[string]string) (PrivateKey, os.Error) {
	p := new(rsa.PrivateKey)
	p.Primes = []*big.Int{nil, nil}
	for k, v := range kv {
		switch k {
		case "modulus", "publicexponent", "privateexponent", "prime1", "prime2":
			v1, err := packBase64([]byte(v))
			if err != nil {
				return nil, err
			}
			switch k {
			case "modulus":
				p.PublicKey.N = big.NewInt(0)
				p.PublicKey.N.SetBytes(v1)
			case "publicexponent":
				i := big.NewInt(0)
				i.SetBytes(v1)
				p.PublicKey.E = int(i.Int64()) // int64 should be large enough
			case "privateexponent":
				p.D = big.NewInt(0)
				p.D.SetBytes(v1)
			case "prime1":
				p.Primes[0] = big.NewInt(0)
				p.Primes[0].SetBytes(v1)
			case "prime2":
				p.Primes[1] = big.NewInt(0)
				p.Primes[1].SetBytes(v1)
			}
		case "exponent1", "exponent2", "coefficient":
			// not used in Go (yet)
		case "created", "publish", "activate":
			// not used in Go (yet)
		}
	}
	return p, nil
}

func (k *RR_DNSKEY) readPrivateKeyECDSA(kv map[string]string) (PrivateKey, os.Error) {
	p := new(ecdsa.PrivateKey)
	p.D = big.NewInt(0)
	// Need to check if we have everything
	for k, v := range kv {
		switch k {
		case "privatekey:":
			v1, err := packBase64([]byte(v))
			if err != nil {
				return nil, err
			}
			p.D.SetBytes(v1)
		case "created:", "publish:", "activate:":
			/* not used in Go (yet) */
		}
	}
	return p, nil
}
<|endoftext|>


<commit_before>package proxy

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"github.com/adamdecaf/go-proxy/codec"
	"golang.org/x/net/html"
	"io"
	"log"
)

type HTMLTransformer struct {
	Transformer
}

func (t HTMLTransformer) Transform(in Response) Response {
	doc, err := html.Parse(in.Reader)
	if err != nil {
		log.Printf("error parsing html document err=%s\n", err)
	}

	var f func(*html.Node)

	f = func(n *html.Node) {
		if n.Type == html.ElementNode && n.Data == "a" {
			for i, a := range n.Attr {
				if a.Key == "href" {
					// todo: need to resolve
					// relative (/about.html)
					// and
					// protcol dependent urls (//foo.com)
					a.Val = fmt.Sprintf("/url/%s", codec.ToBase64(a.Val))
				}
				n.Attr[i] = a
			}
		}
		for c := n.FirstChild; c != nil; c = c.NextSibling {
			f(c)
		}
	}

	f(doc)

	out := new(bytes.Buffer)
	err = html.Render(out, doc)
	if err != nil {
		// log.Printf
		return in
	}

	buff := []io.Reader{out}
	combined := io.MultiReader(buff...)

	return Response{
		Reader: combined,
	}

	// for {
	// 	token := tokenizer.Next()
	// 	switch {
	// 	default:
	// 		// ignore all other html tokens
	// 		continue
	// 	case token == html.StartTagToken:
	// 		t := tokenizer.Token()
	// 		// <a> element
	// 		isAnchor := t.Data == "a"
	// 		if isAnchor {
	// 			// find the `href` attribute
	// 			for _, a := range t.Attr {
	// 				if a.Key == "href" {
	// 					// todo: need to resolve
	// 					// relative (/about.html)
	// 					// and
	// 					// protcol dependent urls (//foo.com)
	// 					encodeBase64(a.Val)
	// 					// todo: encode url and replace it
	// 					fmt.Println("Found href:", )
	// 					break
	// 				}
	// 			}
	// 		}
	// 		// <img> element
	// 		// <script> element
	// 	}
	// }
}

// `encodeBase64` returns a UTF-8 string in it's base64 encoding
func encodeBase64(s string) string {
	bytes := []byte(s)
	return base64.StdEncoding.EncodeToString(bytes)
}

func copyNode(old *html.Node) *html.Node {
	n := new(html.Node)
	n.Type = old.Type
	n.DataAtom = old.DataAtom
	n.Data = old.Data
	n.Attr = make([]html.Attribute, len(old.Attr))
	copy(n.Attr, old.Attr)
	for c := old.FirstChild; c != nil; c = c.NextSibling {
		nc := copyNode(c)
		n.AppendChild(nc)
	}
	return n
}

func replaceNode(old, new *html.Node) *html.Node {
	parent := old.Parent

	// nil would mean the root element
	if parent != nil {
		parent.InsertBefore(copyNode(new), old)
		parent.RemoveChild(old)
	}

	return new
}

func NewHTMLTransformer() Transformer {
	return HTMLTransformer{}
}
<commit_msg>proxy: Remove commented code<commit_after>package proxy

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"github.com/adamdecaf/go-proxy/codec"
	"golang.org/x/net/html"
	"io"
	"log"
)

type HTMLTransformer struct {
	Transformer
}

func (t HTMLTransformer) Transform(in Response) Response {
	doc, err := html.Parse(in.Reader)
	if err != nil {
		log.Printf("error parsing html document err=%s\n", err)
	}

	var f func(*html.Node)

	f = func(n *html.Node) {
		if n.Type == html.ElementNode && n.Data == "a" {
			for i, a := range n.Attr {
				if a.Key == "href" {
					// todo: need to resolve
					// relative (/about.html)
					// and
					// protcol dependent urls (//foo.com)
					a.Val = fmt.Sprintf("/url/%s", codec.ToBase64(a.Val))
				}
				n.Attr[i] = a
			}
		}
		for c := n.FirstChild; c != nil; c = c.NextSibling {
			f(c)
		}
	}

	f(doc)

	out := new(bytes.Buffer)
	err = html.Render(out, doc)
	if err != nil {
		// log.Printf
		return in
	}

	buff := []io.Reader{out}
	combined := io.MultiReader(buff...)

	return Response{
		Reader: combined,
	}
}

// `encodeBase64` returns a UTF-8 string in it's base64 encoding
func encodeBase64(s string) string {
	bytes := []byte(s)
	return base64.StdEncoding.EncodeToString(bytes)
}

func copyNode(old *html.Node) *html.Node {
	n := new(html.Node)
	n.Type = old.Type
	n.DataAtom = old.DataAtom
	n.Data = old.Data
	n.Attr = make([]html.Attribute, len(old.Attr))
	copy(n.Attr, old.Attr)
	for c := old.FirstChild; c != nil; c = c.NextSibling {
		nc := copyNode(c)
		n.AppendChild(nc)
	}
	return n
}

func replaceNode(old, new *html.Node) *html.Node {
	parent := old.Parent

	// nil would mean the root element
	if parent != nil {
		parent.InsertBefore(copyNode(new), old)
		parent.RemoveChild(old)
	}

	return new
}

func NewHTMLTransformer() Transformer {
	return HTMLTransformer{}
}
<|endoftext|>


<commit_before>package recipebuilder

import (
	"fmt"

	"github.com/cloudfoundry-incubator/bbs/models"
	"github.com/cloudfoundry-incubator/diego-ssh/keys"
	fileserver "github.com/cloudfoundry-incubator/file-server"
	"github.com/cloudfoundry-incubator/runtime-schema/cc_messages"
	"github.com/cloudfoundry/gunk/urljoiner"
)

const (
	MinCpuProxy = 256
	MaxCpuProxy = 8192

	DefaultFileDescriptorLimit = uint64(1024)

	LRPLogSource    = "CELL"
	AppLogSource    = "APP"
	HealthLogSource = "HEALTH"

	Router      = "router"
	DefaultPort = uint32(8080)

	DefaultSSHPort = uint32(2222)

	DefaultLANG = "en_US.UTF-8"

	TrustedSystemCertificatesPath = "/etc/cf-system-certificates"
)

var (
	ErrNoDockerImage        = Error{Type: "ErrNoDockerImage", Message: "no docker image provided"}
	ErrNoLifecycleDefined   = Error{Type: "ErrNoLifecycleDefined", Message: "no lifecycle binary bundle defined for stack"}
	ErrDropletSourceMissing = Error{Type: "ErrAppSourceMissing", Message: "desired app missing droplet_uri"}
	ErrDockerImageMissing   = Error{Type: "ErrDockerImageMissing", Message: "desired app missing docker_image"}
	ErrMultipleAppSources   = Error{Type: "ErrMultipleAppSources", Message: "desired app contains both droplet_uri and docker_image; exactly one is required."}
)

type Config struct {
	Lifecycles    map[string]string
	FileServerURL string
	KeyFactory    keys.SSHKeyFactory
}

//go:generate counterfeiter -o ../bulk/fakes/fake_recipe_builder.go . RecipeBuilder
type RecipeBuilder interface {
	Build(*cc_messages.DesireAppRequestFromCC) (*models.DesiredLRP, error)
	BuildTask(*cc_messages.TaskRequestFromCC) (*models.TaskDefinition, error)
	ExtractExposedPorts(*cc_messages.DesireAppRequestFromCC) ([]uint32, error)
}

type Error struct {
	Type    string `json:"name"`
	Message string `json:"message"`
}

func (err Error) Error() string {
	return err.Message
}

func lifecycleDownloadURL(lifecyclePath string, fileServerURL string) string {
	staticPath, err := fileserver.Routes.CreatePathForRoute(fileserver.StaticRoute, nil)
	if err != nil {
		panic("couldn't generate the download path for the bundle of app lifecycle binaries: " + err.Error())
	}

	return urljoiner.Join(fileServerURL, staticPath, lifecyclePath)
}

func cpuWeight(memoryMB int) uint32 {
	cpuProxy := memoryMB

	if cpuProxy > MaxCpuProxy {
		return 100
	}

	if cpuProxy < MinCpuProxy {
		return 1
	}

	return uint32(99.0*(cpuProxy-MinCpuProxy)/(MaxCpuProxy-MinCpuProxy) + 1)
}

func createLrpEnv(env []*models.EnvironmentVariable, exposedPort uint32) []*models.EnvironmentVariable {
	env = append(env, &models.EnvironmentVariable{Name: "PORT", Value: fmt.Sprintf("%d", exposedPort)})
	return env
}

func getParallelAction(ports []uint32, user string) *models.ParallelAction {
	fileDescriptorLimit := DefaultFileDescriptorLimit
	parallelAction := &models.ParallelAction{}
	for _, port := range ports {
		parallelAction.Actions = append(parallelAction.Actions,
			&models.Action{
				RunAction: &models.RunAction{
					User:      user,
					Path:      "/tmp/lifecycle/healthcheck",
					Args:      []string{fmt.Sprintf("-port=%d", port)},
					LogSource: HealthLogSource,
					ResourceLimits: &models.ResourceLimits{
						Nofile: &fileDescriptorLimit,
					},
					SuppressLogOutput: true,
				},
			})
	}
	return parallelAction
}

func getDesiredAppPorts(ports []uint32) []uint32 {
	desiredAppPorts := ports

	if desiredAppPorts == nil {
		desiredAppPorts = []uint32{DefaultPort}
	}
	return desiredAppPorts
}
<commit_msg>remove fileserver dependency<commit_after>package recipebuilder

import (
	"fmt"

	"github.com/cloudfoundry-incubator/bbs/models"
	"github.com/cloudfoundry-incubator/diego-ssh/keys"
	"github.com/cloudfoundry-incubator/runtime-schema/cc_messages"
	"github.com/cloudfoundry/gunk/urljoiner"
)

const (
	MinCpuProxy = 256
	MaxCpuProxy = 8192

	DefaultFileDescriptorLimit = uint64(1024)

	LRPLogSource    = "CELL"
	AppLogSource    = "APP"
	HealthLogSource = "HEALTH"

	Router      = "router"
	DefaultPort = uint32(8080)

	DefaultSSHPort = uint32(2222)

	DefaultLANG = "en_US.UTF-8"

	TrustedSystemCertificatesPath = "/etc/cf-system-certificates"
)

var (
	ErrNoDockerImage        = Error{Type: "ErrNoDockerImage", Message: "no docker image provided"}
	ErrNoLifecycleDefined   = Error{Type: "ErrNoLifecycleDefined", Message: "no lifecycle binary bundle defined for stack"}
	ErrDropletSourceMissing = Error{Type: "ErrAppSourceMissing", Message: "desired app missing droplet_uri"}
	ErrDockerImageMissing   = Error{Type: "ErrDockerImageMissing", Message: "desired app missing docker_image"}
	ErrMultipleAppSources   = Error{Type: "ErrMultipleAppSources", Message: "desired app contains both droplet_uri and docker_image; exactly one is required."}
)

type Config struct {
	Lifecycles    map[string]string
	FileServerURL string
	KeyFactory    keys.SSHKeyFactory
}

//go:generate counterfeiter -o ../bulk/fakes/fake_recipe_builder.go . RecipeBuilder
type RecipeBuilder interface {
	Build(*cc_messages.DesireAppRequestFromCC) (*models.DesiredLRP, error)
	BuildTask(*cc_messages.TaskRequestFromCC) (*models.TaskDefinition, error)
	ExtractExposedPorts(*cc_messages.DesireAppRequestFromCC) ([]uint32, error)
}

type Error struct {
	Type    string `json:"name"`
	Message string `json:"message"`
}

func (err Error) Error() string {
	return err.Message
}

func lifecycleDownloadURL(lifecyclePath string, fileServerURL string) string {
	return urljoiner.Join(fileServerURL, "/v1/static", lifecyclePath)
}

func cpuWeight(memoryMB int) uint32 {
	cpuProxy := memoryMB

	if cpuProxy > MaxCpuProxy {
		return 100
	}

	if cpuProxy < MinCpuProxy {
		return 1
	}

	return uint32(99.0*(cpuProxy-MinCpuProxy)/(MaxCpuProxy-MinCpuProxy) + 1)
}

func createLrpEnv(env []*models.EnvironmentVariable, exposedPort uint32) []*models.EnvironmentVariable {
	env = append(env, &models.EnvironmentVariable{Name: "PORT", Value: fmt.Sprintf("%d", exposedPort)})
	return env
}

func getParallelAction(ports []uint32, user string) *models.ParallelAction {
	fileDescriptorLimit := DefaultFileDescriptorLimit
	parallelAction := &models.ParallelAction{}
	for _, port := range ports {
		parallelAction.Actions = append(parallelAction.Actions,
			&models.Action{
				RunAction: &models.RunAction{
					User:      user,
					Path:      "/tmp/lifecycle/healthcheck",
					Args:      []string{fmt.Sprintf("-port=%d", port)},
					LogSource: HealthLogSource,
					ResourceLimits: &models.ResourceLimits{
						Nofile: &fileDescriptorLimit,
					},
					SuppressLogOutput: true,
				},
			})
	}
	return parallelAction
}

func getDesiredAppPorts(ports []uint32) []uint32 {
	desiredAppPorts := ports

	if desiredAppPorts == nil {
		desiredAppPorts = []uint32{DefaultPort}
	}
	return desiredAppPorts
}
<|endoftext|>


<commit_before>package json

import (
	"encoding/json"

	"github.com/korfuri/goref"
)

func GraphAsJSON(pg goref.PackageGraph, outch chan<- []byte, errch chan<- error, done chan<- struct{}) {
	for _, p := range pg.Packages {
		for _, r := range p.InRefs {
			if j, err := json.Marshal(r); err == nil {
				outch <- j
			} else {
				errch <- err
			}
		}
	}
	done <- struct{}{}
}
<commit_msg>Remove goref/json.<commit_after><|endoftext|>


<commit_before>package events

import (
	"fmt"
	"os"
	"strings"
)

// APIGatewayIdentity is the API Gateway identity information
type APIGatewayIdentity struct {
	AccountID                     string `json:"accountId"`
	APIKey                        string `json:"apiKey"`
	Caller                        string `json:"caller"`
	CognitoAuthenticationProvider string `json:"cognitoAuthenticationProvider"`
	CognitoAuthenticationType     string `json:"cognitoAuthenticationType"`
	CognitoIdentityID             string `json:"cognitoIdentityId"`
	CognitoIdentityPoolID         string `json:"cognitoIdentityPoolId"`
	SourceIP                      string `json:"sourceIp"`
	User                          string `json:"user"`
	UserAgent                     string `json:"userAgent"`
	UserArn                       string `json:"userArn"`
}

// APIGatewayContext is the API-Gateway context information
type APIGatewayContext struct {
	AppID        string             `json:"appId"`
	Method       string             `json:"method"`
	RequestID    string             `json:"requestId"`
	ResourceID   string             `json:"resourceId"`
	ResourcePath string             `json:"resourcePath"`
	Stage        string             `json:"stage"`
	Identity     APIGatewayIdentity `json:"identity"`
}

// APIGatewayRequest represents the API Gateway request that
// is submitted to a Lambda function. This format matches the
// inputmapping_default.VTL templates
type APIGatewayRequest struct {
	Method      string                 `json:"method"`
	Body        interface{}            `json:"body"`
	Headers     map[string]string      `json:"headers"`
	QueryParams map[string]string      `json:"queryParams"`
	PathParams  map[string]string      `json:"pathParams"`
	Context     APIGatewayContext      `json:"context"`
	Authorizer  map[string]interface{} `json:"authorizer"`
}

// NewAPIGatewayMockRequest creates a mock API Gateway request.
// This request format mirrors the VTL templates in
// github.com/mweagle/Sparta/resources/provision/apigateway
func NewAPIGatewayMockRequest(lambdaName string,
	httpMethod string,
	whitelistParamValues map[string]string,
	eventData interface{}) (*APIGatewayRequest, error) {

	apiGatewayRequest := &APIGatewayRequest{
		Method:      httpMethod,
		Body:        eventData,
		Headers:     make(map[string]string, 0),
		QueryParams: make(map[string]string, 0),
		PathParams:  make(map[string]string, 0),
	}
	for eachWhitelistKey, eachWhitelistValue := range whitelistParamValues {
		// Whitelisted params include their
		// namespace as part of the whitelist expression:
		// method.request.querystring.keyName
		parts := strings.Split(eachWhitelistKey, ".")

		// The string should have 4 parts...
		if len(parts) != 4 {
			return nil, fmt.Errorf("Invalid whitelist param name: %s (MUST be: method.request.KEY_TYPE.KEY_NAME, ex: method.request.querystring.myQueryParam", eachWhitelistKey)
		}
		keyType := parts[2]
		keyName := parts[3]
		switch keyType {
		case "header":
			apiGatewayRequest.Headers[keyName] = eachWhitelistValue
		case "querystring":
			apiGatewayRequest.QueryParams[keyName] = eachWhitelistValue
		case "path":
			apiGatewayRequest.PathParams[keyName] = eachWhitelistValue
		default:
			return nil, fmt.Errorf("Unsupported whitelist param type: %s", keyType)
		}
	}

	apiGatewayRequest.Context.AppID = fmt.Sprintf("spartaApp%d", os.Getpid())
	apiGatewayRequest.Context.Method = httpMethod
	apiGatewayRequest.Context.RequestID = "12341234-1234-1234-1234-123412341234"
	apiGatewayRequest.Context.ResourceID = "anon42"
	apiGatewayRequest.Context.ResourcePath = "/mock"
	apiGatewayRequest.Context.Stage = "mock"
	apiGatewayRequest.Context.Identity = APIGatewayIdentity{
		AccountID: "123412341234",
		APIKey:    "",
		Caller:    "",
		CognitoAuthenticationProvider: "",
		CognitoAuthenticationType:     "",
		CognitoIdentityID:             "",
		CognitoIdentityPoolID:         "",
		SourceIP:                      "127.0.0.1",
		User:                          "Unknown",
		UserAgent:                     "Mozilla/Gecko",
		UserArn:                       "",
	}
	return apiGatewayRequest, nil
}
<commit_msg>Define `APIGatewayEnvelope` to allow for custom `Body` extensions<commit_after>package events

import (
	"fmt"
	"os"
	"strings"
)

// APIGatewayIdentity is the API Gateway identity information
type APIGatewayIdentity struct {
	AccountID                     string `json:"accountId"`
	APIKey                        string `json:"apiKey"`
	Caller                        string `json:"caller"`
	CognitoAuthenticationProvider string `json:"cognitoAuthenticationProvider"`
	CognitoAuthenticationType     string `json:"cognitoAuthenticationType"`
	CognitoIdentityID             string `json:"cognitoIdentityId"`
	CognitoIdentityPoolID         string `json:"cognitoIdentityPoolId"`
	SourceIP                      string `json:"sourceIp"`
	User                          string `json:"user"`
	UserAgent                     string `json:"userAgent"`
	UserArn                       string `json:"userArn"`
}

// APIGatewayContext is the API-Gateway context information
type APIGatewayContext struct {
	AppID        string             `json:"appId"`
	Method       string             `json:"method"`
	RequestID    string             `json:"requestId"`
	ResourceID   string             `json:"resourceId"`
	ResourcePath string             `json:"resourcePath"`
	Stage        string             `json:"stage"`
	Identity     APIGatewayIdentity `json:"identity"`
}

// APIGatewayEnvelope is the type that maps to the VTL properties
type APIGatewayEnvelope struct {
	Method      string                 `json:"method"`
	Headers     map[string]string      `json:"headers"`
	QueryParams map[string]string      `json:"queryParams"`
	PathParams  map[string]string      `json:"pathParams"`
	Context     APIGatewayContext      `json:"context"`
	Authorizer  map[string]interface{} `json:"authorizer"`
}

// APIGatewayRequest represents the API Gateway request that
// is submitted to a Lambda function. This format matches the
// inputmapping_default.VTL templates
type APIGatewayRequest struct {
	APIGatewayEnvelope
	Body interface{} `json:"body"`
}

// NewAPIGatewayMockRequest creates a mock API Gateway request.
// This request format mirrors the VTL templates in
// github.com/mweagle/Sparta/resources/provision/apigateway
func NewAPIGatewayMockRequest(lambdaName string,
	httpMethod string,
	whitelistParamValues map[string]string,
	eventData interface{}) (*APIGatewayRequest, error) {

	apiGatewayRequest := &APIGatewayRequest{
		Body: eventData,
		APIGatewayEnvelope: APIGatewayEnvelope{
			Method:      httpMethod,
			Headers:     make(map[string]string, 0),
			QueryParams: make(map[string]string, 0),
			PathParams:  make(map[string]string, 0),
		},
	}
	for eachWhitelistKey, eachWhitelistValue := range whitelistParamValues {
		// Whitelisted params include their
		// namespace as part of the whitelist expression:
		// method.request.querystring.keyName
		parts := strings.Split(eachWhitelistKey, ".")

		// The string should have 4 parts...
		if len(parts) != 4 {
			return nil, fmt.Errorf("Invalid whitelist param name: %s (MUST be: method.request.KEY_TYPE.KEY_NAME, ex: method.request.querystring.myQueryParam", eachWhitelistKey)
		}
		keyType := parts[2]
		keyName := parts[3]
		switch keyType {
		case "header":
			apiGatewayRequest.Headers[keyName] = eachWhitelistValue
		case "querystring":
			apiGatewayRequest.QueryParams[keyName] = eachWhitelistValue
		case "path":
			apiGatewayRequest.PathParams[keyName] = eachWhitelistValue
		default:
			return nil, fmt.Errorf("Unsupported whitelist param type: %s", keyType)
		}
	}

	apiGatewayRequest.Context.AppID = fmt.Sprintf("spartaApp%d", os.Getpid())
	apiGatewayRequest.Context.Method = httpMethod
	apiGatewayRequest.Context.RequestID = "12341234-1234-1234-1234-123412341234"
	apiGatewayRequest.Context.ResourceID = "anon42"
	apiGatewayRequest.Context.ResourcePath = "/mock"
	apiGatewayRequest.Context.Stage = "mock"
	apiGatewayRequest.Context.Identity = APIGatewayIdentity{
		AccountID: "123412341234",
		APIKey:    "",
		Caller:    "",
		CognitoAuthenticationProvider: "",
		CognitoAuthenticationType:     "",
		CognitoIdentityID:             "",
		CognitoIdentityPoolID:         "",
		SourceIP:                      "127.0.0.1",
		User:                          "Unknown",
		UserAgent:                     "Mozilla/Gecko",
		UserArn:                       "",
	}
	return apiGatewayRequest, nil
}
<|endoftext|>