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

// To use with keystone, create s3 style credentials
//   `openstack ec2 credentials create`
//
// To enable, add the following to `/etc/hummingbird/proxy-server.conf`
//
//   [filter:s3api]
//   enabled = true
//
// Example using boto2 and haio with tempauth:
//
//  from boto.s3.connection import S3Connection
//  connection = S3Connection(
//    aws_access_key_id="test:tester",
//    aws_secret_access_key="testing",
//    port=8080,
//    host='127.0.0.1',
//    is_secure=False,
//    calling_format=boto.s3.connection.OrdinaryCallingFormat()
//  )
//  connection.get_all_buckets()
//
//  If you are using keystone auth, substitue the key and access key returned from keystone

package middleware

import (
	"encoding/json"
	"encoding/xml"
	"fmt"
	"net/http"
	"strconv"
	"strings"

	"github.com/troubling/hummingbird/accountserver"
	"github.com/troubling/hummingbird/common/conf"
	"github.com/troubling/hummingbird/common/srv"
	"github.com/uber-go/tally"
)

const (
	s3Xmlns = "http://s3.amazonaws.com/doc/2006-03-01"
)

type s3Owner struct {
	ID          string `xml:"ID"`
	DisplayName string `xml:"DisplayName"`
}

type s3BucketInfo struct {
	Name         string `xml:"Name"`
	CreationDate string `xml:"CreationDate"`
}

type s3BucketList struct {
	XMLName xml.Name       `xml:"ListAllMyBucketsResult"`
	Xmlns   string         `xml:"xmlns,attr"`
	Owner   s3Owner        `xml:"Owner"`
	Buckets []s3BucketInfo `xml:"Buckets>Bucket"`
}

func NewS3BucketList() *s3BucketList {
	return &s3BucketList{Xmlns: s3Xmlns}
}

type s3Error struct {
	XMLName   xml.Name `xml:"Error"`
	Code      string   `xml:"Code"`
	Message   string   `xml:"Message"`
	Resource  string   `xml:"Resource"`
	RequestId string   `xml:"RequestId"`
}

func NewS3Error() *s3Error {
	return &s3Error{}
}

// TODO: Figure out how to plumb S3 Responses
func S3ErrorResponse(w http.ResponseWriter, statusCode int, resource, requestId string) {
	s3err := NewS3Error()
	// TODO: Add all error codes
	if statusCode == 403 {
		statusCode = 403
		s3err.Code = "AccessDenied"
		s3err.Message = "Access Denied"
	}
	s3err.Resource = resource
	s3err.RequestId = requestId
	output, err := xml.MarshalIndent(s3err, "", "  ")
	if err != nil {
		srv.SimpleErrorResponse(w, http.StatusInternalServerError, err.Error())
		return
	}
	output = []byte(xml.Header + string(output))
	headers := w.Header()
	headers.Set("Content-Type", "application/xml; charset=utf-8")
	headers.Set("Content-Length", strconv.Itoa(len(output)))
	w.WriteHeader(statusCode)
	w.Write(output)

}

type s3ApiHandler struct {
	next           http.Handler
	ctx            *ProxyContext
	account        string
	container      string
	object         string
	path           string
	signature      string
	requestsMetric tally.Counter
}

func (s *s3ApiHandler) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
	ctx := GetProxyContext(request)
	// Check if this is an S3 request
	if ctx.S3Auth == nil || strings.HasPrefix(strings.ToLower(request.URL.Path), "/v1/") {
		// Not an S3 request
		s.next.ServeHTTP(writer, request)
		return
	}

	s.container, s.object, _, _ = getPathSegments(request.URL.Path)
	s.account = ctx.S3Auth.Account

	// TODO: Validate the container
	// Generate the hbird api path
	if s.object != "" {
		s.path = fmt.Sprintf("/v1/AUTH_%s/%s/%s", s.account, s.container, s.object)
	} else if s.container != "" {
		s.path = fmt.Sprintf("/v1/AUTH_%s/%s", s.account, s.container)
	} else {
		s.path = fmt.Sprintf("/v1/AUTH_%s", s.account)
	}
	// TODO: Handle metadata?

	if s.object != "" {
		s.handleObjectRequest(writer, request)
		return
	} else if s.container != "" {
		s.handleContainerRequest(writer, request)
		return
	} else {
		s.handleAccountRequest(writer, request)
		return
	}
}

func (s *s3ApiHandler) handleObjectRequest(writer http.ResponseWriter, request *http.Request) {
	// If we didn't get to anything, then return no implemented
	srv.SimpleErrorResponse(writer, http.StatusNotImplemented, "Not Implemented")
}

func (s *s3ApiHandler) handleContainerRequest(writer http.ResponseWriter, request *http.Request) {
	// If we didn't get to anything, then return no implemented
	srv.SimpleErrorResponse(writer, http.StatusNotImplemented, "Not Implemented")
}

func (s *s3ApiHandler) handleAccountRequest(writer http.ResponseWriter, request *http.Request) {
	ctx := GetProxyContext(request)
	if request.Method == "GET" {
		newReq, err := ctx.newSubrequest("GET", s.path, http.NoBody, request, "s3api")
		if err != nil {
			// TODO: Need S3 error responses?
			srv.SimpleErrorResponse(writer, http.StatusInternalServerError, err.Error())
			return
		}
		newReq.Header.Set("Accept", "application/json")
		cap := NewCaptureWriter()
		ctx.serveHTTPSubrequest(cap, newReq)
		if cap.status/100 != 2 {
			srv.StandardResponse(writer, cap.status)
			return
		}
		containerListing := []accountserver.ContainerListingRecord{}
		err = json.Unmarshal(cap.body, &containerListing)
		if err != nil {
			srv.SimpleErrorResponse(writer, http.StatusInternalServerError, err.Error())
			return
		}
		bucketList := NewS3BucketList()
		// TODO: figure out how to get the account
		bucketList.Owner.ID = "ACCOUNT"
		// TODO: Figure out what to put for display name
		bucketList.Owner.DisplayName = "Some Name Goes Here"
		for _, c := range containerListing {
			// TODO: Get s3 style date from timestamp
			bucketList.Buckets = append(bucketList.Buckets, s3BucketInfo{
				Name:         c.Name,
				CreationDate: "2006-02-03T16:45:09.000Z",
			})
		}
		output, err := xml.MarshalIndent(bucketList, "", "  ")
		if err != nil {
			srv.SimpleErrorResponse(writer, http.StatusInternalServerError, err.Error())
			return
		}
		output = []byte(xml.Header + string(output))
		headers := writer.Header()
		headers.Set("Content-Type", "application/xml; charset=utf-8")
		headers.Set("Content-Length", strconv.Itoa(len(output)))
		writer.WriteHeader(200)
		writer.Write(output)
		return

	}

	// If we didn't get to anything, then return not implemented
	srv.SimpleErrorResponse(writer, http.StatusNotImplemented, "Not Implemented")
}

func NewS3Api(config conf.Section, metricsScope tally.Scope) (func(http.Handler) http.Handler, error) {
	enabled, ok := config.Section["enabled"]
	if !ok || strings.Compare(strings.ToLower(enabled), "false") == 0 {
		// s3api is disabled, so pass the request on
		return func(next http.Handler) http.Handler {
			return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
				next.ServeHTTP(writer, request)
			})
		}, nil
	}
	RegisterInfo("s3Api", map[string]interface{}{})
	return s3Api(metricsScope.Counter("s3Api_requests")), nil
}

func s3Api(requestsMetric tally.Counter) func(next http.Handler) http.Handler {
	return func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
			(&s3ApiHandler{next: next, requestsMetric: requestsMetric}).ServeHTTP(writer, request)
		})
	}
}
<commit_msg>HUM-755 Adding S3 Bucket PUT support<commit_after>//  Copyright (c) 2018 Rackspace
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
//  implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.

// To use with keystone, create s3 style credentials
//   `openstack ec2 credentials create`
//
// To enable, add the following to `/etc/hummingbird/proxy-server.conf`
//
//   [filter:s3api]
//   enabled = true
//
// Example using boto2 and haio with tempauth:
//
//  from boto.s3.connection import S3Connection
//  connection = S3Connection(
//    aws_access_key_id="test:tester",
//    aws_secret_access_key="testing",
//    port=8080,
//    host='127.0.0.1',
//    is_secure=False,
//    calling_format=boto.s3.connection.OrdinaryCallingFormat()
//  )
//  connection.get_all_buckets()
//
//  If you are using keystone auth, substitue the key and access key returned from keystone

package middleware

import (
	"encoding/json"
	"encoding/xml"
	"fmt"
	"net/http"
	"strconv"
	"strings"

	"github.com/troubling/hummingbird/accountserver"
	"github.com/troubling/hummingbird/common/conf"
	"github.com/troubling/hummingbird/common/srv"
	"github.com/uber-go/tally"
)

const (
	s3Xmlns = "http://s3.amazonaws.com/doc/2006-03-01"
)

type s3Owner struct {
	ID          string `xml:"ID"`
	DisplayName string `xml:"DisplayName"`
}

type s3BucketInfo struct {
	Name         string `xml:"Name"`
	CreationDate string `xml:"CreationDate"`
}

type s3BucketList struct {
	XMLName xml.Name       `xml:"ListAllMyBucketsResult"`
	Xmlns   string         `xml:"xmlns,attr"`
	Owner   s3Owner        `xml:"Owner"`
	Buckets []s3BucketInfo `xml:"Buckets>Bucket"`
}

func NewS3BucketList() *s3BucketList {
	return &s3BucketList{Xmlns: s3Xmlns}
}

type s3Error struct {
	XMLName   xml.Name `xml:"Error"`
	Code      string   `xml:"Code"`
	Message   string   `xml:"Message"`
	Resource  string   `xml:"Resource"`
	RequestId string   `xml:"RequestId"`
}

func NewS3Error() *s3Error {
	return &s3Error{}
}

// TODO: Figure out how to plumb S3 Responses
func S3ErrorResponse(w http.ResponseWriter, statusCode int, resource, requestId string) {
	s3err := NewS3Error()
	// TODO: Add all error codes
	if statusCode == 403 {
		statusCode = 403
		s3err.Code = "AccessDenied"
		s3err.Message = "Access Denied"
	}
	s3err.Resource = resource
	s3err.RequestId = requestId
	output, err := xml.MarshalIndent(s3err, "", "  ")
	if err != nil {
		srv.SimpleErrorResponse(w, http.StatusInternalServerError, err.Error())
		return
	}
	output = []byte(xml.Header + string(output))
	headers := w.Header()
	headers.Set("Content-Type", "application/xml; charset=utf-8")
	headers.Set("Content-Length", strconv.Itoa(len(output)))
	w.WriteHeader(statusCode)
	w.Write(output)

}

type s3ApiHandler struct {
	next           http.Handler
	ctx            *ProxyContext
	account        string
	container      string
	object         string
	path           string
	signature      string
	requestsMetric tally.Counter
}

func (s *s3ApiHandler) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
	ctx := GetProxyContext(request)
	// Check if this is an S3 request
	if ctx.S3Auth == nil || strings.HasPrefix(strings.ToLower(request.URL.Path), "/v1/") {
		// Not an S3 request
		s.next.ServeHTTP(writer, request)
		return
	}

	s.container, s.object, _, _ = getPathSegments(request.URL.Path)
	s.account = ctx.S3Auth.Account

	// TODO: Validate the container
	// Generate the hbird api path
	if s.object != "" {
		s.path = fmt.Sprintf("/v1/AUTH_%s/%s/%s", s.account, s.container, s.object)
	} else if s.container != "" {
		s.path = fmt.Sprintf("/v1/AUTH_%s/%s", s.account, s.container)
	} else {
		s.path = fmt.Sprintf("/v1/AUTH_%s", s.account)
	}
	// TODO: Handle metadata?

	if s.object != "" {
		s.handleObjectRequest(writer, request)
		return
	} else if s.container != "" {
		s.handleContainerRequest(writer, request)
		return
	} else {
		s.handleAccountRequest(writer, request)
		return
	}
}

func (s *s3ApiHandler) handleObjectRequest(writer http.ResponseWriter, request *http.Request) {
	// If we didn't get to anything, then return no implemented
	srv.SimpleErrorResponse(writer, http.StatusNotImplemented, "Not Implemented")
}

func (s *s3ApiHandler) handleContainerRequest(writer http.ResponseWriter, request *http.Request) {
	// If we didn't get to anything, then return no implemented
	ctx := GetProxyContext(request)
	if request.Method == "PUT" {
		newReq, err := ctx.newSubrequest("PUT", s.path, http.NoBody, request, "s3api")
		if err != nil {
			srv.SimpleErrorResponse(writer, http.StatusInternalServerError, err.Error())
		}
		newReq.Header.Set("Accept", "application/json")
		cap := NewCaptureWriter()
		ctx.serveHTTPSubrequest(cap, newReq)
		if cap.status/100 != 2 {
			srv.StandardResponse(writer, cap.status)
			return
		} else {
			writer.WriteHeader(200)
			return
		}
	}

	srv.SimpleErrorResponse(writer, http.StatusNotImplemented, "Not Implemented")
}

func (s *s3ApiHandler) handleAccountRequest(writer http.ResponseWriter, request *http.Request) {
	ctx := GetProxyContext(request)
	if request.Method == "GET" {
		newReq, err := ctx.newSubrequest("GET", s.path, http.NoBody, request, "s3api")
		if err != nil {
			srv.SimpleErrorResponse(writer, http.StatusInternalServerError, err.Error())
			return
		}
		newReq.Header.Set("Accept", "application/json")
		cap := NewCaptureWriter()
		ctx.serveHTTPSubrequest(cap, newReq)
		if cap.status/100 != 2 {
			srv.StandardResponse(writer, cap.status)
			return
		}
		containerListing := []accountserver.ContainerListingRecord{}
		err = json.Unmarshal(cap.body, &containerListing)
		if err != nil {
			srv.SimpleErrorResponse(writer, http.StatusInternalServerError, err.Error())
			return
		}
		bucketList := NewS3BucketList()
		bucketList.Owner.ID = ctx.S3Auth.Account
		bucketList.Owner.DisplayName = ctx.S3Auth.Account
		// NOTE: The container list api doesn't have a creation date for the container, so we use an "arbitrary" date.
		for _, c := range containerListing {
			bucketList.Buckets = append(bucketList.Buckets, s3BucketInfo{
				Name:         c.Name,
				CreationDate: "2009-02-03T16:45:09.000Z",
			})
		}
		output, err := xml.MarshalIndent(bucketList, "", "  ")
		if err != nil {
			srv.SimpleErrorResponse(writer, http.StatusInternalServerError, err.Error())
			return
		}
		output = []byte(xml.Header + string(output))
		headers := writer.Header()
		headers.Set("Content-Type", "application/xml; charset=utf-8")
		headers.Set("Content-Length", strconv.Itoa(len(output)))
		writer.WriteHeader(200)
		writer.Write(output)
		return

	}

	// No other methods are allowed at the account level
	srv.StandardResponse(writer, http.StatusMethodNotAllowed)
}

func NewS3Api(config conf.Section, metricsScope tally.Scope) (func(http.Handler) http.Handler, error) {
	enabled, ok := config.Section["enabled"]
	if !ok || strings.Compare(strings.ToLower(enabled), "false") == 0 {
		// s3api is disabled, so pass the request on
		return func(next http.Handler) http.Handler {
			return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
				next.ServeHTTP(writer, request)
			})
		}, nil
	}
	RegisterInfo("s3Api", map[string]interface{}{})
	return s3Api(metricsScope.Counter("s3Api_requests")), nil
}

func s3Api(requestsMetric tally.Counter) func(next http.Handler) http.Handler {
	return func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
			(&s3ApiHandler{next: next, requestsMetric: requestsMetric}).ServeHTTP(writer, request)
		})
	}
}
<|endoftext|>


<commit_before>// web.go: Exposes results from api as HTML.
package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"

	"github.com/golang/glog"

	"hkjn.me/junk/coreos/src/api"
	"hkjn.me/junk/coreos/src/etcdwrapper"
)

var (
	apiServer    = flag.String("api_server", "", "If set, HTTP address of API server. If not set, address is read from etcd")
	buildVersion = flag.String("web_version", "unknown revision", "Build version of web server")
	// Note that we always bind to the same port internally; the
	// .service file can map it to any external port that's desired
	// based on which stage we're running.
	bindAddr = ":9000"
	stage    = "" // prod|staging|testN|dev|unittest
)

type (
	// webHandler handles HTTP requests for monkeys.
	webHandler struct {
		p api.MonkeyAPI // provider of the monkeys
	}

	// jsonAPI implements api.MonkeyAPI by HTTP requests to the JSON API service.
	jsonAPI struct{}
)

// ServeHTTP serves the index page.
func (h webHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Note: We just do some arbitrary checks for stage here to prove
	// that we can have different internal behavior in the app
	// depending on which stage we're running on (prod, test, ..). In
	// a real deployment this should be abstracted away in e.g. a
	// shared package that reads some config defining the stages.
	msg := fmt.Sprintf("Hi from web layer on %s?! I don't even know what I'm supposed to do in this kind of environment!", stage)
	if stage == "test" {
		msg = "Hi from web layer on test!"
	} else if stage == "unittest" {
		msg = "Yes, automatic tester, I'm working as intended."
	} else if stage == "prod" {
		msg = "Hi, I'm the sooper productionized prod web layer!"
	}
	m, err := h.p.GetMonkeys()
	if err != nil {
		log.Printf("Error from API: %v\n", err)
		http.Error(w, "Internal server error.", http.StatusInternalServerError)
		return
	}
	// TODO: use html.tmpl.
	fmt.Fprintf(w, "
%s

Here's your monkeys:

%s
", msg, m)
}

// getURL returns the URL for a specific API endpoint.
//
// getURL uses specified value from -api_server if present, otherwise
// reads /services/api/[stage] from etcd.
func getURL(endpoint string) (string, error) {
	server := *apiServer
	if server == "" {
		addr, err := etcdwrapper.Read(fmt.Sprintf("/services/api/%s", stage))
		if err != nil {
			glog.Errorf("failed to get API server from etcd: %v", err)
			return "", err
		}
		glog.Infof("etcd says API server can be found at: %s\n", addr)
		server = addr
	}
	return fmt.Sprintf("http://%s%s", server, endpoint), nil
}

func (p jsonAPI) GetMonkey(id int) (*api.Monkey, error) {
	// TODO: query JSON API here.
	return nil, fmt.Errorf("TODO: implement getMonkey")
}

func (p jsonAPI) GetMonkeys() (*api.Monkeys, error) {
	target, err := getURL("/monkeys")
	if err != nil {
		// TODO: Should return 503 Service Unavailable here - only can
		// happen if etcd doesn't know about our API backend.
		return nil, fmt.Errorf("failed to find URL: %v", err)
	}
	r, err := http.Get(target)
	if err != nil {
		return nil, fmt.Errorf("failed to GET /monkeys: %v", err)
	}
	if r.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("non-success status from GET /monkeys: %s", r.Status)
	}
	m := api.Monkeys{}
	if err = json.NewDecoder(r.Body).Decode(&m); err != nil {
		return nil, fmt.Errorf("couldn't decode response: %v", err)
	}
	return &m, nil
}

func (p jsonAPI) AddMonkey(m api.Monkey) error {
	// TODO: pass data to JSON API here.
	return fmt.Errorf("TODO: implement addMonkey")
}

func main() {
	flag.Parse()
	stage = os.Getenv("STAGE")
	glog.V(2).Infof("web starting with stage=%s, -web_version=%s, -api_server=%s\n", stage, *buildVersion, *apiServer)
	if stage == "" {
		log.Fatalf("FATAL: no STAGE set as environment variable")
	}
	fmt.Printf("[%s] web layer for stage %q binding to %s..\n", *buildVersion, stage, bindAddr)
	http.Handle("/", webHandler{jsonAPI{}})
	log.Fatal(http.ListenAndServe(bindAddr, nil))
}
<commit_msg>adds expvar support for web layer, and some TODOs. now returns 503 Service Unavailable when we can't find API layer<commit_after>// web.go: Exposes results from api as HTML.
package main

import (
	"encoding/json"
	"expvar"
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"

	"github.com/golang/glog"

	"hkjn.me/junk/coreos/src/api"
	"hkjn.me/junk/coreos/src/etcdwrapper"
)

var (
	apiServer = flag.String("api_server", "", "If set, HTTP address of API server. If not set, address is read from etcd")
	// TODO: expose -web_version as expvar so Datadog can graph it.
	buildVersion = flag.String("web_version", "unknown revision", "Build version of web server")
	// Note that we always bind to the same port internally; the
	// .service file can map it to any external port that's desired
	// based on which stage we're running.
	bindAddr = ":9000"
	stage    = "" // prod|staging|testN|dev|unittest
)

type (
	// webHandler handles HTTP requests for monkeys.
	webHandler struct {
		p api.MonkeyAPI // provider of the monkeys
	}

	// jsonAPI implements api.MonkeyAPI by HTTP requests to the JSON API service.
	jsonAPI struct{}
)

// ServeHTTP serves the index page.
func (h webHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Note: We just do some arbitrary checks for stage here to prove
	// that we can have different internal behavior in the app
	// depending on which stage we're running on (prod, test, ..). In
	// a real deployment this should be abstracted away in e.g. a
	// shared package that reads some config defining the stages.
	msg := fmt.Sprintf("Hi from web layer on %s?! I don't even know what I'm supposed to do in this kind of environment!", stage)
	if stage == "test" {
		msg = "Hi from web layer on test!"
	} else if stage == "unittest" {
		msg = "Yes, automatic tester, I'm working as intended."
	} else if stage == "prod" {
		msg = "Hi, I'm the sooper productionized prod web layer!"
	}
	m, err := h.p.GetMonkeys()
	if err != nil {
		// TODO: We could be more discriminating with the type of error
		// here - API could also have a bug or otherwise fail internally
		// for reasons that do not correspond to having an unreachable DB.
		log.Printf("Error from API: %v\n", err)
		http.Error(w, "Not ready to serve.", http.StatusServiceUnavailable)
		return
	}
	// TODO: use html.tmpl.
	fmt.Fprintf(w, "
%s

Here's your monkeys:

%s
", msg, m)
}

// getURL returns the URL for a specific API endpoint.
//
// getURL uses specified value from -api_server if present, otherwise
// reads /services/api/[stage] from etcd.
func getURL(endpoint string) (string, error) {
	server := *apiServer
	if server == "" {
		addr, err := etcdwrapper.Read(fmt.Sprintf("/services/api/%s", stage))
		if err != nil {
			glog.Errorf("failed to get API server from etcd: %v", err)
			return "", err
		}
		glog.Infof("etcd says API server can be found at: %s\n", addr)
		server = addr
	}
	return fmt.Sprintf("http://%s%s", server, endpoint), nil
}

func (p jsonAPI) GetMonkey(id int) (*api.Monkey, error) {
	// TODO: query JSON API here.
	return nil, fmt.Errorf("TODO: implement getMonkey")
}

func (p jsonAPI) GetMonkeys() (*api.Monkeys, error) {
	target, err := getURL("/monkeys")
	if err != nil {
		return nil, fmt.Errorf("failed to find URL: %v", err)
	}
	r, err := http.Get(target)
	if err != nil {
		return nil, fmt.Errorf("failed to GET /monkeys: %v", err)
	}
	if r.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("non-success status from GET /monkeys: %s", r.Status)
	}
	m := api.Monkeys{}
	if err = json.NewDecoder(r.Body).Decode(&m); err != nil {
		return nil, fmt.Errorf("couldn't decode response: %v", err)
	}
	return &m, nil
}

func (p jsonAPI) AddMonkey(m api.Monkey) error {
	// TODO: pass data to JSON API here.
	return fmt.Errorf("TODO: implement addMonkey")
}

func main() {
	flag.Parse()
	stage = os.Getenv("STAGE")
	glog.V(2).Infof("web starting with stage=%s, -web_version=%s, -api_server=%s\n", stage, *buildVersion, *apiServer)
	if stage == "" {
		log.Fatalf("FATAL: no STAGE set as environment variable")
	}
	fmt.Printf("[%s] web layer for stage %q binding to %s..\n", *buildVersion, stage, bindAddr)
	expvar.NewString("build_version").Set(*buildVersion)

	// TODO: Since we import expvar, we will serve internal state at
	// /debug/vars. If this really was an externally-facing web server,
	// we should not be exposing such low-level details to users.
	http.Handle("/", webHandler{jsonAPI{}})
	log.Fatal(http.ListenAndServe(bindAddr, nil))
}
<|endoftext|>


<commit_before>package ssh

import (
	"log"
	"net"
)

// ConnectFunc is a convenience method for returning a function
// that just uses net.Dial to communicate with the remote end that
// is suitable for use with the SSH communicator configuration.
func ConnectFunc(network, addr string) func() (net.Conn, error) {
	return func() (net.Conn, error) {
		log.Printf("Opening conn for SSH to %s %s", network, addr)
		return net.Dial(network, addr)
	}
}
<commit_msg>communicator/ssh: ConnectFunc times out after 15 sceonds<commit_after>package ssh

import (
	"log"
	"net"
	"time"
)

// ConnectFunc is a convenience method for returning a function
// that just uses net.Dial to communicate with the remote end that
// is suitable for use with the SSH communicator configuration.
func ConnectFunc(network, addr string) func() (net.Conn, error) {
	return func() (net.Conn, error) {
		log.Printf("Opening conn for SSH to %s %s", network, addr)
		return net.DialTimeout(network, addr, 15 * time.Second)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"

	"github.com/aaparella/Drago"
)

func main() {
	activations := []Drago.Activator{new(Drago.Sigmoid), new(Drago.Sigmoid)}
	net := Drago.New(.5, 50, []int{2, 3, 3, 1}, activations)
	net.Learn([][][]float64{
		{{0, 0}, {0}},
		{{1, 0}, {0}},
		{{0, 1}, {0}},
		{{1, 1}, {1}},
	})

	fmt.Println(net.Predict([]float64{0, 0}))
	fmt.Println(net.Predict([]float64{0, 1}))
	fmt.Println(net.Predict([]float64{1, 0}))
	fmt.Println(net.Predict([]float64{1, 1}))
}
<commit_msg>Update example<commit_after>package main

import (
	"fmt"

	"github.com/aaparella/Drago"
)

func main() {
	activations := []Drago.Activator{new(Drago.Sigmoid), new(Drago.Sigmoid)}
	net := Drago.New(.5, 50, []int{2, 3, 1}, activations)
	net.Learn([][][]float64{
		{{0, 0}, {0}},
		{{1, 0}, {0}},
		{{0, 1}, {0}},
		{{1, 1}, {1}},
	})

	fmt.Println(net.Predict([]float64{0, 0}))
	fmt.Println(net.Predict([]float64{0, 1}))
	fmt.Println(net.Predict([]float64{1, 0}))
	fmt.Println(net.Predict([]float64{1, 1}))
}
<|endoftext|>


<commit_before>//go:generate mapstructure-to-hcl2 -type Config

package restart

import (
	"bytes"
	"context"
	"fmt"
	"io"

	"log"
	"strings"
	"sync"
	"time"

	"github.com/hashicorp/hcl/v2/hcldec"
	"github.com/hashicorp/packer/common"
	"github.com/hashicorp/packer/common/retry"
	"github.com/hashicorp/packer/helper/config"
	"github.com/hashicorp/packer/packer"
	"github.com/hashicorp/packer/template/interpolate"
	"github.com/masterzen/winrm"
)

var DefaultRestartCommand = `shutdown /r /f /t 0 /c "packer restart"`
var DefaultRestartCheckCommand = winrm.Powershell(`echo ("{0} restarted." -f [System.Net.Dns]::GetHostName())`)
var retryableSleep = 5 * time.Second
var TryCheckReboot = `shutdown /r /f /t 60 /c "packer restart test"`
var AbortReboot = `shutdown /a`

var DefaultRegistryKeys = []string{
	"HKLM:SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Component Based Servicing\\RebootPending",
	"HKLM:SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Component Based Servicing\\PackagesPending",
	"HKLM:Software\\Microsoft\\Windows\\CurrentVersion\\Component Based Servicing\\RebootInProgress",
}

type Config struct {
	common.PackerConfig `mapstructure:",squash"`

	// The command used to restart the guest machine
	RestartCommand string `mapstructure:"restart_command"`

	// The command used to check if the guest machine has restarted
	// The output of this command will be displayed to the user
	RestartCheckCommand string `mapstructure:"restart_check_command"`

	// The timeout for waiting for the machine to restart
	RestartTimeout time.Duration `mapstructure:"restart_timeout"`

	// Whether to check the registry (see RegistryKeys) for pending reboots
	CheckKey bool `mapstructure:"check_registry"`

	// custom keys to check for
	RegistryKeys []string `mapstructure:"registry_keys"`

	ctx interpolate.Context
}

type Provisioner struct {
	config     Config
	comm       packer.Communicator
	ui         packer.Ui
	cancel     chan struct{}
	cancelLock sync.Mutex
}

func (p *Provisioner) ConfigSpec() hcldec.ObjectSpec { return p.config.FlatMapstructure().HCL2Spec() }

func (p *Provisioner) Prepare(raws ...interface{}) error {
	err := config.Decode(&p.config, &config.DecodeOpts{
		Interpolate:        true,
		InterpolateContext: &p.config.ctx,
		InterpolateFilter: &interpolate.RenderFilter{
			Exclude: []string{
				"execute_command",
			},
		},
	}, raws...)
	if err != nil {
		return err
	}

	if p.config.RestartCommand == "" {
		p.config.RestartCommand = DefaultRestartCommand
	}

	if p.config.RestartCheckCommand == "" {
		p.config.RestartCheckCommand = DefaultRestartCheckCommand
	}

	if p.config.RestartTimeout == 0 {
		p.config.RestartTimeout = 5 * time.Minute
	}

	if len(p.config.RegistryKeys) == 0 {
		p.config.RegistryKeys = DefaultRegistryKeys
	}

	return nil
}

func (p *Provisioner) Provision(ctx context.Context, ui packer.Ui, comm packer.Communicator, _ map[string]interface{}) error {
	p.cancelLock.Lock()
	p.cancel = make(chan struct{})
	p.cancelLock.Unlock()

	ui.Say("Restarting Machine")
	p.comm = comm
	p.ui = ui

	var cmd *packer.RemoteCmd
	command := p.config.RestartCommand
	err := retry.Config{StartTimeout: p.config.RestartTimeout}.Run(ctx, func(context.Context) error {
		cmd = &packer.RemoteCmd{Command: command}
		return cmd.RunWithUi(ctx, comm, ui)
	})

	if err != nil {
		return err
	}

	if cmd.ExitStatus() != 0 && cmd.ExitStatus() != 1115 && cmd.ExitStatus() != 1190 {
		return fmt.Errorf("Restart script exited with non-zero exit status: %d", cmd.ExitStatus())
	}

	return waitForRestart(ctx, p, comm)
}

var waitForRestart = func(ctx context.Context, p *Provisioner, comm packer.Communicator) error {
	ui := p.ui
	ui.Say("Waiting for machine to restart...")
	waitDone := make(chan bool, 1)
	timeout := time.After(p.config.RestartTimeout)
	var err error

	p.comm = comm
	var cmd *packer.RemoteCmd
	trycommand := TryCheckReboot
	abortcommand := AbortReboot

	// Stolen from Vagrant reboot checker
	for {
		log.Printf("Check if machine is rebooting...")
		cmd = &packer.RemoteCmd{Command: trycommand}
		err = cmd.RunWithUi(ctx, comm, ui)
		if err != nil {
			// Couldn't execute, we assume machine is rebooting already
			break
		}
		if cmd.ExitStatus() == 1 {
			// SSH provisioner, and we're already rebooting. SSH can reconnect
			// without our help; exit this wait loop.
			break
		}
		if cmd.ExitStatus() == 1115 || cmd.ExitStatus() == 1190 || cmd.ExitStatus() == 1717 {
			// Reboot already in progress but not completed
			log.Printf("Reboot already in progress, waiting...")
			time.Sleep(10 * time.Second)
		}
		if cmd.ExitStatus() == 0 {
			// Cancel reboot we created to test if machine was already rebooting
			cmd = &packer.RemoteCmd{Command: abortcommand}
			cmd.RunWithUi(ctx, comm, ui)
			break
		}
	}

	go func() {
		log.Printf("Waiting for machine to become available...")
		err = waitForCommunicator(ctx, p)
		waitDone <- true
	}()

	log.Printf("Waiting for machine to reboot with timeout: %s", p.config.RestartTimeout)

WaitLoop:
	for {
		// Wait for either WinRM to become available, a timeout to occur,
		// or an interrupt to come through.
		select {
		case <-waitDone:
			if err != nil {
				ui.Error(fmt.Sprintf("Error waiting for machine to restart: %s", err))
				return err
			}

			ui.Say("Machine successfully restarted, moving on")
			close(p.cancel)
			break WaitLoop
		case <-timeout:
			err := fmt.Errorf("Timeout waiting for machine to restart.")
			ui.Error(err.Error())
			close(p.cancel)
			return err
		case <-p.cancel:
			close(waitDone)
			return fmt.Errorf("Interrupt detected, quitting waiting for machine to restart")
		}
	}
	return nil

}

var waitForCommunicator = func(ctx context.Context, p *Provisioner) error {
	runCustomRestartCheck := true
	if p.config.RestartCheckCommand == DefaultRestartCheckCommand {
		runCustomRestartCheck = false
	}
	// This command is configurable by the user to make sure that the
	// vm has met their necessary criteria for having restarted. If the
	// user doesn't set a special restart command, we just run the
	// default as cmdModuleLoad below.
	cmdRestartCheck := &packer.RemoteCmd{Command: p.config.RestartCheckCommand}
	log.Printf("Checking that communicator is connected with: '%s'",
		cmdRestartCheck.Command)
	for {
		select {
		case <-ctx.Done():
			log.Println("Communicator wait canceled, exiting loop")
			return fmt.Errorf("Communicator wait canceled")
		case <-time.After(retryableSleep):
		}
		if runCustomRestartCheck {
			// run user-configured restart check
			err := cmdRestartCheck.RunWithUi(ctx, p.comm, p.ui)
			if err != nil {
				log.Printf("Communication connection err: %s", err)
				continue
			}
			log.Printf("Connected to machine")
			runCustomRestartCheck = false
		}
		// This is the non-user-configurable check that powershell
		// modules have loaded.

		// If we catch the restart in just the right place, we will be able
		// to run the restart check but the output will be an error message
		// about how it needs powershell modules to load, and we will start
		// provisioning before powershell is actually ready.
		// In this next check, we parse stdout to make sure that the command is
		// actually running as expected.
		cmdModuleLoad := &packer.RemoteCmd{Command: DefaultRestartCheckCommand}
		var buf, buf2 bytes.Buffer
		cmdModuleLoad.Stdout = &buf
		cmdModuleLoad.Stdout = io.MultiWriter(cmdModuleLoad.Stdout, &buf2)

		cmdModuleLoad.RunWithUi(ctx, p.comm, p.ui)
		stdoutToRead := buf2.String()

		if !strings.Contains(stdoutToRead, "restarted.") {
			log.Printf("echo didn't succeed; retrying...")
			continue
		}

		if p.config.CheckKey {
			log.Printf("Connected to machine")
			shouldContinue := false
			for _, RegKey := range p.config.RegistryKeys {
				KeyTestCommand := winrm.Powershell(fmt.Sprintf(`Test-Path "%s"`, RegKey))
				cmdKeyCheck := &packer.RemoteCmd{Command: KeyTestCommand}
				log.Printf("Checking registry for pending reboots")
				var buf, buf2 bytes.Buffer
				cmdKeyCheck.Stdout = &buf
				cmdKeyCheck.Stdout = io.MultiWriter(cmdKeyCheck.Stdout, &buf2)

				err := cmdKeyCheck.RunWithUi(ctx, p.comm, p.ui)
				if err != nil {
					log.Printf("Communication connection err: %s", err)
					shouldContinue = true
				}
				cmdKeyCheck.Wait()

				stdoutToRead := buf2.String()
				if strings.Contains(stdoutToRead, "True") {
					log.Printf("RegistryKey %s exists; waiting...", KeyTestCommand)
					shouldContinue = true
				} else {
					log.Printf("No Registry keys found; exiting wait loop")
				}
			}
			if shouldContinue {
				continue
			}
		}
		break
	}

	return nil
}
<commit_msg>RunWithUI already calls Wait on the command<commit_after>//go:generate mapstructure-to-hcl2 -type Config

package restart

import (
	"bytes"
	"context"
	"fmt"
	"io"

	"log"
	"strings"
	"sync"
	"time"

	"github.com/hashicorp/hcl/v2/hcldec"
	"github.com/hashicorp/packer/common"
	"github.com/hashicorp/packer/common/retry"
	"github.com/hashicorp/packer/helper/config"
	"github.com/hashicorp/packer/packer"
	"github.com/hashicorp/packer/template/interpolate"
	"github.com/masterzen/winrm"
)

var DefaultRestartCommand = `shutdown /r /f /t 0 /c "packer restart"`
var DefaultRestartCheckCommand = winrm.Powershell(`echo ("{0} restarted." -f [System.Net.Dns]::GetHostName())`)
var retryableSleep = 5 * time.Second
var TryCheckReboot = `shutdown /r /f /t 60 /c "packer restart test"`
var AbortReboot = `shutdown /a`

var DefaultRegistryKeys = []string{
	"HKLM:SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Component Based Servicing\\RebootPending",
	"HKLM:SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Component Based Servicing\\PackagesPending",
	"HKLM:Software\\Microsoft\\Windows\\CurrentVersion\\Component Based Servicing\\RebootInProgress",
}

type Config struct {
	common.PackerConfig `mapstructure:",squash"`

	// The command used to restart the guest machine
	RestartCommand string `mapstructure:"restart_command"`

	// The command used to check if the guest machine has restarted
	// The output of this command will be displayed to the user
	RestartCheckCommand string `mapstructure:"restart_check_command"`

	// The timeout for waiting for the machine to restart
	RestartTimeout time.Duration `mapstructure:"restart_timeout"`

	// Whether to check the registry (see RegistryKeys) for pending reboots
	CheckKey bool `mapstructure:"check_registry"`

	// custom keys to check for
	RegistryKeys []string `mapstructure:"registry_keys"`

	ctx interpolate.Context
}

type Provisioner struct {
	config     Config
	comm       packer.Communicator
	ui         packer.Ui
	cancel     chan struct{}
	cancelLock sync.Mutex
}

func (p *Provisioner) ConfigSpec() hcldec.ObjectSpec { return p.config.FlatMapstructure().HCL2Spec() }

func (p *Provisioner) Prepare(raws ...interface{}) error {
	err := config.Decode(&p.config, &config.DecodeOpts{
		Interpolate:        true,
		InterpolateContext: &p.config.ctx,
		InterpolateFilter: &interpolate.RenderFilter{
			Exclude: []string{
				"execute_command",
			},
		},
	}, raws...)
	if err != nil {
		return err
	}

	if p.config.RestartCommand == "" {
		p.config.RestartCommand = DefaultRestartCommand
	}

	if p.config.RestartCheckCommand == "" {
		p.config.RestartCheckCommand = DefaultRestartCheckCommand
	}

	if p.config.RestartTimeout == 0 {
		p.config.RestartTimeout = 5 * time.Minute
	}

	if len(p.config.RegistryKeys) == 0 {
		p.config.RegistryKeys = DefaultRegistryKeys
	}

	return nil
}

func (p *Provisioner) Provision(ctx context.Context, ui packer.Ui, comm packer.Communicator, _ map[string]interface{}) error {
	p.cancelLock.Lock()
	p.cancel = make(chan struct{})
	p.cancelLock.Unlock()

	ui.Say("Restarting Machine")
	p.comm = comm
	p.ui = ui

	var cmd *packer.RemoteCmd
	command := p.config.RestartCommand
	err := retry.Config{StartTimeout: p.config.RestartTimeout}.Run(ctx, func(context.Context) error {
		cmd = &packer.RemoteCmd{Command: command}
		return cmd.RunWithUi(ctx, comm, ui)
	})

	if err != nil {
		return err
	}

	if cmd.ExitStatus() != 0 && cmd.ExitStatus() != 1115 && cmd.ExitStatus() != 1190 {
		return fmt.Errorf("Restart script exited with non-zero exit status: %d", cmd.ExitStatus())
	}

	return waitForRestart(ctx, p, comm)
}

var waitForRestart = func(ctx context.Context, p *Provisioner, comm packer.Communicator) error {
	ui := p.ui
	ui.Say("Waiting for machine to restart...")
	waitDone := make(chan bool, 1)
	timeout := time.After(p.config.RestartTimeout)
	var err error

	p.comm = comm
	var cmd *packer.RemoteCmd
	trycommand := TryCheckReboot
	abortcommand := AbortReboot

	// Stolen from Vagrant reboot checker
	for {
		log.Printf("Check if machine is rebooting...")
		cmd = &packer.RemoteCmd{Command: trycommand}
		err = cmd.RunWithUi(ctx, comm, ui)
		if err != nil {
			// Couldn't execute, we assume machine is rebooting already
			break
		}
		if cmd.ExitStatus() == 1 {
			// SSH provisioner, and we're already rebooting. SSH can reconnect
			// without our help; exit this wait loop.
			break
		}
		if cmd.ExitStatus() == 1115 || cmd.ExitStatus() == 1190 || cmd.ExitStatus() == 1717 {
			// Reboot already in progress but not completed
			log.Printf("Reboot already in progress, waiting...")
			time.Sleep(10 * time.Second)
		}
		if cmd.ExitStatus() == 0 {
			// Cancel reboot we created to test if machine was already rebooting
			cmd = &packer.RemoteCmd{Command: abortcommand}
			cmd.RunWithUi(ctx, comm, ui)
			break
		}
	}

	go func() {
		log.Printf("Waiting for machine to become available...")
		err = waitForCommunicator(ctx, p)
		waitDone <- true
	}()

	log.Printf("Waiting for machine to reboot with timeout: %s", p.config.RestartTimeout)

WaitLoop:
	for {
		// Wait for either WinRM to become available, a timeout to occur,
		// or an interrupt to come through.
		select {
		case <-waitDone:
			if err != nil {
				ui.Error(fmt.Sprintf("Error waiting for machine to restart: %s", err))
				return err
			}

			ui.Say("Machine successfully restarted, moving on")
			close(p.cancel)
			break WaitLoop
		case <-timeout:
			err := fmt.Errorf("Timeout waiting for machine to restart.")
			ui.Error(err.Error())
			close(p.cancel)
			return err
		case <-p.cancel:
			close(waitDone)
			return fmt.Errorf("Interrupt detected, quitting waiting for machine to restart")
		}
	}
	return nil

}

var waitForCommunicator = func(ctx context.Context, p *Provisioner) error {
	runCustomRestartCheck := true
	if p.config.RestartCheckCommand == DefaultRestartCheckCommand {
		runCustomRestartCheck = false
	}
	// This command is configurable by the user to make sure that the
	// vm has met their necessary criteria for having restarted. If the
	// user doesn't set a special restart command, we just run the
	// default as cmdModuleLoad below.
	cmdRestartCheck := &packer.RemoteCmd{Command: p.config.RestartCheckCommand}
	log.Printf("Checking that communicator is connected with: '%s'",
		cmdRestartCheck.Command)
	for {
		select {
		case <-ctx.Done():
			log.Println("Communicator wait canceled, exiting loop")
			return fmt.Errorf("Communicator wait canceled")
		case <-time.After(retryableSleep):
		}
		if runCustomRestartCheck {
			// run user-configured restart check
			err := cmdRestartCheck.RunWithUi(ctx, p.comm, p.ui)
			if err != nil {
				log.Printf("Communication connection err: %s", err)
				continue
			}
			log.Printf("Connected to machine")
			runCustomRestartCheck = false
		}
		// This is the non-user-configurable check that powershell
		// modules have loaded.

		// If we catch the restart in just the right place, we will be able
		// to run the restart check but the output will be an error message
		// about how it needs powershell modules to load, and we will start
		// provisioning before powershell is actually ready.
		// In this next check, we parse stdout to make sure that the command is
		// actually running as expected.
		cmdModuleLoad := &packer.RemoteCmd{Command: DefaultRestartCheckCommand}
		var buf, buf2 bytes.Buffer
		cmdModuleLoad.Stdout = &buf
		cmdModuleLoad.Stdout = io.MultiWriter(cmdModuleLoad.Stdout, &buf2)

		cmdModuleLoad.RunWithUi(ctx, p.comm, p.ui)
		stdoutToRead := buf2.String()

		if !strings.Contains(stdoutToRead, "restarted.") {
			log.Printf("echo didn't succeed; retrying...")
			continue
		}

		if p.config.CheckKey {
			log.Printf("Connected to machine")
			shouldContinue := false
			for _, RegKey := range p.config.RegistryKeys {
				KeyTestCommand := winrm.Powershell(fmt.Sprintf(`Test-Path "%s"`, RegKey))
				cmdKeyCheck := &packer.RemoteCmd{Command: KeyTestCommand}
				log.Printf("Checking registry for pending reboots")
				var buf, buf2 bytes.Buffer
				cmdKeyCheck.Stdout = &buf
				cmdKeyCheck.Stdout = io.MultiWriter(cmdKeyCheck.Stdout, &buf2)

				err := cmdKeyCheck.RunWithUi(ctx, p.comm, p.ui)
				if err != nil {
					log.Printf("Communication connection err: %s", err)
					shouldContinue = true
				}

				stdoutToRead := buf2.String()
				if strings.Contains(stdoutToRead, "True") {
					log.Printf("RegistryKey %s exists; waiting...", KeyTestCommand)
					shouldContinue = true
				} else {
					log.Printf("No Registry keys found; exiting wait loop")
				}
			}
			if shouldContinue {
				continue
			}
		}
		break
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	. "github.com/bytbox/goprep/goprep"
	"go/token"
	"os"
)

type BoolStack struct {
	Val  bool
	Base *BoolStack
}

func Push(s *BoolStack, i bool) *BoolStack {
	return &BoolStack{i, s}
}

func Peek(s *BoolStack) bool {
	return s.Val
}

func Pop(s *BoolStack) (*BoolStack, bool) {
	return s.Base, s.Val
}

// Trigger
func Trigger(p func(Token) bool,
	f func(chan Token, chan Token, chan string, chan interface{})) func(*Pipe) {
	return func(p *Pipe) {

	}
}

func main() {
	p := PipeInit(os.Stdin)
	Lines(p)

	s := (*BoolStack)(nil)
	Link(func(in chan Token,
		tOut chan Token,
		out chan string,
		sync chan interface{}) {
		for tok := range in {
			if tok.Token == token.LBRACE {
				s = Push(s, false)
			}
			if tok.Token == token.RBRACE {
				var b bool
				s, b = Pop(s)
				if b {
					out <- "}}()"
					sync <- nil
					continue
				}
			}
			if tok.Str != "gofor" {
				out <- tok.Str
				sync <- nil
				continue
			}
			out <- "go func() { for"
			sync <- nil
			tok = <-in
			for tok.Token != token.LBRACE {
				out <- tok.Str
				sync <- nil
				tok = <-in
			}
			out <- " {"
			s = Push(s, true)
			sync <- nil
		}
		close(tOut)
	})(p)

	PipeEnd(p, os.Stdout)
}
<commit_msg>Removing 'Trigger' for now<commit_after>package main

import (
	. "github.com/bytbox/goprep/goprep"
	"go/token"
	"os"
)

type BoolStack struct {
	Val  bool
	Base *BoolStack
}

func Push(s *BoolStack, i bool) *BoolStack {
	return &BoolStack{i, s}
}

func Peek(s *BoolStack) bool {
	return s.Val
}

func Pop(s *BoolStack) (*BoolStack, bool) {
	return s.Base, s.Val
}

func main() {
	p := PipeInit(os.Stdin)
	Lines(p)

	s := (*BoolStack)(nil)
	Link(func(in chan Token,
		tOut chan Token,
		out chan string,
		sync chan interface{}) {
		for tok := range in {
			if tok.Token == token.LBRACE {
				s = Push(s, false)
			}
			if tok.Token == token.RBRACE {
				var b bool
				s, b = Pop(s)
				if b {
					out <- "}}()"
					sync <- nil
					continue
				}
			}
			if tok.Str != "gofor" {
				out <- tok.Str
				sync <- nil
				continue
			}
			out <- "go func() { for"
			sync <- nil
			tok = <-in
			for tok.Token != token.LBRACE {
				out <- tok.Str
				sync <- nil
				tok = <-in
			}
			out <- " {"
			s = Push(s, true)
			sync <- nil
		}
		close(tOut)
	})(p)

	PipeEnd(p, os.Stdout)
}
<|endoftext|>


<commit_before>package taggolib

import (
	"bytes"
	"reflect"
	"testing"
)

// TestOGGVorbis verifies that all oggParser methods work properly
func TestOGGVorbis(t *testing.T) {
	// Generate a oggParser
	ogg, err := New(bytes.NewReader(oggVorbisFile))
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	// Verify that we actually got a Ogg Vorbis parser
	if reflect.TypeOf(ogg) != reflect.TypeOf(&oggVorbisParser{}) {
		t.Fatalf("unexpected Ogg Vorbis type: %v", reflect.TypeOf(ogg))
	}

	// Verify all exported methods work properly

	// Album
	if ogg.Album() != "Album" {
		t.Fatalf("mismatched tag Album: %v", ogg.Album())
	}

	// AlbumArtist
	if ogg.AlbumArtist() != "AlbumArtist" {
		t.Fatalf("mismatched tag AlbumArtist: %v", ogg.AlbumArtist())
	}

	// Artist
	if ogg.Artist() != "Artist" {
		t.Fatalf("mismatched tag Artist: %v", ogg.Artist())
	}

	// BitDepth
	if ogg.BitDepth() != 16 {
		t.Fatalf("mismatched property BitDepth: %v", ogg.BitDepth())
	}

	// Bitrate
	if ogg.Bitrate() != 192 {
		t.Fatalf("mismatched property Bitrate: %v", ogg.Bitrate())
	}

	// Channels
	if ogg.Channels() != 2 {
		t.Fatalf("mismatched property Channels: %v", ogg.Channels())
	}

	// Comment
	if ogg.Comment() != "Comment" {
		t.Fatalf("mismatched tag Comment: %v", ogg.Comment())
	}

	// Date
	if ogg.Date() != "2014-01-01" {
		t.Fatalf("mismatched tag Date: %v", ogg.Date())
	}

	// DiscNumber
	if ogg.DiscNumber() != 1 {
		t.Fatalf("mismatched tag DiscNumber: %v", ogg.DiscNumber())
	}

	// Duration
	if int(ogg.Duration().Seconds()) != 5 {
		t.Fatalf("mismatched property Duration: %v", ogg.Duration().Seconds())
	}

	// Encoder
	if ogg.Encoder() != "Lavf53.21.1" {
		t.Fatalf("mismatched property Encoder: %v", ogg.Encoder())
	}

	// Format
	if ogg.Format() != "Ogg Vorbis" {
		t.Fatalf("mismatched property Format: %v", ogg.Format())
	}

	// Genre
	if ogg.Genre() != "Genre" {
		t.Fatalf("mismatched tag Genre: %v", ogg.Genre())
	}

	// SampleRate
	if ogg.SampleRate() != 44100 {
		t.Fatalf("mismatched property SampleRate: %v", ogg.SampleRate())
	}

	// Publisher
	if ogg.Publisher() != "Publisher" {
		t.Fatalf("mismatched tag Pubisher: %v", ogg.Publisher())
	}

	// Title
	if ogg.Title() != "Title" {
		t.Fatalf("mismatched tag Title: %v", ogg.Title())
	}

	// TrackNumber
	if ogg.TrackNumber() != 1 {
		t.Fatalf("mismatched tag TrackNumber: %v", ogg.TrackNumber())
	}

	// Check a few raw tags

	if ogg.Tag("ARTIST") != "Artist" {
		t.Fatalf("unexpected raw tag ARTIST: %v", ogg.Tag("ARTIST"))
	}

	if ogg.Tag("ALBUM") != "Album" {
		t.Fatalf("unexpected raw tag ALBUM: %v", ogg.Tag("ALBUM"))
	}

	if ogg.Tag("TITLE") != "Title" {
		t.Fatalf("unexpected raw tag TITLE: %v", ogg.Tag("TITLE"))
	}

	// Check a non-existant tag
	if ogg.Tag("NOTEXISTS") != "" {
		t.Fatalf("unexpected raw tag NOTEXISTS: %v", ogg.Tag("NOTEXISTS"))
	}
}
<commit_msg>oggvorbis_test: fix typo in test<commit_after>package taggolib

import (
	"bytes"
	"reflect"
	"testing"
)

// TestOGGVorbis verifies that all oggParser methods work properly
func TestOGGVorbis(t *testing.T) {
	// Generate a oggParser
	ogg, err := New(bytes.NewReader(oggVorbisFile))
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	// Verify that we actually got a Ogg Vorbis parser
	if reflect.TypeOf(ogg) != reflect.TypeOf(&oggVorbisParser{}) {
		t.Fatalf("unexpected Ogg Vorbis type: %v", reflect.TypeOf(ogg))
	}

	// Verify all exported methods work properly

	// Album
	if ogg.Album() != "Album" {
		t.Fatalf("mismatched tag Album: %v", ogg.Album())
	}

	// AlbumArtist
	if ogg.AlbumArtist() != "AlbumArtist" {
		t.Fatalf("mismatched tag AlbumArtist: %v", ogg.AlbumArtist())
	}

	// Artist
	if ogg.Artist() != "Artist" {
		t.Fatalf("mismatched tag Artist: %v", ogg.Artist())
	}

	// BitDepth
	if ogg.BitDepth() != 16 {
		t.Fatalf("mismatched property BitDepth: %v", ogg.BitDepth())
	}

	// Bitrate
	if ogg.Bitrate() != 192 {
		t.Fatalf("mismatched property Bitrate: %v", ogg.Bitrate())
	}

	// Channels
	if ogg.Channels() != 2 {
		t.Fatalf("mismatched property Channels: %v", ogg.Channels())
	}

	// Comment
	if ogg.Comment() != "Comment" {
		t.Fatalf("mismatched tag Comment: %v", ogg.Comment())
	}

	// Date
	if ogg.Date() != "2014-01-01" {
		t.Fatalf("mismatched tag Date: %v", ogg.Date())
	}

	// DiscNumber
	if ogg.DiscNumber() != 1 {
		t.Fatalf("mismatched tag DiscNumber: %v", ogg.DiscNumber())
	}

	// Duration
	if int(ogg.Duration().Seconds()) != 5 {
		t.Fatalf("mismatched property Duration: %v", ogg.Duration().Seconds())
	}

	// Encoder
	if ogg.Encoder() != "Lavf53.21.1" {
		t.Fatalf("mismatched property Encoder: %v", ogg.Encoder())
	}

	// Format
	if ogg.Format() != "Ogg Vorbis" {
		t.Fatalf("mismatched property Format: %v", ogg.Format())
	}

	// Genre
	if ogg.Genre() != "Genre" {
		t.Fatalf("mismatched tag Genre: %v", ogg.Genre())
	}

	// SampleRate
	if ogg.SampleRate() != 44100 {
		t.Fatalf("mismatched property SampleRate: %v", ogg.SampleRate())
	}

	// Publisher
	if ogg.Publisher() != "Publisher" {
		t.Fatalf("mismatched tag Publisher: %v", ogg.Publisher())
	}

	// Title
	if ogg.Title() != "Title" {
		t.Fatalf("mismatched tag Title: %v", ogg.Title())
	}

	// TrackNumber
	if ogg.TrackNumber() != 1 {
		t.Fatalf("mismatched tag TrackNumber: %v", ogg.TrackNumber())
	}

	// Check a few raw tags

	if ogg.Tag("ARTIST") != "Artist" {
		t.Fatalf("unexpected raw tag ARTIST: %v", ogg.Tag("ARTIST"))
	}

	if ogg.Tag("ALBUM") != "Album" {
		t.Fatalf("unexpected raw tag ALBUM: %v", ogg.Tag("ALBUM"))
	}

	if ogg.Tag("TITLE") != "Title" {
		t.Fatalf("unexpected raw tag TITLE: %v", ogg.Tag("TITLE"))
	}

	// Check a non-existant tag
	if ogg.Tag("NOTEXISTS") != "" {
		t.Fatalf("unexpected raw tag NOTEXISTS: %v", ogg.Tag("NOTEXISTS"))
	}
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package main

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"runtime"
	"strings"

	"github.com/fatih/color"
)

// Manager manages all api communications
type Manager struct {
	URL string `json:"url"`
}

// Token holds the JWT token that is received when authenticating
type Token struct {
	Token string `json:"token"`
}

// Service ...
type Service struct {
	ID         string `json:"service_id"`
	Name       string `json:"service_name"`
	Datacenter string `json:"datacenter_id"`
	Version    string `json:"service_version"`
	Status     string `json:"service_status"`
	Definition string `json:"service_definition"`
	Result     string `json:"service_result"`
	Endpoint   string `json:"service_endpoint"`
}

// Datacenter ...
type Datacenter struct {
	ID   string `json:"datacenter_id"`
	Name string `json:"datacenter_name"`
}

// User ...
type User struct {
	ID       string `json:"user_id"`
	Name     string `json:"user_name"`
	Email    string `json:"user_email"`
	ClientID string `json:"client_id"`
	IsAdmin  bool   `json:"user_admin"`
}

// Group ...
type Group struct {
	ID   string `json:"client_id"`
	Name string `json:"client_name"`
}

// Session ...
type Session struct {
	UserID    string `json:"user_id"`
	ClientID  string `json:"client_id"`
	UserName  string `json:"user_name"`
	UserEmail string `json:"user_email"`
}

func (m *Manager) client() *http.Client {
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	client := &http.Client{Transport: tr}

	return client
}

func (m *Manager) doRequest(url, method string, payload []byte, token string, contentType string) (string, *http.Response, error) {
	url = m.URL + url
	req, err := http.NewRequest(method, url, bytes.NewBuffer(payload))
	if token != "" {
		req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", token))
	}
	if contentType != "" {
		req.Header.Set("Content-Type", contentType)
	}
	resp, err := m.client().Do(req)

	if err != nil {
		return err.Error(), resp, err
	}
	defer resp.Body.Close()
	responseBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		color.Red(err.Error())
	}
	body := string(responseBody)

	if resp.StatusCode != 200 {
		return string(body), resp, errors.New(resp.Status)
	}
	return string(body), resp, nil
}

func (m *Manager) createClient(token string, name string) (string, error) {
	payload := []byte(`{"client_name":"` + name + `"}`)
	body, _, err := m.doRequest("/clients/", "POST", payload, token, "")
	if err != nil {
		return body, err
	}

	color.Green("SUCCESS: Group " + name + " created")

	var client struct {
		ID string `json:"client_id"`
	}
	err = json.Unmarshal([]byte(body), &client)
	if err != nil {
		return "", errors.New("ERROR: Couldn't read response from server")
	}
	return client.ID, nil
}

func (m *Manager) createUser(token string, client string, user string, password string, email string) error {
	payload := []byte(`{"client_id": "` + client + `", "user_name":"` + user + `", "user_email": "` + email + `", "user_password": "` + password + `"}`)
	_, _, err := m.doRequest("/users/", "POST", payload, token, "")
	if err != nil {
		return err
	}
	color.Green("SUCCESS: User " + user + " created")
	return nil
}

func (m *Manager) getUser(token string, userid string) (user User, err error) {
	res, _, err := m.doRequest("/users/"+userid, "GET", nil, token, "application/yaml")
	json.Unmarshal([]byte(res), &user)
	return user, err
}

func (m *Manager) deleteUser(token string, user string) error {
	_, _, err := m.doRequest("/users/"+user, "DELETE", nil, token, "application/yaml")
	return err
}

func (m *Manager) getSession(token string) (session Session, err error) {
	res, _, err := m.doRequest("/session/", "GET", nil, token, "application/yaml")
	json.Unmarshal([]byte(res), &session)
	return session, err
}

// ********************* Login *******************

// Login does a login action against the api
func (m *Manager) Login(username string, password string) (token string, err error) {
	var t Token

	f := url.Values{}
	f.Add("username", username)
	f.Add("password", password)

	url := m.URL + "/auth"
	req, err := http.NewRequest("POST", url, strings.NewReader(f.Encode()))
	req.Form = f
	req.PostForm = f
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")

	resp, err := m.client().Do(req)
	if err != nil {
		return "", err
	}

	if resp.StatusCode != 200 {
		return "", errors.New("Unauthorized")
	}
	defer resp.Body.Close()

	responseBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		color.Red(err.Error())
	}

	err = json.Unmarshal(responseBody, &t)
	if err != nil {
		color.Red(err.Error())
	}

	token = t.Token

	return token, nil
}

// ********************* Update *******************

// ChangePassword ...
func (m *Manager) ChangePassword(token string, userid string, oldpassword string, newpassword string) error {
	payload := []byte(`{"old_password":"` + oldpassword + `", "new_password": "` + newpassword + `"}`)
	_, _, err := m.doRequest("/users/"+userid, "PUT", payload, token, "application/yaml")
	if err != nil {
		return err
	}
	return nil
}

// ChangePasswordByAdmin ...
func (m *Manager) ChangePasswordByAdmin(token string, userid string, newpassword string) error {
	payload := []byte(`{"new_password": "` + newpassword + `"}`)
	_, _, err := m.doRequest("/users/"+userid, "PUT", payload, token, "application/yaml")
	if err != nil {
		return err
	}
	return nil
}

// ********************* Create *******************

// CreateDatacenter ...
func (m *Manager) CreateDatacenter(token string, name string, user string, password string, url string, network string, vseURL string) (string, error) {
	payload := []byte(`{"datacenter_name": "` + name + `", "datacenter_type": "vcloud", "datacenter_region": "LON-001", "datacenter_username":"` + user + `", "datacenter_password":"` + password + `", "external_network":"` + network + `", "vcloud_url":"` + url + `", "vse_url":"` + vseURL + `"}`)
	body, _, err := m.doRequest("/datacenters/", "POST", payload, token, "")
	if err != nil {
		return body, err
	}
	color.Green("SUCCESS: Datacenter " + name + " created")
	return body, err
}

// CreateUser ...
func (m *Manager) CreateUser(name string, email string, user string, password string, adminuser string, adminpassword string) error {
	token, err := m.Login(adminuser, adminpassword)
	if err != nil {
		color.Red(err.Error())
		os.Exit(1)
	}
	c, err := m.createClient(token, name)
	if err != nil {
		color.Red(err.Error() + ": Group " + name + " already exists")
		os.Exit(1)
	}
	res := m.createUser(token, c, user, password, email)
	return res
}

// ********************* Get *******************

// GetUser ...
func (m *Manager) GetUser(token string, userid string) (user User, err error) {
	res, _, err := m.doRequest("/users/"+userid, "GET", nil, token, "application/yaml")
	json.Unmarshal([]byte(res), &user)
	return user, err
}

// GetUUID ...
func (m *Manager) GetUUID(token string, payload []byte) string {
	id, err := buildServiceUUID(payload)
	if err != nil {
		log.Fatal(err)
	}
	body, _, err := m.doRequest("/services/uuid/", "POST", []byte(`{"id":"`+id+`"}`), token, "")
	var dat map[string]interface{}
	json.Unmarshal([]byte(body), &dat)

	if str, ok := dat["uuid"].(string); ok {
		return str
	}
	return ""
}

// ********************* Apply *******************

// Apply ...
func (m *Manager) Apply(token string, path string, monit bool) (string, error) {
	payload, err := ioutil.ReadFile(path)
	if err != nil {
		color.Red(err.Error())
		return "", nil
	}

	color.Green("Environment creation requested")
	println("Ernest will show you all output from your requested service creation")
	println("You can cancel at any moment with Ctrl+C, even the service is still being created, you won't have any output")

	streamID := m.GetUUID(token, payload)
	if streamID == "" {
		color.Red("Please log in")
		return "", nil
	}

	if monit == true {
		go Monitorize(m.URL, token, streamID)
	} else {
		println("Additionally you can trace your service on ernest monitor tool with id: " + streamID)
	}

	if body, _, err := m.doRequest("/services/", "POST", payload, token, "application/yaml"); err != nil {
		return "", errors.New(body)
	}
	if monit == true {
		runtime.Goexit()
	}
	return streamID, nil
}

// ********************* Destroy *******************

// Destroy ...
func (m *Manager) Destroy(token string, name string, monit bool) error {
	body, _, err := m.doRequest("/services/"+name, "DELETE", nil, token, "application/yaml")
	if err != nil {
		return err
	}

	var res map[string]interface{}
	json.Unmarshal([]byte(body), &res)

	if monit == true {
		if str, ok := res["stream_id"].(string); ok {
			Monitorize(m.URL, token, str)
			runtime.Goexit()
		}
	}

	return err
}

// ********************* Reset *******************

// ResetService ...
func (m *Manager) ResetService(name string, token string) error {
	_, _, err := m.doRequest("/services/"+name+"/reset/", "POST", nil, token, "application/yaml")
	return err
}

// ********************* Status *******************

// ServiceStatus ...
func (m *Manager) ServiceStatus(token string, serviceName string) (service Service, err error) {
	body, _, err := m.doRequest("/services/"+serviceName, "GET", []byte(""), token, "")
	if err != nil {
		return service, err
	}
	json.Unmarshal([]byte(body), &service)
	return service, err
}

// ServiceBuildStatus ...
func (m *Manager) ServiceBuildStatus(token string, serviceName string, serviceID string) (service Service, err error) {
	body, _, err := m.doRequest("/services/"+serviceName+"/builds/"+serviceID, "GET", []byte(""), token, "")
	if err != nil {
		return service, err
	}
	json.Unmarshal([]byte(body), &service)
	return service, err
}

// ********************* List *********************

// ListDatacenters ...
func (m *Manager) ListDatacenters(token string) (datacenters []Datacenter, err error) {
	body, _, err := m.doRequest("/datacenters/", "GET", []byte(""), token, "")
	if err != nil {
		return nil, err
	}
	json.Unmarshal([]byte(body), &datacenters)
	return datacenters, err
}

// ListServices ...
func (m *Manager) ListServices(token string) (services []Service, err error) {
	body, _, err := m.doRequest("/services/", "GET", []byte(""), token, "")
	if err != nil {
		return nil, err
	}
	json.Unmarshal([]byte(body), &services)
	return services, err
}

// ListBuilds ...
func (m *Manager) ListBuilds(name string, token string) (builds []Service, err error) {
	body, _, err := m.doRequest("/services/"+name+"/builds/", "GET", []byte(""), token, "")
	if err != nil {
		return nil, err
	}
	json.Unmarshal([]byte(body), &builds)
	return builds, err
}

// ListUsers ...
func (m *Manager) ListUsers(token string) (users []User, err error) {
	body, _, err := m.doRequest("/users/", "GET", []byte(""), token, "")
	if err != nil {
		return nil, err
	}
	json.Unmarshal([]byte(body), &users)
	return users, err
}

// ListGroups ...
func (m *Manager) ListGroups(token string) (groups []Group, err error) {
	body, _, err := m.doRequest("/clients/", "GET", []byte(""), token, "")
	if err != nil {
		return nil, err
	}
	json.Unmarshal([]byte(body), &groups)
	return groups, err
}
<commit_msg>err variable assigned but not used<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package main

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"runtime"
	"strings"

	"github.com/fatih/color"
)

// Manager manages all api communications
type Manager struct {
	URL string `json:"url"`
}

// Token holds the JWT token that is received when authenticating
type Token struct {
	Token string `json:"token"`
}

// Service ...
type Service struct {
	ID         string `json:"service_id"`
	Name       string `json:"service_name"`
	Datacenter string `json:"datacenter_id"`
	Version    string `json:"service_version"`
	Status     string `json:"service_status"`
	Definition string `json:"service_definition"`
	Result     string `json:"service_result"`
	Endpoint   string `json:"service_endpoint"`
}

// Datacenter ...
type Datacenter struct {
	ID   string `json:"datacenter_id"`
	Name string `json:"datacenter_name"`
}

// User ...
type User struct {
	ID       string `json:"user_id"`
	Name     string `json:"user_name"`
	Email    string `json:"user_email"`
	ClientID string `json:"client_id"`
	IsAdmin  bool   `json:"user_admin"`
}

// Group ...
type Group struct {
	ID   string `json:"client_id"`
	Name string `json:"client_name"`
}

// Session ...
type Session struct {
	UserID    string `json:"user_id"`
	ClientID  string `json:"client_id"`
	UserName  string `json:"user_name"`
	UserEmail string `json:"user_email"`
}

func (m *Manager) client() *http.Client {
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	client := &http.Client{Transport: tr}

	return client
}

func (m *Manager) doRequest(url, method string, payload []byte, token string, contentType string) (string, *http.Response, error) {
	url = m.URL + url
	req, err := http.NewRequest(method, url, bytes.NewBuffer(payload))
	if token != "" {
		req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", token))
	}
	if contentType != "" {
		req.Header.Set("Content-Type", contentType)
	}
	resp, err := m.client().Do(req)

	if err != nil {
		return err.Error(), resp, err
	}
	defer resp.Body.Close()
	responseBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		color.Red(err.Error())
	}
	body := string(responseBody)

	if resp.StatusCode != 200 {
		return string(body), resp, errors.New(resp.Status)
	}
	return string(body), resp, nil
}

func (m *Manager) createClient(token string, name string) (string, error) {
	payload := []byte(`{"client_name":"` + name + `"}`)
	body, _, err := m.doRequest("/clients/", "POST", payload, token, "")
	if err != nil {
		return body, err
	}

	color.Green("SUCCESS: Group " + name + " created")

	var client struct {
		ID string `json:"client_id"`
	}
	err = json.Unmarshal([]byte(body), &client)
	if err != nil {
		return "", errors.New("ERROR: Couldn't read response from server")
	}
	return client.ID, nil
}

func (m *Manager) createUser(token string, client string, user string, password string, email string) error {
	payload := []byte(`{"client_id": "` + client + `", "user_name":"` + user + `", "user_email": "` + email + `", "user_password": "` + password + `"}`)
	_, _, err := m.doRequest("/users/", "POST", payload, token, "")
	if err != nil {
		return err
	}
	color.Green("SUCCESS: User " + user + " created")
	return nil
}

func (m *Manager) getUser(token string, userid string) (user User, err error) {
	res, _, err := m.doRequest("/users/"+userid, "GET", nil, token, "application/yaml")
	json.Unmarshal([]byte(res), &user)
	return user, err
}

func (m *Manager) deleteUser(token string, user string) error {
	_, _, err := m.doRequest("/users/"+user, "DELETE", nil, token, "application/yaml")
	return err
}

func (m *Manager) getSession(token string) (session Session, err error) {
	res, _, err := m.doRequest("/session/", "GET", nil, token, "application/yaml")
	json.Unmarshal([]byte(res), &session)
	return session, err
}

// ********************* Login *******************

// Login does a login action against the api
func (m *Manager) Login(username string, password string) (token string, err error) {
	var t Token

	f := url.Values{}
	f.Add("username", username)
	f.Add("password", password)

	url := m.URL + "/auth"
	req, err := http.NewRequest("POST", url, strings.NewReader(f.Encode()))
	req.Form = f
	req.PostForm = f
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")

	resp, err := m.client().Do(req)
	if err != nil {
		return "", err
	}

	if resp.StatusCode != 200 {
		return "", errors.New("Unauthorized")
	}
	defer resp.Body.Close()

	responseBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		color.Red(err.Error())
	}

	err = json.Unmarshal(responseBody, &t)
	if err != nil {
		color.Red(err.Error())
	}

	token = t.Token

	return token, nil
}

// ********************* Update *******************

// ChangePassword ...
func (m *Manager) ChangePassword(token string, userid string, oldpassword string, newpassword string) error {
	payload := []byte(`{"old_password":"` + oldpassword + `", "new_password": "` + newpassword + `"}`)
	_, _, err := m.doRequest("/users/"+userid, "PUT", payload, token, "application/yaml")
	if err != nil {
		return err
	}
	return nil
}

// ChangePasswordByAdmin ...
func (m *Manager) ChangePasswordByAdmin(token string, userid string, newpassword string) error {
	payload := []byte(`{"new_password": "` + newpassword + `"}`)
	_, _, err := m.doRequest("/users/"+userid, "PUT", payload, token, "application/yaml")
	if err != nil {
		return err
	}
	return nil
}

// ********************* Create *******************

// CreateDatacenter ...
func (m *Manager) CreateDatacenter(token string, name string, user string, password string, url string, network string, vseURL string) (string, error) {
	payload := []byte(`{"datacenter_name": "` + name + `", "datacenter_type": "vcloud", "datacenter_region": "LON-001", "datacenter_username":"` + user + `", "datacenter_password":"` + password + `", "external_network":"` + network + `", "vcloud_url":"` + url + `", "vse_url":"` + vseURL + `"}`)
	body, _, err := m.doRequest("/datacenters/", "POST", payload, token, "")
	if err != nil {
		return body, err
	}
	color.Green("SUCCESS: Datacenter " + name + " created")
	return body, err
}

// CreateUser ...
func (m *Manager) CreateUser(name string, email string, user string, password string, adminuser string, adminpassword string) error {
	token, err := m.Login(adminuser, adminpassword)
	if err != nil {
		color.Red(err.Error())
		os.Exit(1)
	}
	c, err := m.createClient(token, name)
	if err != nil {
		color.Red(err.Error() + ": Group " + name + " already exists")
		os.Exit(1)
	}
	res := m.createUser(token, c, user, password, email)
	return res
}

// ********************* Get *******************

// GetUser ...
func (m *Manager) GetUser(token string, userid string) (user User, err error) {
	res, _, err := m.doRequest("/users/"+userid, "GET", nil, token, "application/yaml")
	json.Unmarshal([]byte(res), &user)
	return user, err
}

// GetUUID ...
func (m *Manager) GetUUID(token string, payload []byte) string {
	id, err := buildServiceUUID(payload)
	if err != nil {
		log.Fatal(err)
	}
	body, _, _ := m.doRequest("/services/uuid/", "POST", []byte(`{"id":"`+id+`"}`), token, "")
	var dat map[string]interface{}
	json.Unmarshal([]byte(body), &dat)

	if str, ok := dat["uuid"].(string); ok {
		return str
	}
	return ""
}

// ********************* Apply *******************

// Apply ...
func (m *Manager) Apply(token string, path string, monit bool) (string, error) {
	payload, err := ioutil.ReadFile(path)
	if err != nil {
		color.Red(err.Error())
		return "", nil
	}

	color.Green("Environment creation requested")
	println("Ernest will show you all output from your requested service creation")
	println("You can cancel at any moment with Ctrl+C, even the service is still being created, you won't have any output")

	streamID := m.GetUUID(token, payload)
	if streamID == "" {
		color.Red("Please log in")
		return "", nil
	}

	if monit == true {
		go Monitorize(m.URL, token, streamID)
	} else {
		println("Additionally you can trace your service on ernest monitor tool with id: " + streamID)
	}

	if body, _, err := m.doRequest("/services/", "POST", payload, token, "application/yaml"); err != nil {
		return "", errors.New(body)
	}
	if monit == true {
		runtime.Goexit()
	}
	return streamID, nil
}

// ********************* Destroy *******************

// Destroy ...
func (m *Manager) Destroy(token string, name string, monit bool) error {
	body, _, err := m.doRequest("/services/"+name, "DELETE", nil, token, "application/yaml")
	if err != nil {
		return err
	}

	var res map[string]interface{}
	json.Unmarshal([]byte(body), &res)

	if monit == true {
		if str, ok := res["stream_id"].(string); ok {
			Monitorize(m.URL, token, str)
			runtime.Goexit()
		}
	}

	return err
}

// ********************* Reset *******************

// ResetService ...
func (m *Manager) ResetService(name string, token string) error {
	_, _, err := m.doRequest("/services/"+name+"/reset/", "POST", nil, token, "application/yaml")
	return err
}

// ********************* Status *******************

// ServiceStatus ...
func (m *Manager) ServiceStatus(token string, serviceName string) (service Service, err error) {
	body, _, err := m.doRequest("/services/"+serviceName, "GET", []byte(""), token, "")
	if err != nil {
		return service, err
	}
	json.Unmarshal([]byte(body), &service)
	return service, err
}

// ServiceBuildStatus ...
func (m *Manager) ServiceBuildStatus(token string, serviceName string, serviceID string) (service Service, err error) {
	body, _, err := m.doRequest("/services/"+serviceName+"/builds/"+serviceID, "GET", []byte(""), token, "")
	if err != nil {
		return service, err
	}
	json.Unmarshal([]byte(body), &service)
	return service, err
}

// ********************* List *********************

// ListDatacenters ...
func (m *Manager) ListDatacenters(token string) (datacenters []Datacenter, err error) {
	body, _, err := m.doRequest("/datacenters/", "GET", []byte(""), token, "")
	if err != nil {
		return nil, err
	}
	json.Unmarshal([]byte(body), &datacenters)
	return datacenters, err
}

// ListServices ...
func (m *Manager) ListServices(token string) (services []Service, err error) {
	body, _, err := m.doRequest("/services/", "GET", []byte(""), token, "")
	if err != nil {
		return nil, err
	}
	json.Unmarshal([]byte(body), &services)
	return services, err
}

// ListBuilds ...
func (m *Manager) ListBuilds(name string, token string) (builds []Service, err error) {
	body, _, err := m.doRequest("/services/"+name+"/builds/", "GET", []byte(""), token, "")
	if err != nil {
		return nil, err
	}
	json.Unmarshal([]byte(body), &builds)
	return builds, err
}

// ListUsers ...
func (m *Manager) ListUsers(token string) (users []User, err error) {
	body, _, err := m.doRequest("/users/", "GET", []byte(""), token, "")
	if err != nil {
		return nil, err
	}
	json.Unmarshal([]byte(body), &users)
	return users, err
}

// ListGroups ...
func (m *Manager) ListGroups(token string) (groups []Group, err error) {
	body, _, err := m.doRequest("/clients/", "GET", []byte(""), token, "")
	if err != nil {
		return nil, err
	}
	json.Unmarshal([]byte(body), &groups)
	return groups, err
}
<|endoftext|>


<commit_before>package olbermann

import (
	"log"
	"os"
	"time"
)

type exampleValueSet struct {
	A int `type:"counter" report:"iter,total"`
	B int `type:"counter" report:"ewma,cum,total"`
	//Tps int `type:"counter" report:"iter,cum" name:"tps"`
}

func gen(c chan<- interface{}) {
	for i := 0; i < 10; i++ {
		//c <- &exampleValueSet{A: 1, B: 1, Tps: 198273}
		c <- &exampleValueSet{A: 1, B: 1}
		time.Sleep(400 * time.Millisecond)
	}
}

// This is not a perfect example, because we can't rely on clocks to
// generate the right output.  So we use a log.Logger that doesn't print
// times, and we don't use the iter or cum report types on large values in
// this example.
func Example() {
	c := make(chan interface{}, 10)
	r := &Reporter{C: c}
	go r.Feed()
	killer, err := r.Start(exampleValueSet{}, &DstatStyler{Period: 1, LinesBetweenHeaders: 0, Logger: log.New(os.Stdout, "example: ", 0)})
	if err != nil {
		return
	}
	gen(c)
	close(c)
	killer <- true
	// Output:
	// example: ----------- a ------------ ------------------ b ------------------
	// example:         iter        total |         ewma          cum        total
	// example:         2.00            2 |         2.00         2.00            2
	// example:         1.00            4 |         1.94         2.00            4
	// example:         1.00            7 |         1.87         2.33            7
	// example:         0.50            9 |         1.79         2.25            9
}
<commit_msg>fixed duration in example<commit_after>package olbermann

import (
	"log"
	"os"
	"time"
)

type exampleValueSet struct {
	A int `type:"counter" report:"iter,total"`
	B int `type:"counter" report:"ewma,cum,total"`
	//Tps int `type:"counter" report:"iter,cum" name:"tps"`
}

func gen(c chan<- interface{}) {
	for i := 0; i < 10; i++ {
		//c <- &exampleValueSet{A: 1, B: 1, Tps: 198273}
		c <- &exampleValueSet{A: 1, B: 1}
		time.Sleep(400 * time.Millisecond)
	}
}

// This is not a perfect example, because we can't rely on clocks to
// generate the right output.  So we use a log.Logger that doesn't print
// times, and we don't use the iter or cum report types on large values in
// this example.
func Example() {
	c := make(chan interface{}, 10)
	r := &Reporter{C: c}
	go r.Feed()
	killer, err := r.Start(exampleValueSet{}, &DstatStyler{Period: time.Second, LinesBetweenHeaders: 0, Logger: log.New(os.Stdout, "example: ", 0)})
	if err != nil {
		return
	}
	gen(c)
	close(c)
	killer <- true
	// Output:
	// example: ----------- a ------------ ------------------ b ------------------
	// example:         iter        total |         ewma          cum        total
	// example:         2.00            2 |         2.00         2.00            2
	// example:         1.00            4 |         1.94         2.00            4
	// example:         1.00            7 |         1.87         2.33            7
	// example:         0.50            9 |         1.79         2.25            9
}
<|endoftext|>


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

package azureblob

import (
	"context"
	"encoding/base64"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"testing"

	"github.com/Azure/azure-pipeline-go/pipeline"
	"github.com/Azure/azure-storage-blob-go/azblob"
	"gocloud.dev/blob"
	"gocloud.dev/blob/driver"
	"gocloud.dev/blob/drivertest"
	"gocloud.dev/internal/testing/setup"
)

// Prerequisites for --record mode
// 1. Sign-in to your Azure Subscription at http://portal.azure.com.
//
// 2. Create a Storage Account.
//
// 3. Locate the Access Key (Primary or Secondary) under your Storage Account > Settings > Access Keys.
//
// 4. Create a file in JSON format with the AccountName and AccountKey values.
//
// Example: settings.json
//  {
//    "AccountName": "enter-your-storage-account-name",
//    "AccountKey": "enter-your-storage-account-key"
//  }
//
// 4. Create a container in your Storage Account > Blob. Update the bucketName
// constant to your container name.
//
// Here is a step-by-step walkthrough using the Azure Portal
// https://docs.microsoft.com/en-us/azure/storage/blobs/storage-quickstart-blobs-portal
//
// 5. Run the tests with -record and -settingsfile flags.

const (
	bucketName  = "go-cloud-bucket"
	accountName = AccountName("gocloudblobtests")
)

var pathToSettingsFile = flag.String("settingsfile", "", "path to .json file containing Azure Storage AccountKey and AccountName(required for --record)")

type harness struct {
	pipeline   pipeline.Pipeline
	credential *azblob.SharedKeyCredential
	closer     func()
	httpClient *http.Client
}

func newHarness(ctx context.Context, t *testing.T) (drivertest.Harness, error) {
	var key AccountKey
	if *setup.Record {
		// In Record mode, we load credentials from a JSON settings file.
		type TestSettings struct {
			AccountName AccountName
			AccountKey  AccountKey
		}
		s := &TestSettings{}
		if *pathToSettingsFile == "" {
			t.Fatalf("--settingsfile is required in --record mode.")
		}
		b, err := ioutil.ReadFile(*pathToSettingsFile)
		if err != nil {
			t.Fatalf("Couldn't find settings file at %v: %v", *pathToSettingsFile, err)
		}
		err = json.Unmarshal(b, s)
		if err != nil {
			t.Fatalf("Cannot load settings file %v: %v", *pathToSettingsFile, err)
		}
		if s.AccountName != accountName {
			t.Fatalf("Please update the accountName constant to match your settings file so future records work (%q vs %q)", s.AccountName, accountName)
		}
		key = s.AccountKey
	} else {
		// In replay mode, we use fake credentials.
		key = AccountKey(base64.StdEncoding.EncodeToString([]byte("FAKECREDS")))
	}
	credential, err := NewCredential(accountName, key)
	if err != nil {
		return nil, err
	}
	p, done, httpClient := setup.NewAzureTestPipeline(ctx, t, "blob", credential, string(accountName))
	return &harness{pipeline: p, credential: credential, closer: done, httpClient: httpClient}, nil
}

func (h *harness) HTTPClient() *http.Client {
	return h.httpClient
}

func (h *harness) MakeDriver(ctx context.Context) (driver.Bucket, error) {
	return openBucket(ctx, h.pipeline, accountName, bucketName, &Options{Credential: h.credential})
}

func (h *harness) Close() {
	h.closer()
}

func TestConformance(t *testing.T) {
	// See setup instructions above for more details.
	drivertest.RunConformanceTests(t, newHarness, []drivertest.AsTest{verifyContentLanguage{}})
}

const language = "nl"

// verifyContentLanguage uses As to access the underlying Azure types and
// read/write the ContentLanguage field.
type verifyContentLanguage struct{}

func (verifyContentLanguage) Name() string {
	return "verify ContentLanguage can be written and read through As"
}

func (verifyContentLanguage) BucketCheck(b *blob.Bucket) error {
	var u *azblob.ContainerURL
	if !b.As(&u) {
		return errors.New("Bucket.As failed")
	}
	return nil
}

func (verifyContentLanguage) ErrorCheck(err error) error {
	var to azblob.StorageError
	if !blob.ErrorAs(err, &to) {
		return errors.New("Bucket.ErrorAs failed")
	}
	return nil
}

func (verifyContentLanguage) BeforeWrite(as func(interface{}) bool) error {
	var azOpts *azblob.UploadStreamToBlockBlobOptions
	if !as(&azOpts) {
		return errors.New("Writer.As failed")
	}
	azOpts.BlobHTTPHeaders.ContentLanguage = language
	return nil
}

func (verifyContentLanguage) BeforeList(as func(interface{}) bool) error {
	var azOpts *azblob.ListBlobsSegmentOptions
	if !as(&azOpts) {
		return errors.New("BeforeList.As failed")
	}
	return nil
}

func (verifyContentLanguage) AttributesCheck(attrs *blob.Attributes) error {
	var resp azblob.BlobGetPropertiesResponse
	if !attrs.As(&resp) {
		return errors.New("Attributes.As returned false")
	}
	if got := resp.ContentLanguage(); got != language {
		return fmt.Errorf("got %q want %q", got, language)
	}
	return nil
}

func (verifyContentLanguage) ReaderCheck(r *blob.Reader) error {
	var resp azblob.DownloadResponse
	if !r.As(&resp) {
		return errors.New("Reader.As returned false")
	}
	if got := resp.ContentLanguage(); got != language {
		return fmt.Errorf("got %q want %q", got, language)
	}
	return nil
}

func (verifyContentLanguage) ListObjectCheck(o *blob.ListObject) error {
	if o.IsDir {
		var prefix azblob.BlobPrefix
		if !o.As(&prefix) {
			return errors.New("ListObject.As for directory returned false")
		}
		return nil
	}
	var item azblob.BlobItem
	if !o.As(&item) {
		return errors.New("ListObject.As for object returned false")
	}
	if got := *item.Properties.ContentLanguage; got != language {
		return fmt.Errorf("got %q want %q", got, language)
	}
	return nil
}

func TestOpenBucket(t *testing.T) {
	tests := []struct {
		description   string
		nilPipeline   bool
		accountName   AccountName
		containerName string
		want          string
		wantErr       bool
	}{
		{
			description:   "nil pipeline results in error",
			nilPipeline:   true,
			accountName:   "myaccount",
			containerName: "foo",
			wantErr:       true,
		},
		{
			description:   "empty account name results in error",
			containerName: "foo",
			wantErr:       true,
		},
		{
			description: "empty container name results in error",
			accountName: "myaccount",
			wantErr:     true,
		},
		{
			description:   "success",
			accountName:   "myaccount",
			containerName: "foo",
			want:          "foo",
		},
	}

	ctx := context.Background()
	for _, test := range tests {
		t.Run(test.description, func(t *testing.T) {
			var p pipeline.Pipeline
			if !test.nilPipeline {
				p = NewPipeline(azblob.NewAnonymousCredential(), azblob.PipelineOptions{})
			}
			// Create driver impl.
			drv, err := openBucket(ctx, p, test.accountName, test.containerName, nil)
			if (err != nil) != test.wantErr {
				t.Errorf("got err %v want error %v", err, test.wantErr)
			}
			if err == nil && drv != nil && drv.name != test.want {
				t.Errorf("got %q want %q", drv.name, test.want)
			}
			// Create concrete type.
			_, err = OpenBucket(ctx, p, test.accountName, test.containerName, nil)
			if (err != nil) != test.wantErr {
				t.Errorf("got err %v want error %v", err, test.wantErr)
			}
		})
	}
}

func TestOpenURL(t *testing.T) {

	const (
		accountName = "my-accoun-name"
		accountKey  = "aGVsbG8=" // must be base64 encoded string, this is "hello"
		sasToken    = "my-sas-token"
	)

	makeCredFile := func(name, content string) *os.File {
		f, err := ioutil.TempFile("", "key")
		if err != nil {
			t.Fatal(err)
		}
		if _, err := f.WriteString(content); err != nil {
			t.Fatal(err)
		}
		if err := f.Close(); err != nil {
			t.Fatal(err)
		}
		return f
	}

	keyFile := makeCredFile("key", fmt.Sprintf("{\"AccountName\": %q, \"AccountKey\": %q}", accountName, accountKey))
	defer os.Remove(keyFile.Name())
	badJSONFile := makeCredFile("badjson", "{")
	defer os.Remove(badJSONFile.Name())
	badKeyFile := makeCredFile("badkey", fmt.Sprintf("{\"AccountName\": %q, \"AccountKey\": \"not base 64\"}", accountName))
	defer os.Remove(badKeyFile.Name())
	sasFile := makeCredFile("sas", fmt.Sprintf("{\"AccountName\": %q, \"SASToken\": %q}", accountName, sasToken))
	defer os.Remove(sasFile.Name())

	tests := []struct {
		url      string
		wantName string
		wantErr  bool
		// If we use a key, we should get a non-nil *Credentials in Options.
		wantCreds bool
	}{
		{
			url:       "azblob://mybucket?cred_path=" + keyFile.Name(),
			wantName:  "mybucket",
			wantCreds: true,
		},
		{
			url:       "azblob://mybucket2?cred_path=" + keyFile.Name(),
			wantName:  "mybucket2",
			wantCreds: true,
		},
		{
			url:      "azblob://mybucket?cred_path=" + sasFile.Name(),
			wantName: "mybucket",
		},
		{
			url:      "azblob://mybucket2?cred_path=" + sasFile.Name(),
			wantName: "mybucket2",
		},
		{
			url:     "azblob://foo?cred_path=" + badJSONFile.Name(),
			wantErr: true,
		},
		{
			url:     "azblob://foo?cred_path=" + badKeyFile.Name(),
			wantErr: true,
		},
		{
			url:     "azblob://foo?cred_path=/path/does/not/exist",
			wantErr: true,
		},
	}

	ctx := context.Background()
	for _, test := range tests {
		t.Run(test.url, func(t *testing.T) {
			u, err := url.Parse(test.url)
			if err != nil {
				t.Fatal(err)
			}
			got, err := openURL(ctx, u)
			if (err != nil) != test.wantErr {
				t.Errorf("got err %v want error %v", err, test.wantErr)
			}
			if err != nil {
				return
			}
			gotB, ok := got.(*bucket)
			if !ok {
				t.Fatalf("got type %T want *bucket", got)
			}
			if gotB.name != test.wantName {
				t.Errorf("got bucket name %q want %q", gotB.name, test.wantName)
			}
			if gotCreds := (gotB.opts.Credential != nil); gotCreds != test.wantCreds {
				t.Errorf("got creds? %v want %v", gotCreds, test.wantCreds)
			}
		})
	}
}
<commit_msg>blob/azblob: use env variables for tests instead of a settingsfile (#1113)<commit_after>// Copyright 2018 The Go Cloud Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package azureblob

import (
	"context"
	"encoding/base64"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"testing"

	"github.com/Azure/azure-pipeline-go/pipeline"
	"github.com/Azure/azure-storage-blob-go/azblob"
	"gocloud.dev/blob"
	"gocloud.dev/blob/driver"
	"gocloud.dev/blob/drivertest"
	"gocloud.dev/internal/testing/setup"
)

// Prerequisites for --record mode
// 1. Sign-in to your Azure Subscription at http://portal.azure.com.
//
// 2. Create a Storage Account.
//
// 3. Locate the Access Key (Primary or Secondary) under your Storage Account > Settings > Access Keys.
//
// 4. Set the environment variables AZURE_STORAGE_ACCOUNT, AZURE_STORAGE_KEY to
//    the storage account name and your access key.
//
// 5. Create a container in your Storage Account > Blob. Update the bucketName
// constant to your container name.
//
// Here is a step-by-step walkthrough using the Azure Portal
// https://docs.microsoft.com/en-us/azure/storage/blobs/storage-quickstart-blobs-portal
//
// 5. Run the tests with -record.

const (
	bucketName  = "go-cloud-bucket"
	accountName = AccountName("gocloudblobtests")
)

type harness struct {
	pipeline   pipeline.Pipeline
	credential *azblob.SharedKeyCredential
	closer     func()
	httpClient *http.Client
}

func newHarness(ctx context.Context, t *testing.T) (drivertest.Harness, error) {
	var key AccountKey
	if *setup.Record {
		name, err := DefaultAccountName()
		if err != nil {
			t.Fatal(err)
		}
		if name != accountName {
			t.Fatalf("Please update the accountName constant to match your settings file so future records work (%q vs %q)", name, accountName)
		}
		key, err = DefaultAccountKey()
		if err != nil {
			t.Fatal(err)
		}
	} else {
		// In replay mode, we use fake credentials.
		key = AccountKey(base64.StdEncoding.EncodeToString([]byte("FAKECREDS")))
	}
	credential, err := NewCredential(accountName, key)
	if err != nil {
		return nil, err
	}
	p, done, httpClient := setup.NewAzureTestPipeline(ctx, t, "blob", credential, string(accountName))
	return &harness{pipeline: p, credential: credential, closer: done, httpClient: httpClient}, nil
}

func (h *harness) HTTPClient() *http.Client {
	return h.httpClient
}

func (h *harness) MakeDriver(ctx context.Context) (driver.Bucket, error) {
	return openBucket(ctx, h.pipeline, accountName, bucketName, &Options{Credential: h.credential})
}

func (h *harness) Close() {
	h.closer()
}

func TestConformance(t *testing.T) {
	// See setup instructions above for more details.
	drivertest.RunConformanceTests(t, newHarness, []drivertest.AsTest{verifyContentLanguage{}})
}

const language = "nl"

// verifyContentLanguage uses As to access the underlying Azure types and
// read/write the ContentLanguage field.
type verifyContentLanguage struct{}

func (verifyContentLanguage) Name() string {
	return "verify ContentLanguage can be written and read through As"
}

func (verifyContentLanguage) BucketCheck(b *blob.Bucket) error {
	var u *azblob.ContainerURL
	if !b.As(&u) {
		return errors.New("Bucket.As failed")
	}
	return nil
}

func (verifyContentLanguage) ErrorCheck(err error) error {
	var to azblob.StorageError
	if !blob.ErrorAs(err, &to) {
		return errors.New("Bucket.ErrorAs failed")
	}
	return nil
}

func (verifyContentLanguage) BeforeWrite(as func(interface{}) bool) error {
	var azOpts *azblob.UploadStreamToBlockBlobOptions
	if !as(&azOpts) {
		return errors.New("Writer.As failed")
	}
	azOpts.BlobHTTPHeaders.ContentLanguage = language
	return nil
}

func (verifyContentLanguage) BeforeList(as func(interface{}) bool) error {
	var azOpts *azblob.ListBlobsSegmentOptions
	if !as(&azOpts) {
		return errors.New("BeforeList.As failed")
	}
	return nil
}

func (verifyContentLanguage) AttributesCheck(attrs *blob.Attributes) error {
	var resp azblob.BlobGetPropertiesResponse
	if !attrs.As(&resp) {
		return errors.New("Attributes.As returned false")
	}
	if got := resp.ContentLanguage(); got != language {
		return fmt.Errorf("got %q want %q", got, language)
	}
	return nil
}

func (verifyContentLanguage) ReaderCheck(r *blob.Reader) error {
	var resp azblob.DownloadResponse
	if !r.As(&resp) {
		return errors.New("Reader.As returned false")
	}
	if got := resp.ContentLanguage(); got != language {
		return fmt.Errorf("got %q want %q", got, language)
	}
	return nil
}

func (verifyContentLanguage) ListObjectCheck(o *blob.ListObject) error {
	if o.IsDir {
		var prefix azblob.BlobPrefix
		if !o.As(&prefix) {
			return errors.New("ListObject.As for directory returned false")
		}
		return nil
	}
	var item azblob.BlobItem
	if !o.As(&item) {
		return errors.New("ListObject.As for object returned false")
	}
	if got := *item.Properties.ContentLanguage; got != language {
		return fmt.Errorf("got %q want %q", got, language)
	}
	return nil
}

func TestOpenBucket(t *testing.T) {
	tests := []struct {
		description   string
		nilPipeline   bool
		accountName   AccountName
		containerName string
		want          string
		wantErr       bool
	}{
		{
			description:   "nil pipeline results in error",
			nilPipeline:   true,
			accountName:   "myaccount",
			containerName: "foo",
			wantErr:       true,
		},
		{
			description:   "empty account name results in error",
			containerName: "foo",
			wantErr:       true,
		},
		{
			description: "empty container name results in error",
			accountName: "myaccount",
			wantErr:     true,
		},
		{
			description:   "success",
			accountName:   "myaccount",
			containerName: "foo",
			want:          "foo",
		},
	}

	ctx := context.Background()
	for _, test := range tests {
		t.Run(test.description, func(t *testing.T) {
			var p pipeline.Pipeline
			if !test.nilPipeline {
				p = NewPipeline(azblob.NewAnonymousCredential(), azblob.PipelineOptions{})
			}
			// Create driver impl.
			drv, err := openBucket(ctx, p, test.accountName, test.containerName, nil)
			if (err != nil) != test.wantErr {
				t.Errorf("got err %v want error %v", err, test.wantErr)
			}
			if err == nil && drv != nil && drv.name != test.want {
				t.Errorf("got %q want %q", drv.name, test.want)
			}
			// Create concrete type.
			_, err = OpenBucket(ctx, p, test.accountName, test.containerName, nil)
			if (err != nil) != test.wantErr {
				t.Errorf("got err %v want error %v", err, test.wantErr)
			}
		})
	}
}

func TestOpenURL(t *testing.T) {

	const (
		accountName = "my-accoun-name"
		accountKey  = "aGVsbG8=" // must be base64 encoded string, this is "hello"
		sasToken    = "my-sas-token"
	)

	makeCredFile := func(name, content string) *os.File {
		f, err := ioutil.TempFile("", "key")
		if err != nil {
			t.Fatal(err)
		}
		if _, err := f.WriteString(content); err != nil {
			t.Fatal(err)
		}
		if err := f.Close(); err != nil {
			t.Fatal(err)
		}
		return f
	}

	keyFile := makeCredFile("key", fmt.Sprintf("{\"AccountName\": %q, \"AccountKey\": %q}", accountName, accountKey))
	defer os.Remove(keyFile.Name())
	badJSONFile := makeCredFile("badjson", "{")
	defer os.Remove(badJSONFile.Name())
	badKeyFile := makeCredFile("badkey", fmt.Sprintf("{\"AccountName\": %q, \"AccountKey\": \"not base 64\"}", accountName))
	defer os.Remove(badKeyFile.Name())
	sasFile := makeCredFile("sas", fmt.Sprintf("{\"AccountName\": %q, \"SASToken\": %q}", accountName, sasToken))
	defer os.Remove(sasFile.Name())

	tests := []struct {
		url      string
		wantName string
		wantErr  bool
		// If we use a key, we should get a non-nil *Credentials in Options.
		wantCreds bool
	}{
		{
			url:       "azblob://mybucket?cred_path=" + keyFile.Name(),
			wantName:  "mybucket",
			wantCreds: true,
		},
		{
			url:       "azblob://mybucket2?cred_path=" + keyFile.Name(),
			wantName:  "mybucket2",
			wantCreds: true,
		},
		{
			url:      "azblob://mybucket?cred_path=" + sasFile.Name(),
			wantName: "mybucket",
		},
		{
			url:      "azblob://mybucket2?cred_path=" + sasFile.Name(),
			wantName: "mybucket2",
		},
		{
			url:     "azblob://foo?cred_path=" + badJSONFile.Name(),
			wantErr: true,
		},
		{
			url:     "azblob://foo?cred_path=" + badKeyFile.Name(),
			wantErr: true,
		},
		{
			url:     "azblob://foo?cred_path=/path/does/not/exist",
			wantErr: true,
		},
	}

	ctx := context.Background()
	for _, test := range tests {
		t.Run(test.url, func(t *testing.T) {
			u, err := url.Parse(test.url)
			if err != nil {
				t.Fatal(err)
			}
			got, err := openURL(ctx, u)
			if (err != nil) != test.wantErr {
				t.Errorf("got err %v want error %v", err, test.wantErr)
			}
			if err != nil {
				return
			}
			gotB, ok := got.(*bucket)
			if !ok {
				t.Fatalf("got type %T want *bucket", got)
			}
			if gotB.name != test.wantName {
				t.Errorf("got bucket name %q want %q", gotB.name, test.wantName)
			}
			if gotCreds := (gotB.opts.Credential != nil); gotCreds != test.wantCreds {
				t.Errorf("got creds? %v want %v", gotCreds, test.wantCreds)
			}
		})
	}
}
<|endoftext|>