<commit_before>/*
	A firewall is a device or set of devices designed to permit or deny network transmissions based upon a set of rules and is frequently used to protect networks from unauthorized access while permitting legitimate communications to pass.
  	Firewall profiles represent these sets of rules and allow their application to a set of servers.

	The available commands are:
		list
		show
		create
		update
		delete

	Use "network firewall_profiles --help" on the commandline interface for more information about the available subcommands.

	Firewall Profiles list

	Lists all available firewall profiles.

	Usage:

		firewall_profiles list

	Firewall Profiles show

	Shows information about a specific firewall profile.

	Usage:

		firewall_profiles show (options)

	Options:
		--id <firewall_profile_id> 		firewall profile id

	Firewall Profiles create

	This action creates an firewall profile with the given parameters.

	Usage:

		firewall_profiles create (options)

	Options:
		--name <name> 			Logical name of the firewall profile
		--description <description> 	Description of the firewall profile
		--rules <rules> 	Set of rules of the firewall profile, each rule having the following fields:
								a string protocol, specifying the protocol whose traffic is opened by the rule (TCP or UDP)
								an integer min_port, specifying where the port interval opened by the rule starts
								an integer max_port, specifying where the port interval opened by the rule ends and
								a string cidr_ip, specifying with the CIDR format to which network the rule opens traffic

	Firewall Profiles update

	Updates an existing firewall profile.

	Usage:

		firewall_profiles update (options)

	Options:
		--id <firewall_profile_id> 		firewall profile id
		--name <name> 			Logical name of the firewall profile
		--description <description> 	Description of the firewall profile
		--rules <rules> 	Set of rules of the firewall profile, each rule having the following fields:
								a string protocol, specifying the protocol whose traffic is opened by the rule (TCP or UDP)
								an integer min_port, specifying where the port interval opened by the rule starts
								an integer max_port, specifying where the port interval opened by the rule ends and
								a string cidr_ip, specifying with the CIDR format to which network the rule opens traffic

	Firewall Profiles delete

	Deletes an firewall profile.

	Usage:

		firewall_profiles delete (options)

	Options:
		--id <firewall_profile_id> 		firewall profile id

*/
package firewall_profiles

import (
	"encoding/json"
	"fmt"
	log "github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
	"github.com/flexiant/concerto/utils"
	"github.com/flexiant/concerto/webservice"
	"os"
	"text/tabwriter"
)

type FirewallProfile struct {
	Id          string `json:"id"`
	Name        string `json:"name"`
	Description string `json:"description"`
	Default     string `json:"default"`
	Rules       []Rule `json:"rules"`
}

type Rule struct {
	Protocol string `json:"ip_protocol"`
	MinPort  int    `json:"min_port"`
	MaxPort  int    `json:"max_port"`
	CidrIp   string `json:"cidr_ip"`
}

func cmdList(c *cli.Context) {
	var firewallProfiles []FirewallProfile

	webservice, err := webservice.NewWebService()
	utils.CheckError(err)

	data, err := webservice.Get("/v1/network/firewall_profiles")
	utils.CheckError(err)

	err = json.Unmarshal(data, &firewallProfiles)
	utils.CheckError(err)

	w := tabwriter.NewWriter(os.Stdout, 15, 1, 3, ' ', 0)
	fmt.Fprintln(w, "ID\tNAME\tDESCRIPTION\tDEFAULT\r")

	for _, firewallProfile := range firewallProfiles {
		fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", firewallProfile.Id, firewallProfile.Name, firewallProfile.Description, firewallProfile.Default)
	}

	w.Flush()
}

func cmdShow(c *cli.Context) {
	utils.FlagsRequired(c, []string{"id"})
	var firewallProfile FirewallProfile

	webservice, err := webservice.NewWebService()
	utils.CheckError(err)

	data, err := webservice.Get(fmt.Sprintf("/v1/network/firewall_profiles/%s", c.String("id")))
	utils.CheckError(err)

	err = json.Unmarshal(data, &firewallProfile)
	utils.CheckError(err)

	w := tabwriter.NewWriter(os.Stdout, 15, 1, 3, ' ', 0)
	fmt.Fprintln(w, "ID\tNAME\tDESCRIPTION\tDEFAULT\r")
	fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", firewallProfile.Id, firewallProfile.Name, firewallProfile.Description, firewallProfile.Default)
	fmt.Fprintln(w, "RULES:\r")
	fmt.Fprintln(w, "\tPROTOCOL\tMIN PORT\tMAX PORT\tCIDR IP\r")
	for _, r := range firewallProfile.Rules {
		fmt.Fprintf(w, "\t%s\t%d\t%d\t%s\n", r.Protocol, r.MinPort, r.MaxPort, r.CidrIp)
	}
	w.Flush()
}

func cmdCreate(c *cli.Context) {
	utils.FlagsRequired(c, []string{"name", "description"})
	webservice, err := webservice.NewWebService()
	utils.CheckError(err)

	v := make(map[string]string)

	v["name"] = c.String("name")
	v["description"] = c.String("description")
	if c.IsSet("rules") {
		v["rules"] = c.String("rules")
	}

	jsonBytes, err := json.Marshal(v)
	utils.CheckError(err)
	err, res, _ := webservice.Post("/v1/network/firewall_profiles", jsonBytes)
	if res == nil {
		log.Fatal(err)
	}
	utils.CheckError(err)

	var firewallProfile FirewallProfile

	err = json.Unmarshal(res, &firewallProfile)
	utils.CheckError(err)

	w := tabwriter.NewWriter(os.Stdout, 15, 1, 3, ' ', 0)
	fmt.Fprintln(w, "ID\tNAME\tDESCRIPTION\tDEFAULT\r")
	fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", firewallProfile.Id, firewallProfile.Name, firewallProfile.Description, firewallProfile.Default)
	fmt.Fprintln(w, "RULES:\r")
	fmt.Fprintln(w, "\tPROTOCOL\tMIN PORT\tMAX PORT\tCIDR IP\r")
	for _, r := range firewallProfile.Rules {
		fmt.Fprintf(w, "\t%s\t%d\t%d\t%s\n", r.Protocol, r.MinPort, r.MaxPort, r.CidrIp)
	}
	w.Flush()

}

func cmdUpdate(c *cli.Context) {
	utils.FlagsRequired(c, []string{"id"})
	webservice, err := webservice.NewWebService()
	utils.CheckError(err)

	v := make(map[string]string)

	if c.IsSet("name") {
		v["name"] = c.String("name")
	}
	if c.IsSet("description") {
		v["description"] = c.String("description")
	}
	if c.IsSet("rules") {
		v["rules"] = c.String("rules")
	}

	jsonBytes, err := json.Marshal(v)
	utils.CheckError(err)
	err, res, _ := webservice.Put(fmt.Sprintf("/v1/network/firewall_profiles/%s", c.String("id")), jsonBytes)

	utils.CheckError(err)
	fmt.Println(res)

	var firewallProfile FirewallProfile

	err = json.Unmarshal(res, &firewallProfile)
	utils.CheckError(err)

	w := tabwriter.NewWriter(os.Stdout, 15, 1, 3, ' ', 0)
	fmt.Fprintln(w, "ID\tNAME\tDESCRIPTION\tDEFAULT\r")
	fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", firewallProfile.Id, firewallProfile.Name, firewallProfile.Description, firewallProfile.Default)
	fmt.Fprintln(w, "RULES:\r")
	fmt.Fprintln(w, "\tPROTOCOL\tMIN PORT\tMAX PORT\tCIDR IP\r")
	for _, r := range firewallProfile.Rules {
		fmt.Fprintf(w, "\t%s\t%d\t%d\t%s\n", r.Protocol, r.MinPort, r.MaxPort, r.CidrIp)
	}
	w.Flush()

}

func cmdDelete(c *cli.Context) {
	utils.FlagsRequired(c, []string{"id"})

	webservice, err := webservice.NewWebService()
	utils.CheckError(err)

	err, mesg, res := webservice.Delete(fmt.Sprintf("/v1/network/firewall_profiles/%s", c.String("id")))
	utils.CheckError(err)
	utils.CheckReturnCode(res, mesg)

	fmt.Println(res)
}

func SubCommands() []cli.Command {
	return []cli.Command{
		{
			Name:   "list",
			Usage:  "Lists all existing firewall profiles",
			Action: cmdList,
		},
		{
			Name:   "show",
			Usage:  "Shows information about the firewall profile identified by the given id.",
			Action: cmdShow,
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "id",
					Usage: "Firewall profile Id",
				},
			},
		},
		{
			Name:   "create",
			Usage:  "Creates a a firewall profile with the given parameters.",
			Action: cmdCreate,
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "name",
					Usage: "Logical name of the firewall profile",
				},
				cli.StringFlag{
					Name:  "description",
					Usage: "Description of the firewall profile",
				},
				cli.StringFlag{
					Name:  "rules",
					Usage: "Set of rules of the firewall profile",
				},
			},
		},
		{
			Name:   "update",
			Usage:  "Updates the firewall profile identified by the given id with the given parameters.",
			Action: cmdUpdate,
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "id",
					Usage: "Firewall profile Id",
				},
				cli.StringFlag{
					Name:  "name",
					Usage: "Logical name of the firewall profile",
				},
				cli.StringFlag{
					Name:  "description",
					Usage: "Description of the firewall profile",
				},
				cli.StringFlag{
					Name:  "rules",
					Usage: "Set of rules of the firewall profile",
				},
			},
		},
		{
			Name:   "delete",
			Usage:  "Destroy a firewall profile",
			Action: cmdDelete,
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "id",
					Usage: "Firewall profile Id",
				},
			},
		},
	}
}
<commit_msg>firewall.default property must be bool<commit_after>/*
	A firewall is a device or set of devices designed to permit or deny network transmissions based upon a set of rules and is frequently used to protect networks from unauthorized access while permitting legitimate communications to pass.
  	Firewall profiles represent these sets of rules and allow their application to a set of servers.

	The available commands are:
		list
		show
		create
		update
		delete

	Use "network firewall_profiles --help" on the commandline interface for more information about the available subcommands.

	Firewall Profiles list

	Lists all available firewall profiles.

	Usage:

		firewall_profiles list

	Firewall Profiles show

	Shows information about a specific firewall profile.

	Usage:

		firewall_profiles show (options)

	Options:
		--id <firewall_profile_id> 		firewall profile id

	Firewall Profiles create

	This action creates an firewall profile with the given parameters.

	Usage:

		firewall_profiles create (options)

	Options:
		--name <name> 			Logical name of the firewall profile
		--description <description> 	Description of the firewall profile
		--rules <rules> 	Set of rules of the firewall profile, each rule having the following fields:
								a string protocol, specifying the protocol whose traffic is opened by the rule (TCP or UDP)
								an integer min_port, specifying where the port interval opened by the rule starts
								an integer max_port, specifying where the port interval opened by the rule ends and
								a string cidr_ip, specifying with the CIDR format to which network the rule opens traffic

	Firewall Profiles update

	Updates an existing firewall profile.

	Usage:

		firewall_profiles update (options)

	Options:
		--id <firewall_profile_id> 		firewall profile id
		--name <name> 			Logical name of the firewall profile
		--description <description> 	Description of the firewall profile
		--rules <rules> 	Set of rules of the firewall profile, each rule having the following fields:
								a string protocol, specifying the protocol whose traffic is opened by the rule (TCP or UDP)
								an integer min_port, specifying where the port interval opened by the rule starts
								an integer max_port, specifying where the port interval opened by the rule ends and
								a string cidr_ip, specifying with the CIDR format to which network the rule opens traffic

	Firewall Profiles delete

	Deletes an firewall profile.

	Usage:

		firewall_profiles delete (options)

	Options:
		--id <firewall_profile_id> 		firewall profile id

*/
package firewall_profiles

import (
	"encoding/json"
	"fmt"
	log "github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
	"github.com/flexiant/concerto/utils"
	"github.com/flexiant/concerto/webservice"
	"os"
	"text/tabwriter"
)

type FirewallProfile struct {
	Id          string `json:"id"`
	Name        string `json:"name"`
	Description string `json:"description"`
	Default     bool   `json:"default"`
	Rules       []Rule `json:"rules"`
}

type Rule struct {
	Protocol string `json:"ip_protocol"`
	MinPort  int    `json:"min_port"`
	MaxPort  int    `json:"max_port"`
	CidrIp   string `json:"cidr_ip"`
}

func cmdList(c *cli.Context) {
	var firewallProfiles []FirewallProfile

	webservice, err := webservice.NewWebService()
	utils.CheckError(err)

	data, err := webservice.Get("/v1/network/firewall_profiles")
	utils.CheckError(err)

	err = json.Unmarshal(data, &firewallProfiles)
	utils.CheckError(err)

	w := tabwriter.NewWriter(os.Stdout, 15, 1, 3, ' ', 0)
	fmt.Fprintln(w, "ID\tNAME\tDESCRIPTION\tDEFAULT\r")

	for _, firewallProfile := range firewallProfiles {
		fmt.Fprintf(w, "%s\t%s\t%s\t%t\n", firewallProfile.Id, firewallProfile.Name, firewallProfile.Description, firewallProfile.Default)
	}

	w.Flush()
}

func cmdShow(c *cli.Context) {
	utils.FlagsRequired(c, []string{"id"})
	var firewallProfile FirewallProfile

	webservice, err := webservice.NewWebService()
	utils.CheckError(err)

	data, err := webservice.Get(fmt.Sprintf("/v1/network/firewall_profiles/%s", c.String("id")))
	utils.CheckError(err)

	err = json.Unmarshal(data, &firewallProfile)
	utils.CheckError(err)

	w := tabwriter.NewWriter(os.Stdout, 15, 1, 3, ' ', 0)
	fmt.Fprintln(w, "ID\tNAME\tDESCRIPTION\tDEFAULT\r")
	fmt.Fprintf(w, "%s\t%s\t%s\t%t\n", firewallProfile.Id, firewallProfile.Name, firewallProfile.Description, firewallProfile.Default)
	fmt.Fprintln(w, "RULES:\r")
	fmt.Fprintln(w, "\tPROTOCOL\tMIN PORT\tMAX PORT\tCIDR IP\r")
	for _, r := range firewallProfile.Rules {
		fmt.Fprintf(w, "\t%s\t%d\t%d\t%s\n", r.Protocol, r.MinPort, r.MaxPort, r.CidrIp)
	}
	w.Flush()
}

func cmdCreate(c *cli.Context) {
	utils.FlagsRequired(c, []string{"name", "description"})
	webservice, err := webservice.NewWebService()
	utils.CheckError(err)

	v := make(map[string]string)

	v["name"] = c.String("name")
	v["description"] = c.String("description")
	if c.IsSet("rules") {
		v["rules"] = c.String("rules")
	}

	jsonBytes, err := json.Marshal(v)
	utils.CheckError(err)
	err, res, _ := webservice.Post("/v1/network/firewall_profiles", jsonBytes)
	if res == nil {
		log.Fatal(err)
	}
	utils.CheckError(err)

	var firewallProfile FirewallProfile

	err = json.Unmarshal(res, &firewallProfile)
	utils.CheckError(err)

	w := tabwriter.NewWriter(os.Stdout, 15, 1, 3, ' ', 0)
	fmt.Fprintln(w, "ID\tNAME\tDESCRIPTION\tDEFAULT\r")
	fmt.Fprintf(w, "%s\t%s\t%s\t%t\n", firewallProfile.Id, firewallProfile.Name, firewallProfile.Description, firewallProfile.Default)
	fmt.Fprintln(w, "RULES:\r")
	fmt.Fprintln(w, "\tPROTOCOL\tMIN PORT\tMAX PORT\tCIDR IP\r")
	for _, r := range firewallProfile.Rules {
		fmt.Fprintf(w, "\t%s\t%d\t%d\t%s\n", r.Protocol, r.MinPort, r.MaxPort, r.CidrIp)
	}
	w.Flush()

}

func cmdUpdate(c *cli.Context) {
	utils.FlagsRequired(c, []string{"id"})
	webservice, err := webservice.NewWebService()
	utils.CheckError(err)

	v := make(map[string]string)

	if c.IsSet("name") {
		v["name"] = c.String("name")
	}
	if c.IsSet("description") {
		v["description"] = c.String("description")
	}
	if c.IsSet("rules") {
		v["rules"] = c.String("rules")
	}

	jsonBytes, err := json.Marshal(v)
	utils.CheckError(err)
	err, res, _ := webservice.Put(fmt.Sprintf("/v1/network/firewall_profiles/%s", c.String("id")), jsonBytes)

	utils.CheckError(err)
	fmt.Println(res)

	var firewallProfile FirewallProfile

	err = json.Unmarshal(res, &firewallProfile)
	utils.CheckError(err)

	w := tabwriter.NewWriter(os.Stdout, 15, 1, 3, ' ', 0)
	fmt.Fprintln(w, "ID\tNAME\tDESCRIPTION\tDEFAULT\r")
	fmt.Fprintf(w, "%s\t%s\t%s\t%t\n", firewallProfile.Id, firewallProfile.Name, firewallProfile.Description, firewallProfile.Default)
	fmt.Fprintln(w, "RULES:\r")
	fmt.Fprintln(w, "\tPROTOCOL\tMIN PORT\tMAX PORT\tCIDR IP\r")
	for _, r := range firewallProfile.Rules {
		fmt.Fprintf(w, "\t%s\t%d\t%d\t%s\n", r.Protocol, r.MinPort, r.MaxPort, r.CidrIp)
	}
	w.Flush()

}

func cmdDelete(c *cli.Context) {
	utils.FlagsRequired(c, []string{"id"})

	webservice, err := webservice.NewWebService()
	utils.CheckError(err)

	err, mesg, res := webservice.Delete(fmt.Sprintf("/v1/network/firewall_profiles/%s", c.String("id")))
	utils.CheckError(err)
	utils.CheckReturnCode(res, mesg)

	fmt.Println(res)
}

func SubCommands() []cli.Command {
	return []cli.Command{
		{
			Name:   "list",
			Usage:  "Lists all existing firewall profiles",
			Action: cmdList,
		},
		{
			Name:   "show",
			Usage:  "Shows information about the firewall profile identified by the given id.",
			Action: cmdShow,
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "id",
					Usage: "Firewall profile Id",
				},
			},
		},
		{
			Name:   "create",
			Usage:  "Creates a a firewall profile with the given parameters.",
			Action: cmdCreate,
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "name",
					Usage: "Logical name of the firewall profile",
				},
				cli.StringFlag{
					Name:  "description",
					Usage: "Description of the firewall profile",
				},
				cli.StringFlag{
					Name:  "rules",
					Usage: "Set of rules of the firewall profile",
				},
			},
		},
		{
			Name:   "update",
			Usage:  "Updates the firewall profile identified by the given id with the given parameters.",
			Action: cmdUpdate,
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "id",
					Usage: "Firewall profile Id",
				},
				cli.StringFlag{
					Name:  "name",
					Usage: "Logical name of the firewall profile",
				},
				cli.StringFlag{
					Name:  "description",
					Usage: "Description of the firewall profile",
				},
				cli.StringFlag{
					Name:  "rules",
					Usage: "Set of rules of the firewall profile",
				},
			},
		},
		{
			Name:   "delete",
			Usage:  "Destroy a firewall profile",
			Action: cmdDelete,
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "id",
					Usage: "Firewall profile Id",
				},
			},
		},
	}
}
<|endoftext|>


<commit_before>package router

import (
	"bytes"
	"fmt"
	"log"
	"sort"
	"strings"

	"github.com/hashicorp/otto/ui"
)

// Router is a helper to route subcommands to specific callbacks.
//
// Actions are available on a lot of commands such as dev, deploy, etc. and
// this can be used to add custom actions.
type Router struct {
	Actions map[string]Action
}

// Action defines an action that is available for the router.
type Action interface {
	// Execute is the callback that'll be called to execute this action.
	Execute(ctx Context) error

	// Help is the help text for this action.
	Help() string

	// Synopsis is the text that will be shown as a short sentence
	// about what this action does.
	Synopsis() string
}

// Context is passed to the router and used to select which action is executed.
// This same value will also be passed down into the selected Action's Execute
// function. This is so that actions typecast the context to access
// implementation-specific data.
type Context interface {
	RouteName() string
	RouteArgs() []string
	UI() ui.Ui
}

// Route will route the given Context to the proper Action.
func (r *Router) Route(ctx Context) error {
	if _, ok := r.Actions["help"]; !ok {
		r.Actions["help"] = &SimpleAction{
			ExecuteFunc:  r.help,
			SynopsisText: "This help",
		}
	}

	action, ok := r.Actions[ctx.RouteName()]
	if !ok {
		log.Printf("[DEBUG] No action found: %q; executing help.", ctx.RouteName())
		return r.help(ctx)
	}

	return action.Execute(ctx)
}

func (r *Router) help(ctx Context) error {
	badAction := false
	var message bytes.Buffer

	// If this is the help command we've been given a specific subcommand
	// to look up, then do that.
	if ctx.RouteName() == "help" && len(ctx.RouteArgs()) > 0 {
		if a, ok := r.Actions[ctx.RouteArgs()[0]]; ok {
			ctx.UI().Raw(a.Help())
			return nil
		}
		message.WriteString(fmt.Sprintf(
			"Unsupported action: %s\n\n", ctx.RouteArgs()[0]))
		badAction = true
	}

	// Normal help output...
	if ctx.RouteName() != "" && ctx.RouteName() != "help" {
		message.WriteString(fmt.Sprintf(
			"Unsupported action: %s\n\n", ctx.RouteName()))
		badAction = true
	}

	message.WriteString(fmt.Sprintf(
		"The available subcommands are shown below along with a\n" +
			"brief description of what that command does. For more complete\n" +
			"help, call the `help` subcommand with the name of the specific\n" +
			"subcommand you want help for, such as `help foo`.\n\n" +
			"The subcommand '(default)' is the blank subcommand. For this\n" +
			"you don't specify any additional text.\n\n"))

	longestName := len("(default)")
	actionLines := make([]string, 0, len(r.Actions))

	for n, _ := range r.Actions {
		if len(n) > longestName {
			longestName = len(n)
		}
	}
	fmtStr := fmt.Sprintf("    %%%ds\t%%s\n", longestName)

	for n, a := range r.Actions {
		if n == "" {
			n = "(default)"
		}

		actionLines = append(actionLines, fmt.Sprintf(fmtStr, n, a.Synopsis()))
	}

	sort.Strings(actionLines)
	message.WriteString(strings.Join(actionLines, ""))

	if !badAction {
		ctx.UI().Raw(message.String())
		return nil
	}

	return fmt.Errorf(message.String())
}

type SimpleAction struct {
	ExecuteFunc  func(Context) error
	HelpText     string
	SynopsisText string
}

func (sa *SimpleAction) Execute(ctx Context) error {
	return sa.ExecuteFunc(ctx)
}

func (sa *SimpleAction) Help() string {
	return sa.HelpText
}

func (sa *SimpleAction) Synopsis() string {
	return sa.SynopsisText
}
<commit_msg>helper/router: add newline to the end of help [GH-295]<commit_after>package router

import (
	"bytes"
	"fmt"
	"log"
	"sort"
	"strings"

	"github.com/hashicorp/otto/ui"
)

// Router is a helper to route subcommands to specific callbacks.
//
// Actions are available on a lot of commands such as dev, deploy, etc. and
// this can be used to add custom actions.
type Router struct {
	Actions map[string]Action
}

// Action defines an action that is available for the router.
type Action interface {
	// Execute is the callback that'll be called to execute this action.
	Execute(ctx Context) error

	// Help is the help text for this action.
	Help() string

	// Synopsis is the text that will be shown as a short sentence
	// about what this action does.
	Synopsis() string
}

// Context is passed to the router and used to select which action is executed.
// This same value will also be passed down into the selected Action's Execute
// function. This is so that actions typecast the context to access
// implementation-specific data.
type Context interface {
	RouteName() string
	RouteArgs() []string
	UI() ui.Ui
}

// Route will route the given Context to the proper Action.
func (r *Router) Route(ctx Context) error {
	if _, ok := r.Actions["help"]; !ok {
		r.Actions["help"] = &SimpleAction{
			ExecuteFunc:  r.help,
			SynopsisText: "This help",
		}
	}

	action, ok := r.Actions[ctx.RouteName()]
	if !ok {
		log.Printf("[DEBUG] No action found: %q; executing help.", ctx.RouteName())
		return r.help(ctx)
	}

	return action.Execute(ctx)
}

func (r *Router) help(ctx Context) error {
	badAction := false
	var message bytes.Buffer

	// If this is the help command we've been given a specific subcommand
	// to look up, then do that.
	if ctx.RouteName() == "help" && len(ctx.RouteArgs()) > 0 {
		if a, ok := r.Actions[ctx.RouteArgs()[0]]; ok {
			ctx.UI().Raw(a.Help() + "\n")
			return nil
		}
		message.WriteString(fmt.Sprintf(
			"Unsupported action: %s\n\n", ctx.RouteArgs()[0]))
		badAction = true
	}

	// Normal help output...
	if ctx.RouteName() != "" && ctx.RouteName() != "help" {
		message.WriteString(fmt.Sprintf(
			"Unsupported action: %s\n\n", ctx.RouteName()))
		badAction = true
	}

	message.WriteString(fmt.Sprintf(
		"The available subcommands are shown below along with a\n" +
			"brief description of what that command does. For more complete\n" +
			"help, call the `help` subcommand with the name of the specific\n" +
			"subcommand you want help for, such as `help foo`.\n\n" +
			"The subcommand '(default)' is the blank subcommand. For this\n" +
			"you don't specify any additional text.\n\n"))

	longestName := len("(default)")
	actionLines := make([]string, 0, len(r.Actions))

	for n, _ := range r.Actions {
		if len(n) > longestName {
			longestName = len(n)
		}
	}
	fmtStr := fmt.Sprintf("    %%%ds\t%%s\n", longestName)

	for n, a := range r.Actions {
		if n == "" {
			n = "(default)"
		}

		actionLines = append(actionLines, fmt.Sprintf(fmtStr, n, a.Synopsis()))
	}

	sort.Strings(actionLines)
	message.WriteString(strings.Join(actionLines, ""))

	if !badAction {
		ctx.UI().Raw(message.String())
		return nil
	}

	return fmt.Errorf(message.String())
}

type SimpleAction struct {
	ExecuteFunc  func(Context) error
	HelpText     string
	SynopsisText string
}

func (sa *SimpleAction) Execute(ctx Context) error {
	return sa.ExecuteFunc(ctx)
}

func (sa *SimpleAction) Help() string {
	return sa.HelpText
}

func (sa *SimpleAction) Synopsis() string {
	return sa.SynopsisText
}
<|endoftext|>


<commit_before>package main

import (
  "config"
  "flag"
  "fmt"
  "github.com/weidewang/go-strftime"
  "log"
  "os"
  "path/filepath"
  "strings"
  "time"
)

type RuntimeEnv struct {
  FullPath  string
  Home      string
  AccessLog *log.Logger
  ErrorLog  *log.Logger
}

var g_config config.ConfigFile
var g_env RuntimeEnv

func file_exists(name string) bool {

  if _, err := os.Stat(name); err != nil {
    if os.IsNotExist(err) {
      return false
    }
  }
  return true

}

func show_usage() {

  fmt.Fprintf(os.Stderr,
    "Usage: %s \n",
    os.Args[0])
  flag.PrintDefaults()

}

func find_config_file() (cf string, err error) {

  try_files := []string{
    filepath.Join(g_env.Home, "etc", "config.json"),
  }

  for _, cf = range try_files {
    if file_exists(cf) {
      log.Printf("INFO: Check config file %s", cf)
      return
    }
  }

  err = fmt.Errorf("ERROR: Can't find any config file.")
  return
}

func init() {

  var (
    fullpath string
    err      error
  )

  if fullpath, err = filepath.Abs(os.Args[0]); err != nil {
    log.Fatal(err)
  }

  g_env.FullPath = fullpath

  if strings.HasSuffix(filepath.Dir(fullpath), "bin") {
    fp, _ := filepath.Abs(filepath.Join(filepath.Dir(fullpath), ".."))
    g_env.Home = fp
  } else {
    g_env.Home = filepath.Dir(fullpath)
  }

}

func init_dir(dir string) {

  if !file_exists(dir) {
    os.MkdirAll(dir, 0755)
  }

}

func init_access_log() {

  log_path := g_config.AccessLogFile

  if len(log_path) != 0 && filepath.IsAbs(log_path) {
    g_env.AccessLog = file_logger(log_path)
    return
  }

  if len(log_path) == 0 {
    if fap, err := filepath.Abs(filepath.Join(g_env.Home, "log", "access.log")); err == nil {
      g_env.AccessLog = file_logger(fap)
    }
    return
  }

  if fap, err := filepath.Abs(filepath.Join(g_env.Home, g_config.AccessLogFile)); err == nil {
    g_env.AccessLog = file_logger(fap)
    return
  }

}

func init_error_log() {
  log_path := g_config.ErrorLogFile
  if len(log_path) != 0 && filepath.IsAbs(log_path) {
    g_env.ErrorLog = file_logger(log_path)
    return
  }

  if len(log_path) == 0 {
    if fap, err := filepath.Abs(filepath.Join(g_env.Home, "log", "access.log")); err == nil {
      g_env.ErrorLog = file_logger(fap)
    }
    return
  }

  if fap, err := filepath.Abs(filepath.Join(g_env.Home, log_path)); err == nil {
    g_env.ErrorLog = file_logger(fap)
    return
  }

}

func file_logger(log_path string)(logger *log.Logger) {

  if !filepath.IsAbs(log_path) {
    return
  }

  init_dir(filepath.Dir(log_path))

  if out, err := os.OpenFile(log_path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, os.ModeAppend|0666); err == nil {
    logger = log.New(out, "", 0)
    now := time.Now()
    logger.Printf("#start at: %s\n", strftime.Strftime(&now, "%Y-%m-%d %H:%M:%S"))
  } else {
    log.Fatal(err)
  }
  return
}

func main() {
  var (
    err         error
    config_file string
    host        string
    port        int
  )

  flag.Usage = show_usage
  flag.StringVar(&config_file, "f", "", "config file path")
  flag.IntVar(&port, "p", 9000, "listen port,default 9000")
  flag.StringVar(&host, "h", "", "listen ip,default 127.0.0.1")
  flag.Parse()

  if len(config_file) == 0 {
    config_file, err = find_config_file()
    if err != nil {
      log.Fatal(err)
    }
  }

  if !file_exists(config_file) {
    log.Fatal("ERROR: Can't find any config file.")
    os.Exit(1)
  }

  log.Printf(`INFO: Using config file "%s"`, config_file)
  g_config = config.LoadConfigFile(config_file)

  if g_config.Listen.Port != port {
    g_config.Listen.Port = port
  }

  if len(host) != 0 {
    g_config.Listen.Host = host
  }

  init_access_log()
  init_error_log()

  Run()
}
<commit_msg>修改端口获取方法<commit_after>package main

import (
  "config"
  "flag"
  "fmt"
  "github.com/weidewang/go-strftime"
  "log"
  "os"
  "path/filepath"
  "strings"
  "time"
)

type RuntimeEnv struct {
  FullPath  string
  Home      string
  AccessLog *log.Logger
  ErrorLog  *log.Logger
}

var g_config config.ConfigFile
var g_env RuntimeEnv

func file_exists(name string) bool {

  if _, err := os.Stat(name); err != nil {
    if os.IsNotExist(err) {
      return false
    }
  }
  return true

}

func show_usage() {

  fmt.Fprintf(os.Stderr,
    "Usage: %s \n",
    os.Args[0])
  flag.PrintDefaults()

}

func find_config_file() (cf string, err error) {

  try_files := []string{
    filepath.Join(g_env.Home, "etc", "config.json"),
  }

  for _, cf = range try_files {
    if file_exists(cf) {
      log.Printf("INFO: Check config file %s", cf)
      return
    }
  }

  err = fmt.Errorf("ERROR: Can't find any config file.")
  return
}

func init() {

  var (
    fullpath string
    err      error
  )

  if fullpath, err = filepath.Abs(os.Args[0]); err != nil {
    log.Fatal(err)
  }

  g_env.FullPath = fullpath

  if strings.HasSuffix(filepath.Dir(fullpath), "bin") {
    fp, _ := filepath.Abs(filepath.Join(filepath.Dir(fullpath), ".."))
    g_env.Home = fp
  } else {
    g_env.Home = filepath.Dir(fullpath)
  }

}

func init_dir(dir string) {

  if !file_exists(dir) {
    os.MkdirAll(dir, 0755)
  }

}

func init_access_log() {

  log_path := g_config.AccessLogFile

  if len(log_path) != 0 && filepath.IsAbs(log_path) {
    g_env.AccessLog = file_logger(log_path)
    return
  }

  if len(log_path) == 0 {
    if fap, err := filepath.Abs(filepath.Join(g_env.Home, "log", "access.log")); err == nil {
      g_env.AccessLog = file_logger(fap)
    }
    return
  }

  if fap, err := filepath.Abs(filepath.Join(g_env.Home, g_config.AccessLogFile)); err == nil {
    g_env.AccessLog = file_logger(fap)
    return
  }

}

func init_error_log() {
  log_path := g_config.ErrorLogFile
  if len(log_path) != 0 && filepath.IsAbs(log_path) {
    g_env.ErrorLog = file_logger(log_path)
    return
  }

  if len(log_path) == 0 {
    if fap, err := filepath.Abs(filepath.Join(g_env.Home, "log", "access.log")); err == nil {
      g_env.ErrorLog = file_logger(fap)
    }
    return
  }

  if fap, err := filepath.Abs(filepath.Join(g_env.Home, log_path)); err == nil {
    g_env.ErrorLog = file_logger(fap)
    return
  }

}

func file_logger(log_path string)(logger *log.Logger) {

  if !filepath.IsAbs(log_path) {
    return
  }

  init_dir(filepath.Dir(log_path))

  if out, err := os.OpenFile(log_path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, os.ModeAppend|0666); err == nil {
    logger = log.New(out, "", 0)
    now := time.Now()
    logger.Printf("#start at: %s\n", strftime.Strftime(&now, "%Y-%m-%d %H:%M:%S"))
  } else {
    log.Fatal(err)
  }
  return
}

func main() {
  var (
    err         error
    config_file string
    host        string
    port        int
  )

  flag.Usage = show_usage
  flag.StringVar(&config_file, "f", "", "config file path")
  flag.IntVar(&port, "p", 9000, "listen port,default 9000")
  flag.StringVar(&host, "h", "", "listen ip,default 127.0.0.1")
  flag.Parse()

  if len(config_file) == 0 {
    config_file, err = find_config_file()
    if err != nil {
      log.Fatal(err)
    }
  }

  if !file_exists(config_file) {
    log.Fatal("ERROR: Can't find any config file.")
    os.Exit(1)
  }

  log.Printf(`INFO: Using config file "%s"`, config_file)
  g_config = config.LoadConfigFile(config_file)

  if g_config.Listen.Port <= 0 && port > 0  {
    g_config.Listen.Port = port
  }

  if len(host) != 0 {
    g_config.Listen.Host = host
  }

  init_access_log()
  init_error_log()

  Run()
}
<|endoftext|>


<commit_before>// +build integration,!no-etcd

package integration

import (
	"testing"

	kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
	watchapi "github.com/GoogleCloudPlatform/kubernetes/pkg/watch"

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

func init() {
	requireEtcd()
}

func TestSimpleImageChangeBuildTrigger(t *testing.T) {
	deleteAllEtcdKeys()
	openshift := NewTestOpenshift(t)
	defer openshift.Close()

	imageRepo := &imageapi.ImageRepository{
		ObjectMeta:            kapi.ObjectMeta{Name: "test-image-trigger-repo"},
		DockerImageRepository: "registry:8080/openshift/test-image-trigger",
		Tags: map[string]string{
			"latest": "ref-1",
		},
	}

	config := imageChangeBuildConfig()

	watch, err := openshift.Client.Builds(testNamespace).Watch(labels.Everything(), labels.Everything(), "0")
	if err != nil {
		t.Fatalf("Couldn't subscribe to Builds %v", err)
	}
	defer watch.Stop()

	if imageRepo, err = openshift.Client.ImageRepositories(testNamespace).Create(imageRepo); err != nil {
		t.Fatalf("Couldn't create ImageRepository: %v", err)
	}

	created, err := openshift.Client.BuildConfigs(testNamespace).Create(config)
	if err != nil {
		t.Fatalf("Couldn't create BuildConfig: %v", err)
	}

	watch2, err := openshift.Client.BuildConfigs(testNamespace).Watch(labels.Everything(), labels.Everything(), created.ResourceVersion)
	if err != nil {
		t.Fatalf("Couldn't subscribe to BuildConfigs %v", err)
	}
	defer watch2.Stop()

	imageRepo.Tags["latest"] = "ref-2"

	if _, err = openshift.Client.ImageRepositories(testNamespace).Update(imageRepo); err != nil {
		t.Fatalf("Error updating imageRepo: %v", err)
	}

	event := <-watch.ResultChan()
	if e, a := watchapi.Added, event.Type; e != a {
		t.Fatalf("expected watch event type %s, got %s", e, a)
	}
	newBuild := event.Object.(*buildapi.Build)

	if newBuild.Parameters.Strategy.DockerStrategy.Image != "registry:8080/openshift/test-image-trigger:ref-2" {
		t.Fatalf("Expected build with base image %s, got %s", "registry:8080/openshift/test-image-trigger:ref-2", newBuild.Parameters.Strategy.DockerStrategy.Image)
	}

	event = <-watch.ResultChan()
	if e, a := watchapi.Modified, event.Type; e != a {
		t.Fatalf("expected watch event type %s, got %s", e, a)
	}
	newBuild = event.Object.(*buildapi.Build)
	if newBuild.Parameters.Output.DockerImageReference != "registry:8080/openshift/test-image-trigger:outputtag" {
		t.Fatalf("Expected build with output image %s, got %s", "registry:8080/openshift/test-image-trigger:outputtag", newBuild.Parameters.Output.DockerImageReference)
	}
	if newBuild.Labels["testlabel"] != "testvalue" {
		t.Fatalf("Expected build with label %s=%s from build config got %s=%s", "testlabel", "testvalue", "testlabel", newBuild.Labels["testlabel"])
	}

	event = <-watch2.ResultChan()
	event = <-watch2.ResultChan()

	updatedConfig, err := openshift.Client.BuildConfigs(testNamespace).Get(config.Name)
	if err != nil {
		t.Fatalf("Couldn't get BuildConfig: %v", err)
	}
	if updatedConfig.Triggers[0].ImageChange.LastTriggeredImageID != "ref-2" {
		t.Errorf("Expected imageID ref-2, got %s", updatedConfig.Triggers[0].ImageChange.LastTriggeredImageID)
	}
}

func imageChangeBuildConfig() *buildapi.BuildConfig {
	buildcfg := &buildapi.BuildConfig{
		ObjectMeta: kapi.ObjectMeta{
			Name:   "test-build-cfg",
			Labels: map[string]string{"testlabel": "testvalue"},
		},
		Parameters: buildapi.BuildParameters{
			Source: buildapi.BuildSource{
				Type: "Git",
				Git: &buildapi.GitBuildSource{
					URI: "git://github.com/openshift/ruby-hello-world.git",
				},
				ContextDir: "contextimage",
			},
			Strategy: buildapi.BuildStrategy{
				Type: buildapi.DockerBuildStrategyType,
				DockerStrategy: &buildapi.DockerBuildStrategy{
					Image: "registry:8080/openshift/test-image-trigger",
				},
			},
			Output: buildapi.BuildOutput{
				To: &kapi.ObjectReference{
					Name: "test-image-trigger-repo",
				},
				Tag: "outputtag",
			},
		},
		Triggers: []buildapi.BuildTriggerPolicy{
			{
				Type: buildapi.ImageChangeBuildTriggerType,
				ImageChange: &buildapi.ImageChangeTrigger{
					Image: "registry:8080/openshift/test-image-trigger",
					From: kapi.ObjectReference{
						Name: "test-image-trigger-repo",
					},
					Tag: "latest",
				},
			},
		},
	}
	return buildcfg
}
<commit_msg>create the buildconfig before creating the first imagerepo<commit_after>// +build integration,!no-etcd

package integration

import (
	"testing"

	kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
	watchapi "github.com/GoogleCloudPlatform/kubernetes/pkg/watch"

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

func init() {
	requireEtcd()
}

func TestSimpleImageChangeBuildTrigger(t *testing.T) {
	deleteAllEtcdKeys()
	openshift := NewTestOpenshift(t)
	defer openshift.Close()

	imageRepo := &imageapi.ImageRepository{
		ObjectMeta:            kapi.ObjectMeta{Name: "test-image-trigger-repo"},
		DockerImageRepository: "registry:8080/openshift/test-image-trigger",
		Tags: map[string]string{
			"latest": "ref-1",
		},
	}

	config := imageChangeBuildConfig()

	watch, err := openshift.Client.Builds(testNamespace).Watch(labels.Everything(), labels.Everything(), "0")
	if err != nil {
		t.Fatalf("Couldn't subscribe to Builds %v", err)
	}
	defer watch.Stop()

	created, err := openshift.Client.BuildConfigs(testNamespace).Create(config)
	if err != nil {
		t.Fatalf("Couldn't create BuildConfig: %v", err)
	}
	watch2, err := openshift.Client.BuildConfigs(testNamespace).Watch(labels.Everything(), labels.Everything(), created.ResourceVersion)
	if err != nil {
		t.Fatalf("Couldn't subscribe to BuildConfigs %v", err)
	}
	defer watch2.Stop()

	imageRepo, err = openshift.Client.ImageRepositories(testNamespace).Create(imageRepo)
	if err != nil {
		t.Fatalf("Couldn't create ImageRepository: %v", err)
	}

	// initial build event from the creation of the imagerepo with tag ref-1
	event := <-watch.ResultChan()
	if e, a := watchapi.Added, event.Type; e != a {
		t.Fatalf("expected watch event type %s, got %s", e, a)
	}
	newBuild := event.Object.(*buildapi.Build)
	if newBuild.Parameters.Strategy.DockerStrategy.Image != "registry:8080/openshift/test-image-trigger:ref-1" {
		i, _ := openshift.Client.ImageRepositories(testNamespace).Get(imageRepo.Name)
		bc, _ := openshift.Client.BuildConfigs(testNamespace).Get(config.Name)
		t.Fatalf("Expected build with base image %s, got %s\n, imagerepo is %v\trigger is %s\n", "registry:8080/openshift/test-image-trigger:ref-1", newBuild.Parameters.Strategy.DockerStrategy.Image, i, bc.Triggers[0].ImageChange)
	}
	event = <-watch.ResultChan()
	if e, a := watchapi.Modified, event.Type; e != a {
		t.Fatalf("expected watch event type %s, got %s", e, a)
	}
	newBuild = event.Object.(*buildapi.Build)
	if newBuild.Parameters.Output.DockerImageReference != "registry:8080/openshift/test-image-trigger:outputtag" {
		t.Fatalf("Expected build with output image %s, got %s", "registry:8080/openshift/test-image-trigger:outputtag", newBuild.Parameters.Output.DockerImageReference)
	}
	if newBuild.Labels["testlabel"] != "testvalue" {
		t.Fatalf("Expected build with label %s=%s from build config got %s=%s", "testlabel", "testvalue", "testlabel", newBuild.Labels["testlabel"])
	}
	event = <-watch2.ResultChan()
	updatedConfig, err := openshift.Client.BuildConfigs(testNamespace).Get(config.Name)
	if err != nil {
		t.Fatalf("Couldn't get BuildConfig: %v", err)
	}
	if updatedConfig.Triggers[0].ImageChange.LastTriggeredImageID != "ref-1" {
		t.Errorf("Expected imageID ref-1, got %s", updatedConfig.Triggers[0].ImageChange.LastTriggeredImageID)
	}

	// update the image tag to ref-2 in the imagerepo so we get another build event using that tag.
	imageRepo.Tags["latest"] = "ref-2"
	if _, err = openshift.Client.ImageRepositories(testNamespace).Update(imageRepo); err != nil {
		t.Fatalf("Error updating imageRepo: %v", err)
	}

	event = <-watch.ResultChan()
	if e, a := watchapi.Added, event.Type; e != a {
		t.Fatalf("expected watch event type %s, got %s", e, a)
	}
	newBuild = event.Object.(*buildapi.Build)
	if newBuild.Parameters.Strategy.DockerStrategy.Image != "registry:8080/openshift/test-image-trigger:ref-2" {
		i, _ := openshift.Client.ImageRepositories(testNamespace).Get(imageRepo.Name)
		bc, _ := openshift.Client.BuildConfigs(testNamespace).Get(config.Name)
		t.Fatalf("Expected build with base image %s, got %s\n, imagerepo is %v\trigger is %s\n", "registry:8080/openshift/test-image-trigger:ref-2", newBuild.Parameters.Strategy.DockerStrategy.Image, i, bc.Triggers[0].ImageChange)
	}
	event = <-watch.ResultChan()
	if e, a := watchapi.Modified, event.Type; e != a {
		t.Fatalf("expected watch event type %s, got %s", e, a)
	}
	newBuild = event.Object.(*buildapi.Build)
	if newBuild.Parameters.Output.DockerImageReference != "registry:8080/openshift/test-image-trigger:outputtag" {
		t.Fatalf("Expected build with output image %s, got %s", "registry:8080/openshift/test-image-trigger:outputtag", newBuild.Parameters.Output.DockerImageReference)
	}
	if newBuild.Labels["testlabel"] != "testvalue" {
		t.Fatalf("Expected build with label %s=%s from build config got %s=%s", "testlabel", "testvalue", "testlabel", newBuild.Labels["testlabel"])
	}

	event = <-watch2.ResultChan()
	updatedConfig, err = openshift.Client.BuildConfigs(testNamespace).Get(config.Name)
	if err != nil {
		t.Fatalf("Couldn't get BuildConfig: %v", err)
	}
	if updatedConfig.Triggers[0].ImageChange.LastTriggeredImageID != "ref-2" {
		t.Errorf("Expected imageID ref-2, got %s", updatedConfig.Triggers[0].ImageChange.LastTriggeredImageID)
	}
}

func imageChangeBuildConfig() *buildapi.BuildConfig {
	buildcfg := &buildapi.BuildConfig{
		ObjectMeta: kapi.ObjectMeta{
			Name:   "test-build-cfg",
			Labels: map[string]string{"testlabel": "testvalue"},
		},
		Parameters: buildapi.BuildParameters{
			Source: buildapi.BuildSource{
				Type: "Git",
				Git: &buildapi.GitBuildSource{
					URI: "git://github.com/openshift/ruby-hello-world.git",
				},
				ContextDir: "contextimage",
			},
			Strategy: buildapi.BuildStrategy{
				Type: buildapi.DockerBuildStrategyType,
				DockerStrategy: &buildapi.DockerBuildStrategy{
					Image: "registry:8080/openshift/test-image-trigger",
				},
			},
			Output: buildapi.BuildOutput{
				To: &kapi.ObjectReference{
					Name: "test-image-trigger-repo",
				},
				Tag: "outputtag",
			},
		},
		Triggers: []buildapi.BuildTriggerPolicy{
			{
				Type: buildapi.ImageChangeBuildTriggerType,
				ImageChange: &buildapi.ImageChangeTrigger{
					Image: "registry:8080/openshift/test-image-trigger",
					From: kapi.ObjectReference{
						Name: "test-image-trigger-repo",
					},
					Tag: "latest",
				},
			},
		},
	}
	return buildcfg
}
<|endoftext|>


<commit_before>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 logcfg

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"sort"
	"strings"

	log "github.com/sirupsen/logrus"
	"github.com/spf13/cast"

	"mynewt.apache.org/newt/newt/newtutil"
	"mynewt.apache.org/newt/newt/pkg"
	"mynewt.apache.org/newt/newt/syscfg"
	"mynewt.apache.org/newt/newt/val"
	"mynewt.apache.org/newt/util"
)

const HEADER_PATH = "logcfg/logcfg.h"

type Log struct {
	// Log name; equal to the name of the YAML map that defines the log.
	Name string

	// The package that defines the log.
	Source *pkg.LocalPackage

	// The log's numeric module ID.
	Module val.ValSetting

	// The level assigned to this log.
	Level val.ValSetting
}

// Map of: [log-name] => log
type LogMap map[string]Log

// The log configuration of the target.
type LCfg struct {
	// [log-name] => log
	Logs LogMap

	// Strings describing errors encountered while parsing the log config.
	InvalidSettings []string

	// Contains sets of logs with conflicting module IDs.
	//     [module-ID] => <slice-of-logs-with-module-id>
	ModuleConflicts map[int][]Log
}

// Maps numeric log levels to their string representations.  Used when
// generating the C log macros.
var logLevelNames = []string{
	0: "DEBUG",
	1: "INFO",
	2: "WARN",
	3: "ERROR",
	4: "CRITICAL",
}

func LogLevelString(level int) string {
	if level < 0 || level >= len(logLevelNames) {
		return "???"
	}

	return logLevelNames[level]
}

func NewLCfg() LCfg {
	return LCfg{
		Logs:            map[string]Log{},
		ModuleConflicts: map[int][]Log{},
	}
}

// Parses a single log definition from a YAML map.  The `logMapItf` parameter
// should be a map with the following elements:
//     "module": <module-string>
//     "level": <level-string>
func parseOneLog(name string, lpkg *pkg.LocalPackage, logMapItf interface{},
	cfg *syscfg.Cfg) (Log, error) {

	cl := Log{
		Name:   name,
		Source: lpkg,
	}

	logMap := cast.ToStringMapString(logMapItf)
	if logMap == nil {
		return cl, util.FmtNewtError(
			"\"%s\" missing required field \"module\"", name)
	}

	modStr := logMap["module"]
	if modStr == "" {
		return cl, util.FmtNewtError(
			"\"%s\" missing required field \"module\"", name)
	}
	mod, err := val.ResolveValSetting(modStr, cfg)
	if err != nil {
		return cl, util.FmtNewtError(
			"\"%s\" contains invalid \"module\": %s",
			name, err.Error())
	}
	if _, err := mod.IntVal(); err != nil {
		return cl, util.FmtNewtError(
			"\"%s\" contains invalid \"module\": %s", name, err.Error())
	}

	levelStr := logMap["level"]
	if levelStr == "" {
		return cl, util.FmtNewtError(
			"\"%s\" missing required field \"level\"", name)
	}
	level, err := val.ResolveValSetting(levelStr, cfg)
	if err != nil {
		return cl, util.FmtNewtError(
			"\"%s\" contains invalid \"level\": %s",
			name, err.Error())
	}
	if _, err := level.IntVal(); err != nil {
		return cl, util.FmtNewtError(
			"\"%s\" contains invalid \"level\": %s", name, err.Error())
	}

	cl.Module = mod
	cl.Level = level

	return cl, nil
}

// Reads all the logs defined by the specified package.  The log definitions
// are read from the `syscfg.logs` map in the package's `syscfg.yml` file.
func (lcfg *LCfg) readOnePkg(lpkg *pkg.LocalPackage, cfg *syscfg.Cfg) {
	lsettings := cfg.AllSettingsForLpkg(lpkg)
	logMaps := lpkg.SyscfgY.GetValStringMap("syscfg.logs", lsettings)
	for name, logMapItf := range logMaps {
		cl, err := parseOneLog(name, lpkg, logMapItf, cfg)
		if err != nil {
			lcfg.InvalidSettings =
				append(lcfg.InvalidSettings, strings.TrimSpace(err.Error()))
		} else {
			lcfg.Logs[cl.Name] = cl
		}
	}
}

// Searches the log configuration for logs with identical module IDs.  The log
// configuration object is populated with the results.
func (lcfg *LCfg) detectModuleConflicts() {
	m := map[int][]Log{}

	for _, l := range lcfg.Logs {
		intMod, _ := l.Module.IntVal()
		m[intMod] = append(m[intMod], l)
	}

	for mod, logs := range m {
		if len(logs) > 1 {
			for _, l := range logs {
				lcfg.ModuleConflicts[mod] =
					append(lcfg.ModuleConflicts[mod], l)
			}
		}
	}
}

// Reads all log definitions for each of the specified packages.  The
// returned LCfg object is populated with the result of this operation.
func Read(lpkgs []*pkg.LocalPackage, cfg *syscfg.Cfg) LCfg {
	lcfg := NewLCfg()

	for _, lpkg := range lpkgs {
		lcfg.readOnePkg(lpkg, cfg)
	}

	lcfg.detectModuleConflicts()

	return lcfg
}

// If any errors were encountered while parsing log definitions, this function
// returns a string indicating the errors.  If no errors were encountered, ""
// is returned.
func (lcfg *LCfg) ErrorText() string {
	str := ""

	if len(lcfg.InvalidSettings) > 0 {
		str += "Invalid log definitions detected:"
		for _, e := range lcfg.InvalidSettings {
			str += "\n    " + e
		}
	}

	if len(lcfg.ModuleConflicts) > 0 {
		str += "Log module conflicts detected:\n"
		for mod, logs := range lcfg.ModuleConflicts {
			for _, l := range logs {
				str += fmt.Sprintf("    Module=%d Log=%s Package=%s\n",
					mod, l.Name, l.Source.FullName())
			}
		}

		str +=
			"\nResolve the problem by assigning unique module IDs to each log."
	}

	return str
}

// Retrieves a sorted slice of logs from the receiving log configuration.
func (lcfg *LCfg) sortedLogs() []Log {
	names := make([]string, 0, len(lcfg.Logs))

	for n, _ := range lcfg.Logs {
		names = append(names, n)
	}
	sort.Strings(names)

	logs := make([]Log, 0, len(names))
	for _, n := range names {
		logs = append(logs, lcfg.Logs[n])
	}

	return logs
}

// Writes a no-op stub log C macro definition.
func writeLogStub(logName string, levelStr string, w io.Writer) {
	fmt.Fprintf(w, "#define %s_%s(...) IGNORE(__VA_ARGS__)\n",
		logName, levelStr)
}

// Writes a log C macro definition.
func writeLogMacro(logName string, module int, levelStr string, w io.Writer) {
	fmt.Fprintf(w,
		"#define %s_%s(...) MODLOG_%s(%d, __VA_ARGS__)\n",
		logName, levelStr, levelStr, module)
}

// Write log C macro definitions for each log in the log configuration.
func (lcfg *LCfg) writeLogMacros(w io.Writer) {
	logs := lcfg.sortedLogs()
	for _, l := range logs {
		fmt.Fprintf(w, "\n")

		levelInt, _ := util.AtoiNoOct(l.Level.Value)
		for i, levelStr := range logLevelNames {
			if i < levelInt {
				writeLogStub(l.Name, levelStr, w)
			} else {
				modInt, _ := l.Module.IntVal()
				writeLogMacro(l.Name, modInt, levelStr, w)
			}
		}
	}
}

// Writes a logcfg header file to the specified writer.
func (lcfg *LCfg) write(w io.Writer) {
	fmt.Fprintf(w, newtutil.GeneratedPreamble())

	fmt.Fprintf(w, "#ifndef H_MYNEWT_LOGCFG_\n")
	fmt.Fprintf(w, "#define H_MYNEWT_LOGCFG_\n\n")

	if len(lcfg.Logs) > 0 {
		fmt.Fprintf(w, "#include \"modlog/modlog.h\"\n")
		fmt.Fprintf(w, "#include \"log_common/log_common.h\"\n")

		lcfg.writeLogMacros(w)
		fmt.Fprintf(w, "\n")
	}

	fmt.Fprintf(w, "#endif\n")
}

// Ensures an up-to-date logcfg header is written for the target.
func (lcfg *LCfg) EnsureWritten(includeDir string) error {
	buf := bytes.Buffer{}
	lcfg.write(&buf)

	path := includeDir + "/" + HEADER_PATH

	writeReqd, err := util.FileContentsChanged(path, buf.Bytes())
	if err != nil {
		return err
	}
	if !writeReqd {
		log.Debugf("logcfg unchanged; not writing header file (%s).", path)
		return nil
	}

	log.Debugf("logcfg changed; writing header file (%s).", path)

	if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
		return util.NewNewtError(err.Error())
	}

	if err := ioutil.WriteFile(path, buf.Bytes(), 0644); err != nil {
		return util.NewNewtError(err.Error())
	}

	return nil
}
<commit_msg>logcfg: Describe log level 15 as "DISABLED"<commit_after>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 logcfg

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"sort"
	"strings"

	log "github.com/sirupsen/logrus"
	"github.com/spf13/cast"

	"mynewt.apache.org/newt/newt/newtutil"
	"mynewt.apache.org/newt/newt/pkg"
	"mynewt.apache.org/newt/newt/syscfg"
	"mynewt.apache.org/newt/newt/val"
	"mynewt.apache.org/newt/util"
)

const HEADER_PATH = "logcfg/logcfg.h"

type Log struct {
	// Log name; equal to the name of the YAML map that defines the log.
	Name string

	// The package that defines the log.
	Source *pkg.LocalPackage

	// The log's numeric module ID.
	Module val.ValSetting

	// The level assigned to this log.
	Level val.ValSetting
}

// Map of: [log-name] => log
type LogMap map[string]Log

// The log configuration of the target.
type LCfg struct {
	// [log-name] => log
	Logs LogMap

	// Strings describing errors encountered while parsing the log config.
	InvalidSettings []string

	// Contains sets of logs with conflicting module IDs.
	//     [module-ID] => <slice-of-logs-with-module-id>
	ModuleConflicts map[int][]Log
}

// Maps numeric log levels to their string representations.  Used when
// generating the C log macros.
var logLevelNames = []string{
	0:  "DEBUG",
	1:  "INFO",
	2:  "WARN",
	3:  "ERROR",
	4:  "CRITICAL",
	15: "DISABLED",
}

func LogLevelString(level int) string {
	if level < 0 || level >= len(logLevelNames) {
		return "???"
	}

	return logLevelNames[level]
}

func NewLCfg() LCfg {
	return LCfg{
		Logs:            map[string]Log{},
		ModuleConflicts: map[int][]Log{},
	}
}

// Parses a single log definition from a YAML map.  The `logMapItf` parameter
// should be a map with the following elements:
//     "module": <module-string>
//     "level": <level-string>
func parseOneLog(name string, lpkg *pkg.LocalPackage, logMapItf interface{},
	cfg *syscfg.Cfg) (Log, error) {

	cl := Log{
		Name:   name,
		Source: lpkg,
	}

	logMap := cast.ToStringMapString(logMapItf)
	if logMap == nil {
		return cl, util.FmtNewtError(
			"\"%s\" missing required field \"module\"", name)
	}

	modStr := logMap["module"]
	if modStr == "" {
		return cl, util.FmtNewtError(
			"\"%s\" missing required field \"module\"", name)
	}
	mod, err := val.ResolveValSetting(modStr, cfg)
	if err != nil {
		return cl, util.FmtNewtError(
			"\"%s\" contains invalid \"module\": %s",
			name, err.Error())
	}
	if _, err := mod.IntVal(); err != nil {
		return cl, util.FmtNewtError(
			"\"%s\" contains invalid \"module\": %s", name, err.Error())
	}

	levelStr := logMap["level"]
	if levelStr == "" {
		return cl, util.FmtNewtError(
			"\"%s\" missing required field \"level\"", name)
	}
	level, err := val.ResolveValSetting(levelStr, cfg)
	if err != nil {
		return cl, util.FmtNewtError(
			"\"%s\" contains invalid \"level\": %s",
			name, err.Error())
	}
	if _, err := level.IntVal(); err != nil {
		return cl, util.FmtNewtError(
			"\"%s\" contains invalid \"level\": %s", name, err.Error())
	}

	cl.Module = mod
	cl.Level = level

	return cl, nil
}

// Reads all the logs defined by the specified package.  The log definitions
// are read from the `syscfg.logs` map in the package's `syscfg.yml` file.
func (lcfg *LCfg) readOnePkg(lpkg *pkg.LocalPackage, cfg *syscfg.Cfg) {
	lsettings := cfg.AllSettingsForLpkg(lpkg)
	logMaps := lpkg.SyscfgY.GetValStringMap("syscfg.logs", lsettings)
	for name, logMapItf := range logMaps {
		cl, err := parseOneLog(name, lpkg, logMapItf, cfg)
		if err != nil {
			lcfg.InvalidSettings =
				append(lcfg.InvalidSettings, strings.TrimSpace(err.Error()))
		} else {
			lcfg.Logs[cl.Name] = cl
		}
	}
}

// Searches the log configuration for logs with identical module IDs.  The log
// configuration object is populated with the results.
func (lcfg *LCfg) detectModuleConflicts() {
	m := map[int][]Log{}

	for _, l := range lcfg.Logs {
		intMod, _ := l.Module.IntVal()
		m[intMod] = append(m[intMod], l)
	}

	for mod, logs := range m {
		if len(logs) > 1 {
			for _, l := range logs {
				lcfg.ModuleConflicts[mod] =
					append(lcfg.ModuleConflicts[mod], l)
			}
		}
	}
}

// Reads all log definitions for each of the specified packages.  The
// returned LCfg object is populated with the result of this operation.
func Read(lpkgs []*pkg.LocalPackage, cfg *syscfg.Cfg) LCfg {
	lcfg := NewLCfg()

	for _, lpkg := range lpkgs {
		lcfg.readOnePkg(lpkg, cfg)
	}

	lcfg.detectModuleConflicts()

	return lcfg
}

// If any errors were encountered while parsing log definitions, this function
// returns a string indicating the errors.  If no errors were encountered, ""
// is returned.
func (lcfg *LCfg) ErrorText() string {
	str := ""

	if len(lcfg.InvalidSettings) > 0 {
		str += "Invalid log definitions detected:"
		for _, e := range lcfg.InvalidSettings {
			str += "\n    " + e
		}
	}

	if len(lcfg.ModuleConflicts) > 0 {
		str += "Log module conflicts detected:\n"
		for mod, logs := range lcfg.ModuleConflicts {
			for _, l := range logs {
				str += fmt.Sprintf("    Module=%d Log=%s Package=%s\n",
					mod, l.Name, l.Source.FullName())
			}
		}

		str +=
			"\nResolve the problem by assigning unique module IDs to each log."
	}

	return str
}

// Retrieves a sorted slice of logs from the receiving log configuration.
func (lcfg *LCfg) sortedLogs() []Log {
	names := make([]string, 0, len(lcfg.Logs))

	for n, _ := range lcfg.Logs {
		names = append(names, n)
	}
	sort.Strings(names)

	logs := make([]Log, 0, len(names))
	for _, n := range names {
		logs = append(logs, lcfg.Logs[n])
	}

	return logs
}

// Writes a no-op stub log C macro definition.
func writeLogStub(logName string, levelStr string, w io.Writer) {
	fmt.Fprintf(w, "#define %s_%s(...) IGNORE(__VA_ARGS__)\n",
		logName, levelStr)
}

// Writes a log C macro definition.
func writeLogMacro(logName string, module int, levelStr string, w io.Writer) {
	fmt.Fprintf(w,
		"#define %s_%s(...) MODLOG_%s(%d, __VA_ARGS__)\n",
		logName, levelStr, levelStr, module)
}

// Write log C macro definitions for each log in the log configuration.
func (lcfg *LCfg) writeLogMacros(w io.Writer) {
	logs := lcfg.sortedLogs()
	for _, l := range logs {
		fmt.Fprintf(w, "\n")

		levelInt, _ := util.AtoiNoOct(l.Level.Value)
		for i, levelStr := range logLevelNames {
			if i < levelInt {
				writeLogStub(l.Name, levelStr, w)
			} else {
				modInt, _ := l.Module.IntVal()
				writeLogMacro(l.Name, modInt, levelStr, w)
			}
		}
	}
}

// Writes a logcfg header file to the specified writer.
func (lcfg *LCfg) write(w io.Writer) {
	fmt.Fprintf(w, newtutil.GeneratedPreamble())

	fmt.Fprintf(w, "#ifndef H_MYNEWT_LOGCFG_\n")
	fmt.Fprintf(w, "#define H_MYNEWT_LOGCFG_\n\n")

	if len(lcfg.Logs) > 0 {
		fmt.Fprintf(w, "#include \"modlog/modlog.h\"\n")
		fmt.Fprintf(w, "#include \"log_common/log_common.h\"\n")

		lcfg.writeLogMacros(w)
		fmt.Fprintf(w, "\n")
	}

	fmt.Fprintf(w, "#endif\n")
}

// Ensures an up-to-date logcfg header is written for the target.
func (lcfg *LCfg) EnsureWritten(includeDir string) error {
	buf := bytes.Buffer{}
	lcfg.write(&buf)

	path := includeDir + "/" + HEADER_PATH

	writeReqd, err := util.FileContentsChanged(path, buf.Bytes())
	if err != nil {
		return err
	}
	if !writeReqd {
		log.Debugf("logcfg unchanged; not writing header file (%s).", path)
		return nil
	}

	log.Debugf("logcfg changed; writing header file (%s).", path)

	if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
		return util.NewNewtError(err.Error())
	}

	if err := ioutil.WriteFile(path, buf.Bytes(), 0644); err != nil {
		return util.NewNewtError(err.Error())
	}

	return nil
}
<|endoftext|>


<commit_before>// +build acceptance compute servers

package v2

import (
	"os"
	"testing"

	"github.com/rackspace/gophercloud"
	"github.com/rackspace/gophercloud/acceptance/tools"
	"github.com/rackspace/gophercloud/openstack"
	"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
	"github.com/rackspace/gophercloud/openstack/networking/v2/networks"
	"github.com/rackspace/gophercloud/pagination"
	th "github.com/rackspace/gophercloud/testhelper"
)

func TestListServers(t *testing.T) {
	client, err := newClient()
	if err != nil {
		t.Fatalf("Unable to create a compute client: %v", err)
	}

	t.Logf("ID\tRegion\tName\tStatus\tIPv4\tIPv6")

	pager := servers.List(client, servers.ListOpts{})
	count, pages := 0, 0
	pager.EachPage(func(page pagination.Page) (bool, error) {
		pages++
		t.Logf("---")

		servers, err := servers.ExtractServers(page)
		if err != nil {
			return false, err
		}

		for _, s := range servers {
			t.Logf("%s\t%s\t%s\t%s\t%s\t\n", s.ID, s.Name, s.Status, s.AccessIPv4, s.AccessIPv6)
			count++
		}

		return true, nil
	})

	t.Logf("--------\n%d servers listed on %d pages.\n", count, pages)
}

func networkingClient() (*gophercloud.ServiceClient, error) {
	opts, err := openstack.AuthOptionsFromEnv()
	if err != nil {
		return nil, err
	}

	provider, err := openstack.AuthenticatedClient(opts)
	if err != nil {
		return nil, err
	}

	return openstack.NewNetworkV2(provider, gophercloud.EndpointOpts{
		Name:   "neutron",
		Region: os.Getenv("OS_REGION_NAME"),
	})
}

func createServer(t *testing.T, client *gophercloud.ServiceClient, choices *ComputeChoices) (*servers.Server, error) {
	if testing.Short() {
		t.Skip("Skipping test that requires server creation in short mode.")
	}

	var network networks.Network

	networkingClient, err := networkingClient()
	if err != nil {
		t.Fatalf("Unable to create a networking client: %v", err)
	}

	pager := networks.List(networkingClient, networks.ListOpts{Name: "public", Limit: 1})
	pager.EachPage(func(page pagination.Page) (bool, error) {
		networks, err := networks.ExtractNetworks(page)
		if err != nil {
			t.Errorf("Failed to extract networks: %v", err)
			return false, err
		}

		if len(networks) == 0 {
			t.Fatalf("No networks to attach to server")
			return false, err
		}

		network = networks[0]

		return false, nil
	})

	name := tools.RandomString("ACPTTEST", 16)
	t.Logf("Attempting to create server: %s\n", name)

	pwd := tools.MakeNewPassword("")

	server, err := servers.Create(client, servers.CreateOpts{
		Name:      name,
		FlavorRef: choices.FlavorID,
		ImageRef:  choices.ImageID,
		Networks: []servers.Network{
			servers.Network{UUID: network.ID},
		},
		AdminPass: pwd,
	}).Extract()
	if err != nil {
		t.Fatalf("Unable to create server: %v", err)
	}

	th.AssertEquals(t, pwd, server.AdminPass)

	return server, err
}

func TestCreateDestroyServer(t *testing.T) {
	choices, err := ComputeChoicesFromEnv()
	if err != nil {
		t.Fatal(err)
	}

	client, err := newClient()
	if err != nil {
		t.Fatalf("Unable to create a compute client: %v", err)
	}

	server, err := createServer(t, client, choices)
	if err != nil {
		t.Fatalf("Unable to create server: %v", err)
	}
	defer func() {
		servers.Delete(client, server.ID)
		t.Logf("Server deleted.")
	}()

	if err = waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatalf("Unable to wait for server: %v", err)
	}
}

func TestUpdateServer(t *testing.T) {
	client, err := newClient()
	if err != nil {
		t.Fatalf("Unable to create a compute client: %v", err)
	}

	choices, err := ComputeChoicesFromEnv()
	if err != nil {
		t.Fatal(err)
	}

	server, err := createServer(t, client, choices)
	if err != nil {
		t.Fatal(err)
	}
	defer servers.Delete(client, server.ID)

	if err = waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatal(err)
	}

	alternateName := tools.RandomString("ACPTTEST", 16)
	for alternateName == server.Name {
		alternateName = tools.RandomString("ACPTTEST", 16)
	}

	t.Logf("Attempting to rename the server to %s.", alternateName)

	updated, err := servers.Update(client, server.ID, servers.UpdateOpts{Name: alternateName}).Extract()
	if err != nil {
		t.Fatalf("Unable to rename server: %v", err)
	}

	if updated.ID != server.ID {
		t.Errorf("Updated server ID [%s] didn't match original server ID [%s]!", updated.ID, server.ID)
	}

	err = tools.WaitFor(func() (bool, error) {
		latest, err := servers.Get(client, updated.ID).Extract()
		if err != nil {
			return false, err
		}

		return latest.Name == alternateName, nil
	})
}

func TestActionChangeAdminPassword(t *testing.T) {
	t.Parallel()

	client, err := newClient()
	if err != nil {
		t.Fatalf("Unable to create a compute client: %v", err)
	}

	choices, err := ComputeChoicesFromEnv()
	if err != nil {
		t.Fatal(err)
	}

	server, err := createServer(t, client, choices)
	if err != nil {
		t.Fatal(err)
	}
	defer servers.Delete(client, server.ID)

	if err = waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatal(err)
	}

	randomPassword := tools.MakeNewPassword(server.AdminPass)
	res := servers.ChangeAdminPassword(client, server.ID, randomPassword)
	if res.Err != nil {
		t.Fatal(err)
	}

	if err = waitForStatus(client, server, "PASSWORD"); err != nil {
		t.Fatal(err)
	}

	if err = waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatal(err)
	}
}

func TestActionReboot(t *testing.T) {
	t.Parallel()

	client, err := newClient()
	if err != nil {
		t.Fatalf("Unable to create a compute client: %v", err)
	}

	choices, err := ComputeChoicesFromEnv()
	if err != nil {
		t.Fatal(err)
	}

	server, err := createServer(t, client, choices)
	if err != nil {
		t.Fatal(err)
	}
	defer servers.Delete(client, server.ID)

	if err = waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatal(err)
	}

	res := servers.Reboot(client, server.ID, "aldhjflaskhjf")
	if res.Err == nil {
		t.Fatal("Expected the SDK to provide an ArgumentError here")
	}

	t.Logf("Attempting reboot of server %s", server.ID)
	res = servers.Reboot(client, server.ID, servers.OSReboot)
	if res.Err != nil {
		t.Fatalf("Unable to reboot server: %v", err)
	}

	if err = waitForStatus(client, server, "REBOOT"); err != nil {
		t.Fatal(err)
	}

	if err = waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatal(err)
	}
}

func TestActionRebuild(t *testing.T) {
	t.Parallel()

	client, err := newClient()
	if err != nil {
		t.Fatalf("Unable to create a compute client: %v", err)
	}

	choices, err := ComputeChoicesFromEnv()
	if err != nil {
		t.Fatal(err)
	}

	server, err := createServer(t, client, choices)
	if err != nil {
		t.Fatal(err)
	}
	defer servers.Delete(client, server.ID)

	if err = waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatal(err)
	}

	t.Logf("Attempting to rebuild server %s", server.ID)

	rebuildOpts := servers.RebuildOpts{
		Name:      tools.RandomString("ACPTTEST", 16),
		AdminPass: tools.MakeNewPassword(server.AdminPass),
		ImageID:   choices.ImageID,
	}

	rebuilt, err := servers.Rebuild(client, server.ID, rebuildOpts).Extract()
	if err != nil {
		t.Fatal(err)
	}

	if rebuilt.ID != server.ID {
		t.Errorf("Expected rebuilt server ID of [%s]; got [%s]", server.ID, rebuilt.ID)
	}

	if err = waitForStatus(client, rebuilt, "REBUILD"); err != nil {
		t.Fatal(err)
	}

	if err = waitForStatus(client, rebuilt, "ACTIVE"); err != nil {
		t.Fatal(err)
	}
}

func resizeServer(t *testing.T, client *gophercloud.ServiceClient, server *servers.Server, choices *ComputeChoices) {
	if err := waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatal(err)
	}

	t.Logf("Attempting to resize server [%s]", server.ID)

	opts := &servers.ResizeOpts{
		FlavorRef: choices.FlavorIDResize,
	}
	if res := servers.Resize(client, server.ID, opts); res.Err != nil {
		t.Fatal(res.Err)
	}

	if err := waitForStatus(client, server, "VERIFY_RESIZE"); err != nil {
		t.Fatal(err)
	}
}

func TestActionResizeConfirm(t *testing.T) {
	t.Parallel()

	choices, err := ComputeChoicesFromEnv()
	if err != nil {
		t.Fatal(err)
	}

	client, err := newClient()
	if err != nil {
		t.Fatalf("Unable to create a compute client: %v", err)
	}

	server, err := createServer(t, client, choices)
	if err != nil {
		t.Fatal(err)
	}
	defer servers.Delete(client, server.ID)
	resizeServer(t, client, server, choices)

	t.Logf("Attempting to confirm resize for server %s", server.ID)

	if res := servers.ConfirmResize(client, server.ID); res.Err != nil {
		t.Fatal(err)
	}

	if err = waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatal(err)
	}
}

func TestActionResizeRevert(t *testing.T) {
	t.Parallel()

	choices, err := ComputeChoicesFromEnv()
	if err != nil {
		t.Fatal(err)
	}

	client, err := newClient()
	if err != nil {
		t.Fatalf("Unable to create a compute client: %v", err)
	}

	server, err := createServer(t, client, choices)
	if err != nil {
		t.Fatal(err)
	}
	defer servers.Delete(client, server.ID)
	resizeServer(t, client, server, choices)

	t.Logf("Attempting to revert resize for server %s", server.ID)

	if res := servers.RevertResize(client, server.ID); res.Err != nil {
		t.Fatal(err)
	}

	if err = waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatal(err)
	}
}

func TestServerMetadata(t *testing.T) {
	t.Parallel()

	choices, err := ComputeChoicesFromEnv()
	th.AssertNoErr(t, err)

	client, err := newClient()
	if err != nil {
		t.Fatalf("Unable to create a compute client: %v", err)
	}

	server, err := createServer(t, client, choices)
	if err != nil {
		t.Fatal(err)
	}
	defer servers.Delete(client, server.ID)
	if err = waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatal(err)
	}

	metadata, err := servers.UpdateMetadata(client, server.ID, servers.MetadataOpts{
		"foo":  "bar",
		"this": "that",
	}).Extract()
	th.AssertNoErr(t, err)
	t.Logf("UpdateMetadata result: %+v\n", metadata)

	err = servers.DeleteMetadatum(client, server.ID, "foo").ExtractErr()
	th.AssertNoErr(t, err)

	metadata, err = servers.CreateMetadatum(client, server.ID, servers.MetadatumOpts{
		"foo": "baz",
	}).Extract()
	th.AssertNoErr(t, err)
	t.Logf("CreateMetadatum result: %+v\n", metadata)

	metadata, err = servers.Metadatum(client, server.ID, "foo").Extract()
	th.AssertNoErr(t, err)
	t.Logf("Metadatum result: %+v\n", metadata)
	th.AssertEquals(t, "baz", metadata["foo"])

	metadata, err = servers.Metadata(client, server.ID).Extract()
	th.AssertNoErr(t, err)
	t.Logf("Metadata result: %+v\n", metadata)

	metadata, err = servers.ResetMetadata(client, server.ID, servers.MetadataOpts{}).Extract()
	th.AssertNoErr(t, err)
	t.Logf("ResetMetadata result: %+v\n", metadata)
	th.AssertDeepEquals(t, map[string]string{}, metadata)
}
<commit_msg>openstack list server addresses acceptance tests<commit_after>// +build acceptance compute servers

package v2

import (
	"os"
	"testing"

	"github.com/rackspace/gophercloud"
	"github.com/rackspace/gophercloud/acceptance/tools"
	"github.com/rackspace/gophercloud/openstack"
	"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
	"github.com/rackspace/gophercloud/openstack/networking/v2/networks"
	"github.com/rackspace/gophercloud/pagination"
	th "github.com/rackspace/gophercloud/testhelper"
)

func TestListServers(t *testing.T) {
	client, err := newClient()
	if err != nil {
		t.Fatalf("Unable to create a compute client: %v", err)
	}

	t.Logf("ID\tRegion\tName\tStatus\tIPv4\tIPv6")

	pager := servers.List(client, servers.ListOpts{})
	count, pages := 0, 0
	pager.EachPage(func(page pagination.Page) (bool, error) {
		pages++
		t.Logf("---")

		servers, err := servers.ExtractServers(page)
		if err != nil {
			return false, err
		}

		for _, s := range servers {
			t.Logf("%s\t%s\t%s\t%s\t%s\t\n", s.ID, s.Name, s.Status, s.AccessIPv4, s.AccessIPv6)
			count++
		}

		return true, nil
	})

	t.Logf("--------\n%d servers listed on %d pages.\n", count, pages)
}

func networkingClient() (*gophercloud.ServiceClient, error) {
	opts, err := openstack.AuthOptionsFromEnv()
	if err != nil {
		return nil, err
	}

	provider, err := openstack.AuthenticatedClient(opts)
	if err != nil {
		return nil, err
	}

	return openstack.NewNetworkV2(provider, gophercloud.EndpointOpts{
		Name:   "neutron",
		Region: os.Getenv("OS_REGION_NAME"),
	})
}

func createServer(t *testing.T, client *gophercloud.ServiceClient, choices *ComputeChoices) (*servers.Server, error) {
	if testing.Short() {
		t.Skip("Skipping test that requires server creation in short mode.")
	}

	var network networks.Network

	networkingClient, err := networkingClient()
	if err != nil {
		t.Fatalf("Unable to create a networking client: %v", err)
	}

	pager := networks.List(networkingClient, networks.ListOpts{Name: "public", Limit: 1})
	pager.EachPage(func(page pagination.Page) (bool, error) {
		networks, err := networks.ExtractNetworks(page)
		if err != nil {
			t.Errorf("Failed to extract networks: %v", err)
			return false, err
		}

		if len(networks) == 0 {
			t.Fatalf("No networks to attach to server")
			return false, err
		}

		network = networks[0]

		return false, nil
	})

	name := tools.RandomString("ACPTTEST", 16)
	t.Logf("Attempting to create server: %s\n", name)

	pwd := tools.MakeNewPassword("")

	server, err := servers.Create(client, servers.CreateOpts{
		Name:      name,
		FlavorRef: choices.FlavorID,
		ImageRef:  choices.ImageID,
		Networks: []servers.Network{
			servers.Network{UUID: network.ID},
		},
		AdminPass: pwd,
	}).Extract()
	if err != nil {
		t.Fatalf("Unable to create server: %v", err)
	}

	th.AssertEquals(t, pwd, server.AdminPass)

	return server, err
}

func TestCreateDestroyServer(t *testing.T) {
	choices, err := ComputeChoicesFromEnv()
	if err != nil {
		t.Fatal(err)
	}

	client, err := newClient()
	if err != nil {
		t.Fatalf("Unable to create a compute client: %v", err)
	}

	server, err := createServer(t, client, choices)
	if err != nil {
		t.Fatalf("Unable to create server: %v", err)
	}
	defer func() {
		servers.Delete(client, server.ID)
		t.Logf("Server deleted.")
	}()

	if err = waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatalf("Unable to wait for server: %v", err)
	}

	pager := servers.ListAddresses(client, server.ID)
	pager.EachPage(func(page pagination.Page) (bool, error) {
		networks, err := servers.ExtractAddresses(page)
		if err != nil {
			return false, err
		}

		for n, a := range networks {
			t.Logf("%s: %+v\n", n, a)
		}
		return true, nil
	})

	pager = servers.ListAddressesByNetwork(client, server.ID, "public")
	pager.EachPage(func(page pagination.Page) (bool, error) {
		network, err := servers.ExtractNetworkAddresses(page)
		if err != nil {
			return false, err
		}

		for n, a := range network {
			t.Logf("%s: %+v\n", n, a)
		}
		return true, nil
	})
}

func TestUpdateServer(t *testing.T) {
	client, err := newClient()
	if err != nil {
		t.Fatalf("Unable to create a compute client: %v", err)
	}

	choices, err := ComputeChoicesFromEnv()
	if err != nil {
		t.Fatal(err)
	}

	server, err := createServer(t, client, choices)
	if err != nil {
		t.Fatal(err)
	}
	defer servers.Delete(client, server.ID)

	if err = waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatal(err)
	}

	alternateName := tools.RandomString("ACPTTEST", 16)
	for alternateName == server.Name {
		alternateName = tools.RandomString("ACPTTEST", 16)
	}

	t.Logf("Attempting to rename the server to %s.", alternateName)

	updated, err := servers.Update(client, server.ID, servers.UpdateOpts{Name: alternateName}).Extract()
	if err != nil {
		t.Fatalf("Unable to rename server: %v", err)
	}

	if updated.ID != server.ID {
		t.Errorf("Updated server ID [%s] didn't match original server ID [%s]!", updated.ID, server.ID)
	}

	err = tools.WaitFor(func() (bool, error) {
		latest, err := servers.Get(client, updated.ID).Extract()
		if err != nil {
			return false, err
		}

		return latest.Name == alternateName, nil
	})
}

func TestActionChangeAdminPassword(t *testing.T) {
	t.Parallel()

	client, err := newClient()
	if err != nil {
		t.Fatalf("Unable to create a compute client: %v", err)
	}

	choices, err := ComputeChoicesFromEnv()
	if err != nil {
		t.Fatal(err)
	}

	server, err := createServer(t, client, choices)
	if err != nil {
		t.Fatal(err)
	}
	defer servers.Delete(client, server.ID)

	if err = waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatal(err)
	}

	randomPassword := tools.MakeNewPassword(server.AdminPass)
	res := servers.ChangeAdminPassword(client, server.ID, randomPassword)
	if res.Err != nil {
		t.Fatal(err)
	}

	if err = waitForStatus(client, server, "PASSWORD"); err != nil {
		t.Fatal(err)
	}

	if err = waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatal(err)
	}
}

func TestActionReboot(t *testing.T) {
	t.Parallel()

	client, err := newClient()
	if err != nil {
		t.Fatalf("Unable to create a compute client: %v", err)
	}

	choices, err := ComputeChoicesFromEnv()
	if err != nil {
		t.Fatal(err)
	}

	server, err := createServer(t, client, choices)
	if err != nil {
		t.Fatal(err)
	}
	defer servers.Delete(client, server.ID)

	if err = waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatal(err)
	}

	res := servers.Reboot(client, server.ID, "aldhjflaskhjf")
	if res.Err == nil {
		t.Fatal("Expected the SDK to provide an ArgumentError here")
	}

	t.Logf("Attempting reboot of server %s", server.ID)
	res = servers.Reboot(client, server.ID, servers.OSReboot)
	if res.Err != nil {
		t.Fatalf("Unable to reboot server: %v", err)
	}

	if err = waitForStatus(client, server, "REBOOT"); err != nil {
		t.Fatal(err)
	}

	if err = waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatal(err)
	}
}

func TestActionRebuild(t *testing.T) {
	t.Parallel()

	client, err := newClient()
	if err != nil {
		t.Fatalf("Unable to create a compute client: %v", err)
	}

	choices, err := ComputeChoicesFromEnv()
	if err != nil {
		t.Fatal(err)
	}

	server, err := createServer(t, client, choices)
	if err != nil {
		t.Fatal(err)
	}
	defer servers.Delete(client, server.ID)

	if err = waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatal(err)
	}

	t.Logf("Attempting to rebuild server %s", server.ID)

	rebuildOpts := servers.RebuildOpts{
		Name:      tools.RandomString("ACPTTEST", 16),
		AdminPass: tools.MakeNewPassword(server.AdminPass),
		ImageID:   choices.ImageID,
	}

	rebuilt, err := servers.Rebuild(client, server.ID, rebuildOpts).Extract()
	if err != nil {
		t.Fatal(err)
	}

	if rebuilt.ID != server.ID {
		t.Errorf("Expected rebuilt server ID of [%s]; got [%s]", server.ID, rebuilt.ID)
	}

	if err = waitForStatus(client, rebuilt, "REBUILD"); err != nil {
		t.Fatal(err)
	}

	if err = waitForStatus(client, rebuilt, "ACTIVE"); err != nil {
		t.Fatal(err)
	}
}

func resizeServer(t *testing.T, client *gophercloud.ServiceClient, server *servers.Server, choices *ComputeChoices) {
	if err := waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatal(err)
	}

	t.Logf("Attempting to resize server [%s]", server.ID)

	opts := &servers.ResizeOpts{
		FlavorRef: choices.FlavorIDResize,
	}
	if res := servers.Resize(client, server.ID, opts); res.Err != nil {
		t.Fatal(res.Err)
	}

	if err := waitForStatus(client, server, "VERIFY_RESIZE"); err != nil {
		t.Fatal(err)
	}
}

func TestActionResizeConfirm(t *testing.T) {
	t.Parallel()

	choices, err := ComputeChoicesFromEnv()
	if err != nil {
		t.Fatal(err)
	}

	client, err := newClient()
	if err != nil {
		t.Fatalf("Unable to create a compute client: %v", err)
	}

	server, err := createServer(t, client, choices)
	if err != nil {
		t.Fatal(err)
	}
	defer servers.Delete(client, server.ID)
	resizeServer(t, client, server, choices)

	t.Logf("Attempting to confirm resize for server %s", server.ID)

	if res := servers.ConfirmResize(client, server.ID); res.Err != nil {
		t.Fatal(err)
	}

	if err = waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatal(err)
	}
}

func TestActionResizeRevert(t *testing.T) {
	t.Parallel()

	choices, err := ComputeChoicesFromEnv()
	if err != nil {
		t.Fatal(err)
	}

	client, err := newClient()
	if err != nil {
		t.Fatalf("Unable to create a compute client: %v", err)
	}

	server, err := createServer(t, client, choices)
	if err != nil {
		t.Fatal(err)
	}
	defer servers.Delete(client, server.ID)
	resizeServer(t, client, server, choices)

	t.Logf("Attempting to revert resize for server %s", server.ID)

	if res := servers.RevertResize(client, server.ID); res.Err != nil {
		t.Fatal(err)
	}

	if err = waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatal(err)
	}
}

func TestServerMetadata(t *testing.T) {
	t.Parallel()

	choices, err := ComputeChoicesFromEnv()
	th.AssertNoErr(t, err)

	client, err := newClient()
	if err != nil {
		t.Fatalf("Unable to create a compute client: %v", err)
	}

	server, err := createServer(t, client, choices)
	if err != nil {
		t.Fatal(err)
	}
	defer servers.Delete(client, server.ID)
	if err = waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatal(err)
	}

	metadata, err := servers.UpdateMetadata(client, server.ID, servers.MetadataOpts{
		"foo":  "bar",
		"this": "that",
	}).Extract()
	th.AssertNoErr(t, err)
	t.Logf("UpdateMetadata result: %+v\n", metadata)

	err = servers.DeleteMetadatum(client, server.ID, "foo").ExtractErr()
	th.AssertNoErr(t, err)

	metadata, err = servers.CreateMetadatum(client, server.ID, servers.MetadatumOpts{
		"foo": "baz",
	}).Extract()
	th.AssertNoErr(t, err)
	t.Logf("CreateMetadatum result: %+v\n", metadata)

	metadata, err = servers.Metadatum(client, server.ID, "foo").Extract()
	th.AssertNoErr(t, err)
	t.Logf("Metadatum result: %+v\n", metadata)
	th.AssertEquals(t, "baz", metadata["foo"])

	metadata, err = servers.Metadata(client, server.ID).Extract()
	th.AssertNoErr(t, err)
	t.Logf("Metadata result: %+v\n", metadata)

	metadata, err = servers.ResetMetadata(client, server.ID, servers.MetadataOpts{}).Extract()
	th.AssertNoErr(t, err)
	t.Logf("ResetMetadata result: %+v\n", metadata)
	th.AssertDeepEquals(t, map[string]string{}, metadata)
}
<|endoftext|>


<commit_before>package handlers

import (
	"encoding/json"
	"log"
	"net/http"

	"html/template"
)

// ReportHandler handles the report page
func ReportHandler(w http.ResponseWriter, r *http.Request, repo string) {
	log.Println("report", repo)
	t := template.Must(template.New("report.html").Delims("[[", "]]").ParseFiles("templates/report.html"))
	resp, err := getFromCache(repo)
	needToLoad := false
	if err != nil {
		log.Println("ERROR:", err) // log error, but continue
		needToLoad = true
	}

	respBytes, err := json.Marshal(resp)
	if err != nil {
		log.Println("ERROR: marshaling json: ", err)
		http.Error(w, "Failed to load cache object", 500)
		return
	}

	t.Execute(w, map[string]interface{}{"repo": repo, "response": string(respBytes), "loading": needToLoad})
}
<commit_msg>make log line a bit more descriptive/easier to find<commit_after>package handlers

import (
	"encoding/json"
	"log"
	"net/http"

	"html/template"
)

// ReportHandler handles the report page
func ReportHandler(w http.ResponseWriter, r *http.Request, repo string) {
	log.Printf("Displaying report: %q", repo)
	t := template.Must(template.New("report.html").Delims("[[", "]]").ParseFiles("templates/report.html"))
	resp, err := getFromCache(repo)
	needToLoad := false
	if err != nil {
		log.Println("ERROR:", err) // log error, but continue
		needToLoad = true
	}

	respBytes, err := json.Marshal(resp)
	if err != nil {
		log.Println("ERROR: marshaling json: ", err)
		http.Error(w, "Failed to load cache object", 500)
		return
	}

	t.Execute(w, map[string]interface{}{"repo": repo, "response": string(respBytes), "loading": needToLoad})
}
<|endoftext|>