<commit_before>package s3

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

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/aws/corehandlers"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/request"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/pkg/errors"
	"github.com/smira/aptly/aptly"
	"github.com/smira/aptly/utils"
	"github.com/smira/go-aws-auth"
)

// PublishedStorage abstract file system with published files (actually hosted on S3)
type PublishedStorage struct {
	s3               *s3.S3
	config           *aws.Config
	bucket           string
	acl              string
	prefix           string
	storageClass     string
	encryptionMethod string
	plusWorkaround   bool
	disableMultiDel  bool
	pathCache        map[string]string
}

// Check interface
var (
	_ aptly.PublishedStorage = (*PublishedStorage)(nil)
)

// NewPublishedStorageRaw creates published storage from raw aws credentials
func NewPublishedStorageRaw(
	bucket, defaultACL, prefix, storageClass, encryptionMethod string,
	plusWorkaround, disabledMultiDel bool,
	config *aws.Config,
) (*PublishedStorage, error) {
	if defaultACL == "" {
		defaultACL = "private"
	}

	if storageClass == "STANDARD" {
		storageClass = ""
	}

	sess, err := session.NewSession(config)
	if err != nil {
		return nil, err
	}

	result := &PublishedStorage{
		s3:               s3.New(sess),
		bucket:           bucket,
		config:           config,
		acl:              defaultACL,
		prefix:           prefix,
		storageClass:     storageClass,
		encryptionMethod: encryptionMethod,
		plusWorkaround:   plusWorkaround,
		disableMultiDel:  disabledMultiDel,
	}

	return result, nil
}

// NewPublishedStorage creates new instance of PublishedStorage with specified S3 access
// keys, region and bucket name
func NewPublishedStorage(accessKey, secretKey, sessionToken, region, endpoint, bucket, defaultACL, prefix,
	storageClass, encryptionMethod string, plusWorkaround, disableMultiDel, forceSigV2, debug bool) (*PublishedStorage, error) {

	config := &aws.Config{
		Region: aws.String(region),
	}

	if endpoint != "" {
		config = config.WithEndpoint(endpoint).WithS3ForcePathStyle(true)
	}

	if accessKey != "" {
		config.Credentials = credentials.NewStaticCredentials(accessKey, secretKey, sessionToken)
	}

	if debug {
		config = config.WithLogLevel(aws.LogDebug)
	}

	result, err := NewPublishedStorageRaw(bucket, defaultACL, prefix, storageClass,
		encryptionMethod, plusWorkaround, disableMultiDel, config)

	if err == nil && forceSigV2 {
		creds := []awsauth.Credentials{}

		if accessKey != "" {
			creds = append(creds, awsauth.Credentials{
				AccessKeyID:     accessKey,
				SecretAccessKey: secretKey,
			})
		}

		result.s3.Handlers.Sign.Clear()
		result.s3.Handlers.Sign.PushBackNamed(corehandlers.BuildContentLengthHandler)
		result.s3.Handlers.Sign.PushBack(func(req *request.Request) {
			awsauth.SignS3(req.HTTPRequest, creds...)
		})
	}

	return result, err
}

// String
func (storage *PublishedStorage) String() string {
	return fmt.Sprintf("S3: %s:%s/%s", *storage.config.Region, storage.bucket, storage.prefix)
}

// MkDir creates directory recursively under public path
func (storage *PublishedStorage) MkDir(path string) error {
	// no op for S3
	return nil
}

// PutFile puts file into published storage at specified path
func (storage *PublishedStorage) PutFile(path string, sourceFilename string) error {
	var (
		source *os.File
		err    error
	)
	source, err = os.Open(sourceFilename)
	if err != nil {
		return err
	}
	defer source.Close()

	err = storage.putFile(path, source)
	if err != nil {
		err = errors.Wrap(err, fmt.Sprintf("error uploading %s to %s", sourceFilename, storage))
	}

	return err
}

// putFile uploads file-like object to
func (storage *PublishedStorage) putFile(path string, source io.ReadSeeker) error {

	params := &s3.PutObjectInput{
		Bucket: aws.String(storage.bucket),
		Key:    aws.String(filepath.Join(storage.prefix, path)),
		Body:   source,
		ACL:    aws.String(storage.acl),
	}
	if storage.storageClass != "" {
		params.StorageClass = aws.String(storage.storageClass)
	}
	if storage.encryptionMethod != "" {
		params.ServerSideEncryption = aws.String(storage.encryptionMethod)
	}

	_, err := storage.s3.PutObject(params)
	if err != nil {
		return err
	}

	if storage.plusWorkaround && strings.Contains(path, "+") {
		_, err = source.Seek(0, 0)
		if err != nil {
			return err
		}

		return storage.putFile(strings.Replace(path, "+", " ", -1), source)
	}
	return nil
}

// Remove removes single file under public path
func (storage *PublishedStorage) Remove(path string) error {
	params := &s3.DeleteObjectInput{
		Bucket: aws.String(storage.bucket),
		Key:    aws.String(filepath.Join(storage.prefix, path)),
	}
	_, err := storage.s3.DeleteObject(params)
	if err != nil {
		return errors.Wrap(err, fmt.Sprintf("error deleting %s from %s", path, storage))
	}

	if storage.plusWorkaround && strings.Contains(path, "+") {
		// try to remove workaround version, but don't care about result
		_ = storage.Remove(strings.Replace(path, "+", " ", -1))
	}
	return nil
}

// RemoveDirs removes directory structure under public path
func (storage *PublishedStorage) RemoveDirs(path string, progress aptly.Progress) error {
	const page = 1000

	filelist, _, err := storage.internalFilelist(path, false)
	if err != nil {
		return err
	}

	if storage.disableMultiDel {
		for i := range filelist {
			params := &s3.DeleteObjectInput{
				Bucket: aws.String(storage.bucket),
				Key:    aws.String(filepath.Join(storage.prefix, path, filelist[i])),
			}
			_, err := storage.s3.DeleteObject(params)
			if err != nil {
				return fmt.Errorf("error deleting path %s from %s: %s", filelist[i], storage, err)
			}
		}
	} else {
		numParts := (len(filelist) + page - 1) / page

		for i := 0; i < numParts; i++ {
			var part []string
			if i == numParts-1 {
				part = filelist[i*page:]
			} else {
				part = filelist[i*page : (i+1)*page]
			}
			paths := make([]*s3.ObjectIdentifier, len(part))

			for i := range part {
				paths[i] = &s3.ObjectIdentifier{
					Key: aws.String(filepath.Join(storage.prefix, path, part[i])),
				}
			}

			params := &s3.DeleteObjectsInput{
				Bucket: aws.String(storage.bucket),
				Delete: &s3.Delete{
					Objects: paths,
					Quiet:   aws.Bool(true),
				},
			}

			_, err := storage.s3.DeleteObjects(params)
			if err != nil {
				return fmt.Errorf("error deleting multiple paths from %s: %s", storage, err)
			}
		}
	}

	return nil
}

// LinkFromPool links package file from pool to dist's pool location
//
// publishedDirectory is desired location in pool (like prefix/pool/component/liba/libav/)
// sourcePool is instance of aptly.PackagePool
// sourcePath is filepath to package file in package pool
//
// LinkFromPool returns relative path for the published file to be included in package index
func (storage *PublishedStorage) LinkFromPool(publishedDirectory, baseName string, sourcePool aptly.PackagePool,
	sourcePath string, sourceChecksums utils.ChecksumInfo, force bool) error {

	relPath := filepath.Join(publishedDirectory, baseName)
	poolPath := filepath.Join(storage.prefix, relPath)

	if storage.pathCache == nil {
		paths, md5s, err := storage.internalFilelist("", true)
		if err != nil {
			return errors.Wrap(err, "error caching paths under prefix")
		}

		storage.pathCache = make(map[string]string, len(paths))

		for i := range paths {
			storage.pathCache[paths[i]] = md5s[i]
		}
	}

	destinationMD5, exists := storage.pathCache[relPath]
	sourceMD5 := sourceChecksums.MD5

	if exists {
		if sourceMD5 == "" {
			return fmt.Errorf("unable to compare object, MD5 checksum missing")
		}

		if destinationMD5 == sourceMD5 {
			return nil
		}

		if !force && destinationMD5 != sourceMD5 {
			return fmt.Errorf("error putting file to %s: file already exists and is different: %s", poolPath, storage)

		}
	}

	source, err := sourcePool.Open(sourcePath)
	if err != nil {
		return err
	}
	defer source.Close()

	err = storage.putFile(relPath, source)
	if err == nil {
		storage.pathCache[relPath] = sourceMD5
	} else {
		err = errors.Wrap(err, fmt.Sprintf("error uploading %s to %s: %s", sourcePath, storage, poolPath))
	}

	return err
}

// Filelist returns list of files under prefix
func (storage *PublishedStorage) Filelist(prefix string) ([]string, error) {
	paths, _, err := storage.internalFilelist(prefix, true)
	return paths, err
}

func (storage *PublishedStorage) internalFilelist(prefix string, hidePlusWorkaround bool) (paths []string, md5s []string, err error) {
	paths = make([]string, 0, 1024)
	md5s = make([]string, 0, 1024)
	prefix = filepath.Join(storage.prefix, prefix)
	if prefix != "" {
		prefix += "/"
	}

	params := &s3.ListObjectsInput{
		Bucket:  aws.String(storage.bucket),
		Prefix:  aws.String(prefix),
		MaxKeys: aws.Int64(1000),
	}

	err = storage.s3.ListObjectsPages(params, func(contents *s3.ListObjectsOutput, lastPage bool) bool {
		for _, key := range contents.Contents {
			if storage.plusWorkaround && hidePlusWorkaround && strings.Contains(*key.Key, " ") {
				// if we use plusWorkaround, we want to hide those duplicates
				/// from listing
				continue
			}

			if prefix == "" {
				paths = append(paths, *key.Key)
			} else {
				paths = append(paths, (*key.Key)[len(prefix):])
			}
			md5s = append(md5s, strings.Replace(*key.ETag, "\"", "", -1))
		}

		return true
	})

	if err != nil {
		return nil, nil, fmt.Errorf("error listing under prefix %s in %s: %s", prefix, storage, err)
	}

	return paths, md5s, nil
}

// RenameFile renames (moves) file
func (storage *PublishedStorage) RenameFile(oldName, newName string) error {
	source := fmt.Sprintf("/%s/%s", storage.bucket, filepath.Join(storage.prefix, oldName))

	params := &s3.CopyObjectInput{
		Bucket:     aws.String(storage.bucket),
		CopySource: aws.String(source),
		Key:        aws.String(filepath.Join(storage.prefix, newName)),
		ACL:        aws.String(storage.acl),
	}

	if storage.storageClass != "" {
		params.StorageClass = aws.String(storage.storageClass)
	}
	if storage.encryptionMethod != "" {
		params.ServerSideEncryption = aws.String(storage.encryptionMethod)
	}

	_, err := storage.s3.CopyObject(params)
	if err != nil {
		return fmt.Errorf("error copying %s -> %s in %s: %s", oldName, newName, storage, err)
	}

	return storage.Remove(oldName)
}

// SymLink creates a copy of src file and adds link information as meta data
func (storage *PublishedStorage) SymLink(src string, dst string) error {

	params := &s3.CopyObjectInput{
		Bucket:     aws.String(storage.bucket),
		CopySource: aws.String(filepath.Join(storage.prefix, src)),
		Key:        aws.String(filepath.Join(storage.prefix, dst)),
		ACL:        aws.String(storage.acl),
		Metadata: map[string]*string{
			"SymLink": aws.String(src),
		},
		MetadataDirective: aws.String("REPLACE"),
	}

	if storage.storageClass != "" {
		params.StorageClass = aws.String(storage.storageClass)
	}
	if storage.encryptionMethod != "" {
		params.ServerSideEncryption = aws.String(storage.encryptionMethod)
	}

	_, err := storage.s3.CopyObject(params)
	if err != nil {
		return fmt.Errorf("error symlinking %s -> %s in %s: %s", src, dst, storage, err)
	}

	return err
}

// HardLink using symlink functionality as hard links do not exist
func (storage *PublishedStorage) HardLink(src string, dst string) error {
	return storage.SymLink(src, dst)
}

// FileExists returns true if path exists
func (storage *PublishedStorage) FileExists(path string) (bool, error) {
	params := &s3.HeadObjectInput{
		Bucket: aws.String(storage.bucket),
		Key:    aws.String(filepath.Join(storage.prefix, path)),
	}
	_, err := storage.s3.HeadObject(params)
	if err != nil {
		aerr, ok := err.(awserr.Error)
		if ok && aerr.Code() == s3.ErrCodeNoSuchKey {
			return false, nil
		}

		return false, err
	}

	return true, nil
}

// ReadLink returns the symbolic link pointed to by path.
// This simply reads text file created with SymLink
func (storage *PublishedStorage) ReadLink(path string) (string, error) {
	params := &s3.HeadObjectInput{
		Bucket: aws.String(storage.bucket),
		Key:    aws.String(filepath.Join(storage.prefix, path)),
	}
	output, err := storage.s3.HeadObject(params)
	if err != nil {
		return "", err
	}

	return aws.StringValue(output.Metadata["SymLink"]), nil
}
<commit_msg>S3 FileExists fix<commit_after>package s3

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

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/aws/corehandlers"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/request"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/pkg/errors"
	"github.com/smira/aptly/aptly"
	"github.com/smira/aptly/utils"
	"github.com/smira/go-aws-auth"
)

const errCodeNotFound = "NotFound"

// PublishedStorage abstract file system with published files (actually hosted on S3)
type PublishedStorage struct {
	s3               *s3.S3
	config           *aws.Config
	bucket           string
	acl              string
	prefix           string
	storageClass     string
	encryptionMethod string
	plusWorkaround   bool
	disableMultiDel  bool
	pathCache        map[string]string
}

// Check interface
var (
	_ aptly.PublishedStorage = (*PublishedStorage)(nil)
)

// NewPublishedStorageRaw creates published storage from raw aws credentials
func NewPublishedStorageRaw(
	bucket, defaultACL, prefix, storageClass, encryptionMethod string,
	plusWorkaround, disabledMultiDel bool,
	config *aws.Config,
) (*PublishedStorage, error) {
	if defaultACL == "" {
		defaultACL = "private"
	}

	if storageClass == "STANDARD" {
		storageClass = ""
	}

	sess, err := session.NewSession(config)
	if err != nil {
		return nil, err
	}

	result := &PublishedStorage{
		s3:               s3.New(sess),
		bucket:           bucket,
		config:           config,
		acl:              defaultACL,
		prefix:           prefix,
		storageClass:     storageClass,
		encryptionMethod: encryptionMethod,
		plusWorkaround:   plusWorkaround,
		disableMultiDel:  disabledMultiDel,
	}

	return result, nil
}

// NewPublishedStorage creates new instance of PublishedStorage with specified S3 access
// keys, region and bucket name
func NewPublishedStorage(accessKey, secretKey, sessionToken, region, endpoint, bucket, defaultACL, prefix,
	storageClass, encryptionMethod string, plusWorkaround, disableMultiDel, forceSigV2, debug bool) (*PublishedStorage, error) {

	config := &aws.Config{
		Region: aws.String(region),
	}

	if endpoint != "" {
		config = config.WithEndpoint(endpoint).WithS3ForcePathStyle(true)
	}

	if accessKey != "" {
		config.Credentials = credentials.NewStaticCredentials(accessKey, secretKey, sessionToken)
	}

	if debug {
		config = config.WithLogLevel(aws.LogDebug)
	}

	result, err := NewPublishedStorageRaw(bucket, defaultACL, prefix, storageClass,
		encryptionMethod, plusWorkaround, disableMultiDel, config)

	if err == nil && forceSigV2 {
		creds := []awsauth.Credentials{}

		if accessKey != "" {
			creds = append(creds, awsauth.Credentials{
				AccessKeyID:     accessKey,
				SecretAccessKey: secretKey,
			})
		}

		result.s3.Handlers.Sign.Clear()
		result.s3.Handlers.Sign.PushBackNamed(corehandlers.BuildContentLengthHandler)
		result.s3.Handlers.Sign.PushBack(func(req *request.Request) {
			awsauth.SignS3(req.HTTPRequest, creds...)
		})
	}

	return result, err
}

// String
func (storage *PublishedStorage) String() string {
	return fmt.Sprintf("S3: %s:%s/%s", *storage.config.Region, storage.bucket, storage.prefix)
}

// MkDir creates directory recursively under public path
func (storage *PublishedStorage) MkDir(path string) error {
	// no op for S3
	return nil
}

// PutFile puts file into published storage at specified path
func (storage *PublishedStorage) PutFile(path string, sourceFilename string) error {
	var (
		source *os.File
		err    error
	)
	source, err = os.Open(sourceFilename)
	if err != nil {
		return err
	}
	defer source.Close()

	err = storage.putFile(path, source)
	if err != nil {
		err = errors.Wrap(err, fmt.Sprintf("error uploading %s to %s", sourceFilename, storage))
	}

	return err
}

// putFile uploads file-like object to
func (storage *PublishedStorage) putFile(path string, source io.ReadSeeker) error {

	params := &s3.PutObjectInput{
		Bucket: aws.String(storage.bucket),
		Key:    aws.String(filepath.Join(storage.prefix, path)),
		Body:   source,
		ACL:    aws.String(storage.acl),
	}
	if storage.storageClass != "" {
		params.StorageClass = aws.String(storage.storageClass)
	}
	if storage.encryptionMethod != "" {
		params.ServerSideEncryption = aws.String(storage.encryptionMethod)
	}

	_, err := storage.s3.PutObject(params)
	if err != nil {
		return err
	}

	if storage.plusWorkaround && strings.Contains(path, "+") {
		_, err = source.Seek(0, 0)
		if err != nil {
			return err
		}

		return storage.putFile(strings.Replace(path, "+", " ", -1), source)
	}
	return nil
}

// Remove removes single file under public path
func (storage *PublishedStorage) Remove(path string) error {
	params := &s3.DeleteObjectInput{
		Bucket: aws.String(storage.bucket),
		Key:    aws.String(filepath.Join(storage.prefix, path)),
	}
	_, err := storage.s3.DeleteObject(params)
	if err != nil {
		return errors.Wrap(err, fmt.Sprintf("error deleting %s from %s", path, storage))
	}

	if storage.plusWorkaround && strings.Contains(path, "+") {
		// try to remove workaround version, but don't care about result
		_ = storage.Remove(strings.Replace(path, "+", " ", -1))
	}
	return nil
}

// RemoveDirs removes directory structure under public path
func (storage *PublishedStorage) RemoveDirs(path string, progress aptly.Progress) error {
	const page = 1000

	filelist, _, err := storage.internalFilelist(path, false)
	if err != nil {
		return err
	}

	if storage.disableMultiDel {
		for i := range filelist {
			params := &s3.DeleteObjectInput{
				Bucket: aws.String(storage.bucket),
				Key:    aws.String(filepath.Join(storage.prefix, path, filelist[i])),
			}
			_, err := storage.s3.DeleteObject(params)
			if err != nil {
				return fmt.Errorf("error deleting path %s from %s: %s", filelist[i], storage, err)
			}
		}
	} else {
		numParts := (len(filelist) + page - 1) / page

		for i := 0; i < numParts; i++ {
			var part []string
			if i == numParts-1 {
				part = filelist[i*page:]
			} else {
				part = filelist[i*page : (i+1)*page]
			}
			paths := make([]*s3.ObjectIdentifier, len(part))

			for i := range part {
				paths[i] = &s3.ObjectIdentifier{
					Key: aws.String(filepath.Join(storage.prefix, path, part[i])),
				}
			}

			params := &s3.DeleteObjectsInput{
				Bucket: aws.String(storage.bucket),
				Delete: &s3.Delete{
					Objects: paths,
					Quiet:   aws.Bool(true),
				},
			}

			_, err := storage.s3.DeleteObjects(params)
			if err != nil {
				return fmt.Errorf("error deleting multiple paths from %s: %s", storage, err)
			}
		}
	}

	return nil
}

// LinkFromPool links package file from pool to dist's pool location
//
// publishedDirectory is desired location in pool (like prefix/pool/component/liba/libav/)
// sourcePool is instance of aptly.PackagePool
// sourcePath is filepath to package file in package pool
//
// LinkFromPool returns relative path for the published file to be included in package index
func (storage *PublishedStorage) LinkFromPool(publishedDirectory, baseName string, sourcePool aptly.PackagePool,
	sourcePath string, sourceChecksums utils.ChecksumInfo, force bool) error {

	relPath := filepath.Join(publishedDirectory, baseName)
	poolPath := filepath.Join(storage.prefix, relPath)

	if storage.pathCache == nil {
		paths, md5s, err := storage.internalFilelist("", true)
		if err != nil {
			return errors.Wrap(err, "error caching paths under prefix")
		}

		storage.pathCache = make(map[string]string, len(paths))

		for i := range paths {
			storage.pathCache[paths[i]] = md5s[i]
		}
	}

	destinationMD5, exists := storage.pathCache[relPath]
	sourceMD5 := sourceChecksums.MD5

	if exists {
		if sourceMD5 == "" {
			return fmt.Errorf("unable to compare object, MD5 checksum missing")
		}

		if destinationMD5 == sourceMD5 {
			return nil
		}

		if !force && destinationMD5 != sourceMD5 {
			return fmt.Errorf("error putting file to %s: file already exists and is different: %s", poolPath, storage)

		}
	}

	source, err := sourcePool.Open(sourcePath)
	if err != nil {
		return err
	}
	defer source.Close()

	err = storage.putFile(relPath, source)
	if err == nil {
		storage.pathCache[relPath] = sourceMD5
	} else {
		err = errors.Wrap(err, fmt.Sprintf("error uploading %s to %s: %s", sourcePath, storage, poolPath))
	}

	return err
}

// Filelist returns list of files under prefix
func (storage *PublishedStorage) Filelist(prefix string) ([]string, error) {
	paths, _, err := storage.internalFilelist(prefix, true)
	return paths, err
}

func (storage *PublishedStorage) internalFilelist(prefix string, hidePlusWorkaround bool) (paths []string, md5s []string, err error) {
	paths = make([]string, 0, 1024)
	md5s = make([]string, 0, 1024)
	prefix = filepath.Join(storage.prefix, prefix)
	if prefix != "" {
		prefix += "/"
	}

	params := &s3.ListObjectsInput{
		Bucket:  aws.String(storage.bucket),
		Prefix:  aws.String(prefix),
		MaxKeys: aws.Int64(1000),
	}

	err = storage.s3.ListObjectsPages(params, func(contents *s3.ListObjectsOutput, lastPage bool) bool {
		for _, key := range contents.Contents {
			if storage.plusWorkaround && hidePlusWorkaround && strings.Contains(*key.Key, " ") {
				// if we use plusWorkaround, we want to hide those duplicates
				/// from listing
				continue
			}

			if prefix == "" {
				paths = append(paths, *key.Key)
			} else {
				paths = append(paths, (*key.Key)[len(prefix):])
			}
			md5s = append(md5s, strings.Replace(*key.ETag, "\"", "", -1))
		}

		return true
	})

	if err != nil {
		return nil, nil, fmt.Errorf("error listing under prefix %s in %s: %s", prefix, storage, err)
	}

	return paths, md5s, nil
}

// RenameFile renames (moves) file
func (storage *PublishedStorage) RenameFile(oldName, newName string) error {
	source := fmt.Sprintf("/%s/%s", storage.bucket, filepath.Join(storage.prefix, oldName))

	params := &s3.CopyObjectInput{
		Bucket:     aws.String(storage.bucket),
		CopySource: aws.String(source),
		Key:        aws.String(filepath.Join(storage.prefix, newName)),
		ACL:        aws.String(storage.acl),
	}

	if storage.storageClass != "" {
		params.StorageClass = aws.String(storage.storageClass)
	}
	if storage.encryptionMethod != "" {
		params.ServerSideEncryption = aws.String(storage.encryptionMethod)
	}

	_, err := storage.s3.CopyObject(params)
	if err != nil {
		return fmt.Errorf("error copying %s -> %s in %s: %s", oldName, newName, storage, err)
	}

	return storage.Remove(oldName)
}

// SymLink creates a copy of src file and adds link information as meta data
func (storage *PublishedStorage) SymLink(src string, dst string) error {

	params := &s3.CopyObjectInput{
		Bucket:     aws.String(storage.bucket),
		CopySource: aws.String(filepath.Join(storage.prefix, src)),
		Key:        aws.String(filepath.Join(storage.prefix, dst)),
		ACL:        aws.String(storage.acl),
		Metadata: map[string]*string{
			"SymLink": aws.String(src),
		},
		MetadataDirective: aws.String("REPLACE"),
	}

	if storage.storageClass != "" {
		params.StorageClass = aws.String(storage.storageClass)
	}
	if storage.encryptionMethod != "" {
		params.ServerSideEncryption = aws.String(storage.encryptionMethod)
	}

	_, err := storage.s3.CopyObject(params)
	if err != nil {
		return fmt.Errorf("error symlinking %s -> %s in %s: %s", src, dst, storage, err)
	}

	return err
}

// HardLink using symlink functionality as hard links do not exist
func (storage *PublishedStorage) HardLink(src string, dst string) error {
	return storage.SymLink(src, dst)
}

// FileExists returns true if path exists
func (storage *PublishedStorage) FileExists(path string) (bool, error) {
	params := &s3.HeadObjectInput{
		Bucket: aws.String(storage.bucket),
		Key:    aws.String(filepath.Join(storage.prefix, path)),
	}
	_, err := storage.s3.HeadObject(params)
	if err != nil {
		aerr, ok := err.(awserr.Error)
		if ok && aerr.Code() == errCodeNotFound {
			return false, nil
		}

		return false, err
	}

	return true, nil
}

// ReadLink returns the symbolic link pointed to by path.
// This simply reads text file created with SymLink
func (storage *PublishedStorage) ReadLink(path string) (string, error) {
	params := &s3.HeadObjectInput{
		Bucket: aws.String(storage.bucket),
		Key:    aws.String(filepath.Join(storage.prefix, path)),
	}
	output, err := storage.s3.HeadObject(params)
	if err != nil {
		return "", err
	}

	return aws.StringValue(output.Metadata["SymLink"]), nil
}
<|endoftext|>


<commit_before>// Copyright 2013 Andreas Koch. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package console

import (
	"fmt"
	"io"
	"os"
)

const (
	LogLevelDebug = "Debug"
	LogLevelInfo  = "Info"
	LogLevelWarn  = "Warn"
	LogLevelError = "Error"
	LogLevelFatal = "Fatal"
)

func New() *ConsoleLogger {
	return &ConsoleLogger{
		output: os.Stdout,
	}
}

type ConsoleLogger struct {
	output io.Writer
}

func (logger *ConsoleLogger) SetOutput(w io.Writer) {
	logger.output = w
}

func (logger *ConsoleLogger) Debug(format string, v ...interface{}) {
	fmt.Fprintf(logger.output, fmt.Sprintf("[%s] %s\n", LogLevelDebug, format), v)
}

func (logger *ConsoleLogger) Info(format string, v ...interface{}) {
	fmt.Fprintf(logger.output, fmt.Sprintf("[%s] %s\n", LogLevelInfo, format), v)
}

func (logger *ConsoleLogger) Warn(format string, v ...interface{}) {
	fmt.Fprintf(logger.output, fmt.Sprintf("[%s] %s\n", LogLevelWarn, format), v)
}

func (logger *ConsoleLogger) Error(format string, v ...interface{}) {
	fmt.Fprintf(logger.output, fmt.Sprintf("[%s] %s\n", LogLevelError, format), v)
}

func (logger *ConsoleLogger) Fatal(format string, v ...interface{}) {
	fmt.Fprintf(logger.output, fmt.Sprintf("[%s] %s\n", LogLevelFatal, format), v)
}
<commit_msg>Changed the format of the console logger so that the log level is separated from the message to make the message more readable.<commit_after>// Copyright 2013 Andreas Koch. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package console

import (
	"fmt"
	"io"
	"os"
)

const (
	LogLevelDebug = "Debug"
	LogLevelInfo  = "Info"
	LogLevelWarn  = "Warn"
	LogLevelError = "Error"
	LogLevelFatal = "Fatal"
)

func New() *ConsoleLogger {
	return &ConsoleLogger{
		output: os.Stdout,
	}
}

type ConsoleLogger struct {
	output io.Writer
}

func (logger *ConsoleLogger) SetOutput(w io.Writer) {
	logger.output = w
}

func (logger *ConsoleLogger) Debug(format string, v ...interface{}) {
	fmt.Fprintf(logger.output, fmt.Sprintf("%s: \t%s\n", LogLevelDebug, format), v)
}

func (logger *ConsoleLogger) Info(format string, v ...interface{}) {
	fmt.Fprintf(logger.output, fmt.Sprintf("%s: \t%s\n", LogLevelInfo, format), v)
}

func (logger *ConsoleLogger) Warn(format string, v ...interface{}) {
	fmt.Fprintf(logger.output, fmt.Sprintf("%s: \t%s\n", LogLevelWarn, format), v)
}

func (logger *ConsoleLogger) Error(format string, v ...interface{}) {
	fmt.Fprintf(logger.output, fmt.Sprintf("%s: \t%s\n", LogLevelError, format), v)
}

func (logger *ConsoleLogger) Fatal(format string, v ...interface{}) {
	fmt.Fprintf(logger.output, fmt.Sprintf("%s: \t%s\n", LogLevelFatal, format), v)
}
<|endoftext|>


<commit_before>// Copyright 2012 The go-gl Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package gl

// #include "gl.h"
import "C"
import "unsafe"

// UniformLocation
//TODO

type UniformLocation int

func (location UniformLocation) Uniform1f(x float32) {
	C.glUniform1f(C.GLint(location), C.GLfloat(x))
}

func (location UniformLocation) Uniform2f(x float32, y float32) {
	C.glUniform2f(C.GLint(location), C.GLfloat(x), C.GLfloat(y))
}

func (location UniformLocation) Uniform3f(x float32, y float32, z float32) {
	C.glUniform3f(C.GLint(location), C.GLfloat(x), C.GLfloat(y), C.GLfloat(z))
}

func (location UniformLocation) Uniform1ui(x uint) {
	C.glUniform1ui(C.GLint(location), C.GLuint(x))
}
func (location UniformLocation) Uniform2ui(x uint, y uint) {
	C.glUniform2ui(C.GLint(location), C.GLuint(x), C.GLuint(y))
}

func (location UniformLocation) Uniform3ui(x uint, y uint, z uint) {
	C.glUniform3ui(C.GLint(location), C.GLuint(x), C.GLuint(y), C.GLuint(z))
}

func (location UniformLocation) Uniform4ui(x uint, y uint, z uint, w uint) {
	C.glUniform4ui(C.GLint(location), C.GLuint(x), C.GLuint(y), C.GLuint(z), C.GLuint(w))
}

func (location UniformLocation) Uniform1uiv(v ...uint32) {
	if len(v) < 1 {
		panic("Invalid array length - must be at least 1")
	}
	C.glUniform1uiv(C.GLint(location), C.GLsizei(len(v)), (*C.GLuint)((unsafe.Pointer)(&v[0])))
}

func (location UniformLocation) Uniform2uiv(v ...[2]uint32) {
	if len(v) < 1 {
		panic("Invalid array length - must be at least 1")
	}
	C.glUniform2uiv(C.GLint(location), C.GLsizei(len(v)), (*C.GLuint)((unsafe.Pointer)(&v[0])))
}

func (location UniformLocation) Uniform3uiv(v ...[3]uint32) {
	if len(v) < 1 {
		panic("Invalid array length - must be at least 1")
	}
	C.glUniform3uiv(C.GLint(location), C.GLsizei(len(v)), (*C.GLuint)((unsafe.Pointer)(&v[0])))
}

func (location UniformLocation) Uniform4uiv(v ...[4]uint32) {
	if len(v) < 1 {
		panic("Invalid array length - must be at least 1")
	}
	C.glUniform4uiv(C.GLint(location), C.GLsizei(len(v)), (*C.GLuint)((unsafe.Pointer)(&v[0])))
}

func (location UniformLocation) Uniform1fv(v ...float32) {
	if len(v) < 1 {
		panic("Invalid array length - must be at least 1")
	}
	C.glUniform1fv(C.GLint(location), C.GLsizei(len(v)), (*C.GLfloat)((unsafe.Pointer)(&v[0])))
}

func (location UniformLocation) Uniform1i(x int) {
	C.glUniform1i(C.GLint(location), C.GLint(x))
}

func (location UniformLocation) Uniform1iv(v ...int32) {
	if len(v) < 1 {
		panic("Invalid array length - must be at least 1")
	}
	C.glUniform1iv(C.GLint(location), C.GLsizei(len(v)), (*C.GLint)((unsafe.Pointer)(&v[0])))
}

func (location UniformLocation) Uniform2fv(v ...[2]float32) {
	if len(v) < 1 {
		panic("Invalid array length - must be at least 1")
	}
	C.glUniform2fv(C.GLint(location), C.GLsizei(len(v)), (*C.GLfloat)((unsafe.Pointer)(&v[0])))
}

func (location UniformLocation) Uniform2i(x int, y int) {
	C.glUniform2i(C.GLint(location), C.GLint(x), C.GLint(y))
}

func (location UniformLocation) Uniform2iv(v ...[2]int32) {
	if len(v) < 1 {
		panic("Invalid array length - must be at least 1")
	}
	C.glUniform2iv(C.GLint(location), C.GLsizei(len(v)), (*C.GLint)((unsafe.Pointer)(&v[0])))
}

func (location UniformLocation) Uniform3fv(v ...[3]float32) {
	if len(v) < 1 {
		panic("Invalid array length - must be at least 1")
	}
	C.glUniform3fv(C.GLint(location), C.GLsizei(len(v)), (*C.GLfloat)((unsafe.Pointer)(&v[0])))
}

func (location UniformLocation) Uniform3i(x int, y int, z int) {
	C.glUniform3i(C.GLint(location), C.GLint(x), C.GLint(y), C.GLint(z))
}

func (location UniformLocation) Uniform3iv(v ...[3]int32) {
	if len(v) < 1 {
		panic("Invalid array length - must be at least 1")
	}
	C.glUniform3iv(C.GLint(location), C.GLsizei(len(v)), (*C.GLint)((unsafe.Pointer)(&v[0])))
}

func (location UniformLocation) Uniform4f(x float32, y float32, z float32, w float32) {
	C.glUniform4f(C.GLint(location), C.GLfloat(x), C.GLfloat(y), C.GLfloat(z), C.GLfloat(w))
}

func (location UniformLocation) Uniform4fv(v ...[4]float32) {
	if len(v) < 1 {
		panic("Invalid array length - must be at least 1")
	}
	C.glUniform4fv(C.GLint(location), C.GLsizei(len(v)), (*C.GLfloat)((unsafe.Pointer)(&v[0])))
}

func (location UniformLocation) Uniform4i(x int, y int, z int, w int) {
	C.glUniform4i(C.GLint(location), C.GLint(x), C.GLint(y), C.GLint(z), C.GLint(w))
}

func (location UniformLocation) Uniform4iv(v ...[4]int32) {
	if len(v) < 1 {
		panic("Invalid array length - must be at least 1")
	}
	C.glUniform4iv(C.GLint(location), C.GLsizei(len(v)), (*C.GLint)((unsafe.Pointer)(&v[0])))
}

func (location UniformLocation) UniformMatrix2fv(transpose bool, list ...[4]float32) {
	if len(list) < 1 {
		panic("Invalid array length - must be at least 1")
	}
	C.glUniformMatrix2fv(C.GLint(location), C.GLsizei(len(list)), glBool(transpose), ((*C.GLfloat)((unsafe.Pointer)(&list[0]))))
}

func (location UniformLocation) UniformMatrix2f(transpose bool, matrix *[4]float32) {
	if matrix == nil {
		panic("Matrix is nil")
	}
	C.glUniformMatrix2fv(C.GLint(location), 1, glBool(transpose), ((*C.GLfloat)((unsafe.Pointer)(&matrix[0]))))
}

func (location UniformLocation) UniformMatrix3fv(transpose bool, list ...[9]float32) {
	if len(list) < 1 {
		panic("Invalid array length - must be at least 1")
	}
	C.glUniformMatrix3fv(C.GLint(location), C.GLsizei(len(list)), glBool(transpose), ((*C.GLfloat)((unsafe.Pointer)(&list[0]))))
}

func (location UniformLocation) UniformMatrix3f(transpose bool, matrix *[9]float32) {
	if matrix == nil {
		panic("Matrix is nil")
	}
	C.glUniformMatrix3fv(C.GLint(location), 1, glBool(transpose), ((*C.GLfloat)((unsafe.Pointer)(&matrix[0]))))
}

func (location UniformLocation) UniformMatrix4fv(transpose bool, list ...[16]float32) {
	if len(list) < 1 {
		panic("Invalid array length - must be at least 1")
	}
	C.glUniformMatrix4fv(C.GLint(location), C.GLsizei(len(list)), glBool(transpose), ((*C.GLfloat)((unsafe.Pointer)(&list[0]))))
}

func (location UniformLocation) UniformMatrix4f(transpose bool, matrix *[16]float32) {
	if matrix == nil {
		panic("Matrix is nil")
	}
	C.glUniformMatrix4fv(C.GLint(location), 1, glBool(transpose), ((*C.GLfloat)((unsafe.Pointer)(&matrix[0]))))
}

func (location UniformLocation) UniformMatrix2x3fv(transpose bool, list ...[6]float32) {
	if len(list) < 1 {
		panic("Invalid array length - must be at least 1")
	}
	C.glUniformMatrix2x3fv(C.GLint(location), C.GLsizei(len(list)), glBool(transpose), ((*C.GLfloat)((unsafe.Pointer)(&list[0]))))
}

func (location UniformLocation) UniformMatrix2x3f(transpose bool, matrix *[6]float32) {
	if matrix == nil {
		panic("Matrix is nil")
	}
	C.glUniformMatrix2x3fv(C.GLint(location), 1, glBool(transpose), ((*C.GLfloat)((unsafe.Pointer)(&matrix[0]))))
}

func (location UniformLocation) UniformMatrix3x2fv(transpose bool, list ...[6]float32) {
	if len(list) < 1 {
		panic("Invalid array length - must be at least 1")
	}
	C.glUniformMatrix3x2fv(C.GLint(location), C.GLsizei(len(list)), glBool(transpose), ((*C.GLfloat)((unsafe.Pointer)(&list[0]))))
}

func (location UniformLocation) UniformMatrix3x2f(transpose bool, matrix *[6]float32) {
	if matrix == nil {
		panic("Matrix is nil")
	}
	C.glUniformMatrix3x2fv(C.GLint(location), 1, glBool(transpose), ((*C.GLfloat)((unsafe.Pointer)(&matrix[0]))))
}

func (location UniformLocation) UniformMatrix2x4fv(transpose bool, list ...[8]float32) {
	if len(list) < 1 {
		panic("Invalid array length - must be at least 1")
	}
	C.glUniformMatrix2x4fv(C.GLint(location), C.GLsizei(len(list)), glBool(transpose), ((*C.GLfloat)((unsafe.Pointer)(&list[0]))))
}

func (location UniformLocation) UniformMatrix2x4f(transpose bool, matrix *[8]float32) {
	if matrix == nil {
		panic("Matrix is nil")
	}
	C.glUniformMatrix2x4fv(C.GLint(location), 1, glBool(transpose), ((*C.GLfloat)((unsafe.Pointer)(&matrix[0]))))
}

func (location UniformLocation) UniformMatrix4x2fv(transpose bool, list ...[8]float32) {
	if len(list) < 1 {
		panic("Invalid array length - must be at least 1")
	}
	C.glUniformMatrix4x2fv(C.GLint(location), C.GLsizei(len(list)), glBool(transpose), ((*C.GLfloat)((unsafe.Pointer)(&list[0]))))
}

func (location UniformLocation) UniformMatrix4x2f(transpose bool, matrix *[8]float32) {
	if matrix == nil {
		panic("Matrix is nil")
	}
	C.glUniformMatrix4x2fv(C.GLint(location), 1, glBool(transpose), ((*C.GLfloat)((unsafe.Pointer)(&matrix[0]))))
}

func (location UniformLocation) UniformMatrix3x4fv(transpose bool, list ...[12]float32) {
	if len(list) < 1 {
		panic("Invalid array length - must be at least 1")
	}
	C.glUniformMatrix3x4fv(C.GLint(location), C.GLsizei(len(list)), glBool(transpose), ((*C.GLfloat)((unsafe.Pointer)(&list[0]))))
}

func (location UniformLocation) UniformMatrix3x4f(transpose bool, matrix *[12]float32) {
	if matrix == nil {
		panic("Matrix is nil")
	}
	C.glUniformMatrix3x4fv(C.GLint(location), 1, glBool(transpose), ((*C.GLfloat)((unsafe.Pointer)(&matrix[0]))))
}

func (location UniformLocation) UniformMatrix4x3fv(transpose bool, list ...[12]float32) {
	if len(list) < 1 {
		panic("Invalid array length - must be at least 1")
	}
	C.glUniformMatrix4x3fv(C.GLint(location), C.GLsizei(len(list)), glBool(transpose), ((*C.GLfloat)((unsafe.Pointer)(&list[0]))))
}

func (location UniformLocation) UniformMatrix4x3f(transpose bool, matrix *[12]float32) {
	if matrix == nil {
		panic("Matrix is nil")
	}
	C.glUniformMatrix4x3fv(C.GLint(location), 1, glBool(transpose), ((*C.GLfloat)((unsafe.Pointer)(&matrix[0]))))
}
<commit_msg>Fixed the mess.<commit_after>// Copyright 2012 The go-gl Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package gl

// #include "gl.h"
import "C"
import "unsafe"

// UniformLocation
//TODO

type UniformLocation int

func (location UniformLocation) Uniform1f(x float32) {
	C.glUniform1f(C.GLint(location), C.GLfloat(x))
}

func (location UniformLocation) Uniform2f(x float32, y float32) {
	C.glUniform2f(C.GLint(location), C.GLfloat(x), C.GLfloat(y))
}

func (location UniformLocation) Uniform3f(x float32, y float32, z float32) {
	C.glUniform3f(C.GLint(location), C.GLfloat(x), C.GLfloat(y), C.GLfloat(z))
}

func (location UniformLocation) Uniform1fv(count int, v []float32) {
	if len(v) < 1 {
		panic("Invalid array length - must be at least 1")
	}
	C.glUniform1fv(C.GLint(location), C.GLsizei(count), (*C.GLfloat)(&v[0]))
}

func (location UniformLocation) Uniform1i(x int) {
	C.glUniform1i(C.GLint(location), C.GLint(x))
}

func (location UniformLocation) Uniform1iv(count int, v []int32) {
	if len(v) < 1 {
		panic("Invalid array length - must be at least 1")
	}
	C.glUniform1iv(C.GLint(location), C.GLsizei(count), (*C.GLint)(&v[0]))
}

func (location UniformLocation) Uniform2fv(count int, v []float32) {
	if len(v) < 1 {
		panic("Invalid array length - must be at least 1")
	}
	C.glUniform2fv(C.GLint(location), C.GLsizei(count), (*C.GLfloat)(&v[0]))
}

func (location UniformLocation) Uniform2i(x int, y int) {
	C.glUniform2i(C.GLint(location), C.GLint(x), C.GLint(y))
}

func (location UniformLocation) Uniform2iv(count int, v []int32) {
	if len(v) < 1 {
		panic("Invalid array length - must be at least 1")
	}
	C.glUniform2iv(C.GLint(location), C.GLsizei(count), (*C.GLint)(&v[0]))
}

func (location UniformLocation) Uniform3fv(count int, v []float32) {
	if len(v) < 1 {
		panic("Invalid array length - must be at least 1")
	}
	C.glUniform3fv(C.GLint(location), C.GLsizei(count), (*C.GLfloat)(&v[0]))
}

func (location UniformLocation) Uniform3i(x int, y int, z int) {
	C.glUniform3i(C.GLint(location), C.GLint(x), C.GLint(y), C.GLint(z))
}

func (location UniformLocation) Uniform3iv(count int, v []int32) {
	if len(v) < 1 {
		panic("Invalid array length - must be at least 1")
	}
	C.glUniform3iv(C.GLint(location), C.GLsizei(count), (*C.GLint)(&v[0]))
}

func (location UniformLocation) Uniform4f(x float32, y float32, z float32, w float32) {
	C.glUniform4f(C.GLint(location), C.GLfloat(x), C.GLfloat(y), C.GLfloat(z), C.GLfloat(w))
}

func (location UniformLocation) Uniform4fv(count int, v []float32) {
	if len(v) < 1 {
		panic("Invalid array length - must be at least 1")
	}
	C.glUniform4fv(C.GLint(location), C.GLsizei(count), (*C.GLfloat)(&v[0]))
}

func (location UniformLocation) Uniform4i(x int, y int, z int, w int) {
	C.glUniform4i(C.GLint(location), C.GLint(x), C.GLint(y), C.GLint(z), C.GLint(w))
}

func (location UniformLocation) Uniform4iv(count int, v []int32) {
	if len(v) < 1 {
		panic("Invalid array length - must be at least 1")
	}
	C.glUniform4iv(C.GLint(location), C.GLsizei(count), (*C.GLint)(&v[0]))
}

func (location UniformLocation) UniformMatrix2fv(transpose bool, list ...[4]float32) {
	if len(list) < 1 {
		panic("Invalid array length - must be at least 1")
	}
	C.glUniformMatrix2fv(C.GLint(location), C.GLsizei(len(list)), glBool(transpose), ((*C.GLfloat)((unsafe.Pointer)(&list[0]))))
}

func (location UniformLocation) UniformMatrix2f(transpose bool, matrix *[4]float32) {
	if matrix == nil {
		panic("Matrix is nil")
	}
	C.glUniformMatrix2fv(C.GLint(location), 1, glBool(transpose), ((*C.GLfloat)((unsafe.Pointer)(&matrix[0]))))
}

func (location UniformLocation) UniformMatrix3fv(transpose bool, list ...[9]float32) {
	if len(list) < 1 {
		panic("Invalid array length - must be at least 1")
	}
	C.glUniformMatrix3fv(C.GLint(location), C.GLsizei(len(list)), glBool(transpose), ((*C.GLfloat)((unsafe.Pointer)(&list[0]))))
}

func (location UniformLocation) UniformMatrix3f(transpose bool, matrix *[9]float32) {
	if matrix == nil {
		panic("Matrix is nil")
	}
	C.glUniformMatrix3fv(C.GLint(location), 1, glBool(transpose), ((*C.GLfloat)((unsafe.Pointer)(&matrix[0]))))
}

func (location UniformLocation) UniformMatrix4fv(transpose bool, list ...[16]float32) {
	if len(list) < 1 {
		panic("Invalid array length - must be at least 1")
	}
	C.glUniformMatrix4fv(C.GLint(location), C.GLsizei(len(list)), glBool(transpose), ((*C.GLfloat)((unsafe.Pointer)(&list[0]))))
}

func (location UniformLocation) UniformMatrix4f(transpose bool, matrix *[16]float32) {
	if matrix == nil {
		panic("Matrix is nil")
	}
	C.glUniformMatrix4fv(C.GLint(location), 1, glBool(transpose), ((*C.GLfloat)((unsafe.Pointer)(&matrix[0]))))
}

func (location UniformLocation) UniformMatrix2x3fv(transpose bool, list ...[6]float32) {
	if len(list) < 1 {
		panic("Invalid array length - must be at least 1")
	}
	C.glUniformMatrix2x3fv(C.GLint(location), C.GLsizei(len(list)), glBool(transpose), ((*C.GLfloat)((unsafe.Pointer)(&list[0]))))
}

func (location UniformLocation) UniformMatrix2x3f(transpose bool, matrix *[6]float32) {
	if matrix == nil {
		panic("Matrix is nil")
	}
	C.glUniformMatrix2x3fv(C.GLint(location), 1, glBool(transpose), ((*C.GLfloat)((unsafe.Pointer)(&matrix[0]))))
}

func (location UniformLocation) UniformMatrix3x2fv(transpose bool, list ...[6]float32) {
	if len(list) < 1 {
		panic("Invalid array length - must be at least 1")
	}
	C.glUniformMatrix3x2fv(C.GLint(location), C.GLsizei(len(list)), glBool(transpose), ((*C.GLfloat)((unsafe.Pointer)(&list[0]))))
}

func (location UniformLocation) UniformMatrix3x2f(transpose bool, matrix *[6]float32) {
	if matrix == nil {
		panic("Matrix is nil")
	}
	C.glUniformMatrix3x2fv(C.GLint(location), 1, glBool(transpose), ((*C.GLfloat)((unsafe.Pointer)(&matrix[0]))))
}

func (location UniformLocation) UniformMatrix2x4fv(transpose bool, list ...[8]float32) {
	if len(list) < 1 {
		panic("Invalid array length - must be at least 1")
	}
	C.glUniformMatrix2x4fv(C.GLint(location), C.GLsizei(len(list)), glBool(transpose), ((*C.GLfloat)((unsafe.Pointer)(&list[0]))))
}

func (location UniformLocation) UniformMatrix2x4f(transpose bool, matrix *[8]float32) {
	if matrix == nil {
		panic("Matrix is nil")
	}
	C.glUniformMatrix2x4fv(C.GLint(location), 1, glBool(transpose), ((*C.GLfloat)((unsafe.Pointer)(&matrix[0]))))
}

func (location UniformLocation) UniformMatrix4x2fv(transpose bool, list ...[8]float32) {
	if len(list) < 1 {
		panic("Invalid array length - must be at least 1")
	}
	C.glUniformMatrix4x2fv(C.GLint(location), C.GLsizei(len(list)), glBool(transpose), ((*C.GLfloat)((unsafe.Pointer)(&list[0]))))
}

func (location UniformLocation) UniformMatrix4x2f(transpose bool, matrix *[8]float32) {
	if matrix == nil {
		panic("Matrix is nil")
	}
	C.glUniformMatrix4x2fv(C.GLint(location), 1, glBool(transpose), ((*C.GLfloat)((unsafe.Pointer)(&matrix[0]))))
}

func (location UniformLocation) UniformMatrix3x4fv(transpose bool, list ...[12]float32) {
	if len(list) < 1 {
		panic("Invalid array length - must be at least 1")
	}
	C.glUniformMatrix3x4fv(C.GLint(location), C.GLsizei(len(list)), glBool(transpose), ((*C.GLfloat)((unsafe.Pointer)(&list[0]))))
}

func (location UniformLocation) UniformMatrix3x4f(transpose bool, matrix *[12]float32) {
	if matrix == nil {
		panic("Matrix is nil")
	}
	C.glUniformMatrix3x4fv(C.GLint(location), 1, glBool(transpose), ((*C.GLfloat)((unsafe.Pointer)(&matrix[0]))))
}

func (location UniformLocation) UniformMatrix4x3fv(transpose bool, list ...[12]float32) {
	if len(list) < 1 {
		panic("Invalid array length - must be at least 1")
	}
	C.glUniformMatrix4x3fv(C.GLint(location), C.GLsizei(len(list)), glBool(transpose), ((*C.GLfloat)((unsafe.Pointer)(&list[0]))))
}

func (location UniformLocation) UniformMatrix4x3f(transpose bool, matrix *[12]float32) {
	if matrix == nil {
		panic("Matrix is nil")
	}
	C.glUniformMatrix4x3fv(C.GLint(location), 1, glBool(transpose), ((*C.GLfloat)((unsafe.Pointer)(&matrix[0]))))
}
<|endoftext|>


<commit_before>package email

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"io/ioutil"
	"net/smtp"
	"path/filepath"
	"strings"
	"time"
)

const (
	server       = "localhost:25"
	nlgidsPrefix = "[NLgids] "
)

var (
	//to = []string{"ans@nlgids.london", "miek@miek.nl"}
	to   = []string{"miek@miek.nl"}
	from = "nlgids@nlgids.london"
)

func NewContact(subject string, body *bytes.Buffer) *Message {
	m := NewMessage(nlgidsPrefix+subject, body.String())
	m.From = from
	m.To = to
	return m
}

func NewBooking(subject string, body *bytes.Buffer) *Message {
	return nil
}

func NewInvoice(subject string, body *bytes.Buffer, pdfName string, pdf []byte) *Message {
	m := NewMessage(nlgidsPrefix+subject, body.String())
	m.From = from
	m.To = to
	m.AttachBytes(pdfName, pdf)
	return m
}

// Do sends an email message.
func (m *Message) Do() error { return Send(server, nil, m) }

// Everything below:

// Copyright 2012 Santiago Corredoira
// Distributed under a BSD-like license.

type Attachment struct {
	Filename string
	Data     []byte
	Inline   bool
}

type Message struct {
	From            string
	To              []string
	Cc              []string
	Bcc             []string
	ReplyTo         string
	Subject         string
	Body            string
	BodyContentType string
	Attachments     map[string]*Attachment
}

func (m *Message) attach(file string, inline bool) error {
	data, err := ioutil.ReadFile(file)
	if err != nil {
		return err
	}
	m.attachBytes(file, data, inline)
	return nil
}

func (m *Message) attachBytes(file string, data []byte, inline bool) {
	_, filename := filepath.Split(file)

	m.Attachments[filename] = &Attachment{
		Filename: filename,
		Data:     data,
		Inline:   inline,
	}
}

func (m *Message) AttachBytes(file string, data []byte) {
	m.attachBytes(file, data, false)
}

func (m *Message) InlineBytes(file string, data []byte) {
	m.attachBytes(file, data, true)
}

func (m *Message) Attach(file string) error {
	return m.attach(file, false)
}

func (m *Message) Inline(file string) error {
	return m.attach(file, true)
}

func newMessage(subject string, body string, bodyContentType string) *Message {
	m := &Message{Subject: subject, Body: body, BodyContentType: bodyContentType}

	m.Attachments = make(map[string]*Attachment)

	return m
}

// NewMessage returns a new Message that can compose an email with attachments
func NewMessage(subject string, body string) *Message {
	return newMessage(subject, body, "text/plain")
}

// NewMessage returns a new Message that can compose an HTML email with attachments
func NewHTMLMessage(subject string, body string) *Message {
	return newMessage(subject, body, "text/html")
}

// ToList returns all the recipients of the email
func (m *Message) Tolist() []string {
	tolist := m.To

	for _, cc := range m.Cc {
		tolist = append(tolist, cc)
	}

	for _, bcc := range m.Bcc {
		tolist = append(tolist, bcc)
	}

	return tolist
}

// Bytes returns the mail data
func (m *Message) Bytes() []byte {
	buf := bytes.NewBuffer(nil)

	buf.WriteString("From: " + m.From + "\r\n")

	t := time.Now()
	buf.WriteString("Date: " + t.Format(time.RFC822) + "\r\n")

	buf.WriteString("To: " + strings.Join(m.To, ",") + "\r\n")
	if len(m.Cc) > 0 {
		buf.WriteString("Cc: " + strings.Join(m.Cc, ",") + "\r\n")
	}

	buf.WriteString("Subject: " + m.Subject + "\r\n")

	if len(m.ReplyTo) > 0 {
		buf.WriteString("Reply-To: " + m.ReplyTo + "\r\n")
	}

	buf.WriteString("MIME-Version: 1.0\r\n")

	boundary := "f46d043c813270fc6b04c2d223da"

	if len(m.Attachments) > 0 {
		buf.WriteString("Content-Type: multipart/mixed; boundary=" + boundary + "\r\n")
		buf.WriteString("--" + boundary + "\r\n")
	}

	buf.WriteString(fmt.Sprintf("Content-Type: %s; charset=utf-8\r\n\r\n", m.BodyContentType))
	buf.WriteString(m.Body)
	buf.WriteString("\r\n")

	if len(m.Attachments) > 0 {
		for _, attachment := range m.Attachments {
			buf.WriteString("\r\n\r\n--" + boundary + "\r\n")

			if attachment.Inline {
				buf.WriteString("Content-Type: message/rfc822\r\n")
				buf.WriteString("Content-Disposition: inline; filename=\"" + attachment.Filename + "\"\r\n\r\n")

				buf.Write(attachment.Data)
			} else {
				buf.WriteString("Content-Type: application/octet-stream\r\n")
				buf.WriteString("Content-Transfer-Encoding: base64\r\n")
				buf.WriteString("Content-Disposition: attachment; filename=\"" + attachment.Filename + "\"\r\n\r\n")

				b := make([]byte, base64.StdEncoding.EncodedLen(len(attachment.Data)))
				base64.StdEncoding.Encode(b, attachment.Data)

				// write base64 content in lines of up to 76 chars
				for i, l := 0, len(b); i < l; i++ {
					buf.WriteByte(b[i])
					if (i+1)%76 == 0 {
						buf.WriteString("\r\n")
					}
				}
			}

			buf.WriteString("\r\n--" + boundary)
		}

		buf.WriteString("--")
	}

	return buf.Bytes()
}

func Send(addr string, auth smtp.Auth, m *Message) error {
	return smtp.SendMail(addr, auth, m.From, m.Tolist(), m.Bytes())
}
<commit_msg>another from address<commit_after>package email

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"io/ioutil"
	"net/smtp"
	"path/filepath"
	"strings"
	"time"
)

const (
	server       = "localhost:25"
	nlgidsPrefix = "[NLgids] "
)

var (
	//to = []string{"ans@nlgids.london", "miek@miek.nl"}
	to   = []string{"miek@miek.nl"}
	from = "nlgids@x64.atoom.net"
)

func NewContact(subject string, body *bytes.Buffer) *Message {
	m := NewMessage(nlgidsPrefix+subject, body.String())
	m.From = from
	m.To = to
	return m
}

func NewBooking(subject string, body *bytes.Buffer) *Message {
	return nil
}

func NewInvoice(subject string, body *bytes.Buffer, pdfName string, pdf []byte) *Message {
	m := NewMessage(nlgidsPrefix+subject, body.String())
	m.From = from
	m.To = to
	m.AttachBytes(pdfName, pdf)
	return m
}

// Do sends an email message.
func (m *Message) Do() error { return Send(server, nil, m) }

// Everything below:

// Copyright 2012 Santiago Corredoira
// Distributed under a BSD-like license.

type Attachment struct {
	Filename string
	Data     []byte
	Inline   bool
}

type Message struct {
	From            string
	To              []string
	Cc              []string
	Bcc             []string
	ReplyTo         string
	Subject         string
	Body            string
	BodyContentType string
	Attachments     map[string]*Attachment
}

func (m *Message) attach(file string, inline bool) error {
	data, err := ioutil.ReadFile(file)
	if err != nil {
		return err
	}
	m.attachBytes(file, data, inline)
	return nil
}

func (m *Message) attachBytes(file string, data []byte, inline bool) {
	_, filename := filepath.Split(file)

	m.Attachments[filename] = &Attachment{
		Filename: filename,
		Data:     data,
		Inline:   inline,
	}
}

func (m *Message) AttachBytes(file string, data []byte) {
	m.attachBytes(file, data, false)
}

func (m *Message) InlineBytes(file string, data []byte) {
	m.attachBytes(file, data, true)
}

func (m *Message) Attach(file string) error {
	return m.attach(file, false)
}

func (m *Message) Inline(file string) error {
	return m.attach(file, true)
}

func newMessage(subject string, body string, bodyContentType string) *Message {
	m := &Message{Subject: subject, Body: body, BodyContentType: bodyContentType}

	m.Attachments = make(map[string]*Attachment)

	return m
}

// NewMessage returns a new Message that can compose an email with attachments
func NewMessage(subject string, body string) *Message {
	return newMessage(subject, body, "text/plain")
}

// NewMessage returns a new Message that can compose an HTML email with attachments
func NewHTMLMessage(subject string, body string) *Message {
	return newMessage(subject, body, "text/html")
}

// ToList returns all the recipients of the email
func (m *Message) Tolist() []string {
	tolist := m.To

	for _, cc := range m.Cc {
		tolist = append(tolist, cc)
	}

	for _, bcc := range m.Bcc {
		tolist = append(tolist, bcc)
	}

	return tolist
}

// Bytes returns the mail data
func (m *Message) Bytes() []byte {
	buf := bytes.NewBuffer(nil)

	buf.WriteString("From: " + m.From + "\r\n")

	t := time.Now()
	buf.WriteString("Date: " + t.Format(time.RFC822) + "\r\n")

	buf.WriteString("To: " + strings.Join(m.To, ",") + "\r\n")
	if len(m.Cc) > 0 {
		buf.WriteString("Cc: " + strings.Join(m.Cc, ",") + "\r\n")
	}

	buf.WriteString("Subject: " + m.Subject + "\r\n")

	if len(m.ReplyTo) > 0 {
		buf.WriteString("Reply-To: " + m.ReplyTo + "\r\n")
	}

	buf.WriteString("MIME-Version: 1.0\r\n")

	boundary := "f46d043c813270fc6b04c2d223da"

	if len(m.Attachments) > 0 {
		buf.WriteString("Content-Type: multipart/mixed; boundary=" + boundary + "\r\n")
		buf.WriteString("--" + boundary + "\r\n")
	}

	buf.WriteString(fmt.Sprintf("Content-Type: %s; charset=utf-8\r\n\r\n", m.BodyContentType))
	buf.WriteString(m.Body)
	buf.WriteString("\r\n")

	if len(m.Attachments) > 0 {
		for _, attachment := range m.Attachments {
			buf.WriteString("\r\n\r\n--" + boundary + "\r\n")

			if attachment.Inline {
				buf.WriteString("Content-Type: message/rfc822\r\n")
				buf.WriteString("Content-Disposition: inline; filename=\"" + attachment.Filename + "\"\r\n\r\n")

				buf.Write(attachment.Data)
			} else {
				buf.WriteString("Content-Type: application/octet-stream\r\n")
				buf.WriteString("Content-Transfer-Encoding: base64\r\n")
				buf.WriteString("Content-Disposition: attachment; filename=\"" + attachment.Filename + "\"\r\n\r\n")

				b := make([]byte, base64.StdEncoding.EncodedLen(len(attachment.Data)))
				base64.StdEncoding.Encode(b, attachment.Data)

				// write base64 content in lines of up to 76 chars
				for i, l := 0, len(b); i < l; i++ {
					buf.WriteByte(b[i])
					if (i+1)%76 == 0 {
						buf.WriteString("\r\n")
					}
				}
			}

			buf.WriteString("\r\n--" + boundary)
		}

		buf.WriteString("--")
	}

	return buf.Bytes()
}

func Send(addr string, auth smtp.Auth, m *Message) error {
	return smtp.SendMail(addr, auth, m.From, m.Tolist(), m.Bytes())
}
<|endoftext|>


<commit_before>package registry

import (
	"crypto/tls"
	"crypto/x509"
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"path"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/docker/docker/autogen/dockerversion"
	"github.com/docker/docker/pkg/parsers/kernel"
	"github.com/docker/docker/pkg/timeoutconn"
	"github.com/docker/docker/pkg/transport"
	"github.com/docker/docker/pkg/useragent"
)

var (
	ErrAlreadyExists = errors.New("Image already exists")
	ErrDoesNotExist  = errors.New("Image does not exist")
	errLoginRequired = errors.New("Authentication is required.")
)

type TimeoutType uint32

const (
	NoTimeout TimeoutType = iota
	ReceiveTimeout
	ConnectTimeout
)

// dockerUserAgent is the User-Agent the Docker client uses to identify itself.
// It is populated on init(), comprising version information of different components.
var dockerUserAgent string

func init() {
	httpVersion := make([]useragent.VersionInfo, 0, 6)
	httpVersion = append(httpVersion, useragent.VersionInfo{"docker", dockerversion.VERSION})
	httpVersion = append(httpVersion, useragent.VersionInfo{"go", runtime.Version()})
	httpVersion = append(httpVersion, useragent.VersionInfo{"git-commit", dockerversion.GITCOMMIT})
	if kernelVersion, err := kernel.GetKernelVersion(); err == nil {
		httpVersion = append(httpVersion, useragent.VersionInfo{"kernel", kernelVersion.String()})
	}
	httpVersion = append(httpVersion, useragent.VersionInfo{"os", runtime.GOOS})
	httpVersion = append(httpVersion, useragent.VersionInfo{"arch", runtime.GOARCH})

	dockerUserAgent = useragent.AppendVersions("", httpVersion...)
}

type httpsRequestModifier struct {
	mu        sync.Mutex
	tlsConfig *tls.Config
}

// DRAGONS(tiborvass): If someone wonders why do we set tlsconfig in a roundtrip,
// it's because it's so as to match the current behavior in master: we generate the
// certpool on every-goddam-request. It's not great, but it allows people to just put
// the certs in /etc/docker/certs.d/.../ and let docker "pick it up" immediately. Would
// prefer an fsnotify implementation, but that was out of scope of my refactoring.
func (m *httpsRequestModifier) ModifyRequest(req *http.Request) error {
	var (
		roots   *x509.CertPool
		certs   []tls.Certificate
		hostDir string
	)

	if req.URL.Scheme == "https" {
		hasFile := func(files []os.FileInfo, name string) bool {
			for _, f := range files {
				if f.Name() == name {
					return true
				}
			}
			return false
		}

		if runtime.GOOS == "windows" {
			hostDir = path.Join(os.TempDir(), "/docker/certs.d", req.URL.Host)
		} else {
			hostDir = path.Join("/etc/docker/certs.d", req.URL.Host)
		}
		logrus.Debugf("hostDir: %s", hostDir)
		fs, err := ioutil.ReadDir(hostDir)
		if err != nil && !os.IsNotExist(err) {
			return nil
		}

		for _, f := range fs {
			if strings.HasSuffix(f.Name(), ".crt") {
				if roots == nil {
					roots = x509.NewCertPool()
				}
				logrus.Debugf("crt: %s", hostDir+"/"+f.Name())
				data, err := ioutil.ReadFile(filepath.Join(hostDir, f.Name()))
				if err != nil {
					return err
				}
				roots.AppendCertsFromPEM(data)
			}
			if strings.HasSuffix(f.Name(), ".cert") {
				certName := f.Name()
				keyName := certName[:len(certName)-5] + ".key"
				logrus.Debugf("cert: %s", hostDir+"/"+f.Name())
				if !hasFile(fs, keyName) {
					return fmt.Errorf("Missing key %s for certificate %s", keyName, certName)
				}
				cert, err := tls.LoadX509KeyPair(filepath.Join(hostDir, certName), path.Join(hostDir, keyName))
				if err != nil {
					return err
				}
				certs = append(certs, cert)
			}
			if strings.HasSuffix(f.Name(), ".key") {
				keyName := f.Name()
				certName := keyName[:len(keyName)-4] + ".cert"
				logrus.Debugf("key: %s", hostDir+"/"+f.Name())
				if !hasFile(fs, certName) {
					return fmt.Errorf("Missing certificate %s for key %s", certName, keyName)
				}
			}
		}
		m.mu.Lock()
		m.tlsConfig.RootCAs = roots
		m.tlsConfig.Certificates = certs
		m.mu.Unlock()
	}
	return nil
}

func NewTransport(timeout TimeoutType, secure bool) http.RoundTripper {
	tlsConfig := &tls.Config{
		// Avoid fallback to SSL protocols < TLS1.0
		MinVersion:         tls.VersionTLS10,
		InsecureSkipVerify: !secure,
	}

	tr := &http.Transport{
		DisableKeepAlives: true,
		Proxy:             http.ProxyFromEnvironment,
		TLSClientConfig:   tlsConfig,
	}

	switch timeout {
	case ConnectTimeout:
		tr.Dial = func(proto string, addr string) (net.Conn, error) {
			// Set the connect timeout to 30 seconds to allow for slower connection
			// times...
			d := net.Dialer{Timeout: 30 * time.Second, DualStack: true}

			conn, err := d.Dial(proto, addr)
			if err != nil {
				return nil, err
			}
			// Set the recv timeout to 10 seconds
			conn.SetDeadline(time.Now().Add(10 * time.Second))
			return conn, nil
		}
	case ReceiveTimeout:
		tr.Dial = func(proto string, addr string) (net.Conn, error) {
			d := net.Dialer{DualStack: true}

			conn, err := d.Dial(proto, addr)
			if err != nil {
				return nil, err
			}
			conn = timeoutconn.New(conn, 1*time.Minute)
			return conn, nil
		}
	}

	if secure {
		// note: httpsTransport also handles http transport
		// but for HTTPS, it sets up the certs
		return transport.NewTransport(tr, &httpsRequestModifier{tlsConfig: tlsConfig})
	}

	return tr
}

// DockerHeaders returns request modifiers that ensure requests have
// the User-Agent header set to dockerUserAgent and that metaHeaders
// are added.
func DockerHeaders(metaHeaders http.Header) []transport.RequestModifier {
	modifiers := []transport.RequestModifier{
		transport.NewHeaderRequestModifier(http.Header{"User-Agent": []string{dockerUserAgent}}),
	}
	if metaHeaders != nil {
		modifiers = append(modifiers, transport.NewHeaderRequestModifier(metaHeaders))
	}
	return modifiers
}

func HTTPClient(transport http.RoundTripper) *http.Client {
	if transport == nil {
		transport = NewTransport(ConnectTimeout, true)
	}

	return &http.Client{
		Transport:     transport,
		CheckRedirect: AddRequiredHeadersToRedirectedRequests,
	}
}

func trustedLocation(req *http.Request) bool {
	var (
		trusteds = []string{"docker.com", "docker.io"}
		hostname = strings.SplitN(req.Host, ":", 2)[0]
	)
	if req.URL.Scheme != "https" {
		return false
	}

	for _, trusted := range trusteds {
		if hostname == trusted || strings.HasSuffix(hostname, "."+trusted) {
			return true
		}
	}
	return false
}

func AddRequiredHeadersToRedirectedRequests(req *http.Request, via []*http.Request) error {
	if via != nil && via[0] != nil {
		if trustedLocation(req) && trustedLocation(via[0]) {
			req.Header = via[0].Header
			return nil
		}
		for k, v := range via[0].Header {
			if k != "Authorization" {
				for _, vv := range v {
					req.Header.Add(k, vv)
				}
			}
		}
	}
	return nil
}
<commit_msg>Remove RC4 from the list of registry cipher suites<commit_after>package registry

import (
	"crypto/tls"
	"crypto/x509"
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"path"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/docker/docker/autogen/dockerversion"
	"github.com/docker/docker/pkg/parsers/kernel"
	"github.com/docker/docker/pkg/timeoutconn"
	"github.com/docker/docker/pkg/tlsconfig"
	"github.com/docker/docker/pkg/transport"
	"github.com/docker/docker/pkg/useragent"
)

var (
	ErrAlreadyExists = errors.New("Image already exists")
	ErrDoesNotExist  = errors.New("Image does not exist")
	errLoginRequired = errors.New("Authentication is required.")
)

type TimeoutType uint32

const (
	NoTimeout TimeoutType = iota
	ReceiveTimeout
	ConnectTimeout
)

// dockerUserAgent is the User-Agent the Docker client uses to identify itself.
// It is populated on init(), comprising version information of different components.
var dockerUserAgent string

func init() {
	httpVersion := make([]useragent.VersionInfo, 0, 6)
	httpVersion = append(httpVersion, useragent.VersionInfo{"docker", dockerversion.VERSION})
	httpVersion = append(httpVersion, useragent.VersionInfo{"go", runtime.Version()})
	httpVersion = append(httpVersion, useragent.VersionInfo{"git-commit", dockerversion.GITCOMMIT})
	if kernelVersion, err := kernel.GetKernelVersion(); err == nil {
		httpVersion = append(httpVersion, useragent.VersionInfo{"kernel", kernelVersion.String()})
	}
	httpVersion = append(httpVersion, useragent.VersionInfo{"os", runtime.GOOS})
	httpVersion = append(httpVersion, useragent.VersionInfo{"arch", runtime.GOARCH})

	dockerUserAgent = useragent.AppendVersions("", httpVersion...)
}

type httpsRequestModifier struct {
	mu        sync.Mutex
	tlsConfig *tls.Config
}

// DRAGONS(tiborvass): If someone wonders why do we set tlsconfig in a roundtrip,
// it's because it's so as to match the current behavior in master: we generate the
// certpool on every-goddam-request. It's not great, but it allows people to just put
// the certs in /etc/docker/certs.d/.../ and let docker "pick it up" immediately. Would
// prefer an fsnotify implementation, but that was out of scope of my refactoring.
func (m *httpsRequestModifier) ModifyRequest(req *http.Request) error {
	var (
		roots   *x509.CertPool
		certs   []tls.Certificate
		hostDir string
	)

	if req.URL.Scheme == "https" {
		hasFile := func(files []os.FileInfo, name string) bool {
			for _, f := range files {
				if f.Name() == name {
					return true
				}
			}
			return false
		}

		if runtime.GOOS == "windows" {
			hostDir = path.Join(os.TempDir(), "/docker/certs.d", req.URL.Host)
		} else {
			hostDir = path.Join("/etc/docker/certs.d", req.URL.Host)
		}
		logrus.Debugf("hostDir: %s", hostDir)
		fs, err := ioutil.ReadDir(hostDir)
		if err != nil && !os.IsNotExist(err) {
			return nil
		}

		for _, f := range fs {
			if strings.HasSuffix(f.Name(), ".crt") {
				if roots == nil {
					roots = x509.NewCertPool()
				}
				logrus.Debugf("crt: %s", hostDir+"/"+f.Name())
				data, err := ioutil.ReadFile(filepath.Join(hostDir, f.Name()))
				if err != nil {
					return err
				}
				roots.AppendCertsFromPEM(data)
			}
			if strings.HasSuffix(f.Name(), ".cert") {
				certName := f.Name()
				keyName := certName[:len(certName)-5] + ".key"
				logrus.Debugf("cert: %s", hostDir+"/"+f.Name())
				if !hasFile(fs, keyName) {
					return fmt.Errorf("Missing key %s for certificate %s", keyName, certName)
				}
				cert, err := tls.LoadX509KeyPair(filepath.Join(hostDir, certName), path.Join(hostDir, keyName))
				if err != nil {
					return err
				}
				certs = append(certs, cert)
			}
			if strings.HasSuffix(f.Name(), ".key") {
				keyName := f.Name()
				certName := keyName[:len(keyName)-4] + ".cert"
				logrus.Debugf("key: %s", hostDir+"/"+f.Name())
				if !hasFile(fs, certName) {
					return fmt.Errorf("Missing certificate %s for key %s", certName, keyName)
				}
			}
		}
		m.mu.Lock()
		m.tlsConfig.RootCAs = roots
		m.tlsConfig.Certificates = certs
		m.mu.Unlock()
	}
	return nil
}

func NewTransport(timeout TimeoutType, secure bool) http.RoundTripper {
	tlsConfig := &tls.Config{
		// Avoid fallback to SSL protocols < TLS1.0
		MinVersion:         tls.VersionTLS10,
		InsecureSkipVerify: !secure,
		CipherSuites:       tlsconfig.DefaultServerAcceptedCiphers,
	}

	tr := &http.Transport{
		DisableKeepAlives: true,
		Proxy:             http.ProxyFromEnvironment,
		TLSClientConfig:   tlsConfig,
	}

	switch timeout {
	case ConnectTimeout:
		tr.Dial = func(proto string, addr string) (net.Conn, error) {
			// Set the connect timeout to 30 seconds to allow for slower connection
			// times...
			d := net.Dialer{Timeout: 30 * time.Second, DualStack: true}

			conn, err := d.Dial(proto, addr)
			if err != nil {
				return nil, err
			}
			// Set the recv timeout to 10 seconds
			conn.SetDeadline(time.Now().Add(10 * time.Second))
			return conn, nil
		}
	case ReceiveTimeout:
		tr.Dial = func(proto string, addr string) (net.Conn, error) {
			d := net.Dialer{DualStack: true}

			conn, err := d.Dial(proto, addr)
			if err != nil {
				return nil, err
			}
			conn = timeoutconn.New(conn, 1*time.Minute)
			return conn, nil
		}
	}

	if secure {
		// note: httpsTransport also handles http transport
		// but for HTTPS, it sets up the certs
		return transport.NewTransport(tr, &httpsRequestModifier{tlsConfig: tlsConfig})
	}

	return tr
}

// DockerHeaders returns request modifiers that ensure requests have
// the User-Agent header set to dockerUserAgent and that metaHeaders
// are added.
func DockerHeaders(metaHeaders http.Header) []transport.RequestModifier {
	modifiers := []transport.RequestModifier{
		transport.NewHeaderRequestModifier(http.Header{"User-Agent": []string{dockerUserAgent}}),
	}
	if metaHeaders != nil {
		modifiers = append(modifiers, transport.NewHeaderRequestModifier(metaHeaders))
	}
	return modifiers
}

func HTTPClient(transport http.RoundTripper) *http.Client {
	if transport == nil {
		transport = NewTransport(ConnectTimeout, true)
	}

	return &http.Client{
		Transport:     transport,
		CheckRedirect: AddRequiredHeadersToRedirectedRequests,
	}
}

func trustedLocation(req *http.Request) bool {
	var (
		trusteds = []string{"docker.com", "docker.io"}
		hostname = strings.SplitN(req.Host, ":", 2)[0]
	)
	if req.URL.Scheme != "https" {
		return false
	}

	for _, trusted := range trusteds {
		if hostname == trusted || strings.HasSuffix(hostname, "."+trusted) {
			return true
		}
	}
	return false
}

func AddRequiredHeadersToRedirectedRequests(req *http.Request, via []*http.Request) error {
	if via != nil && via[0] != nil {
		if trustedLocation(req) && trustedLocation(via[0]) {
			req.Header = via[0].Header
			return nil
		}
		for k, v := range via[0].Header {
			if k != "Authorization" {
				for _, vv := range v {
					req.Header.Add(k, vv)
				}
			}
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package tests_test

import (
	"io"
	"os/exec"
	"strings"
	"time"

	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	"kubevirt.io/client-go/kubecli"

	"kubevirt.io/kubevirt/tests"

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

const (
	// Define relevant k8s versions
	relevantk8sVer = "1.16.2"

	// Define a timeout for read opeartions in order to prevent test hanging
	readTimeout     = 1 * time.Minute
	processWaitTime = 10 * time.Second

	bufferSize = 1024
)

var _ = Describe("[rfe_id:3423][crit:high][vendor:cnv-qe@redhat.com][level:component]VmWatch", func() {
	tests.FlagParse()

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

	type vmStatus struct {
		name,
		age,
		running,
		volume string
	}

	type vmiStatus struct {
		name,
		age,
		phase,
		ip,
		node string
	}

	newVMStatus := func(fields []string) *vmStatus {
		flen := len(fields)
		stat := &vmStatus{}

		switch {
		case flen > 3:
			stat.volume = fields[3]
			fallthrough
		case flen > 2:
			stat.running = fields[2]
			fallthrough
		case flen > 1:
			stat.age = fields[1]
			fallthrough
		case flen > 0:
			stat.name = fields[0]
		}

		return stat
	}

	newVMIStatus := func(fields []string) *vmiStatus {
		flen := len(fields)
		stat := &vmiStatus{}

		switch {
		case flen > 4:
			stat.node = fields[4]
			fallthrough
		case flen > 3:
			stat.ip = fields[3]
			fallthrough
		case flen > 2:
			stat.phase = fields[2]
			fallthrough
		case flen > 1:
			stat.age = fields[1]
			fallthrough
		case flen > 0:
			stat.name = fields[0]
		}

		return stat
	}

	// Fail the test if stderr has something to read
	failOnError := func(rc io.ReadCloser) {
		defer GinkgoRecover()

		buf := make([]byte, bufferSize)

		n, err := rc.Read(buf)

		if err != nil && n > 0 {
			rc.Close()
			Fail(string(buf[:n]))
		}
	}

	// Reads from stdin until a newline character is found
	readLine := func(rc io.ReadCloser, timeout time.Duration) string {
		lineChan := make(chan string)

		go func() {
			defer GinkgoRecover()

			var line strings.Builder
			buf := make([]byte, 1)
			defer close(lineChan)

			for {
				n, err := rc.Read(buf)

				if err != nil && err != io.EOF && !strings.Contains(err.Error(), "file already closed") {
					Fail(err.Error())
					return
				}

				if n > 0 {
					if buf[0] != '\n' {
						line.WriteByte(buf[0])
					} else {
						break
					}
				}
			}

			lineChan <- line.String()
		}()

		select {
		case line := <-lineChan:
			return line
		case <-time.After(timeout):
			err := rc.Close()
			Expect(err).ToNot(HaveOccurred(), "stdout should have been closed properly")

			Fail("Timeout reached on read operation")

			return ""
		}
	}

	// Reads VM status from the given pipe (stdin in this case) and
	// returns a new status.
	// if old_status is non-nil, the function will read status lines until
	// new_status.running != old_status.running in order to skip duplicated status lines
	readVMStatus := func(rc io.ReadCloser, old_status *vmStatus, timeout time.Duration) *vmStatus {
		new_stat := newVMStatus(strings.Fields(readLine(rc, timeout)))

		for old_status != nil && new_stat.running == old_status.running {
			new_stat = newVMStatus(strings.Fields(readLine(rc, timeout)))
		}

		return new_stat
	}

	// Reads VMI status from the given pipe (stdin in this case) and
	// returns a new status.
	// if old_status is non-nil, the function will read status lines until
	// new_status.phase != old_status.phase in order to skip duplicated lines
	readVMIStatus := func(rc io.ReadCloser, old_status *vmiStatus, timeout time.Duration) *vmiStatus {
		newStat := newVMIStatus(strings.Fields(readLine(rc, timeout)))

		for old_status != nil && newStat.phase == old_status.phase {
			newStat = newVMIStatus(strings.Fields(readLine(rc, timeout)))
		}

		return newStat
	}

	// Create a command with output/error redirection.
	// Returns (cmd, stdout, stderr)
	createCommandWithNSAndRedirect := func(namespace, cmdName string, args ...string) (*exec.Cmd, io.ReadCloser, io.ReadCloser) {
		cmdName, cmd, err := tests.CreateCommandWithNS(namespace, cmdName, args...)

		Expect(cmdName).ToNot(Equal(""))
		Expect(cmd).ToNot(BeNil())
		Expect(err).ToNot(HaveOccurred(), "Command should have been created with proper kubectl/oc arguments")

		// Output redirection
		stdOut, err := cmd.StdoutPipe()
		Expect(err).ToNot(HaveOccurred(), "stdout should have been redirected")
		Expect(stdOut).ToNot(BeNil())

		stdErr, err := cmd.StderrPipe()
		Expect(err).ToNot(HaveOccurred(), "stderr should have been redirected")
		Expect(stdErr).ToNot(BeNil())

		return cmd, stdOut, stdErr
	}

	BeforeEach(func() {
		tests.SkipIfVersionBelow("Printing format for `kubectl get -w` on custom resources is only relevant for 1.16.2+", relevantk8sVer)
	})

	It("[test_id:3468]Should update vm status with the proper columns using 'kubectl get vm -w'", func() {
		By("Creating a new VM spec")
		vm := tests.NewRandomVMWithEphemeralDisk(tests.ContainerDiskFor(tests.ContainerDiskCirros))
		Expect(vm).ToNot(BeNil())

		By("Setting up the kubectl command")
		cmd, stdout, stderr :=
			createCommandWithNSAndRedirect(vm.ObjectMeta.Namespace, tests.GetK8sCmdClient(), "get", "vm", "-w")
		Expect(cmd).ToNot(BeNil())

		err = cmd.Start()
		Expect(err).ToNot(HaveOccurred(), "Command should have started successfully")

		defer cmd.Process.Kill()

		time.Sleep(processWaitTime)

		go failOnError(stderr)

		By("Applying the VM to the cluster")
		vm, err := virtCli.VirtualMachine(vm.ObjectMeta.Namespace).Create(vm)
		Expect(err).ToNot(HaveOccurred(), "VM should have been added to the cluster")

		// Read column titles
		vmStatus := readVMStatus(stdout, nil, readTimeout)
		Expect(vmStatus.name).To(Equal("NAME"))
		Expect(vmStatus.age).To(Equal("AGE"))
		Expect(vmStatus.running).To(Equal("RUNNING"))
		Expect(vmStatus.volume).To(Equal("VOLUME"))

		// Read first status of the vm
		vmStatus = readVMStatus(stdout, vmStatus, readTimeout)
		Expect(vmStatus.name).To(Equal(vm.Name))
		Expect(vmStatus.running).To(Equal("false"))

		By("Starting the VM")
		vm = tests.StartVirtualMachine(vm)

		vmStatus = readVMStatus(stdout, vmStatus, readTimeout)
		Expect(vmStatus.running).To(Equal("true"))

		By("Restarting the VM")
		err = virtCli.VirtualMachine(vm.ObjectMeta.Namespace).Restart(vm.ObjectMeta.Name)
		Expect(err).ToNot(HaveOccurred(), "VM should have been restarted")

		vmStatus = readVMStatus(stdout, nil, readTimeout)
		Expect(vmStatus.running).To(Equal("true"))

		By("Stopping the VM")
		vm = tests.StopVirtualMachine(vm)

		vmStatus = readVMStatus(stdout, vmStatus, readTimeout)
		Expect(vmStatus.running).To(Equal("false"))

		By("Deleting the VM")
		err = virtCli.VirtualMachine(vm.ObjectMeta.Namespace).Delete(vm.ObjectMeta.Name, &v1.DeleteOptions{})
		Expect(err).ToNot(HaveOccurred(), "VM should have been deleted from the cluster")
	})

	It("[test_id:3466]Should update vmi status with the proper columns using 'kubectl get vmi -w'", func() {
		By("Creating a random VMI spec")
		vm := tests.NewRandomVMWithEphemeralDisk(tests.ContainerDiskFor(tests.ContainerDiskCirros))
		Expect(vm).ToNot(BeNil())

		By("Setting up the kubectl command")
		cmd, stdout, stderr :=
			createCommandWithNSAndRedirect(vm.ObjectMeta.Namespace, tests.GetK8sCmdClient(), "get", "vmi", "-w")
		Expect(cmd).ToNot(BeNil())

		err = cmd.Start()
		Expect(err).ToNot(HaveOccurred(), "Command should have stared successfully")

		defer cmd.Process.Kill()

		go failOnError(stderr)

		time.Sleep(processWaitTime)

		By("Applying vmi to the cluster")
		vm, err = virtCli.VirtualMachine(vm.ObjectMeta.Namespace).Create(vm)
		Expect(err).ToNot(HaveOccurred(), "VMI should have been added to the cluster")

		// Start a VMI
		vm = tests.StartVirtualMachine(vm)

		// Read the column titles
		vmiStatus := readVMIStatus(stdout, nil, readTimeout)
		Expect(vmiStatus.name).To(Equal("NAME"))
		Expect(vmiStatus.age).To(Equal("AGE"))
		Expect(vmiStatus.phase).To(Equal("PHASE"))
		Expect(vmiStatus.ip).To(Equal("IP"))
		Expect(vmiStatus.node).To(Equal("NODENAME"))

		vmiStatus = readVMIStatus(stdout, vmiStatus, readTimeout)
		Expect(vmiStatus.phase).To(Equal(""))

		vmiStatus = readVMIStatus(stdout, vmiStatus, readTimeout)
		Expect(vmiStatus.phase).To(Equal("Pending"))

		vmiStatus = readVMIStatus(stdout, vmiStatus, readTimeout)
		Expect(vmiStatus.phase).To(Equal("Scheduling"))

		vmiStatus = readVMIStatus(stdout, vmiStatus, readTimeout)
		Expect(vmiStatus.phase).To(Equal("Scheduled"))

		vmiStatus = readVMIStatus(stdout, vmiStatus, readTimeout)
		Expect(vmiStatus.phase).To(Equal("Running"))

		// Restart the VMI
		err = virtCli.VirtualMachine(vm.ObjectMeta.Namespace).Restart(vm.ObjectMeta.Name)
		Expect(err).ToNot(HaveOccurred(), "VMI should have been restarted")

		vmiStatus = readVMIStatus(stdout, vmiStatus, readTimeout)
		Expect(vmiStatus.phase).To(Equal("Failed"))

		vmiStatus = readVMIStatus(stdout, vmiStatus, readTimeout)
		Expect(vmiStatus.phase).To(Equal(""))

		vmiStatus = readVMIStatus(stdout, vmiStatus, readTimeout)
		Expect(vmiStatus.phase).To(Equal("Pending"))

		vmiStatus = readVMIStatus(stdout, vmiStatus, readTimeout)
		Expect(vmiStatus.phase).To(Equal("Scheduling"))

		vmiStatus = readVMIStatus(stdout, vmiStatus, readTimeout)
		Expect(vmiStatus.phase).To(Equal("Scheduled"))

		vmiStatus = readVMIStatus(stdout, vmiStatus, readTimeout)
		Expect(vmiStatus.phase).To(Equal("Running"))
	})
})
<commit_msg>Increased process wait time<commit_after>package tests_test

import (
	"io"
	"os/exec"
	"strings"
	"time"

	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	"kubevirt.io/client-go/kubecli"

	"kubevirt.io/kubevirt/tests"

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

const (
	// Define relevant k8s versions
	relevantk8sVer = "1.16.2"

	// Define a timeout for read opeartions in order to prevent test hanging
	readTimeout     = 1 * time.Minute
	processWaitTime = 1 * time.Minute

	bufferSize = 1024
)

var _ = Describe("[rfe_id:3423][crit:high][vendor:cnv-qe@redhat.com][level:component]VmWatch", func() {
	tests.FlagParse()

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

	type vmStatus struct {
		name,
		age,
		running,
		volume string
	}

	type vmiStatus struct {
		name,
		age,
		phase,
		ip,
		node string
	}

	newVMStatus := func(fields []string) *vmStatus {
		flen := len(fields)
		stat := &vmStatus{}

		switch {
		case flen > 3:
			stat.volume = fields[3]
			fallthrough
		case flen > 2:
			stat.running = fields[2]
			fallthrough
		case flen > 1:
			stat.age = fields[1]
			fallthrough
		case flen > 0:
			stat.name = fields[0]
		}

		return stat
	}

	newVMIStatus := func(fields []string) *vmiStatus {
		flen := len(fields)
		stat := &vmiStatus{}

		switch {
		case flen > 4:
			stat.node = fields[4]
			fallthrough
		case flen > 3:
			stat.ip = fields[3]
			fallthrough
		case flen > 2:
			stat.phase = fields[2]
			fallthrough
		case flen > 1:
			stat.age = fields[1]
			fallthrough
		case flen > 0:
			stat.name = fields[0]
		}

		return stat
	}

	// Fail the test if stderr has something to read
	failOnError := func(rc io.ReadCloser) {
		defer GinkgoRecover()

		buf := make([]byte, bufferSize)

		n, err := rc.Read(buf)

		if err != nil && n > 0 {
			rc.Close()
			Fail(string(buf[:n]))
		}
	}

	// Reads from stdin until a newline character is found
	readLine := func(rc io.ReadCloser, timeout time.Duration) string {
		lineChan := make(chan string)

		go func() {
			defer GinkgoRecover()

			var line strings.Builder
			buf := make([]byte, 1)
			defer close(lineChan)

			for {
				n, err := rc.Read(buf)

				if err != nil && err != io.EOF && !strings.Contains(err.Error(), "file already closed") {
					Fail(err.Error())
					return
				}

				if n > 0 {
					if buf[0] != '\n' {
						line.WriteByte(buf[0])
					} else {
						break
					}
				}
			}

			lineChan <- line.String()
		}()

		select {
		case line := <-lineChan:
			return line
		case <-time.After(timeout):
			err := rc.Close()
			Expect(err).ToNot(HaveOccurred(), "stdout should have been closed properly")

			Fail("Timeout reached on read operation")

			return ""
		}
	}

	// Reads VM status from the given pipe (stdin in this case) and
	// returns a new status.
	// if old_status is non-nil, the function will read status lines until
	// new_status.running != old_status.running in order to skip duplicated status lines
	readVMStatus := func(rc io.ReadCloser, old_status *vmStatus, timeout time.Duration) *vmStatus {
		new_stat := newVMStatus(strings.Fields(readLine(rc, timeout)))

		for old_status != nil && new_stat.running == old_status.running {
			new_stat = newVMStatus(strings.Fields(readLine(rc, timeout)))
		}

		return new_stat
	}

	// Reads VMI status from the given pipe (stdin in this case) and
	// returns a new status.
	// if old_status is non-nil, the function will read status lines until
	// new_status.phase != old_status.phase in order to skip duplicated lines
	readVMIStatus := func(rc io.ReadCloser, old_status *vmiStatus, timeout time.Duration) *vmiStatus {
		newStat := newVMIStatus(strings.Fields(readLine(rc, timeout)))

		for old_status != nil && newStat.phase == old_status.phase {
			newStat = newVMIStatus(strings.Fields(readLine(rc, timeout)))
		}

		return newStat
	}

	// Create a command with output/error redirection.
	// Returns (cmd, stdout, stderr)
	createCommandWithNSAndRedirect := func(namespace, cmdName string, args ...string) (*exec.Cmd, io.ReadCloser, io.ReadCloser) {
		cmdName, cmd, err := tests.CreateCommandWithNS(namespace, cmdName, args...)

		Expect(cmdName).ToNot(Equal(""))
		Expect(cmd).ToNot(BeNil())
		Expect(err).ToNot(HaveOccurred(), "Command should have been created with proper kubectl/oc arguments")

		// Output redirection
		stdOut, err := cmd.StdoutPipe()
		Expect(err).ToNot(HaveOccurred(), "stdout should have been redirected")
		Expect(stdOut).ToNot(BeNil())

		stdErr, err := cmd.StderrPipe()
		Expect(err).ToNot(HaveOccurred(), "stderr should have been redirected")
		Expect(stdErr).ToNot(BeNil())

		return cmd, stdOut, stdErr
	}

	BeforeEach(func() {
		tests.SkipIfVersionBelow("Printing format for `kubectl get -w` on custom resources is only relevant for 1.16.2+", relevantk8sVer)
	})

	It("[test_id:3468]Should update vm status with the proper columns using 'kubectl get vm -w'", func() {
		By("Creating a new VM spec")
		vm := tests.NewRandomVMWithEphemeralDisk(tests.ContainerDiskFor(tests.ContainerDiskCirros))
		Expect(vm).ToNot(BeNil())

		By("Setting up the kubectl command")
		cmd, stdout, stderr :=
			createCommandWithNSAndRedirect(vm.ObjectMeta.Namespace, tests.GetK8sCmdClient(), "get", "vm", "-w")
		Expect(cmd).ToNot(BeNil())

		err = cmd.Start()
		Expect(err).ToNot(HaveOccurred(), "Command should have started successfully")

		defer cmd.Process.Kill()

		time.Sleep(processWaitTime)

		go failOnError(stderr)

		By("Applying the VM to the cluster")
		vm, err := virtCli.VirtualMachine(vm.ObjectMeta.Namespace).Create(vm)
		Expect(err).ToNot(HaveOccurred(), "VM should have been added to the cluster")

		// Read column titles
		vmStatus := readVMStatus(stdout, nil, readTimeout)
		Expect(vmStatus.name).To(Equal("NAME"))
		Expect(vmStatus.age).To(Equal("AGE"))
		Expect(vmStatus.running).To(Equal("RUNNING"))
		Expect(vmStatus.volume).To(Equal("VOLUME"))

		// Read first status of the vm
		vmStatus = readVMStatus(stdout, vmStatus, readTimeout)
		Expect(vmStatus.name).To(Equal(vm.Name))
		Expect(vmStatus.running).To(Equal("false"))

		By("Starting the VM")
		vm = tests.StartVirtualMachine(vm)

		vmStatus = readVMStatus(stdout, vmStatus, readTimeout)
		Expect(vmStatus.running).To(Equal("true"))

		By("Restarting the VM")
		err = virtCli.VirtualMachine(vm.ObjectMeta.Namespace).Restart(vm.ObjectMeta.Name)
		Expect(err).ToNot(HaveOccurred(), "VM should have been restarted")

		vmStatus = readVMStatus(stdout, nil, readTimeout)
		Expect(vmStatus.running).To(Equal("true"))

		By("Stopping the VM")
		vm = tests.StopVirtualMachine(vm)

		vmStatus = readVMStatus(stdout, vmStatus, readTimeout)
		Expect(vmStatus.running).To(Equal("false"))

		By("Deleting the VM")
		err = virtCli.VirtualMachine(vm.ObjectMeta.Namespace).Delete(vm.ObjectMeta.Name, &v1.DeleteOptions{})
		Expect(err).ToNot(HaveOccurred(), "VM should have been deleted from the cluster")
	})

	It("[test_id:3466]Should update vmi status with the proper columns using 'kubectl get vmi -w'", func() {
		By("Creating a random VMI spec")
		vm := tests.NewRandomVMWithEphemeralDisk(tests.ContainerDiskFor(tests.ContainerDiskCirros))
		Expect(vm).ToNot(BeNil())

		By("Setting up the kubectl command")
		cmd, stdout, stderr :=
			createCommandWithNSAndRedirect(vm.ObjectMeta.Namespace, tests.GetK8sCmdClient(), "get", "vmi", "-w")
		Expect(cmd).ToNot(BeNil())

		err = cmd.Start()
		Expect(err).ToNot(HaveOccurred(), "Command should have stared successfully")

		defer cmd.Process.Kill()

		go failOnError(stderr)

		time.Sleep(processWaitTime)

		By("Applying vmi to the cluster")
		vm, err = virtCli.VirtualMachine(vm.ObjectMeta.Namespace).Create(vm)
		Expect(err).ToNot(HaveOccurred(), "VMI should have been added to the cluster")

		// Start a VMI
		vm = tests.StartVirtualMachine(vm)

		// Read the column titles
		vmiStatus := readVMIStatus(stdout, nil, readTimeout)
		Expect(vmiStatus.name).To(Equal("NAME"))
		Expect(vmiStatus.age).To(Equal("AGE"))
		Expect(vmiStatus.phase).To(Equal("PHASE"))
		Expect(vmiStatus.ip).To(Equal("IP"))
		Expect(vmiStatus.node).To(Equal("NODENAME"))

		vmiStatus = readVMIStatus(stdout, vmiStatus, readTimeout)
		Expect(vmiStatus.phase).To(Equal(""))

		vmiStatus = readVMIStatus(stdout, vmiStatus, readTimeout)
		Expect(vmiStatus.phase).To(Equal("Pending"))

		vmiStatus = readVMIStatus(stdout, vmiStatus, readTimeout)
		Expect(vmiStatus.phase).To(Equal("Scheduling"))

		vmiStatus = readVMIStatus(stdout, vmiStatus, readTimeout)
		Expect(vmiStatus.phase).To(Equal("Scheduled"))

		vmiStatus = readVMIStatus(stdout, vmiStatus, readTimeout)
		Expect(vmiStatus.phase).To(Equal("Running"))

		// Restart the VMI
		err = virtCli.VirtualMachine(vm.ObjectMeta.Namespace).Restart(vm.ObjectMeta.Name)
		Expect(err).ToNot(HaveOccurred(), "VMI should have been restarted")

		vmiStatus = readVMIStatus(stdout, vmiStatus, readTimeout)
		Expect(vmiStatus.phase).To(Equal("Failed"))

		vmiStatus = readVMIStatus(stdout, vmiStatus, readTimeout)
		Expect(vmiStatus.phase).To(Equal(""))

		vmiStatus = readVMIStatus(stdout, vmiStatus, readTimeout)
		Expect(vmiStatus.phase).To(Equal("Pending"))

		vmiStatus = readVMIStatus(stdout, vmiStatus, readTimeout)
		Expect(vmiStatus.phase).To(Equal("Scheduling"))

		vmiStatus = readVMIStatus(stdout, vmiStatus, readTimeout)
		Expect(vmiStatus.phase).To(Equal("Scheduled"))

		vmiStatus = readVMIStatus(stdout, vmiStatus, readTimeout)
		Expect(vmiStatus.phase).To(Equal("Running"))
	})
})
<|endoftext|>


<commit_before>// package uroot contains various functions that might be needed more than
// one place.
package uroot

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"
	"syscall"
)

const PATH = "/bin:/ubin:/buildbin:/usr/local/bin"

// TODO: make this a map so it's easier to find dups.
type dir struct {
	name string
	mode os.FileMode
}

type file struct {
	contents string
	mode os.FileMode
}

// TODO: make this a map so it's easier to find dups.
type dev struct {
	name  string
	mode  os.FileMode
	magic int
	howmany int
}
type mount struct {
	source string
	target string
	fstype string
	flags  uintptr
	opts   string
}

var (
	Envs []string
	env = map[string]string{
		"LD_LIBRARY_PATH": "/usr/local/lib",
		"GOROOT":          "/go",
		"GOPATH":          "/",
		"CGO_ENABLED":     "0",
	}

	dirs = []dir{
		{name: "/proc", mode: os.FileMode(0555)},
		{name: "/sys", mode: os.FileMode(0555)},
		{name: "/buildbin", mode: os.FileMode(0777)},
		{name: "/ubin", mode: os.FileMode(0777)},
		{name: "/tmp", mode: os.FileMode(0777)},
		{name: "/env", mode: os.FileMode(0777)},
		{name: "/etc", mode: os.FileMode(0777)},
		{name: "/tcz", mode: os.FileMode(0777)},
		{name: "/dev", mode: os.FileMode(0777)},
		{name: "/lib", mode: os.FileMode(0777)},
		{name: "/usr/lib", mode: os.FileMode(0777)},
		{name: "/go/pkg/linux_amd64", mode: os.FileMode(0777)},
	}
	devs = []dev{
		// chicken and egg: these need to be there before you start. So, sadly,
		// we will always need dev.cpio.
		//{name: "/dev/null", mode: os.FileMode(0660) | 020000, magic: 0x0103},
		//{name: "/dev/console", mode: os.FileMode(0660) | 020000, magic: 0x0501},
	}
	namespace = []mount{
		{source: "proc", target: "/proc", fstype: "proc", flags: syscall.MS_MGC_VAL | syscall.MS_RDONLY, opts: ""},
		{source: "sys", target: "/sys", fstype: "sysfs", flags: syscall.MS_MGC_VAL | syscall.MS_RDONLY, opts: ""},
	}

	files = map[string] file {
		"/etc/resolv.conf": {contents: `nameserver 8.8.8.8`, mode: os.FileMode(0644)},
	}
)

// build the root file system.
func Rootfs() {
	// Pick some reasonable values in the (unlikely!) even that Uname fails.
	uname := "linux"
	mach := "x86_64"
	// There are three possible places for go:
	// The first is in /go/bin/$OS_$ARCH
	// The second is in /go/bin [why they still use this path is anyone's guess]
	// The third is in /go/pkg/tool/$OS_$ARCH
	if u, err := Uname(); err != nil {
		log.Printf("uroot.Utsname fails: %v, so assume %v_%v\n", uname, mach)
	} else {
		// Sadly, go and the OS disagree on case.
		uname = strings.ToLower(u.Sysname)
		mach = strings.ToLower(u.Machine)
		// Yes, we really have to do this stupid thing.
		if mach[0:3] == "arm" {
			mach = "arm"
		}
	}
	env["PATH"] = fmt.Sprintf("/go/bin/%s_%s:/go/bin:/go/pkg/tool/%s_%s:%v", uname, mach, uname, mach, PATH)

	for k, v := range env {
		os.Setenv(k, v)
		Envs = append(Envs, k+"="+v)
	}

	for _, m := range dirs {
		if err := os.MkdirAll(m.name, m.mode); err != nil {
			log.Printf("mkdir :%s: mode %o: %v\n", m.name, m.mode, err)
			continue
		}
	}

	for _, d := range devs {
		syscall.Unlink(d.name)
		if err := syscall.Mknod(d.name, uint32(d.mode), d.magic); err != nil {
			log.Printf("mknod :%s: mode %o: magic: %v: %v\n", d.name, d.mode, d.magic, err)
			continue
		}
	}

	for _, m := range namespace {
		if err := syscall.Mount(m.source, m.target, m.fstype, m.flags, m.opts); err != nil {
			log.Printf("Mount :%s: on :%s: type :%s: flags %x: %v\n", m.source, m.target, m.fstype, m.flags, m.opts, err)
		}

	}

	for name, m := range files {
		if err := ioutil.WriteFile(name, []byte(m.contents), m.mode); err != nil {
			log.Printf("Error writeing %v: %v", name, err)
		}
	}

	// only in case of emergency.
	if false {
		if err := filepath.Walk("/", func(name string, fi os.FileInfo, err error) error {
			if err != nil {
				fmt.Printf(" WALK FAIL%v: %v\n", name, err)
				// That's ok, sometimes things are not there.
				return nil
			}
			fmt.Printf("%v\n", name)
			return nil
		}); err != nil {
			log.Printf("WALK fails %v\n", err)
		}
	}
}
<commit_msg>Simple fixes at uroot/root.go, log.Printf missing args and gofmt<commit_after>// package uroot contains various functions that might be needed more than
// one place.
package uroot

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"
	"syscall"
)

const PATH = "/bin:/ubin:/buildbin:/usr/local/bin"

// TODO: make this a map so it's easier to find dups.
type dir struct {
	name string
	mode os.FileMode
}

type file struct {
	contents string
	mode     os.FileMode
}

// TODO: make this a map so it's easier to find dups.
type dev struct {
	name    string
	mode    os.FileMode
	magic   int
	howmany int
}
type mount struct {
	source string
	target string
	fstype string
	flags  uintptr
	opts   string
}

var (
	Envs []string
	env  = map[string]string{
		"LD_LIBRARY_PATH": "/usr/local/lib",
		"GOROOT":          "/go",
		"GOPATH":          "/",
		"CGO_ENABLED":     "0",
	}

	dirs = []dir{
		{name: "/proc", mode: os.FileMode(0555)},
		{name: "/sys", mode: os.FileMode(0555)},
		{name: "/buildbin", mode: os.FileMode(0777)},
		{name: "/ubin", mode: os.FileMode(0777)},
		{name: "/tmp", mode: os.FileMode(0777)},
		{name: "/env", mode: os.FileMode(0777)},
		{name: "/etc", mode: os.FileMode(0777)},
		{name: "/tcz", mode: os.FileMode(0777)},
		{name: "/dev", mode: os.FileMode(0777)},
		{name: "/lib", mode: os.FileMode(0777)},
		{name: "/usr/lib", mode: os.FileMode(0777)},
		{name: "/go/pkg/linux_amd64", mode: os.FileMode(0777)},
	}
	devs = []dev{
	// chicken and egg: these need to be there before you start. So, sadly,
	// we will always need dev.cpio.
	//{name: "/dev/null", mode: os.FileMode(0660) | 020000, magic: 0x0103},
	//{name: "/dev/console", mode: os.FileMode(0660) | 020000, magic: 0x0501},
	}
	namespace = []mount{
		{source: "proc", target: "/proc", fstype: "proc", flags: syscall.MS_MGC_VAL | syscall.MS_RDONLY, opts: ""},
		{source: "sys", target: "/sys", fstype: "sysfs", flags: syscall.MS_MGC_VAL | syscall.MS_RDONLY, opts: ""},
	}

	files = map[string]file{
		"/etc/resolv.conf": {contents: `nameserver 8.8.8.8`, mode: os.FileMode(0644)},
	}
)

// build the root file system.
func Rootfs() {
	// Pick some reasonable values in the (unlikely!) even that Uname fails.
	uname := "linux"
	mach := "x86_64"
	// There are three possible places for go:
	// The first is in /go/bin/$OS_$ARCH
	// The second is in /go/bin [why they still use this path is anyone's guess]
	// The third is in /go/pkg/tool/$OS_$ARCH
	if u, err := Uname(); err != nil {
		log.Printf("uroot.Utsname fails: %v, so assume %v_%v\n", err, uname, mach)
	} else {
		// Sadly, go and the OS disagree on case.
		uname = strings.ToLower(u.Sysname)
		mach = strings.ToLower(u.Machine)
		// Yes, we really have to do this stupid thing.
		if mach[0:3] == "arm" {
			mach = "arm"
		}
	}
	env["PATH"] = fmt.Sprintf("/go/bin/%s_%s:/go/bin:/go/pkg/tool/%s_%s:%v", uname, mach, uname, mach, PATH)

	for k, v := range env {
		os.Setenv(k, v)
		Envs = append(Envs, k+"="+v)
	}

	for _, m := range dirs {
		if err := os.MkdirAll(m.name, m.mode); err != nil {
			log.Printf("mkdir :%s: mode %o: %v\n", m.name, m.mode, err)
			continue
		}
	}

	for _, d := range devs {
		syscall.Unlink(d.name)
		if err := syscall.Mknod(d.name, uint32(d.mode), d.magic); err != nil {
			log.Printf("mknod :%s: mode %o: magic: %v: %v\n", d.name, d.mode, d.magic, err)
			continue
		}
	}

	for _, m := range namespace {
		if err := syscall.Mount(m.source, m.target, m.fstype, m.flags, m.opts); err != nil {
			log.Printf("Mount :%s: on :%s: type :%s: flags %x opts: %s: %v\n", m.source, m.target, m.fstype, m.flags, m.opts, err)
		}

	}

	for name, m := range files {
		if err := ioutil.WriteFile(name, []byte(m.contents), m.mode); err != nil {
			log.Printf("Error writeing %v: %v", name, err)
		}
	}

	// only in case of emergency.
	if false {
		if err := filepath.Walk("/", func(name string, fi os.FileInfo, err error) error {
			if err != nil {
				fmt.Printf(" WALK FAIL%v: %v\n", name, err)
				// That's ok, sometimes things are not there.
				return nil
			}
			fmt.Printf("%v\n", name)
			return nil
		}); err != nil {
			log.Printf("WALK fails %v\n", err)
		}
	}
}
<|endoftext|>


<commit_before>package thumbnailer

import (
	"fmt"
	"os"
	"path/filepath"
	"testing"
)

// func Test_generateThumbnail(t *testing.T){
//
// }

func Test_GenerateThumbnails(t *testing.T) {
	pwd, err := os.Getwd()
	if err != nil {
		t.Fatal("Failed to get the current directory: %s", err)
	}
	fmt.Println("Current dir:", pwd)
	opt := ThumbnailOpt{Width: 100, Height: 100}
	opts := make([]ThumbnailOpt, 0)
	opts = append(opts, opt)
	tm := ThumbnailerMessage{
		SrcImage:  filepath.Join("file://", pwd, "testdata", "pic.jpg"),
		DstFolder: "file:///tmp",
		Opts:      opts}
	results := tm.GenerateThumbnails()
	for result := range results {
		if result.Err != nil {
			t.Fatal("An error occured while generating a thumb :", result.Err)
		}
		// Clean up the generated thumb
		if err := os.Remove(result.Thumbnail.Path); err != nil {
			t.Fatal("Failed to delete the generated thumb:", err)
		}
	}
}
<commit_msg>Reorganize the thumbnailer internals<commit_after>package thumbnailer

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"testing"
)

func testThumbnailerMessage() ThumbnailerMessage {
	pwd, err := os.Getwd()
	if err != nil {
		log.Fatal("Failed to get the current directory: %s", err)
	}
	fmt.Println("Current dir:", pwd)
	opt := ThumbnailOpt{Width: 100, Height: 100}
	opts := make([]ThumbnailOpt, 0)
	opts = append(opts, opt)
	return ThumbnailerMessage{
		SrcImage:  filepath.Join("file://", pwd, "testdata", "pic.jpg"),
		DstFolder: "file:///tmp",
		Opts:      opts}

}

func Test_thumbURL(t *testing.T) {
	expected := "/tmp/pic_s100x100.jpg"
	tm := testThumbnailerMessage()
	url, err := tm.thumbURL(tm.Opts[0])
	if err != nil {
		t.Fatal("Failed to generate the thumbURL :", err)
	}
	if url.Path != expected {
		t.Fatalf("got: %s, expected: %s", url.Path, expected)
	}
}

func Test_generateThumbnail(t *testing.T) {
	tm := testThumbnailerMessage()
	src, err := tm.Open()
	if err != nil {
		t.Fatalf("Failed to open tm.SrcImage: %v", err)
	}
	tm.generateThumbnail(src, tm.Opts[0])
}

func Test_GenerateThumbnails(t *testing.T) {
	tm := testThumbnailerMessage()
	results := tm.GenerateThumbnails()
	for result := range results {
		if result.Err != nil {
			t.Fatal("An error occured while generating a thumb :", result.Err)
		}
		// Clean up the generated thumb
		if err := os.Remove(result.Thumbnail.Path); err != nil {
			t.Fatal("Failed to delete the generated thumb:", err)
		}
	}
}
<|endoftext|>