<commit_before>package main

import (
	"crypto/rand"
	"encoding/base64"
	"fmt"
	"koding/tools/config"
	"koding/tools/sockjs"
	"strconv"
	"strings"
	"time"

	"github.com/streadway/amqp"
)

type Client struct {
	Session        *sockjs.Session
	ControlChannel *amqp.Channel
	SocketId       string
	Broker         *Broker
	LastPayload    string
	Subscriptions  map[string]bool
}

// NewClient retuns a new client that is defined on a given session.
func NewClient(session *sockjs.Session, broker *Broker) *Client {
	socketID := randomString()
	session.Tag = socketID

	controlChannel, err := broker.PublishConn.Channel()
	if err != nil {
		panic(err)
	}

	subscriptions := make(map[string]bool)

	fmt.Println("adding to subscriptionsMap")
	globalMapMutex.Lock()
	socketSubscriptionsMap[socketID] = &subscriptions
	globalMapMutex.Unlock()

	fmt.Println("returning new client")
	return &Client{
		Session:        session,
		SocketId:       socketID,
		ControlChannel: controlChannel,
		Broker:         broker,
		Subscriptions:  subscriptions,
	}
}

// Close should be called whenever a client disconnects.
func (c *Client) Close() {
	globalMapMutex.Lock()
	for routingKeyPrefix := range c.Subscriptions {
		c.RemoveFromRoute(routingKeyPrefix)
	}
	globalMapMutex.Unlock()

	time.AfterFunc(5*time.Minute, func() {
		globalMapMutex.Lock()
		delete(socketSubscriptionsMap, c.SocketId)
		globalMapMutex.Unlock()
	})

	for {
		err := c.ControlChannel.Publish(config.Current.Broker.AuthAllExchange, "broker.clientDisconnected", false, false, amqp.Publishing{Body: []byte(c.SocketId)})
		if err == nil {
			break
		}
		if amqpError, isAmqpError := err.(*amqp.Error); !isAmqpError || amqpError.Code != 504 {
			panic(err)
		}
		c.resetControlChannel()
	}

	c.ControlChannel.Close()
}

// handleSessionMessage handles the received message from the client. It
// passes a response back to the client or publish the received message to a
// rabbitmq exchange for further process.
func (c *Client) handleSessionMessage(data interface{}) {
	defer log.RecoverAndLog()

	message := data.(map[string]interface{})
	log.Debug("Received message: %v", message)

	action := message["action"]
	switch action {
	case "subscribe":
		globalMapMutex.Lock()
		defer globalMapMutex.Unlock()
		for _, routingKeyPrefix := range strings.Split(message["routingKeyPrefix"].(string), " ") {
			c.Subscribe(routingKeyPrefix)
		}

		sendToClient(c.Session, "broker.subscribed", message["routingKeyPrefix"])

	case "resubscribe":
		globalMapMutex.Lock()
		defer globalMapMutex.Unlock()
		oldSubscriptions, found := socketSubscriptionsMap[message["socketId"].(string)]
		if found {
			for routingKeyPrefix := range *oldSubscriptions {
				c.Subscribe(routingKeyPrefix)
			}
		}
		sendToClient(c.Session, "broker.resubscribed", found)

	case "unsubscribe":
		globalMapMutex.Lock()
		defer globalMapMutex.Unlock()
		for _, routingKeyPrefix := range strings.Split(message["routingKeyPrefix"].(string), " ") {
			c.Unsubscribe(routingKeyPrefix)
		}

	case "publish":
		exchange := message["exchange"].(string)
		routingKey := message["routingKey"].(string)
		payload := message["payload"].(string)

		publish := func(exchange, routingKey, payload string) error {
			if !strings.HasPrefix(routingKey, "client.") {
				return fmt.Errorf("Invalid routing key: %v socketId: %v", routingKey, c.SocketId)
			}

			for {
				c.LastPayload = ""
				err := c.ControlChannel.Publish(exchange, routingKey, false, false, amqp.Publishing{CorrelationId: c.SocketId, Body: []byte(payload)})
				if err == nil {
					c.LastPayload = payload
					break
				}

				if amqpError, isAmqpError := err.(*amqp.Error); !isAmqpError || amqpError.Code != 504 {
					log.Warning("payload: %v routing key: %v exchange: %v err: %v",
						payload, routingKey, exchange, err)
				}

				time.Sleep(time.Second / 4) // penalty for crashing the AMQP channel
				c.resetControlChannel()
			}

			return nil
		}

		publish(exchange, routingKey, payload)

	case "ping":
		sendToClient(c.Session, "broker.pong", nil)

	default:
		log.Warning("Invalid action. message: %v socketId: %v", message, c.SocketId)

	}
}

// randomString() returns a new 16 char length random string
func randomString() string {
	r := make([]byte, 128/8)
	rand.Read(r)
	return base64.StdEncoding.EncodeToString(r)
}

// gaugeStart starts the gauge for a given session. It returns a new
// function which ends the gauge for the given session. Usually one invokes
// gaugeStart and calls the returned function in a defer statement.
func (c *Client) gaugeStart() (gaugeEnd func()) {
	log.Debug("Client connected: %v", c.Session.Tag)
	changeClientsGauge(1)
	changeNewClientsGauge(1)
	if c.Session.IsWebsocket {
		changeWebsocketClientsGauge(1)
	}

	return func() {
		log.Debug("Client disconnected: %v", c.Session.Tag)
		changeClientsGauge(-1)
		if c.Session.IsWebsocket {
			changeWebsocketClientsGauge(-1)
		}
	}
}

// resetControlChannel closes the current client's control channel and creates
// a new channel. It also listens to any server side error and publish back
// the error to the client.
func (c *Client) resetControlChannel() {
	if c.ControlChannel != nil {
		c.ControlChannel.Close()
	}

	var err error
	c.ControlChannel, err = c.Broker.PublishConn.Channel()
	if err != nil {
		panic(err)
	}

	go func() {
		defer log.RecoverAndLog()

		for amqpErr := range c.ControlChannel.NotifyClose(make(chan *amqp.Error)) {
			if !(strings.Contains(amqpErr.Error(), "NOT_FOUND") && (strings.Contains(amqpErr.Error(), "koding-social-") || strings.Contains(amqpErr.Error(), "auth-"))) {
				log.Warning("AMQP channel: %v Last publish payload: %v", amqpErr.Error(), c.LastPayload)
			}

			sendToClient(c.Session, "broker.error", map[string]interface{}{
				"code":    amqpErr.Code,
				"reason":  amqpErr.Reason,
				"server":  amqpErr.Server,
				"recover": amqpErr.Recover,
			})
		}
	}()
}

// RemoveFromRoute removes the sessions for the given routingKeyPrefix.
func (c *Client) RemoveFromRoute(routingKeyPrefix string) {
	routeSessions := routeMap[routingKeyPrefix]
	for i, routeSession := range routeSessions {
		if routeSession == c.Session {
			routeSessions[i] = routeSessions[len(routeSessions)-1]
			routeSessions = routeSessions[:len(routeSessions)-1]
			break
		}
	}
	if len(routeSessions) == 0 {
		delete(routeMap, routingKeyPrefix)
		return
	}
	routeMap[routingKeyPrefix] = routeSessions
}

// Subscribe add the given routingKeyPrefix to the list of subscriptions
// associated with this client.
func (c *Client) Subscribe(routingKeyPrefix string) {
	if c.Subscriptions[routingKeyPrefix] {
		log.Warning("Duplicate subscription to same routing key. %v %v", c.Session.Tag, routingKeyPrefix)
		return
	}

	if len(c.Subscriptions) > 0 && len(c.Subscriptions)%2000 == 0 {
		log.Warning("Client with more than %v subscriptions %v",
			strconv.Itoa(len(c.Subscriptions)), c.Session.Tag)
	}

	routeMap[routingKeyPrefix] = append(routeMap[routingKeyPrefix], c.Session)
	c.Subscriptions[routingKeyPrefix] = true

}

// Unsubscribe deletes the given routingKey prefix from the subscription list
// and removes it from the global route map
func (c *Client) Unsubscribe(routingKeyPrefix string) {
	c.RemoveFromRoute(routingKeyPrefix)
	delete(c.Subscriptions, routingKeyPrefix)
}
<commit_msg>use named constants<commit_after>package main

import (
	"crypto/rand"
	"encoding/base64"
	"fmt"
	"koding/tools/config"
	"koding/tools/sockjs"
	"strconv"
	"strings"
	"time"

	"github.com/streadway/amqp"
)

type Client struct {
	Session        *sockjs.Session
	ControlChannel *amqp.Channel
	SocketId       string
	Broker         *Broker
	LastPayload    string
	Subscriptions  map[string]bool
}

// NewClient retuns a new client that is defined on a given session.
func NewClient(session *sockjs.Session, broker *Broker) *Client {
	socketID := randomString()
	session.Tag = socketID

	controlChannel, err := broker.PublishConn.Channel()
	if err != nil {
		panic(err)
	}

	subscriptions := make(map[string]bool)

	fmt.Println("adding to subscriptionsMap")
	globalMapMutex.Lock()
	socketSubscriptionsMap[socketID] = &subscriptions
	globalMapMutex.Unlock()

	fmt.Println("returning new client")
	return &Client{
		Session:        session,
		SocketId:       socketID,
		ControlChannel: controlChannel,
		Broker:         broker,
		Subscriptions:  subscriptions,
	}
}

// Close should be called whenever a client disconnects.
func (c *Client) Close() {
	globalMapMutex.Lock()
	for routingKeyPrefix := range c.Subscriptions {
		c.RemoveFromRoute(routingKeyPrefix)
	}
	globalMapMutex.Unlock()

	time.AfterFunc(5*time.Minute, func() {
		globalMapMutex.Lock()
		delete(socketSubscriptionsMap, c.SocketId)
		globalMapMutex.Unlock()
	})

	for {
		err := c.ControlChannel.Publish(config.Current.Broker.AuthAllExchange, "broker.clientDisconnected", false, false, amqp.Publishing{Body: []byte(c.SocketId)})
		if err == nil {
			break
		}
		if amqpError, isAmqpError := err.(*amqp.Error); !isAmqpError || amqpError.Code != amqp.ChannelError {
			panic(err)
		}
		c.resetControlChannel()
	}

	c.ControlChannel.Close()
}

// handleSessionMessage handles the received message from the client. It
// passes a response back to the client or publish the received message to a
// rabbitmq exchange for further process.
func (c *Client) handleSessionMessage(data interface{}) {
	defer log.RecoverAndLog()

	message := data.(map[string]interface{})
	log.Debug("Received message: %v", message)

	action := message["action"]
	switch action {
	case "subscribe":
		globalMapMutex.Lock()
		defer globalMapMutex.Unlock()
		for _, routingKeyPrefix := range strings.Split(message["routingKeyPrefix"].(string), " ") {
			c.Subscribe(routingKeyPrefix)
		}

		sendToClient(c.Session, "broker.subscribed", message["routingKeyPrefix"])

	case "resubscribe":
		globalMapMutex.Lock()
		defer globalMapMutex.Unlock()
		oldSubscriptions, found := socketSubscriptionsMap[message["socketId"].(string)]
		if found {
			for routingKeyPrefix := range *oldSubscriptions {
				c.Subscribe(routingKeyPrefix)
			}
		}
		sendToClient(c.Session, "broker.resubscribed", found)

	case "unsubscribe":
		globalMapMutex.Lock()
		defer globalMapMutex.Unlock()
		for _, routingKeyPrefix := range strings.Split(message["routingKeyPrefix"].(string), " ") {
			c.Unsubscribe(routingKeyPrefix)
		}

	case "publish":
		exchange := message["exchange"].(string)
		routingKey := message["routingKey"].(string)
		payload := message["payload"].(string)

		publish := func(exchange, routingKey, payload string) error {
			if !strings.HasPrefix(routingKey, "client.") {
				return fmt.Errorf("Invalid routing key: %v socketId: %v", routingKey, c.SocketId)
			}

			for {
				c.LastPayload = ""
				err := c.ControlChannel.Publish(exchange, routingKey, false, false, amqp.Publishing{CorrelationId: c.SocketId, Body: []byte(payload)})
				if err == nil {
					c.LastPayload = payload
					break
				}

				if amqpError, isAmqpError := err.(*amqp.Error); !isAmqpError || amqpError.Code != amqp.ChannelError {
					log.Warning("payload: %v routing key: %v exchange: %v err: %v",
						payload, routingKey, exchange, err)
				}

				time.Sleep(time.Second / 4) // penalty for crashing the AMQP channel
				c.resetControlChannel()
			}

			return nil
		}

		publish(exchange, routingKey, payload)

	case "ping":
		sendToClient(c.Session, "broker.pong", nil)

	default:
		log.Warning("Invalid action. message: %v socketId: %v", message, c.SocketId)

	}
}

// randomString() returns a new 16 char length random string
func randomString() string {
	r := make([]byte, 128/8)
	rand.Read(r)
	return base64.StdEncoding.EncodeToString(r)
}

// gaugeStart starts the gauge for a given session. It returns a new
// function which ends the gauge for the given session. Usually one invokes
// gaugeStart and calls the returned function in a defer statement.
func (c *Client) gaugeStart() (gaugeEnd func()) {
	log.Debug("Client connected: %v", c.Session.Tag)
	changeClientsGauge(1)
	changeNewClientsGauge(1)
	if c.Session.IsWebsocket {
		changeWebsocketClientsGauge(1)
	}

	return func() {
		log.Debug("Client disconnected: %v", c.Session.Tag)
		changeClientsGauge(-1)
		if c.Session.IsWebsocket {
			changeWebsocketClientsGauge(-1)
		}
	}
}

// resetControlChannel closes the current client's control channel and creates
// a new channel. It also listens to any server side error and publish back
// the error to the client.
func (c *Client) resetControlChannel() {
	if c.ControlChannel != nil {
		c.ControlChannel.Close()
	}

	var err error
	c.ControlChannel, err = c.Broker.PublishConn.Channel()
	if err != nil {
		panic(err)
	}

	go func() {
		defer log.RecoverAndLog()

		for amqpErr := range c.ControlChannel.NotifyClose(make(chan *amqp.Error)) {
			if !(strings.Contains(amqpErr.Error(), "NOT_FOUND") && (strings.Contains(amqpErr.Error(), "koding-social-") || strings.Contains(amqpErr.Error(), "auth-"))) {
				log.Warning("AMQP channel: %v Last publish payload: %v", amqpErr.Error(), c.LastPayload)
			}

			sendToClient(c.Session, "broker.error", map[string]interface{}{
				"code":    amqpErr.Code,
				"reason":  amqpErr.Reason,
				"server":  amqpErr.Server,
				"recover": amqpErr.Recover,
			})
		}
	}()
}

// RemoveFromRoute removes the sessions for the given routingKeyPrefix.
func (c *Client) RemoveFromRoute(routingKeyPrefix string) {
	routeSessions := routeMap[routingKeyPrefix]
	for i, routeSession := range routeSessions {
		if routeSession == c.Session {
			routeSessions[i] = routeSessions[len(routeSessions)-1]
			routeSessions = routeSessions[:len(routeSessions)-1]
			break
		}
	}
	if len(routeSessions) == 0 {
		delete(routeMap, routingKeyPrefix)
		return
	}
	routeMap[routingKeyPrefix] = routeSessions
}

// Subscribe add the given routingKeyPrefix to the list of subscriptions
// associated with this client.
func (c *Client) Subscribe(routingKeyPrefix string) {
	if c.Subscriptions[routingKeyPrefix] {
		log.Warning("Duplicate subscription to same routing key. %v %v", c.Session.Tag, routingKeyPrefix)
		return
	}

	if len(c.Subscriptions) > 0 && len(c.Subscriptions)%2000 == 0 {
		log.Warning("Client with more than %v subscriptions %v",
			strconv.Itoa(len(c.Subscriptions)), c.Session.Tag)
	}

	routeMap[routingKeyPrefix] = append(routeMap[routingKeyPrefix], c.Session)
	c.Subscriptions[routingKeyPrefix] = true

}

// Unsubscribe deletes the given routingKey prefix from the subscription list
// and removes it from the global route map
func (c *Client) Unsubscribe(routingKeyPrefix string) {
	c.RemoveFromRoute(routingKeyPrefix)
	delete(c.Subscriptions, routingKeyPrefix)
}
<|endoftext|>


<commit_before>package gitlab

import "fmt"

// EpicIssuesService handles communication with the epic issue related methods
// of the GitLab API.
//
// GitLab API docs: https://docs.gitlab.com/ee/api/epic_issues.html
type EpicIssuesService struct {
	client *Client
}

// ListEpicIssues get a list of epic issues.
//
// Gitlab API docs:
// https://docs.gitlab.com/ee/api/epic_issues.html#list-issues-for-an-epic
func (s *EpicIssuesService) ListEpicIssues(gid interface{}, epic int, opt *ListOptions, options ...RequestOptionFunc) ([]*Issue, *Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("groups/%s/epics/%d/issues", pathEscape(group), epic)

	req, err := s.client.NewRequest("GET", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	var i []*Issue
	resp, err := s.client.Do(req, &i)
	if err != nil {
		return nil, resp, err
	}

	return i, resp, err
}

// EpicIssueAssignment contains both the Epic and Issue objects returned from Gitlab w/ the assignment ID
type EpicIssueAssignment struct {
	ID    int    `json:"id"`
	Epic  *Epic  `json:"epic"`
	Issue *Issue `json:"issue"`
}

// AssignEpicIssue assigns an existing issue to an Epic
//
// Gitlab API Docs: https://docs.gitlab.com/ee/api/epic_issues.html#assign-an-issue-to-the-epic
func (s *EpicIssuesService) AssignEpicIssue(gid interface{}, epic int, issue int, options ...RequestOptionFunc) (*EpicIssueAssignment, *Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, nil, err
	}

	u := fmt.Sprintf("groups/%s/epics/%d/issues/%d", pathEscape(group), epic, issue)

	req, err := s.client.NewRequest("POST", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	var a *EpicIssueAssignment

	resp, err := s.client.Do(req, &a)
	if err != nil {
		return nil, resp, err
	}

	return a, resp, err
}

// RemoveEpicIssue removes an issue from an Epic
//
// Gitlab API Docs: https://docs.gitlab.com/ee/api/epic_issues.html#remove-an-issue-from-the-epic
func (s *EpicIssuesService) RemoveEpicIssue(gid interface{}, epic int, epicIssue int, options ...RequestOptionFunc) (*EpicIssueAssignment, *Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, nil, err
	}

	u := fmt.Sprintf("groups/%s/epics/%d/issues/%d", pathEscape(group), epic, epicIssue)

	req, err := s.client.NewRequest("DELETE", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	var a *EpicIssueAssignment

	resp, err := s.client.Do(req, &a)
	if err != nil {
		return nil, resp, err
	}

	return a, resp, err
}

// UpdateEpicIsssueAssignmentOptions describes options to move issues within an epic
type UpdateEpicIsssueAssignmentOptions struct {
	*ListOptions
	MoveBeforeID int `json:"move_before_id"`
	MoveAfterID  int `json:"move_after_id"`
}

// UpdateEpicIssueAssignment moves an issue before or after another issue in an epic issue list
//
// Gitlab API Docs:
// https://docs.gitlab.com/ee/api/epic_issues.html#update-epic---issue-association
func (s *EpicIssuesService) UpdateEpicIssueAssignment(gid interface{}, epic int, epicIssue int, opt *UpdateEpicIsssueAssignmentOptions, options ...RequestOptionFunc) ([]*Issue, *Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, nil, err
	}

	u := fmt.Sprintf("groups/%s/epics/%d/issues/%d", pathEscape(group), epic, epicIssue)

	req, err := s.client.NewRequest("PUT", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	var i []*Issue

	resp, err := s.client.Do(req, &i)
	if err != nil {
		return nil, resp, err
	}

	return i, resp, err
}
<commit_msg>remove spare newline<commit_after>package gitlab

import "fmt"

// EpicIssuesService handles communication with the epic issue related methods
// of the GitLab API.
//
// GitLab API docs: https://docs.gitlab.com/ee/api/epic_issues.html
type EpicIssuesService struct {
	client *Client
}

// ListEpicIssues get a list of epic issues.
//
// Gitlab API docs:
// https://docs.gitlab.com/ee/api/epic_issues.html#list-issues-for-an-epic
func (s *EpicIssuesService) ListEpicIssues(gid interface{}, epic int, opt *ListOptions, options ...RequestOptionFunc) ([]*Issue, *Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("groups/%s/epics/%d/issues", pathEscape(group), epic)

	req, err := s.client.NewRequest("GET", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	var i []*Issue
	resp, err := s.client.Do(req, &i)
	if err != nil {
		return nil, resp, err
	}

	return i, resp, err
}

// EpicIssueAssignment contains both the Epic and Issue objects returned from Gitlab w/ the assignment ID
type EpicIssueAssignment struct {
	ID    int    `json:"id"`
	Epic  *Epic  `json:"epic"`
	Issue *Issue `json:"issue"`
}

// AssignEpicIssue assigns an existing issue to an Epic
//
// Gitlab API Docs: https://docs.gitlab.com/ee/api/epic_issues.html#assign-an-issue-to-the-epic
func (s *EpicIssuesService) AssignEpicIssue(gid interface{}, epic int, issue int, options ...RequestOptionFunc) (*EpicIssueAssignment, *Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, nil, err
	}

	u := fmt.Sprintf("groups/%s/epics/%d/issues/%d", pathEscape(group), epic, issue)

	req, err := s.client.NewRequest("POST", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	var a *EpicIssueAssignment

	resp, err := s.client.Do(req, &a)
	if err != nil {
		return nil, resp, err
	}

	return a, resp, err
}

// RemoveEpicIssue removes an issue from an Epic
//
// Gitlab API Docs: https://docs.gitlab.com/ee/api/epic_issues.html#remove-an-issue-from-the-epic
func (s *EpicIssuesService) RemoveEpicIssue(gid interface{}, epic int, epicIssue int, options ...RequestOptionFunc) (*EpicIssueAssignment, *Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, nil, err
	}

	u := fmt.Sprintf("groups/%s/epics/%d/issues/%d", pathEscape(group), epic, epicIssue)

	req, err := s.client.NewRequest("DELETE", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	var a *EpicIssueAssignment

	resp, err := s.client.Do(req, &a)
	if err != nil {
		return nil, resp, err
	}

	return a, resp, err
}

// UpdateEpicIsssueAssignmentOptions describes options to move issues within an epic
type UpdateEpicIsssueAssignmentOptions struct {
	*ListOptions
	MoveBeforeID int `json:"move_before_id"`
	MoveAfterID  int `json:"move_after_id"`
}

// UpdateEpicIssueAssignment moves an issue before or after another issue in an epic issue list
//
// Gitlab API Docs:
// https://docs.gitlab.com/ee/api/epic_issues.html#update-epic---issue-association
func (s *EpicIssuesService) UpdateEpicIssueAssignment(gid interface{}, epic int, epicIssue int, opt *UpdateEpicIsssueAssignmentOptions, options ...RequestOptionFunc) ([]*Issue, *Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("groups/%s/epics/%d/issues/%d", pathEscape(group), epic, epicIssue)

	req, err := s.client.NewRequest("PUT", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	var i []*Issue

	resp, err := s.client.Do(req, &i)
	if err != nil {
		return nil, resp, err
	}

	return i, resp, err
}
<|endoftext|>


<commit_before>package travel

import (
	"fmt"
)

type TraversalError interface {
	Error() string
	Code() int
}

type TraversalNotFoundError struct {
	path []string
	code int
}
type TraversalRootTreeError struct {
	err  error
	code int
}
type TraversalInternalError struct {
	msg  string
	code int
}
type TraversalUnknownHandlerError struct {
	path []string
	code int
}

func (t TraversalNotFoundError) Error() string {
	return fmt.Sprintf("404 Not Found: %v", t.path)
}

func (t TraversalNotFoundError) Code() int {
	return t.code
}

func (t TraversalUnknownHandlerError) Error() string {
	return fmt.Sprintf("Handler not found for route: %v\n", t.path)
}

func (t TraversalUnknownHandlerError) Code() int {
	return t.code
}

func (t TraversalRootTreeError) Error() string {
	return t.err.Error()
}

func (t TraversalRootTreeError) Code() int {
	return t.code
}

func (t TraversalInternalError) Error() string {
	return fmt.Sprintf("Internal traversal error (bug?): %v", t.msg)
}

func (t TraversalInternalError) Code() int {
	return t.code
}

func NotFoundError(r []string) TraversalError {
	return TraversalNotFoundError{
		path: r,
		code: 404,
	}
}

func UnknownHandlerError(r []string) TraversalUnknownHandlerError {
	return TraversalUnknownHandlerError{
		path: r,
		code: 501,
	}
}

func RootTreeError(err error) TraversalRootTreeError {
	return TraversalRootTreeError{
		err:  err,
		code: 500,
	}
}

func InternalError(m string) TraversalInternalError {
	return TraversalInternalError{
		msg:  m,
		code: 500,
	}
}
<commit_msg>use net.http status constants<commit_after>package travel

import (
	"fmt"
	"net/http"
)

type TraversalError interface {
	Error() string
	Code() int
}

type TraversalNotFoundError struct {
	path []string
	code int
}
type TraversalRootTreeError struct {
	err  error
	code int
}
type TraversalInternalError struct {
	msg  string
	code int
}
type TraversalUnknownHandlerError struct {
	path []string
	code int
}

func (t TraversalNotFoundError) Error() string {
	return fmt.Sprintf("404 Not Found: %v", t.path)
}

func (t TraversalNotFoundError) Code() int {
	return t.code
}

func (t TraversalUnknownHandlerError) Error() string {
	return fmt.Sprintf("Handler not found for route: %v\n", t.path)
}

func (t TraversalUnknownHandlerError) Code() int {
	return t.code
}

func (t TraversalRootTreeError) Error() string {
	return t.err.Error()
}

func (t TraversalRootTreeError) Code() int {
	return t.code
}

func (t TraversalInternalError) Error() string {
	return fmt.Sprintf("Internal traversal error (bug?): %v", t.msg)
}

func (t TraversalInternalError) Code() int {
	return t.code
}

func NotFoundError(r []string) TraversalError {
	return TraversalNotFoundError{
		path: r,
		code: http.StatusNotFound,
	}
}

func UnknownHandlerError(r []string) TraversalUnknownHandlerError {
	return TraversalUnknownHandlerError{
		path: r,
		code: http.StatusNotImplemented,
	}
}

func RootTreeError(err error) TraversalRootTreeError {
	return TraversalRootTreeError{
		err:  err,
		code: http.StatusInternalServerError,
	}
}

func InternalError(m string) TraversalInternalError {
	return TraversalInternalError{
		msg:  m,
		code: http.StatusInternalServerError,
	}
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"fmt"
	"net/http"
	"os"
	"path"

	"github.com/spf13/cobra"

	"github.com/ovh/cds/sdk"

	"github.com/ovh/cds/cli/cds/action"
	"github.com/ovh/cds/cli/cds/admin"
	"github.com/ovh/cds/cli/cds/application"
	"github.com/ovh/cds/cli/cds/artifact"
	"github.com/ovh/cds/cli/cds/dashboard"
	"github.com/ovh/cds/cli/cds/environment"
	"github.com/ovh/cds/cli/cds/generate"
	"github.com/ovh/cds/cli/cds/group"
	"github.com/ovh/cds/cli/cds/internal"
	"github.com/ovh/cds/cli/cds/login"
	"github.com/ovh/cds/cli/cds/pipeline"
	"github.com/ovh/cds/cli/cds/project"
	"github.com/ovh/cds/cli/cds/track"
	"github.com/ovh/cds/cli/cds/trigger"
	"github.com/ovh/cds/cli/cds/update"
	"github.com/ovh/cds/cli/cds/user"
	"github.com/ovh/cds/cli/cds/version"
	"github.com/ovh/cds/cli/cds/wizard"
	"github.com/ovh/cds/cli/cds/worker"
)

var rootCmd = &cobra.Command{
	Use:   "cds",
	Short: "CDS - Command Line Tool",
	Long:  `CDS - Command Line Tool`,
}

func displayWarnings() {
	// Display warnings, on failure, fail silently
	warnings, err := sdk.GetWarnings()
	if err == nil && len(warnings) > 0 {
		fmt.Printf("/!\\ %d warnings found in your CDS configuration:\n", len(warnings))
		for _, w := range warnings {
			fmt.Printf("- %s\n", w.Message)
		}
		fmt.Printf("\n")
	}
}

func main() {
	rootCmd.PersistentFlags().StringVarP(&internal.ConfigFile, "file", "f", "", "set configuration file")
	rootCmd.PersistentFlags().BoolVarP(&internal.Verbose, "verbose", "v", false, "verbose output")
	rootCmd.PersistentFlags().BoolVarP(&internal.NoWarnings, "no-warnings", "w", false, "do not display warnings")
	rootCmd.PersistentFlags().BoolVarP(&internal.InsecureSkipVerifyTLS, "insecure", "k", false, `(SSL) This option explicitly allows curl to perform "insecure" SSL connections and transfers.`)

	rootCmd.PersistentPreRun = func(cmd *cobra.Command, args []string) {
		//ConfigFile default file
		if internal.ConfigFile == "" {
			internal.ConfigFile = path.Join(os.Getenv("HOME"), ".cds", "config.json")
		}

		//Set the config file
		sdk.CDSConfigFile = internal.ConfigFile

		//On login command: do nothing
		if cmd == login.Cmd {
			return
		}

		//If file doesn't exist, stop here
		if _, err := os.Stat(internal.ConfigFile); os.IsNotExist(err) {
			sdk.Exit("File %s doesn't exists", internal.ConfigFile)
			return
		}

		//Do not check warning on user command
		if cmd == user.Cmd {
			return
		}

		//Manage warnings
		if internal.NoWarnings {
			return
		}

		//Set http client
		c := &http.Client{
			Transport: &http.Transport{
				TLSClientConfig: &tls.Config{InsecureSkipVerify: internal.InsecureSkipVerifyTLS},
			}}
		sdk.SetHTTPClient(c)

		displayWarnings()
	}

	rootCmd.AddCommand(login.Cmd)
	rootCmd.AddCommand(action.Cmd)
	rootCmd.AddCommand(application.Cmd())
	rootCmd.AddCommand(artifact.Cmd)
	rootCmd.AddCommand(environment.Cmd())
	rootCmd.AddCommand(statusCmd())
	rootCmd.AddCommand(pipeline.Cmd())
	rootCmd.AddCommand(project.Cmd)
	rootCmd.AddCommand(group.Cmd)
	rootCmd.AddCommand(user.Cmd)
	rootCmd.AddCommand(worker.Cmd)
	rootCmd.AddCommand(update.Cmd)
	rootCmd.AddCommand(version.Cmd)
	rootCmd.AddCommand(trigger.Cmd())
	rootCmd.AddCommand(dashboard.Cmd)
	rootCmd.AddCommand(wizard.Cmd)
	rootCmd.AddCommand(track.Cmd)
	rootCmd.AddCommand(generate.Cmd())
	rootCmd.AddCommand(admin.Cmd())

	if err := rootCmd.Execute(); err != nil {
		os.Exit(1)
	}
}
<commit_msg>fix (cli): unable to disable warning and skip TLS verify (#174)<commit_after>package main

import (
	"crypto/tls"
	"fmt"
	"net/http"
	"os"
	"path"

	"github.com/spf13/cobra"

	"github.com/ovh/cds/sdk"

	"github.com/ovh/cds/cli/cds/action"
	"github.com/ovh/cds/cli/cds/admin"
	"github.com/ovh/cds/cli/cds/application"
	"github.com/ovh/cds/cli/cds/artifact"
	"github.com/ovh/cds/cli/cds/dashboard"
	"github.com/ovh/cds/cli/cds/environment"
	"github.com/ovh/cds/cli/cds/generate"
	"github.com/ovh/cds/cli/cds/group"
	"github.com/ovh/cds/cli/cds/internal"
	"github.com/ovh/cds/cli/cds/login"
	"github.com/ovh/cds/cli/cds/pipeline"
	"github.com/ovh/cds/cli/cds/project"
	"github.com/ovh/cds/cli/cds/track"
	"github.com/ovh/cds/cli/cds/trigger"
	"github.com/ovh/cds/cli/cds/update"
	"github.com/ovh/cds/cli/cds/user"
	"github.com/ovh/cds/cli/cds/version"
	"github.com/ovh/cds/cli/cds/wizard"
	"github.com/ovh/cds/cli/cds/worker"
)

var rootCmd = &cobra.Command{
	Use:   "cds",
	Short: "CDS - Command Line Tool",
	Long:  `CDS - Command Line Tool`,
}

func displayWarnings() {
	// Display warnings, on failure, fail silently
	warnings, err := sdk.GetWarnings()
	if err == nil && len(warnings) > 0 {
		fmt.Printf("/!\\ %d warnings found in your CDS configuration:\n", len(warnings))
		for _, w := range warnings {
			fmt.Printf("- %s\n", w.Message)
		}
		fmt.Printf("\n")
	}
}

func main() {
	rootCmd.PersistentFlags().StringVarP(&internal.ConfigFile, "file", "f", "", "set configuration file")
	rootCmd.PersistentFlags().BoolVarP(&internal.Verbose, "verbose", "v", false, "verbose output")
	rootCmd.PersistentFlags().BoolVarP(&internal.NoWarnings, "no-warnings", "w", false, "do not display warnings")
	rootCmd.PersistentFlags().BoolVarP(&internal.InsecureSkipVerifyTLS, "insecure", "k", false, `(SSL) This option explicitly allows curl to perform "insecure" SSL connections and transfers.`)

	rootCmd.PersistentPreRun = func(cmd *cobra.Command, args []string) {
		//ConfigFile default file
		if internal.ConfigFile == "" {
			internal.ConfigFile = path.Join(os.Getenv("HOME"), ".cds", "config.json")
		}

		//Set the config file
		sdk.CDSConfigFile = internal.ConfigFile

		//On login command: do nothing
		if cmd == login.Cmd {
			return
		}

		//If file doesn't exist, stop here
		if _, err := os.Stat(internal.ConfigFile); os.IsNotExist(err) {
			sdk.Exit("File %s doesn't exists", internal.ConfigFile)
			return
		}

		//Set http client
		c := &http.Client{
			Transport: &http.Transport{
				TLSClientConfig: &tls.Config{InsecureSkipVerify: internal.InsecureSkipVerifyTLS},
			}}
		sdk.SetHTTPClient(c)

		//Manage warnings
		if !internal.NoWarnings && cmd != user.Cmd {
			displayWarnings()
		}

	}

	rootCmd.AddCommand(login.Cmd)
	rootCmd.AddCommand(action.Cmd)
	rootCmd.AddCommand(application.Cmd())
	rootCmd.AddCommand(artifact.Cmd)
	rootCmd.AddCommand(environment.Cmd())
	rootCmd.AddCommand(statusCmd())
	rootCmd.AddCommand(pipeline.Cmd())
	rootCmd.AddCommand(project.Cmd)
	rootCmd.AddCommand(group.Cmd)
	rootCmd.AddCommand(user.Cmd)
	rootCmd.AddCommand(worker.Cmd)
	rootCmd.AddCommand(update.Cmd)
	rootCmd.AddCommand(version.Cmd)
	rootCmd.AddCommand(trigger.Cmd())
	rootCmd.AddCommand(dashboard.Cmd)
	rootCmd.AddCommand(wizard.Cmd)
	rootCmd.AddCommand(track.Cmd)
	rootCmd.AddCommand(generate.Cmd())
	rootCmd.AddCommand(admin.Cmd())

	if err := rootCmd.Execute(); err != nil {
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package cli

import (
	"testing"

	"github.com/libopenstorage/openstorage/api"
	"github.com/stretchr/testify/require"
)

func TestCmdMarshalProto(t *testing.T) {
	volumeSpec := &api.VolumeSpec{
		Size:   64,
		Format: api.FSType_FS_TYPE_EXT4,
	}
	data := cmdMarshalProto(volumeSpec, false)
	require.Equal(
		t,
		`{
 "ephemeral": false,
 "size": "64",
 "format": "ext4",
 "block_size": "0",
 "ha_level": "0",
 "cos": 0,
 "dedupe": false,
 "snapshot_interval": 0,
 "shared": false,
 "aggregation_level": 0,
 "encrypted": false,
 "passphrase": ""
}`,
		data,
	)
}
<commit_msg>fix build<commit_after>package cli

import (
	"testing"

	"github.com/libopenstorage/openstorage/api"
	"github.com/stretchr/testify/require"
)

func TestCmdMarshalProto(t *testing.T) {
	volumeSpec := &api.VolumeSpec{
		Size:   64,
		Format: api.FSType_FS_TYPE_EXT4,
	}
	data := cmdMarshalProto(volumeSpec, false)
	require.Equal(
		t,
		`{
 "ephemeral": false,
 "size": "64",
 "format": "ext4",
 "block_size": "0",
 "ha_level": "0",
 "cos": 0,
 "dedupe": false,
 "snapshot_interval": 0,
 "shared": false,
 "aggregation_level": 0,
 "encrypted": false,
 "passphrase": "",
 "snapshot_schedule": ""
}`,
		data,
	)
}
<|endoftext|>


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

package testutil

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"time"

	"github.com/gorilla/mux"
	"github.com/rackspace/gophercloud"
)

// ComputeAPIPort is the compute service port the testutil identity service will use by default
const ComputeAPIPort = "8774"

// ComputeURL is the compute service URL the testutil identity service will use by default
var ComputeURL = "https://localhost:" + ComputeAPIPort

// IdentityURL is the URL for the testutil identity service
var IdentityURL string

// ComputeUser is the test user/tenant name the testutil identity service will use by default
var ComputeUser = "f452bbc7-5076-44d5-922c-3b9d2ce1503f"

func authHandler(w http.ResponseWriter, r *http.Request) {
	token := `
		{
			"token": {
				"methods": [
					"password"
				],
				"roles": [
					{
						"id" : "12345",
						"name" : "admin"
					}
				],
				"expires_at": "%s",
				"project": {
					"domain": {
						"id": "default",
						"name": "Default"
					},
					"id": "%s",
					"name": "admin"
				},
				"catalog": [
					{
						"endpoints": [
							{
								"region_id": "RegionOne",
								"url": "%s/v3",
								"region": "RegionOne",
								"interface": "public",
								"id": "068d1b359ee84b438266cb736d81de97"
							},
							{
								"region_id": "RegionOne",
								"url": "%s/v3",
								"region": "RegionOne",
								"interface": "admin",
								"id": "8bfc846841ab441ca38471be6d164ced"
							},
							{
								"region_id": "RegionOne",
								"url": "%s/v3",
								"region": "RegionOne",
								"interface": "internal",
								"id": "beb6d358c3654b4bada04d4663b640b9"
							}
						],
						"type": "identity",
						"id": "050726f278654128aba89757ae25950c",
						"name": "keystone"
					}
				],
			       "extras": {},
			       "user": {
				       "domain": {
				               "id": "default",
				               "name": "Default"
				        },
				       "id": "ee4dfb6e5540447cb3741905149d9b6e",
			               "name": "admin"
			        },
			        "audit_ids": [
				        "3T2dc1CGQxyJsHdDu1xkcw"
			        ],
			        "issued_at": "%s"
			}
		}`

	t := []byte(fmt.Sprintf(token,
		time.Now().Add(1*time.Hour).Format(gophercloud.RFC3339Milli),
		ComputeUser, IdentityURL, IdentityURL,
		IdentityURL, time.Now().Format(gophercloud.RFC3339Milli)))
	w.Header().Set("X-Subject-Token", "imavalidtoken")
	w.WriteHeader(http.StatusCreated)
	w.Write(t)
}

func validateHandler(w http.ResponseWriter, r *http.Request) {
	tenantURL := ComputeURL + "/v2.1/" + ComputeUser
	token := `
	{
		"token": {
		        "methods": [
		                "token"
		        ],
		        "expires_at": "%s",
		        "extras": {},
		        "user": {
				"domain": {
					"id": "default",
					"name": "Default"
				},
				"id": "10a2e6e717a245d9acad3e5f97aeca3d",
				"name": "admin"
			},
			"roles": [
				{
					"id" : "12345",
					"name" : "admin"
				}
			],
			"project": {
				"domain": {
					"id": "default",
					"name": "Default"
				},
				"id": "%s",
				"name": "admin"
			},
			"catalog": [
				{
					"endpoints": [
						{
							"region_id": "RegionOne",
							"url": "%s/v3",
							"region": "RegionOne",
							"interface": "public",
							"id": "068d1b359ee84b438266cb736d81de97"
						},
						{
							"region_id": "RegionOne",
							"url": "%s/v3",
							"region": "RegionOne",
							"interface": "admin",
							"id": "8bfc846841ab441ca38471be6d164ced"
						},
						{
							"region_id": "RegionOne",
							"url": "%s/v3",
							"region": "RegionOne",
							"interface": "internal",
							"id": "beb6d358c3654b4bada04d4663b640b9"
						}
					],
					"type": "identity",
					"id": "050726f278654128aba89757ae25950c",
					"name": "keystone"
				},
				{
			                "endpoints": [
					         {
							"region_id": "RegionOne",
							"url": "%s",
							"region": "RegionOne",
							"interface": "admin",
							"id": "2511589f262a407bb0071a814a480af4"
						},
						{
							"region_id": "RegionOne",
							"url": "%s",
							"region": "RegionOne",
							"interface": "internal",
							"id": "9cf9209ae4fc4673a7295611001cf0ae"
						},
						{
							"region_id": "RegionOne",
							"url": "%s",
							"region": "RegionOne",
							"interface": "public",
							"id": "d200b2509e1343e3887dcc465b4fa534"
						}
					],
					"type": "compute",
					"id": "a226b3eeb5594f50bf8b6df94636ed28",
					"name": "ciao"
				}
			],
			"audit_ids": [
			        "mAjXQhiYRyKwkB4qygdLVg"
			],
			"issued_at": "%s"
		}
	}`

	t := []byte(fmt.Sprintf(token,
		time.Now().Add(1*time.Hour).Format(gophercloud.RFC3339Milli),
		ComputeUser, IdentityURL, IdentityURL,
		IdentityURL, tenantURL, tenantURL,
		tenantURL, time.Now().Format(gophercloud.RFC3339Milli)))
	w.WriteHeader(http.StatusOK)
	w.Write(t)
}

func projectsHandler(w http.ResponseWriter, r *http.Request) {
	response := `
	{
		"projects": [
			{
				"description": "fake project1",
				"domain_id": "default",
				"enabled": true,
				"id": "456788",
				"parent_id": "212223",
				"links": {
					"self": "%s/v3/projects/456788"
				},
				"name": "ilovepuppies"
			}
		],
		"links": {
			"self": "%s/v3/users/10a2e6e717a245d9acad3e5f97aeca3d/projects",
			"previous": null,
			"next": null
		}
	}`

	p := []byte(fmt.Sprintf(response, IdentityURL, IdentityURL))
	w.WriteHeader(http.StatusOK)
	w.Write(p)
}

// IdentityHandlers creates a mux.Router for identity POST and GET handlers
func IdentityHandlers() *mux.Router {
	r := mux.NewRouter()

	r.HandleFunc("/v3/auth/tokens", authHandler).Methods("POST")
	r.HandleFunc("/v3/auth/tokens", validateHandler).Methods("GET")
	r.HandleFunc("/v3/users/10a2e6e717a245d9acad3e5f97aeca3d/projects", projectsHandler).Methods("GET")

	return r
}

// IdentityConfig contains the URL of the ciao compute service, and the TenantID of
// the tenant you want tokens to be sent for.  The test Identity service only supports
// authentication of a single tenant, and gives the token an admin role.
type IdentityConfig struct {
	ComputeURL string
	ProjectID  string
}

// StartIdentityServer starts a fake keystone service for unit testing ciao.
func StartIdentityServer(config IdentityConfig) *httptest.Server {
	id := httptest.NewServer(IdentityHandlers())
	if id == nil {
		return nil
	}

	if config.ComputeURL != "" {
		ComputeURL = config.ComputeURL
	}
	if config.ProjectID != "" {
		ComputeUser = config.ProjectID
	}
	IdentityURL = id.URL

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

package testutil

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"time"

	"github.com/gorilla/mux"
	"github.com/rackspace/gophercloud"
)

// ComputeAPIPort is the compute service port the testutil identity service will use by default
const ComputeAPIPort = "8774"

// ComputeURL is the compute service URL the testutil identity service will use by default
var ComputeURL = "https://localhost:" + ComputeAPIPort

// IdentityURL is the URL for the testutil identity service
var IdentityURL string

// ComputeUser is the test user/tenant name the testutil identity service will use by default
var ComputeUser = "f452bbc7-5076-44d5-922c-3b9d2ce1503f"

func authHandler(w http.ResponseWriter, r *http.Request) {
	token := `
		{
			"token": {
				"methods": [
					"password"
				],
				"roles": [
					{
						"id" : "12345",
						"name" : "admin"
					}
				],
				"expires_at": "%s",
				"project": {
					"domain": {
						"id": "default",
						"name": "Default"
					},
					"id": "%s",
					"name": "admin"
				},
				"catalog": [
					{
						"endpoints": [
							{
								"region_id": "RegionOne",
								"url": "%s/v3",
								"region": "RegionOne",
								"interface": "public",
								"id": "068d1b359ee84b438266cb736d81de97"
							},
							{
								"region_id": "RegionOne",
								"url": "%s/v3",
								"region": "RegionOne",
								"interface": "admin",
								"id": "8bfc846841ab441ca38471be6d164ced"
							},
							{
								"region_id": "RegionOne",
								"url": "%s/v3",
								"region": "RegionOne",
								"interface": "internal",
								"id": "beb6d358c3654b4bada04d4663b640b9"
							}
						],
						"type": "identity",
						"id": "050726f278654128aba89757ae25950c",
						"name": "keystone"
					}
				],
			       "extras": {},
			       "user": {
				       "domain": {
				               "id": "default",
				               "name": "Default"
				        },
				       "id": "ee4dfb6e5540447cb3741905149d9b6e",
			               "name": "admin"
			        },
			        "audit_ids": [
				        "3T2dc1CGQxyJsHdDu1xkcw"
			        ],
			        "issued_at": "%s"
			}
		}`

	t := []byte(fmt.Sprintf(token,
		time.Now().Add(1*time.Hour).Format(gophercloud.RFC3339Milli),
		ComputeUser, IdentityURL, IdentityURL,
		IdentityURL, time.Now().Format(gophercloud.RFC3339Milli)))
	w.Header().Set("X-Subject-Token", "imavalidtoken")
	w.WriteHeader(http.StatusCreated)
	w.Write(t)
}

func validateHandler(w http.ResponseWriter, r *http.Request) {
	tenantURL := ComputeURL + "/v2.1/" + ComputeUser
	token := `
	{
		"token": {
		        "methods": [
		                "token"
		        ],
		        "expires_at": "%s",
		        "extras": {},
		        "user": {
				"domain": {
					"id": "default",
					"name": "Default"
				},
				"id": "10a2e6e717a245d9acad3e5f97aeca3d",
				"name": "admin"
			},
			"roles": [
				{
					"id" : "12345",
					"name" : "admin"
				}
			],
			"project": {
				"domain": {
					"id": "default",
					"name": "Default"
				},
				"id": "%s",
				"name": "admin"
			},
			"catalog": [
				{
					"endpoints": [
						{
							"region_id": "RegionOne",
							"url": "%s/v3",
							"region": "RegionOne",
							"interface": "public",
							"id": "068d1b359ee84b438266cb736d81de97"
						},
						{
							"region_id": "RegionOne",
							"url": "%s/v3",
							"region": "RegionOne",
							"interface": "admin",
							"id": "8bfc846841ab441ca38471be6d164ced"
						},
						{
							"region_id": "RegionOne",
							"url": "%s/v3",
							"region": "RegionOne",
							"interface": "internal",
							"id": "beb6d358c3654b4bada04d4663b640b9"
						}
					],
					"type": "identity",
					"id": "050726f278654128aba89757ae25950c",
					"name": "keystone"
				},
				{
			                "endpoints": [
					         {
							"region_id": "RegionOne",
							"url": "%s",
							"region": "RegionOne",
							"interface": "admin",
							"id": "2511589f262a407bb0071a814a480af4"
						},
						{
							"region_id": "RegionOne",
							"url": "%s",
							"region": "RegionOne",
							"interface": "internal",
							"id": "9cf9209ae4fc4673a7295611001cf0ae"
						},
						{
							"region_id": "RegionOne",
							"url": "%s",
							"region": "RegionOne",
							"interface": "public",
							"id": "d200b2509e1343e3887dcc465b4fa534"
						}
					],
					"type": "compute",
					"id": "a226b3eeb5594f50bf8b6df94636ed28",
					"name": "ciao"
				}
			],
			"audit_ids": [
			        "mAjXQhiYRyKwkB4qygdLVg"
			],
			"issued_at": "%s"
		}
	}`

	t := []byte(fmt.Sprintf(token,
		time.Now().Add(1*time.Hour).Format(gophercloud.RFC3339Milli),
		ComputeUser, IdentityURL, IdentityURL,
		IdentityURL, tenantURL, tenantURL,
		tenantURL, time.Now().Format(gophercloud.RFC3339Milli)))
	w.WriteHeader(http.StatusOK)
	w.Write(t)
}

func projectsHandler(w http.ResponseWriter, r *http.Request) {
	response := `
	{
		"projects": [
			{
				"description": "fake project1",
				"domain_id": "default",
				"enabled": true,
				"id": "456788",
				"parent_id": "212223",
				"links": {
					"self": "%s/v3/projects/456788"
				},
				"name": "ilovepuppies"
			}
		],
		"links": {
			"self": "%s/v3/users/10a2e6e717a245d9acad3e5f97aeca3d/projects",
			"previous": null,
			"next": null
		}
	}`

	p := []byte(fmt.Sprintf(response, IdentityURL, IdentityURL))
	w.WriteHeader(http.StatusOK)
	w.Write(p)
}

// IdentityHandlers creates a mux.Router for identity POST and GET handlers
func IdentityHandlers() *mux.Router {
	r := mux.NewRouter()

	r.HandleFunc("/v3/auth/tokens", authHandler).Methods("POST")
	r.HandleFunc("/v3/auth/tokens", validateHandler).Methods("GET")
	r.HandleFunc("/v3/users/10a2e6e717a245d9acad3e5f97aeca3d/projects", projectsHandler).Methods("GET")

	return r
}

// IdentityConfig contains the URL of the ciao compute service, and the TenantID of
// the tenant you want tokens to be sent for.  The test Identity service only supports
// authentication of a single tenant, and gives the token an admin role.
type IdentityConfig struct {
	ComputeURL string
	ProjectID  string
}

// StartIdentityServer starts a fake keystone service for unit testing ciao.
// Caller must call Close() on the returned *httptest.Server.
func StartIdentityServer(config IdentityConfig) *httptest.Server {
	id := httptest.NewServer(IdentityHandlers())
	if id == nil {
		return nil
	}

	if config.ComputeURL != "" {
		ComputeURL = config.ComputeURL
	}
	if config.ProjectID != "" {
		ComputeUser = config.ProjectID
	}
	IdentityURL = id.URL

	return id
}
<|endoftext|>


<commit_before>package web

import (
	"crypto/rand"
	"encoding/base64"
	mrand "math/rand"
	"net/http"
	"testing"
)

/*
The core benchmarks here are based on cypriss's mux benchmarks, which can be
found here:
https://github.com/cypriss/golang-mux-benchmark

They happen to play very well into Goji's router's strengths.
*/

type nilRouter struct{}

var helloWorld = []byte("Hello world!\n")

func (_ nilRouter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.Write(helloWorld)
}

type nilResponse struct{}

func (_ nilResponse) Write(buf []byte) (int, error) {
	return len(buf), nil
}
func (_ nilResponse) Header() http.Header {
	return nil
}
func (_ nilResponse) WriteHeader(code int) {
}

func trivialMiddleware(h http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		h.ServeHTTP(w, r)
	}
	return http.HandlerFunc(fn)
}

var w nilResponse

func addRoutes(m *Mux, prefix string) {
	m.Get(prefix, nilRouter{})
	m.Post(prefix, nilRouter{})
	m.Get(prefix+"/:id", nilRouter{})
	m.Put(prefix+"/:id", nilRouter{})
	m.Delete(prefix+"/:id", nilRouter{})
}

func randString() string {
	var buf [6]byte
	rand.Reader.Read(buf[:])
	return base64.URLEncoding.EncodeToString(buf[:])
}

func genPrefixes(n int) []string {
	p := make([]string, n)
	for i := range p {
		p[i] = "/" + randString()
	}
	return p
}

func genRequests(prefixes []string) []*http.Request {
	rs := make([]*http.Request, 5*len(prefixes))
	for i, prefix := range prefixes {
		rs[5*i+0], _ = http.NewRequest("GET", prefix, nil)
		rs[5*i+1], _ = http.NewRequest("POST", prefix, nil)
		rs[5*i+2], _ = http.NewRequest("GET", prefix+"/foo", nil)
		rs[5*i+3], _ = http.NewRequest("PUT", prefix+"/foo", nil)
		rs[5*i+4], _ = http.NewRequest("DELETE", prefix+"/foo", nil)
	}
	return rs
}

func permuteRequests(reqs []*http.Request) []*http.Request {
	out := make([]*http.Request, len(reqs))
	perm := mrand.Perm(len(reqs))
	for i, req := range reqs {
		out[perm[i]] = req
	}
	return out
}

func benchN(b *testing.B, n int) {
	m := New()
	prefixes := genPrefixes(n)
	for _, prefix := range prefixes {
		addRoutes(m, prefix)
	}
	reqs := permuteRequests(genRequests(prefixes))

	b.ResetTimer()
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		m.ServeHTTP(w, reqs[i%len(reqs)])
	}
}

func benchM(b *testing.B, n int) {
	m := New()
	m.Get("/", nilRouter{})
	for i := 0; i < n; i++ {
		m.Use(trivialMiddleware)
	}
	r, _ := http.NewRequest("GET", "/", nil)

	b.ResetTimer()
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		m.ServeHTTP(w, r)
	}
}

func BenchmarkStatic(b *testing.B) {
	m := New()
	m.Get("/", nilRouter{})
	r, _ := http.NewRequest("GET", "/", nil)

	b.ResetTimer()
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		m.ServeHTTP(w, r)
	}
}

func BenchmarkRoute5(b *testing.B) {
	benchN(b, 1)
}
func BenchmarkRoute50(b *testing.B) {
	benchN(b, 10)
}
func BenchmarkRoute500(b *testing.B) {
	benchN(b, 100)
}
func BenchmarkRoute5000(b *testing.B) {
	benchN(b, 1000)
}

func BenchmarkMiddleware1(b *testing.B) {
	benchM(b, 1)
}
func BenchmarkMiddleware10(b *testing.B) {
	benchM(b, 10)
}
func BenchmarkMiddleware100(b *testing.B) {
	benchM(b, 100)
}
<commit_msg>Benchmark goji/web in parallel<commit_after>package web

import (
	"crypto/rand"
	"encoding/base64"
	mrand "math/rand"
	"net/http"
	"testing"
)

/*
The core benchmarks here are based on cypriss's mux benchmarks, which can be
found here:
https://github.com/cypriss/golang-mux-benchmark

They happen to play very well into Goji's router's strengths.
*/

type nilRouter struct{}

var helloWorld = []byte("Hello world!\n")

func (_ nilRouter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.Write(helloWorld)
}

type nilResponse struct{}

func (_ nilResponse) Write(buf []byte) (int, error) {
	return len(buf), nil
}
func (_ nilResponse) Header() http.Header {
	return nil
}
func (_ nilResponse) WriteHeader(code int) {
}

func trivialMiddleware(h http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		h.ServeHTTP(w, r)
	}
	return http.HandlerFunc(fn)
}

var w nilResponse

func addRoutes(m *Mux, prefix string) {
	m.Get(prefix, nilRouter{})
	m.Post(prefix, nilRouter{})
	m.Get(prefix+"/:id", nilRouter{})
	m.Put(prefix+"/:id", nilRouter{})
	m.Delete(prefix+"/:id", nilRouter{})
}

func randString() string {
	var buf [6]byte
	rand.Reader.Read(buf[:])
	return base64.URLEncoding.EncodeToString(buf[:])
}

func genPrefixes(n int) []string {
	p := make([]string, n)
	for i := range p {
		p[i] = "/" + randString()
	}
	return p
}

func genRequests(prefixes []string) []*http.Request {
	rs := make([]*http.Request, 5*len(prefixes))
	for i, prefix := range prefixes {
		rs[5*i+0], _ = http.NewRequest("GET", prefix, nil)
		rs[5*i+1], _ = http.NewRequest("POST", prefix, nil)
		rs[5*i+2], _ = http.NewRequest("GET", prefix+"/foo", nil)
		rs[5*i+3], _ = http.NewRequest("PUT", prefix+"/foo", nil)
		rs[5*i+4], _ = http.NewRequest("DELETE", prefix+"/foo", nil)
	}
	return rs
}

func permuteRequests(reqs []*http.Request) []*http.Request {
	out := make([]*http.Request, len(reqs))
	perm := mrand.Perm(len(reqs))
	for i, req := range reqs {
		out[perm[i]] = req
	}
	return out
}

func benchN(b *testing.B, n int) {
	m := New()
	prefixes := genPrefixes(n)
	for _, prefix := range prefixes {
		addRoutes(m, prefix)
	}
	m.Compile()
	reqs := permuteRequests(genRequests(prefixes))

	b.ResetTimer()
	b.ReportAllocs()
	b.RunParallel(func(pb *testing.PB) {
		i := 0
		for pb.Next() {
			i++
			m.ServeHTTP(w, reqs[i%len(reqs)])
		}
	})
}

func benchM(b *testing.B, n int) {
	m := New()
	m.Get("/", nilRouter{})
	for i := 0; i < n; i++ {
		m.Use(trivialMiddleware)
	}
	r, _ := http.NewRequest("GET", "/", nil)
	m.Compile()

	b.ResetTimer()
	b.ReportAllocs()
	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			m.ServeHTTP(w, r)
		}
	})
}

func BenchmarkStatic(b *testing.B) {
	m := New()
	m.Get("/", nilRouter{})
	r, _ := http.NewRequest("GET", "/", nil)
	m.Compile()

	b.ResetTimer()
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		m.ServeHTTP(w, r)
	}
}

func BenchmarkRoute5(b *testing.B) {
	benchN(b, 1)
}
func BenchmarkRoute50(b *testing.B) {
	benchN(b, 10)
}
func BenchmarkRoute500(b *testing.B) {
	benchN(b, 100)
}
func BenchmarkRoute5000(b *testing.B) {
	benchN(b, 1000)
}

func BenchmarkMiddleware1(b *testing.B) {
	benchM(b, 1)
}
func BenchmarkMiddleware10(b *testing.B) {
	benchM(b, 10)
}
func BenchmarkMiddleware100(b *testing.B) {
	benchM(b, 100)
}
<|endoftext|>


<commit_before>package dbus

import (
	"github.com/guelfey/go.dbus"
	"time"
)

const (
	cleanIgnoreInterval = int64(10 * time.Second)
	ignoreInterval      = int64(30 * time.Millisecond)
)

func (c *Conn) initSubscription() {
	c.subscriber.ignore = make(map[dbus.ObjectPath]int64)
}

// Returns two unbuffered channels which will receive all changed units every
// @interval@ seconds.  Deleted units are sent as nil.
func (c *Conn) SubscribeUnits(interval time.Duration) (<-chan map[string]*UnitStatus, <-chan error) {
	return c.SubscribeUnitsCustom(interval, 0, func(u1, u2 *UnitStatus) bool { return *u1 != *u2 })
}

// SubscribeUnitsCustom is like SubscribeUnits but lets you specify the buffer
// size of the channels and the comparison function for detecting changes.
func (c *Conn) SubscribeUnitsCustom(interval time.Duration, buffer int, isChanged func(*UnitStatus, *UnitStatus) bool) (<-chan map[string]*UnitStatus, <-chan error) {
	old := make(map[string]*UnitStatus)
	statusChan := make(chan map[string]*UnitStatus, buffer)
	errChan := make(chan error, buffer)

	go func() {
		for {
			timerChan := time.After(interval)

			units, err := c.ListUnits()
			if err == nil {
				cur := make(map[string]*UnitStatus)
				for i := range units {
					cur[units[i].Name] = &units[i]
				}

				// add all new or changed units
				changed := make(map[string]*UnitStatus)
				for n, u := range cur {
					if oldU, ok := old[n]; !ok || isChanged(oldU, u) {
						changed[n] = u
					}
					delete(old, n)
				}

				// add all deleted units
				for oldN := range old {
					changed[oldN] = nil
				}

				old = cur

				statusChan <- changed
			} else {
				errChan <- err
			}

			<-timerChan
		}
	}()

	return statusChan, errChan
}

type SubStateUpdate struct {
	UnitName string
	SubState string
}

type Error string

func (e Error) Error() string {
	return string(e)
}

// SetSubStateSubscriber writes to updateCh when any unit's substate changes.
// Althrough this writes to updateCh on every state change, the reported state
// may be more recent than the change that generated it (due to an unavoidable
// race in the systemd dbus interface).  That is, this method provides a good
// way to keep a current view of all units' states, but is not guaranteed to
// show every state transition they go through.  Furthermore, state changes
// will only be written to the channel with non-blocking writes.  If updateCh
// is full, it attempts to write an error to errCh; if errCh is full, the error
// passes silently.
func (c *Conn) SetSubStateSubscriber(updateCh chan<- *SubStateUpdate, errCh chan<- error) {
	c.subscriber.Lock()
	defer c.subscriber.Unlock()
	c.subscriber.updateCh = updateCh
	c.subscriber.errCh = errCh
}

func (c *Conn) sendSubStateUpdate(path dbus.ObjectPath) {
	c.subscriber.Lock()
	defer c.subscriber.Unlock()
	if c.subscriber.updateCh == nil {
		return
	}

	if c.shouldIgnore(path) {
		return
	}

	info, err := c.getUnitInfo(path)
	if err != nil {
		select {
		case c.subscriber.errCh <- err:
		default:
		}
	}

	name := info["Id"].Value().(string)
	substate := info["SubState"].Value().(string)

	update := &SubStateUpdate{name, substate}
	select {
	case c.subscriber.updateCh <- update:
	default:
		select {
		case c.subscriber.errCh <- Error("update channel full!"):
		default:
		}
	}

	c.updateIgnore(path, info)
}

func (c *Conn) getUnitInfo(path dbus.ObjectPath) (map[string]dbus.Variant, error) {
	var err error
	var props map[string]dbus.Variant
	obj := c.sysconn.Object("org.freedesktop.systemd1", path)
	err = obj.Call("GetAll", 0, "org.freedesktop.systemd1.Unit").Store(&props)
	if err != nil {
		return nil, err
	}
	return props, nil
}

// The ignore functions work around a wart in the systemd dbus interface.
// Requesting the properties of an unloaded unit will cause systemd to send a
// pair of UnitNew/UnitRemoved signals.  Because we need to get a unit's
// properties on UnitNew (as that's the only indication of a new unit coming up
// for the first time), we would enter an infinite loop if we did not attempt
// to detect and ignore these spurious signals.  The signal themselves are
// indistinguishable from relevant ones, so we (somewhat hackishly) ignore an
// unloaded unit's signals for a short time after requesting its properties.
// This means that we will miss e.g. a transient unit being restarted
// *immediately* upon failure and also a transient unit being started
// immediately after requesting its status (with systemctl status, for example,
// because this causes a UnitNew signal to be sent which then causes us to fetch
// the properties).

func (c *Conn) shouldIgnore(path dbus.ObjectPath) bool {
	t, ok := c.subscriber.ignore[path]
	return ok && t >= time.Now().UnixNano()
}

func (c *Conn) updateIgnore(path dbus.ObjectPath, info map[string]dbus.Variant) {
	c.cleanIgnore()

	// unit is unloaded - it will trigger bad systemd dbus behavior
	if info["LoadState"].Value().(string) == "not-found" {
		c.subscriber.ignore[path] = time.Now().UnixNano() + ignoreInterval
	}
}

// without this, ignore would grow unboundedly over time
func (c *Conn) cleanIgnore() {
	now := time.Now().UnixNano()
	if c.subscriber.cleanIgnore < now {
		c.subscriber.cleanIgnore = now + cleanIgnoreInterval

		for p, t := range c.subscriber.ignore {
			if t < now {
				delete(c.subscriber.ignore, p)
			}
		}
	}
}
<commit_msg>fix(GetUnitInfo): GetUnitInfo is used by coreinit<commit_after>package dbus

import (
	"github.com/guelfey/go.dbus"
	"time"
)

const (
	cleanIgnoreInterval = int64(10 * time.Second)
	ignoreInterval      = int64(30 * time.Millisecond)
)

func (c *Conn) initSubscription() {
	c.subscriber.ignore = make(map[dbus.ObjectPath]int64)
}

// Returns two unbuffered channels which will receive all changed units every
// @interval@ seconds.  Deleted units are sent as nil.
func (c *Conn) SubscribeUnits(interval time.Duration) (<-chan map[string]*UnitStatus, <-chan error) {
	return c.SubscribeUnitsCustom(interval, 0, func(u1, u2 *UnitStatus) bool { return *u1 != *u2 })
}

// SubscribeUnitsCustom is like SubscribeUnits but lets you specify the buffer
// size of the channels and the comparison function for detecting changes.
func (c *Conn) SubscribeUnitsCustom(interval time.Duration, buffer int, isChanged func(*UnitStatus, *UnitStatus) bool) (<-chan map[string]*UnitStatus, <-chan error) {
	old := make(map[string]*UnitStatus)
	statusChan := make(chan map[string]*UnitStatus, buffer)
	errChan := make(chan error, buffer)

	go func() {
		for {
			timerChan := time.After(interval)

			units, err := c.ListUnits()
			if err == nil {
				cur := make(map[string]*UnitStatus)
				for i := range units {
					cur[units[i].Name] = &units[i]
				}

				// add all new or changed units
				changed := make(map[string]*UnitStatus)
				for n, u := range cur {
					if oldU, ok := old[n]; !ok || isChanged(oldU, u) {
						changed[n] = u
					}
					delete(old, n)
				}

				// add all deleted units
				for oldN := range old {
					changed[oldN] = nil
				}

				old = cur

				statusChan <- changed
			} else {
				errChan <- err
			}

			<-timerChan
		}
	}()

	return statusChan, errChan
}

type SubStateUpdate struct {
	UnitName string
	SubState string
}

type Error string

func (e Error) Error() string {
	return string(e)
}

// SetSubStateSubscriber writes to updateCh when any unit's substate changes.
// Althrough this writes to updateCh on every state change, the reported state
// may be more recent than the change that generated it (due to an unavoidable
// race in the systemd dbus interface).  That is, this method provides a good
// way to keep a current view of all units' states, but is not guaranteed to
// show every state transition they go through.  Furthermore, state changes
// will only be written to the channel with non-blocking writes.  If updateCh
// is full, it attempts to write an error to errCh; if errCh is full, the error
// passes silently.
func (c *Conn) SetSubStateSubscriber(updateCh chan<- *SubStateUpdate, errCh chan<- error) {
	c.subscriber.Lock()
	defer c.subscriber.Unlock()
	c.subscriber.updateCh = updateCh
	c.subscriber.errCh = errCh
}

func (c *Conn) sendSubStateUpdate(path dbus.ObjectPath) {
	c.subscriber.Lock()
	defer c.subscriber.Unlock()
	if c.subscriber.updateCh == nil {
		return
	}

	if c.shouldIgnore(path) {
		return
	}

	info, err := c.GetUnitInfo(path)
	if err != nil {
		select {
		case c.subscriber.errCh <- err:
		default:
		}
	}

	name := info["Id"].Value().(string)
	substate := info["SubState"].Value().(string)

	update := &SubStateUpdate{name, substate}
	select {
	case c.subscriber.updateCh <- update:
	default:
		select {
		case c.subscriber.errCh <- Error("update channel full!"):
		default:
		}
	}

	c.updateIgnore(path, info)
}

func (c *Conn) GetUnitInfo(path dbus.ObjectPath) (map[string]dbus.Variant, error) {
	var err error
	var props map[string]dbus.Variant
	obj := c.sysconn.Object("org.freedesktop.systemd1", path)
	err = obj.Call("GetAll", 0, "org.freedesktop.systemd1.Unit").Store(&props)
	if err != nil {
		return nil, err
	}
	return props, nil
}

// The ignore functions work around a wart in the systemd dbus interface.
// Requesting the properties of an unloaded unit will cause systemd to send a
// pair of UnitNew/UnitRemoved signals.  Because we need to get a unit's
// properties on UnitNew (as that's the only indication of a new unit coming up
// for the first time), we would enter an infinite loop if we did not attempt
// to detect and ignore these spurious signals.  The signal themselves are
// indistinguishable from relevant ones, so we (somewhat hackishly) ignore an
// unloaded unit's signals for a short time after requesting its properties.
// This means that we will miss e.g. a transient unit being restarted
// *immediately* upon failure and also a transient unit being started
// immediately after requesting its status (with systemctl status, for example,
// because this causes a UnitNew signal to be sent which then causes us to fetch
// the properties).

func (c *Conn) shouldIgnore(path dbus.ObjectPath) bool {
	t, ok := c.subscriber.ignore[path]
	return ok && t >= time.Now().UnixNano()
}

func (c *Conn) updateIgnore(path dbus.ObjectPath, info map[string]dbus.Variant) {
	c.cleanIgnore()

	// unit is unloaded - it will trigger bad systemd dbus behavior
	if info["LoadState"].Value().(string) == "not-found" {
		c.subscriber.ignore[path] = time.Now().UnixNano() + ignoreInterval
	}
}

// without this, ignore would grow unboundedly over time
func (c *Conn) cleanIgnore() {
	now := time.Now().UnixNano()
	if c.subscriber.cleanIgnore < now {
		c.subscriber.cleanIgnore = now + cleanIgnoreInterval

		for p, t := range c.subscriber.ignore {
			if t < now {
				delete(c.subscriber.ignore, p)
			}
		}
	}
}
<|endoftext|>


<commit_before>package controllers

import (
	"fmt"
	"html/template"
	"time"

	"github.com/chenxin0723/ilove/app/models"
	"github.com/chenxin0723/ilove/config"
	"github.com/chenxin0723/ilove/config/admin"
	"github.com/chenxin0723/ilove/config/bindatafs"
	"github.com/chenxin0723/ilove/config/db"
	"github.com/chenxin0723/ilove/utils"
	"github.com/gin-gonic/gin"
	"github.com/qor/i18n"
	"github.com/qor/i18n/inline_edit"
	"github.com/qor/render"
	"github.com/qor/widget"
)

var Render *render.Render

func init() {
	Render = render.New(&render.Config{ViewPaths: []string{"app/views"}})
	Render.SetAssetFS(bindatafs.AssetFS.NameSpace("views"))
}

func SetContext(ctx *gin.Context) {
	funcMap := utils.FuncMap(ctx.Writer, ctx.Request)
	funcMap["T"] = func(key string, args ...interface{}) template.HTML {
		if len(args) == 0 {
			args = []interface{}{key}
		} else {
			args = append([]interface{}{key}, args...)
		}

		localeI18n := db.I18n.Fallbacks("en-us").(*i18n.I18n)
		var inlineEdit bool
		if config.IsDraft() {
			inlineEdit = true
		}
		return inline_edit.InlineEdit(localeI18n, "en-us", inlineEdit)(key, args...)
	}

	funcMap["get_setting"] = func() interface{} {
		var page_setting models.PageSetting
		db.DB.Preload("StorySections").Last(&page_setting)
		fmt.Println("###################", page_setting.StorySections)
		return page_setting
	}
	funcMap["inlineEdit"] = func() bool {
		return admin.ActionBar.EditMode(ctx.Writer, ctx.Request)
	}
	options := map[string]interface{}{}
	options["Request"] = ctx.Request
	widgetContext := admin.Widgets.NewContext(&widget.Context{
		DB:         db.DB,
		InlineEdit: admin.ActionBar.EditMode(ctx.Writer, ctx.Request),
		Options:    options,
	})

	funcMap["CommonTest"] = func() template.HTML {
		return widgetContext.Render("CommonTest", "CommonTest")
	}

	ctx.Set("FuncMap", funcMap)
}

func Home(ctx *gin.Context) {
	FuncMap := ctx.MustGet("FuncMap").(template.FuncMap)

	viewCtx := map[string]interface{}{}
	if config.IsDraft() {
		qorAdminCssJs := template.HTML(`<script type="text/javascript" src="/system/qor_vendor.js"></script><link rel="stylesheet" href="/system/qor_admin.css"><script defer async type="text/javascript" src="/system/qor_admin.js"></script>`)
		viewCtx["ActionBar"] = qorAdminCssJs + admin.ActionBar.Render(ctx.Writer, ctx.Request)
	} else {
		viewCtx["ActionBar"] = ""
	}

	viewCtx["PageType"] = "Homepage"
	viewCtx["Now"] = time.Now().Format("Mon Jan 2 . 2006")
	Render.Layout("application").Funcs(FuncMap).Execute("index", viewCtx, ctx.Request, ctx.Writer)
	return
}
<commit_msg>xin commit<commit_after>package controllers

import (
	"html/template"
	"time"

	"github.com/chenxin0723/ilove/app/models"
	"github.com/chenxin0723/ilove/config"
	"github.com/chenxin0723/ilove/config/admin"
	"github.com/chenxin0723/ilove/config/bindatafs"
	"github.com/chenxin0723/ilove/config/db"
	"github.com/chenxin0723/ilove/utils"
	"github.com/gin-gonic/gin"
	"github.com/qor/i18n"
	"github.com/qor/i18n/inline_edit"
	"github.com/qor/render"
	"github.com/qor/widget"
)

var Render *render.Render

func init() {
	Render = render.New(&render.Config{ViewPaths: []string{"app/views"}})
	Render.SetAssetFS(bindatafs.AssetFS.NameSpace("views"))
}

func SetContext(ctx *gin.Context) {
	funcMap := utils.FuncMap(ctx.Writer, ctx.Request)
	funcMap["T"] = func(key string, args ...interface{}) template.HTML {
		if len(args) == 0 {
			args = []interface{}{key}
		} else {
			args = append([]interface{}{key}, args...)
		}

		localeI18n := db.I18n.Fallbacks("en-us").(*i18n.I18n)
		var inlineEdit bool
		if config.IsDraft() {
			inlineEdit = admin.ActionBar.EditMode(ctx.Writer, ctx.Request)
		}
		return inline_edit.InlineEdit(localeI18n, "en-us", inlineEdit)(key, args...)
	}

	funcMap["get_setting"] = func() interface{} {
		var page_setting models.PageSetting
		db.DB.Preload("StorySections").Last(&page_setting)
		return page_setting
	}
	funcMap["inlineEdit"] = func() bool {
		return admin.ActionBar.EditMode(ctx.Writer, ctx.Request)
	}
	options := map[string]interface{}{}
	options["Request"] = ctx.Request
	widgetContext := admin.Widgets.NewContext(&widget.Context{
		DB:         db.DB,
		InlineEdit: admin.ActionBar.EditMode(ctx.Writer, ctx.Request),
		Options:    options,
	})

	funcMap["CommonTest"] = func() template.HTML {
		return widgetContext.Render("CommonTest", "CommonTest")
	}

	ctx.Set("FuncMap", funcMap)
}

func Home(ctx *gin.Context) {
	FuncMap := ctx.MustGet("FuncMap").(template.FuncMap)

	viewCtx := map[string]interface{}{}
	if config.IsDraft() {
		qorAdminCssJs := template.HTML(`<script type="text/javascript" src="/system/qor_vendor.js"></script><link rel="stylesheet" href="/system/qor_admin.css"><script defer async type="text/javascript" src="/system/qor_admin.js"></script>`)
		viewCtx["ActionBar"] = qorAdminCssJs + admin.ActionBar.Render(ctx.Writer, ctx.Request)
	} else {
		viewCtx["ActionBar"] = ""
	}

	viewCtx["PageType"] = "Homepage"
	viewCtx["Now"] = time.Now().Format("Mon Jan 2 . 2006")
	Render.Layout("application").Funcs(FuncMap).Execute("index", viewCtx, ctx.Request, ctx.Writer)
	return
}
<|endoftext|>


<commit_before>package cli

import (
	"flag"
	"fmt"
	"log"
	"os"
	"sync"

	"github.com/opentable/sous/config"
	"github.com/opentable/sous/graph"
	"github.com/opentable/sous/lib"
	"github.com/opentable/sous/util/cmdr"
)

// SousQueryGDM is the description of the `sous query gdm` command
type SousQueryGDM struct {
	StateManager *graph.ClientStateManager
	flags        struct {
		noimage bool
		format  string
	}
	SousGraph *graph.SousGraph
}

func init() { QuerySubcommands["gdm"] = &SousQueryGDM{} }

const sousQueryGDMHelp = `The intended state of deployment for every project and every cluster known to Sous.

The results of 'sous query gdm' and 'sous query ads' will not be identical if
a problem is preventing sous from modifying the current state of Singularity.
`

// Help prints the help
func (*SousQueryGDM) Help() string { return sousQueryGDMHelp }

// RegisterOn adds options set by flags to the injection graph.
func (*SousQueryGDM) RegisterOn(psy Addable) {
	psy.Add(graph.DryrunNeither)
	psy.Add(&config.DeployFilterFlags{})
}

// AddFlags adds the flags for 'sous query gdm'.
func (sb *SousQueryGDM) AddFlags(fs *flag.FlagSet) {
	fs.BoolVar(&sb.flags.noimage, "noimage", false, "list only deployments that have no registered image")
	fs.StringVar(&sb.flags.format, "format", "table", "output format, one of (table, json)")
}

func (sb *SousQueryGDM) dump(ds sous.Deployments) cmdr.Result {
	var err error
	switch sb.flags.format {
	default:
		err = fmt.Errorf("output format %q not allowed, pick one of: table, json", sb.flags.format)
		fallthrough
	case "table":
		sous.DumpDeployments(os.Stdout, ds)
	case "json":
		sous.JSONDeployments(os.Stdout, ds)
	}
	if err != nil {
		return cmdr.EnsureErrorResult(err)
	}
	return cmdr.Success()
}

// Execute defines the behavior of `sous query gdm`
func (sb *SousQueryGDM) Execute(args []string) cmdr.Result {

	state, err := sb.StateManager.ReadState()
	if err != nil {
		return EnsureErrorResult(err)
	}
	deployments, err := state.Deployments()

	totalCount := deployments.Len()

	if err != nil {
		return EnsureErrorResult(err)
	}
	if !sb.flags.noimage {
		return sb.dump(deployments)
	}

	filtered := sous.NewDeployments()
	wg := sync.WaitGroup{}

	ds := deployments.Snapshot()

	wg.Add(len(ds))
	errs := make(chan error, len(ds))
	getArtifactMutex := sync.Mutex{}

	for _, d := range ds {
		d := d
		go func() {
			defer wg.Done()
			opts := graph.ArtifactOpts{
				SourceID: config.NewSourceIDFlags(d.SourceID),
			}
			getArtifactMutex.Lock()
			getArtifact, err := sb.SousGraph.GetGetArtifact(opts)
			getArtifactMutex.Unlock()
			if err != nil {
				errs <- err
				return
			}
			exists, err := getArtifact.ArtifactExists()
			if err != nil {
				errs <- err
				return
			}
			if exists {
				filtered.Add(d)
			}
		}()
	}
	wg.Wait()
	close(errs)

	for err := range errs {
		log.Println(err)
	}

	filteredCount := filtered.Len()
	log.Printf("%d/%d deployments matched your filter", filteredCount, totalCount)
	return sb.dump(filtered)

}
<commit_msg>cli: query gdm filters: hasimage zeroinstances<commit_after>package cli

import (
	"flag"
	"fmt"
	"log"
	"os"
	"strconv"
	"strings"
	"sync"

	"github.com/opentable/sous/config"
	"github.com/opentable/sous/graph"
	"github.com/opentable/sous/lib"
	"github.com/opentable/sous/util/cmdr"
)

// SousQueryGDM is the description of the `sous query gdm` command
type SousQueryGDM struct {
	StateManager *graph.ClientStateManager
	flags        struct {
		filters string
		format  string
	}
	SousGraph *graph.SousGraph
}

func init() { QuerySubcommands["gdm"] = &SousQueryGDM{} }

const sousQueryGDMHelp = `The intended state of deployment for every project and every cluster known to Sous.

The results of 'sous query gdm' and 'sous query ads' will not be identical if
a problem is preventing sous from modifying the current state of Singularity.
`

// Help prints the help
func (*SousQueryGDM) Help() string { return sousQueryGDMHelp }

// RegisterOn adds options set by flags to the injection graph.
func (*SousQueryGDM) RegisterOn(psy Addable) {
	psy.Add(graph.DryrunNeither)
	psy.Add(&config.DeployFilterFlags{})
}

// AddFlags adds the flags for 'sous query gdm'.
func (sb *SousQueryGDM) AddFlags(fs *flag.FlagSet) {
	fs.StringVar(&sb.flags.filters, "filters", "", "filter the output, space-separatey list, e.g. 'hasimage=true zeroinstances=false")
	fs.StringVar(&sb.flags.format, "format", "table", "output format, one of (table, json)")
}

func (sb *SousQueryGDM) dump(ds sous.Deployments) cmdr.Result {
	var err error
	switch sb.flags.format {
	default:
		err = fmt.Errorf("output format %q not allowed, pick one of: table, json", sb.flags.format)
		fallthrough
	case "table":
		sous.DumpDeployments(os.Stdout, ds)
	case "json":
		sous.JSONDeployments(os.Stdout, ds)
	}
	if err != nil {
		return cmdr.EnsureErrorResult(err)
	}
	return cmdr.Success()
}

func (sb *SousQueryGDM) hasImageFilter(deployments sous.Deployments, which bool) sous.Deployments {
	filtered := sous.NewDeployments()
	wg := sync.WaitGroup{}

	ds := deployments.Snapshot()

	wg.Add(len(ds))
	errs := make(chan error, len(ds))
	getArtifactMutex := sync.Mutex{}

	for _, d := range ds {
		d := d
		go func() {
			defer wg.Done()
			opts := graph.ArtifactOpts{
				SourceID: config.NewSourceIDFlags(d.SourceID),
			}
			getArtifactMutex.Lock()
			getArtifact, err := sb.SousGraph.GetGetArtifact(opts)
			getArtifactMutex.Unlock()
			if err != nil {
				errs <- err
				return
			}
			exists, err := getArtifact.ArtifactExists()
			if err != nil {
				errs <- err
				return
			}
			if exists {
				filtered.Add(d)
			}
		}()
	}
	wg.Wait()
	close(errs)

	for err := range errs {
		log.Println(err)
	}
	return filtered
}

func zeroInstanceFilter(ds sous.Deployments, which bool) sous.Deployments {
	return ds.Filter(func(d *sous.Deployment) bool {
		return d.NumInstances == 0 == which
	})
}

func (sb *SousQueryGDM) getFilter(name string) (func(sous.Deployments, bool) sous.Deployments, error) {
	switch name {
	default:
		return nil, fmt.Errorf("filter %q not recognised; pick either hasimage or zeroinstances", name)
	case "hasimage":
		return sb.hasImageFilter, nil
	case "zeroinstances":
		return zeroInstanceFilter, nil
	}
}

func (sb *SousQueryGDM) parseFilters() ([]func(sous.Deployments) sous.Deployments, error) {
	var filters []func(sous.Deployments) sous.Deployments
	if sb.flags.filters == "" {
		return nil, nil
	}
	parts := strings.Fields(sb.flags.filters)
	for _, p := range parts {
		kv := strings.Split(p, "=")
		if len(kv) != 2 {
			return nil, cmdr.UsageErrorf("filter %q not valid; format is name=(true|false)")
		}
		k, v := kv[0], kv[1]
		f, err := sb.getFilter(k)
		if err != nil {
			return nil, err
		}
		tf, err := strconv.ParseBool(v)
		if err != nil {
			return nil, cmdr.UsageErrorf("filter %q accepts true or false, not %q", k, v)
		}
		filters = append(filters, func(ds sous.Deployments) sous.Deployments {
			return f(ds, tf)
		})
	}
	return filters, nil
}

func (sb *SousQueryGDM) filter(ds sous.Deployments) (sous.Deployments, error) {
	filters, err := sb.parseFilters()
	if err != nil {
		return sous.NewDeployments(), err
	}
	for _, f := range filters {
		ds = f(ds)
	}
	return ds, nil
}

// Execute defines the behavior of `sous query gdm`
func (sb *SousQueryGDM) Execute(args []string) cmdr.Result {

	state, err := sb.StateManager.ReadState()
	if err != nil {
		return EnsureErrorResult(err)
	}
	deployments, err := state.Deployments()

	totalCount := deployments.Len()

	if err != nil {
		return EnsureErrorResult(err)
	}

	filtered, err := sb.filter(deployments)
	if err != nil {
		return cmdr.EnsureErrorResult(err)
	}

	filteredCount := filtered.Len()
	log.Printf("%d results (of %q total deployments)", filteredCount, totalCount)
	return sb.dump(filtered)

}
<|endoftext|>


<commit_before>package client

import (
	"bytes"
	"os"
	"testing"
	"time"

	"../net"
	"../redlot"
)

var (
	client *Client
	err    error
)

func TestMain(m *testing.M) {
	// clean env
	os.RemoveAll("/tmp/data")
	os.RemoveAll("/tmp/meta")

	os.Exit(func() (r int) {
		options := &redlot.Options{
			DataPath: "/tmp",
		}

		go net.Serve(":9999", options)

		// Wait 1ms to start server.
		time.Sleep(5e6)

		r = m.Run()

		client.Close()
		os.RemoveAll("/tmp/data")
		os.RemoveAll("/tmp/meta")
		return r
	}())
}

func TestNewClient(t *testing.T) {
	o := &Options{
		Addr: "127.0.0.1:9999",
	}
	client, err = NewClient(o)
	if err != nil || client == nil {
		t.Logf("client: %+v, err: %v\n", client, err)
		t.Fail()
	}
}

func TestCmd(t *testing.T) {
	r := client.Cmd("set", "k", "v")
	if r.State != ReplyOK {
		t.Logf("Cmd [set k v] reply error: %s", r.State)
		t.Fail()
	}
	r = client.Cmd("get", "k")
	if r.State != ReplyOK {
		t.Logf("Cmd [get k] reply state error: %s", r.State)
		t.Fail()
	}
	if len(r.Data) != 1 {
		t.Logf("Cmd [get k] reply length error, expect 1, but %d", len(r.Data))
		t.Fail()
	}
	if string(r.Data[0]) != "v" {
		t.Logf("Cmd [get k] reply data error, expect string \"v\" , but %s", string(r.Data[0]))
		t.Fail()
	}

}

func TestSendBuf(t *testing.T) {
	var tests = []struct {
		in  []interface{}
		out string
	}{
		{[]interface{}{"set", "age", "19"}, "*3\r\n$3\r\nset\r\n$3\r\nage\r\n$2\r\n19\r\n"},
	}

	var buf []byte
	var err error

	for k, test := range tests {
		buf, err = client.sendBuf(test.in)
		if err != nil {
			t.Logf("%d [% #v] => [% #v], error: %s\n", k, test.in, buf, err.Error())
			t.Fail()
		}
		if !bytes.Equal(buf, []byte(test.out)) {
			t.Logf("%d [% #v] => [% #v], expect: [% #v]\n", k, test.in, string(buf), test.out)
			t.Fail()
		}
	}
}
<commit_msg>Test case of convert int,int8,int16,int32,int64 to send buf.<commit_after>package client

import (
	"bytes"
	"os"
	"testing"
	"time"

	"../net"
	"../redlot"
)

var (
	client *Client
	err    error
)

func TestMain(m *testing.M) {
	// clean env
	os.RemoveAll("/tmp/data")
	os.RemoveAll("/tmp/meta")

	os.Exit(func() (r int) {
		options := &redlot.Options{
			DataPath: "/tmp",
		}

		go net.Serve(":9999", options)

		// Wait 1ms to start server.
		time.Sleep(5e6)

		r = m.Run()

		client.Close()
		os.RemoveAll("/tmp/data")
		os.RemoveAll("/tmp/meta")
		return r
	}())
}

func TestNewClient(t *testing.T) {
	o := &Options{
		Addr: "127.0.0.1:9999",
	}
	client, err = NewClient(o)
	if err != nil || client == nil {
		t.Logf("client: %+v, err: %v\n", client, err)
		t.Fail()
	}
}

func TestCmd(t *testing.T) {
	r := client.Cmd("set", "k", "v")
	if r.State != ReplyOK {
		t.Logf("Cmd [set k v] reply error: %s", r.State)
		t.Fail()
	}
	r = client.Cmd("get", "k")
	if r.State != ReplyOK {
		t.Logf("Cmd [get k] reply state error: %s", r.State)
		t.Fail()
	}
	if len(r.Data) != 1 {
		t.Logf("Cmd [get k] reply length error, expect 1, but %d", len(r.Data))
		t.Fail()
	}
	if string(r.Data[0]) != "v" {
		t.Logf("Cmd [get k] reply data error, expect string \"v\" , but %s", string(r.Data[0]))
		t.Fail()
	}

}

func TestSendBuf(t *testing.T) {
	var tests = []struct {
		in  []interface{}
		out string
	}{
		{[]interface{}{"set", "age", "19"}, "*3\r\n$3\r\nset\r\n$3\r\nage\r\n$2\r\n19\r\n"},
		{[]interface{}{"set", "age", int(19)}, "*3\r\n$3\r\nset\r\n$3\r\nage\r\n$2\r\n19\r\n"},
		{[]interface{}{"set", "age", int8(19)}, "*3\r\n$3\r\nset\r\n$3\r\nage\r\n$2\r\n19\r\n"},
		{[]interface{}{"set", "age", int16(19)}, "*3\r\n$3\r\nset\r\n$3\r\nage\r\n$2\r\n19\r\n"},
		{[]interface{}{"set", "age", int32(19)}, "*3\r\n$3\r\nset\r\n$3\r\nage\r\n$2\r\n19\r\n"},
		{[]interface{}{"set", "age", int64(19)}, "*3\r\n$3\r\nset\r\n$3\r\nage\r\n$2\r\n19\r\n"},
	}

	var buf []byte
	var err error

	for k, test := range tests {
		buf, err = client.sendBuf(test.in)
		if err != nil {
			t.Logf("%d [% #v] => [% #v], error: %s\n", k, test.in, buf, err.Error())
			t.Fail()
		}
		if !bytes.Equal(buf, []byte(test.out)) {
			t.Logf("%d [% #v] => [% #v], expect: [% #v]\n", k, test.in, string(buf), test.out)
			t.Fail()
		}
	}
}
<|endoftext|>


<commit_before>package client

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

	"github.com/docker/notary/trustmanager"
)

// TestInitRepo runs through the process of initializing a repository and makes
// sure the repository looks correct on disk.
func TestInitRepo(t *testing.T) {
	// Temporary directory where test files will be created
	tempBaseDir, err := ioutil.TempDir("", "notary-test-")
	if err != nil {
		t.Fatalf("failed to create a temporary directory: %s", err)
	}

	client, err := NewClient(tempBaseDir)
	if err != nil {
		t.Fatalf("error creating client: %s", err)
	}

	rootKeyID, err := client.GenRootKey("passphrase")
	if err != nil {
		t.Fatalf("error generating root key: %s", err)
	}

	rootKey, err := client.GetRootKey(rootKeyID, "passphrase")
	if err != nil {
		t.Fatalf("error retreiving root key: %s", err)
	}

	gun := "docker.com/notary"
	repo, err := client.InitRepository(gun, "", nil, rootKey)
	if err != nil {
		t.Fatalf("error creating repository: %s", err)
	}

	// Inspect contents of the temporary directory
	expectedDirs := []string{
		"private",
		filepath.Join("private", gun),
		filepath.Join("private", "root_keys"),
		"trusted_certificates",
		filepath.Join("trusted_certificates", gun),
		"tuf",
		filepath.Join("tuf", gun, "metadata"),
		filepath.Join("tuf", gun, "targets"),
	}
	for _, dir := range expectedDirs {
		fi, err := os.Stat(filepath.Join(tempBaseDir, dir))
		if err != nil {
			t.Fatalf("missing directory in base directory: %s", dir)
		}
		if !fi.Mode().IsDir() {
			t.Fatalf("%s is not a directory", dir)
		}
	}

	// Look for keys in private. The filenames should match the key IDs
	// in the private key store.
	privKeyList := repo.privKeyStore.ListAll()
	for _, privKeyName := range privKeyList {
		if _, err := os.Stat(privKeyName); err != nil {
			t.Fatalf("missing private key: %s", privKeyName)
		}
	}

	// Look for keys in root_keys
	// There should be a file named after the key ID of the root key we
	// passed in.
	rootKeyFilename := rootKey.ID() + ".key"
	if _, err := os.Stat(filepath.Join(tempBaseDir, "private", "root_keys", rootKeyFilename)); err != nil {
		t.Fatal("missing root key")
	}

	// Also expect a symlink from the key ID of the certificate key to this
	// root key
	certificates := client.certificateStore.GetCertificates()
	if len(certificates) != 1 {
		t.Fatalf("unexpected number of certificates (%d)", len(certificates))
	}

	certID := trustmanager.FingerprintCert(certificates[0])

	actualDest, err := os.Readlink(filepath.Join(tempBaseDir, "private", "root_keys", certID+".key"))
	if err != nil {
		t.Fatal("missing symlink to root key")
	}

	if actualDest != rootKeyFilename {
		t.Fatalf("symlink to root key has wrong destination (got: %s, expected: %s)", actualDest, rootKeyFilename)
	}

	// There should be a trusted certificate
	if _, err := os.Stat(filepath.Join(tempBaseDir, "trusted_certificates", gun, certID+".crt")); err != nil {
		t.Fatal("missing trusted certificate")
	}

	// Check that tuf metadata files were created
	expectedTUFMetadataFiles := []string{
		filepath.Join("tuf", gun, "metadata", "root.json"),
		filepath.Join("tuf", gun, "metadata", "snapshot.json"),
		filepath.Join("tuf", gun, "metadata", "targets.json"),
	}
	for _, filename := range expectedTUFMetadataFiles {
		_, err := os.Stat(filepath.Join(tempBaseDir, filename))
		if err != nil {
			t.Fatalf("missing TUF metadata file: %s", filename)
		}
	}
}
<commit_msg>Extend TestInitRepo to parse and sanity-check TUF metadata<commit_after>package client

import (
	"encoding/json"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"testing"

	"github.com/docker/notary/trustmanager"
	"github.com/endophage/gotuf/data"
)

// TestInitRepo runs through the process of initializing a repository and makes
// sure the repository looks correct on disk.
func TestInitRepo(t *testing.T) {
	// Temporary directory where test files will be created
	tempBaseDir, err := ioutil.TempDir("", "notary-test-")
	if err != nil {
		t.Fatalf("failed to create a temporary directory: %s", err)
	}

	client, err := NewClient(tempBaseDir)
	if err != nil {
		t.Fatalf("error creating client: %s", err)
	}

	rootKeyID, err := client.GenRootKey("passphrase")
	if err != nil {
		t.Fatalf("error generating root key: %s", err)
	}

	rootKey, err := client.GetRootKey(rootKeyID, "passphrase")
	if err != nil {
		t.Fatalf("error retreiving root key: %s", err)
	}

	gun := "docker.com/notary"
	repo, err := client.InitRepository(gun, "", nil, rootKey)
	if err != nil {
		t.Fatalf("error creating repository: %s", err)
	}

	// Inspect contents of the temporary directory
	expectedDirs := []string{
		"private",
		filepath.Join("private", gun),
		filepath.Join("private", "root_keys"),
		"trusted_certificates",
		filepath.Join("trusted_certificates", gun),
		"tuf",
		filepath.Join("tuf", gun, "metadata"),
		filepath.Join("tuf", gun, "targets"),
	}
	for _, dir := range expectedDirs {
		fi, err := os.Stat(filepath.Join(tempBaseDir, dir))
		if err != nil {
			t.Fatalf("missing directory in base directory: %s", dir)
		}
		if !fi.Mode().IsDir() {
			t.Fatalf("%s is not a directory", dir)
		}
	}

	// Look for keys in private. The filenames should match the key IDs
	// in the private key store.
	privKeyList := repo.privKeyStore.ListAll()
	for _, privKeyName := range privKeyList {
		if _, err := os.Stat(privKeyName); err != nil {
			t.Fatalf("missing private key: %s", privKeyName)
		}
	}

	// Look for keys in root_keys
	// There should be a file named after the key ID of the root key we
	// passed in.
	rootKeyFilename := rootKey.ID() + ".key"
	if _, err := os.Stat(filepath.Join(tempBaseDir, "private", "root_keys", rootKeyFilename)); err != nil {
		t.Fatal("missing root key")
	}

	// Also expect a symlink from the key ID of the certificate key to this
	// root key
	certificates := client.certificateStore.GetCertificates()
	if len(certificates) != 1 {
		t.Fatalf("unexpected number of certificates (%d)", len(certificates))
	}

	certID := trustmanager.FingerprintCert(certificates[0])

	actualDest, err := os.Readlink(filepath.Join(tempBaseDir, "private", "root_keys", certID+".key"))
	if err != nil {
		t.Fatal("missing symlink to root key")
	}

	if actualDest != rootKeyFilename {
		t.Fatalf("symlink to root key has wrong destination (got: %s, expected: %s)", actualDest, rootKeyFilename)
	}

	// There should be a trusted certificate
	if _, err := os.Stat(filepath.Join(tempBaseDir, "trusted_certificates", gun, certID+".crt")); err != nil {
		t.Fatal("missing trusted certificate")
	}

	// Sanity check the TUF metadata files. Verify that they exist, the JSON is
	// well-formed, and the signatures exist. For the root.json file, also check
	// that the root, snapshot, and targets key IDs are present.
	expectedTUFMetadataFiles := []string{
		filepath.Join("tuf", gun, "metadata", "root.json"),
		filepath.Join("tuf", gun, "metadata", "snapshot.json"),
		filepath.Join("tuf", gun, "metadata", "targets.json"),
	}
	for _, filename := range expectedTUFMetadataFiles {
		fullPath := filepath.Join(tempBaseDir, filename)
		_, err := os.Stat(fullPath)
		if err != nil {
			t.Fatalf("missing TUF metadata file: %s", filename)
		}

		jsonBytes, err := ioutil.ReadFile(fullPath)
		if err != nil {
			t.Fatalf("error reading TUF metadata file %s: %s", filename, err)
		}

		var decoded data.Signed
		if err := json.Unmarshal(jsonBytes, &decoded); err != nil {
			t.Fatalf("error parsing TUF metadata file %s: %s", filename, err)
		}

		if len(decoded.Signatures) != 1 {
			t.Fatalf("incorrect number of signatures in TUF metadata file %s", filename)
		}

		if decoded.Signatures[0].KeyID == "" || decoded.Signatures[0].Method == "" || len(decoded.Signatures[0].Signature) == 0 {
			t.Fatalf("bad content in signature on TUF metadata file %s", filename)
		}

		// Special case for root.json: also check that the signed
		// content for keys and roles
		if strings.HasSuffix(filename, "root.json") {
			var decodedRoot data.Root
			if err := json.Unmarshal(decoded.Signed, &decodedRoot); err != nil {
				t.Fatalf("error parsing root.json signed section: %s", err)
			}

			if decodedRoot.Type != "Root" {
				t.Fatal("_type mismatch in root.json")
			}

			if decodedRoot.Type != "Root" {
				t.Fatal("_type mismatch in root.json")
			}

			// Expect 4 keys in the Keys map: root, targets, snapshot, timestamp
			if len(decodedRoot.Keys) != 4 {
				t.Fatal("wrong number of keys in root.json")
			}

			roleCount := 0
			for role := range decodedRoot.Roles {
				roleCount++
				if role != "root" && role != "snapshot" && role != "targets" && role != "timestamp" {
					t.Fatalf("unexpected role %s in root.json", role)
				}
			}
			if roleCount != 4 {
				t.Fatalf("wrong number of roles (%d) in root.json", roleCount)
			}
		}
	}
}
<|endoftext|>