<commit_before>/*
Copyright (c) 2017 VMware, Inc. All Rights Reserved.

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 pbm

import (
	"context"
	"fmt"

	"github.com/vmware/govmomi/pbm/methods"
	"github.com/vmware/govmomi/pbm/types"
	"github.com/vmware/govmomi/vim25"
	"github.com/vmware/govmomi/vim25/soap"
	vim "github.com/vmware/govmomi/vim25/types"
)

const (
	Namespace = "pbm"
	Path      = "/pbm"
)

var (
	ServiceInstance = vim.ManagedObjectReference{
		Type:  "PbmServiceInstance",
		Value: "ServiceInstance",
	}
)

type Client struct {
	*soap.Client

	ServiceContent types.PbmServiceInstanceContent
}

func NewClient(ctx context.Context, c *vim25.Client) (*Client, error) {
	sc := c.Client.NewServiceClient(Path, Namespace)

	req := types.PbmRetrieveServiceContent{
		This: ServiceInstance,
	}

	res, err := methods.PbmRetrieveServiceContent(ctx, sc, &req)
	if err != nil {
		return nil, err
	}

	return &Client{sc, res.Returnval}, nil
}

func (c *Client) QueryProfile(ctx context.Context, rtype types.PbmProfileResourceType, category string) ([]types.PbmProfileId, error) {
	req := types.PbmQueryProfile{
		This:            c.ServiceContent.ProfileManager,
		ResourceType:    rtype,
		ProfileCategory: category,
	}

	res, err := methods.PbmQueryProfile(ctx, c, &req)
	if err != nil {
		return nil, err
	}

	return res.Returnval, nil
}

func (c *Client) RetrieveContent(ctx context.Context, ids []types.PbmProfileId) ([]types.BasePbmProfile, error) {
	req := types.PbmRetrieveContent{
		This:       c.ServiceContent.ProfileManager,
		ProfileIds: ids,
	}

	res, err := methods.PbmRetrieveContent(ctx, c, &req)
	if err != nil {
		return nil, err
	}

	return res.Returnval, nil
}

type PlacementCompatibilityResult []types.PbmPlacementCompatibilityResult

func (c *Client) CheckRequirements(ctx context.Context, hubs []types.PbmPlacementHub, ref *types.PbmServerObjectRef, preq []types.BasePbmPlacementRequirement) (PlacementCompatibilityResult, error) {
	req := types.PbmCheckRequirements{
		This:                        c.ServiceContent.PlacementSolver,
		HubsToSearch:                hubs,
		PlacementSubjectRef:         ref,
		PlacementSubjectRequirement: preq,
	}

	res, err := methods.PbmCheckRequirements(ctx, c, &req)
	if err != nil {
		return nil, err
	}

	return res.Returnval, nil
}

func (l PlacementCompatibilityResult) CompatibleDatastores() []types.PbmPlacementHub {
	var compatibleDatastores []types.PbmPlacementHub

	for _, res := range l {
		if len(res.Error) == 0 {
			compatibleDatastores = append(compatibleDatastores, res.Hub)
		}
	}
	return compatibleDatastores
}

func (l PlacementCompatibilityResult) NonCompatibleDatastores() []types.PbmPlacementHub {
	var nonCompatibleDatastores []types.PbmPlacementHub

	for _, res := range l {
		if len(res.Error) > 0 {
			nonCompatibleDatastores = append(nonCompatibleDatastores, res.Hub)
		}
	}
	return nonCompatibleDatastores
}

func (c *Client) CreateProfile(ctx context.Context, capabilityProfileCreateSpec types.PbmCapabilityProfileCreateSpec) (*types.PbmProfileId, error) {
	req := types.PbmCreate{
		This:       c.ServiceContent.ProfileManager,
		CreateSpec: capabilityProfileCreateSpec,
	}

	res, err := methods.PbmCreate(ctx, c, &req)
	if err != nil {
		return nil, err
	}

	return &res.Returnval, nil
}

func (c *Client) UpdateProfile(ctx context.Context, id types.PbmProfileId, updateSpec types.PbmCapabilityProfileUpdateSpec) error {
	req := types.PbmUpdate{
		This:       c.ServiceContent.ProfileManager,
		ProfileId:  id,
		UpdateSpec: updateSpec,
	}

	_, err := methods.PbmUpdate(ctx, c, &req)
	if err != nil {
		return err
	}

	return nil
}

func (c *Client) DeleteProfile(ctx context.Context, ids []types.PbmProfileId) ([]types.PbmProfileOperationOutcome, error) {
	req := types.PbmDelete{
		This:      c.ServiceContent.ProfileManager,
		ProfileId: ids,
	}

	res, err := methods.PbmDelete(ctx, c, &req)
	if err != nil {
		return nil, err
	}

	return res.Returnval, nil
}

func (c *Client) QueryAssociatedEntity(ctx context.Context, id types.PbmProfileId, entityType string) ([]types.PbmServerObjectRef, error) {
	req := types.PbmQueryAssociatedEntity{
		This:       c.ServiceContent.ProfileManager,
		Profile:    id,
		EntityType: entityType,
	}

	res, err := methods.PbmQueryAssociatedEntity(ctx, c, &req)
	if err != nil {
		return nil, err
	}

	return res.Returnval, nil
}

func (c *Client) QueryAssociatedEntities(ctx context.Context, ids []types.PbmProfileId) ([]types.PbmQueryProfileResult, error) {
	req := types.PbmQueryAssociatedEntities{
		This:     c.ServiceContent.ProfileManager,
		Profiles: ids,
	}

	res, err := methods.PbmQueryAssociatedEntities(ctx, c, &req)
	if err != nil {
		return nil, err
	}

	return res.Returnval, nil
}

func (c *Client) ProfileIDByName(ctx context.Context, profileName string) (string, error) {
	resourceType := types.PbmProfileResourceType{
		ResourceType: string(types.PbmProfileResourceTypeEnumSTORAGE),
	}
	category := types.PbmProfileCategoryEnumREQUIREMENT
	ids, err := c.QueryProfile(ctx, resourceType, string(category))
	if err != nil {
		return "", err
	}

	profiles, err := c.RetrieveContent(ctx, ids)
	if err != nil {
		return "", err
	}

	for i := range profiles {
		profile := profiles[i].GetPbmProfile()
		if profile.Name == profileName {
			return profile.ProfileId.UniqueId, nil
		}
	}
	return "", fmt.Errorf("no pbm profile found with name: %q", profileName)
}
<commit_msg>Add FetchCapabilityMetadata method to Pbm client<commit_after>/*
Copyright (c) 2017 VMware, Inc. All Rights Reserved.

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 pbm

import (
	"context"
	"fmt"

	"github.com/vmware/govmomi/pbm/methods"
	"github.com/vmware/govmomi/pbm/types"
	"github.com/vmware/govmomi/vim25"
	"github.com/vmware/govmomi/vim25/soap"
	vim "github.com/vmware/govmomi/vim25/types"
)

const (
	Namespace = "pbm"
	Path      = "/pbm"
)

var (
	ServiceInstance = vim.ManagedObjectReference{
		Type:  "PbmServiceInstance",
		Value: "ServiceInstance",
	}
)

type Client struct {
	*soap.Client

	ServiceContent types.PbmServiceInstanceContent
}

func NewClient(ctx context.Context, c *vim25.Client) (*Client, error) {
	sc := c.Client.NewServiceClient(Path, Namespace)

	req := types.PbmRetrieveServiceContent{
		This: ServiceInstance,
	}

	res, err := methods.PbmRetrieveServiceContent(ctx, sc, &req)
	if err != nil {
		return nil, err
	}

	return &Client{sc, res.Returnval}, nil
}

func (c *Client) QueryProfile(ctx context.Context, rtype types.PbmProfileResourceType, category string) ([]types.PbmProfileId, error) {
	req := types.PbmQueryProfile{
		This:            c.ServiceContent.ProfileManager,
		ResourceType:    rtype,
		ProfileCategory: category,
	}

	res, err := methods.PbmQueryProfile(ctx, c, &req)
	if err != nil {
		return nil, err
	}

	return res.Returnval, nil
}

func (c *Client) RetrieveContent(ctx context.Context, ids []types.PbmProfileId) ([]types.BasePbmProfile, error) {
	req := types.PbmRetrieveContent{
		This:       c.ServiceContent.ProfileManager,
		ProfileIds: ids,
	}

	res, err := methods.PbmRetrieveContent(ctx, c, &req)
	if err != nil {
		return nil, err
	}

	return res.Returnval, nil
}

type PlacementCompatibilityResult []types.PbmPlacementCompatibilityResult

func (c *Client) CheckRequirements(ctx context.Context, hubs []types.PbmPlacementHub, ref *types.PbmServerObjectRef, preq []types.BasePbmPlacementRequirement) (PlacementCompatibilityResult, error) {
	req := types.PbmCheckRequirements{
		This:                        c.ServiceContent.PlacementSolver,
		HubsToSearch:                hubs,
		PlacementSubjectRef:         ref,
		PlacementSubjectRequirement: preq,
	}

	res, err := methods.PbmCheckRequirements(ctx, c, &req)
	if err != nil {
		return nil, err
	}

	return res.Returnval, nil
}

func (l PlacementCompatibilityResult) CompatibleDatastores() []types.PbmPlacementHub {
	var compatibleDatastores []types.PbmPlacementHub

	for _, res := range l {
		if len(res.Error) == 0 {
			compatibleDatastores = append(compatibleDatastores, res.Hub)
		}
	}
	return compatibleDatastores
}

func (l PlacementCompatibilityResult) NonCompatibleDatastores() []types.PbmPlacementHub {
	var nonCompatibleDatastores []types.PbmPlacementHub

	for _, res := range l {
		if len(res.Error) > 0 {
			nonCompatibleDatastores = append(nonCompatibleDatastores, res.Hub)
		}
	}
	return nonCompatibleDatastores
}

func (c *Client) CreateProfile(ctx context.Context, capabilityProfileCreateSpec types.PbmCapabilityProfileCreateSpec) (*types.PbmProfileId, error) {
	req := types.PbmCreate{
		This:       c.ServiceContent.ProfileManager,
		CreateSpec: capabilityProfileCreateSpec,
	}

	res, err := methods.PbmCreate(ctx, c, &req)
	if err != nil {
		return nil, err
	}

	return &res.Returnval, nil
}

func (c *Client) UpdateProfile(ctx context.Context, id types.PbmProfileId, updateSpec types.PbmCapabilityProfileUpdateSpec) error {
	req := types.PbmUpdate{
		This:       c.ServiceContent.ProfileManager,
		ProfileId:  id,
		UpdateSpec: updateSpec,
	}

	_, err := methods.PbmUpdate(ctx, c, &req)
	if err != nil {
		return err
	}

	return nil
}

func (c *Client) DeleteProfile(ctx context.Context, ids []types.PbmProfileId) ([]types.PbmProfileOperationOutcome, error) {
	req := types.PbmDelete{
		This:      c.ServiceContent.ProfileManager,
		ProfileId: ids,
	}

	res, err := methods.PbmDelete(ctx, c, &req)
	if err != nil {
		return nil, err
	}

	return res.Returnval, nil
}

func (c *Client) QueryAssociatedEntity(ctx context.Context, id types.PbmProfileId, entityType string) ([]types.PbmServerObjectRef, error) {
	req := types.PbmQueryAssociatedEntity{
		This:       c.ServiceContent.ProfileManager,
		Profile:    id,
		EntityType: entityType,
	}

	res, err := methods.PbmQueryAssociatedEntity(ctx, c, &req)
	if err != nil {
		return nil, err
	}

	return res.Returnval, nil
}

func (c *Client) QueryAssociatedEntities(ctx context.Context, ids []types.PbmProfileId) ([]types.PbmQueryProfileResult, error) {
	req := types.PbmQueryAssociatedEntities{
		This:     c.ServiceContent.ProfileManager,
		Profiles: ids,
	}

	res, err := methods.PbmQueryAssociatedEntities(ctx, c, &req)
	if err != nil {
		return nil, err
	}

	return res.Returnval, nil
}

func (c *Client) ProfileIDByName(ctx context.Context, profileName string) (string, error) {
	resourceType := types.PbmProfileResourceType{
		ResourceType: string(types.PbmProfileResourceTypeEnumSTORAGE),
	}
	category := types.PbmProfileCategoryEnumREQUIREMENT
	ids, err := c.QueryProfile(ctx, resourceType, string(category))
	if err != nil {
		return "", err
	}

	profiles, err := c.RetrieveContent(ctx, ids)
	if err != nil {
		return "", err
	}

	for i := range profiles {
		profile := profiles[i].GetPbmProfile()
		if profile.Name == profileName {
			return profile.ProfileId.UniqueId, nil
		}
	}
	return "", fmt.Errorf("no pbm profile found with name: %q", profileName)
}

func (c *Client) FetchCapabilityMetadata(ctx context.Context, rtype *types.PbmProfileResourceType, vendorUuid string) ([]types.PbmCapabilityMetadataPerCategory, error) {
	req := types.PbmFetchCapabilityMetadata{
		This:         c.ServiceContent.ProfileManager,
		ResourceType: rtype,
		VendorUuid:   vendorUuid,
	}

	res, err := methods.PbmFetchCapabilityMetadata(ctx, c, &req)
	if err != nil {
		return nil, err
	}

	return res.Returnval, nil
}
<|endoftext|>


<commit_before>package carbon

/*
Schemas read code from https://github.com/grobian/carbonwriter/
*/

import (
	"fmt"
	"regexp"
	"sort"
	"strconv"
	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/alyu/configparser"
	"github.com/grobian/go-whisper"
)

type whisperSchemaItem struct {
	name         string
	pattern      *regexp.Regexp
	retentionStr string
	retentions   whisper.Retentions
	priority     int
}

type whisperSchemaItemByPriority []*whisperSchemaItem

func (v whisperSchemaItemByPriority) Len() int           { return len(v) }
func (v whisperSchemaItemByPriority) Swap(i, j int)      { v[i], v[j] = v[j], v[i] }
func (v whisperSchemaItemByPriority) Less(i, j int) bool { return v[i].priority >= v[j].priority }

// WhisperSchemas ...
type WhisperSchemas struct {
	Data []*whisperSchemaItem
}

// ParseRetentionDefs copy of original ParseRetentionDefs from go-whisper
// With support where old format:
//   secondsPerPoint:numberOfPoints
func ParseRetentionDefs(retentionDefs string) (whisper.Retentions, error) {
	retentions := make(whisper.Retentions, 0)
	for _, retentionDef := range strings.Split(retentionDefs, ",") {
		// check if old format
		row := strings.Split(retentionDef, ":")
		if len(row) == 2 {
			val1, err1 := strconv.ParseInt(row[0], 10, 0)
			val2, err2 := strconv.ParseInt(row[1], 10, 0)

			if err1 == nil && err2 == nil {
				retentionDef = fmt.Sprintf("%d:%d", val1, val1*val2)
			}
		}

		// new format
		retention, err := whisper.ParseRetentionDef(retentionDef)
		if err != nil {
			return nil, err
		}
		retentions = append(retentions, retention)
	}
	return retentions, nil
}

// NewWhisperSchemas create instance of WhisperSchemas
func NewWhisperSchemas() *WhisperSchemas {
	return &WhisperSchemas{
		Data: make([]*whisperSchemaItem, 0),
	}
}

// ReadWhisperSchemas ...
func ReadWhisperSchemas(file string) (*WhisperSchemas, error) {
	config, err := configparser.Read(file)
	if err != nil {
		return nil, err
	}
	// pp.Println(config)
	sections, err := config.AllSections()
	if err != nil {
		return nil, err
	}

	result := NewWhisperSchemas()

	for _, s := range sections {
		item := &whisperSchemaItem{}
		// this is mildly stupid, but I don't feel like forking
		// configparser just for this
		item.name =
			strings.Trim(strings.SplitN(s.String(), "\n", 2)[0], " []")
		if item.name == "" {
			continue
		}
		item.pattern, err = regexp.Compile(s.ValueOf("pattern"))
		if err != nil {
			logrus.Errorf("failed to parse pattern '%s'for [%s]: %s",
				s.ValueOf("pattern"), item.name, err.Error())
			return nil, err
		}
		item.retentionStr = s.ValueOf("retentions")
		item.retentions, err = ParseRetentionDefs(item.retentionStr)

		p, err := strconv.ParseInt(s.ValueOf("priority"), 10, 0)
		if err != nil {
			return nil, err
		}
		item.priority = int(p)
		// item.priority = (s.ValueOf("priority"))
		logrus.Debugf("adding schema [%s] pattern = %s retentions = %s",
			item.name, s.ValueOf("pattern"), item.retentionStr)

		result.Data = append(result.Data, item)
	}

	sort.Sort(whisperSchemaItemByPriority(result.Data))

	return result, nil
}

// Match find schema for metric
func (s *WhisperSchemas) match(metric string) *whisperSchemaItem {
	for _, s := range s.Data {
		if s.pattern.MatchString(metric) {
			return s
		}
	}
	return nil
}
<commit_msg>sort schemas with same priority by position in file<commit_after>package carbon

/*
Schemas read code from https://github.com/grobian/carbonwriter/
*/

import (
	"fmt"
	"regexp"
	"sort"
	"strconv"
	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/alyu/configparser"
	"github.com/grobian/go-whisper"
)

type whisperSchemaItem struct {
	name         string
	pattern      *regexp.Regexp
	retentionStr string
	retentions   whisper.Retentions
	priority     int64
}

type whisperSchemaItemByPriority []*whisperSchemaItem

func (v whisperSchemaItemByPriority) Len() int           { return len(v) }
func (v whisperSchemaItemByPriority) Swap(i, j int)      { v[i], v[j] = v[j], v[i] }
func (v whisperSchemaItemByPriority) Less(i, j int) bool { return v[i].priority >= v[j].priority }

// WhisperSchemas ...
type WhisperSchemas struct {
	Data []*whisperSchemaItem
}

// ParseRetentionDefs copy of original ParseRetentionDefs from go-whisper
// With support where old format:
//   secondsPerPoint:numberOfPoints
func ParseRetentionDefs(retentionDefs string) (whisper.Retentions, error) {
	retentions := make(whisper.Retentions, 0)
	for _, retentionDef := range strings.Split(retentionDefs, ",") {
		// check if old format
		row := strings.Split(retentionDef, ":")
		if len(row) == 2 {
			val1, err1 := strconv.ParseInt(row[0], 10, 0)
			val2, err2 := strconv.ParseInt(row[1], 10, 0)

			if err1 == nil && err2 == nil {
				retentionDef = fmt.Sprintf("%d:%d", val1, val1*val2)
			}
		}

		// new format
		retention, err := whisper.ParseRetentionDef(retentionDef)
		if err != nil {
			return nil, err
		}
		retentions = append(retentions, retention)
	}
	return retentions, nil
}

// NewWhisperSchemas create instance of WhisperSchemas
func NewWhisperSchemas() *WhisperSchemas {
	return &WhisperSchemas{
		Data: make([]*whisperSchemaItem, 0),
	}
}

// ReadWhisperSchemas ...
func ReadWhisperSchemas(file string) (*WhisperSchemas, error) {
	config, err := configparser.Read(file)
	if err != nil {
		return nil, err
	}
	// pp.Println(config)
	sections, err := config.AllSections()
	if err != nil {
		return nil, err
	}

	result := NewWhisperSchemas()

	for index, s := range sections {
		item := &whisperSchemaItem{}
		// this is mildly stupid, but I don't feel like forking
		// configparser just for this
		item.name =
			strings.Trim(strings.SplitN(s.String(), "\n", 2)[0], " []")
		if item.name == "" {
			continue
		}
		item.pattern, err = regexp.Compile(s.ValueOf("pattern"))
		if err != nil {
			logrus.Errorf("failed to parse pattern '%s'for [%s]: %s",
				s.ValueOf("pattern"), item.name, err.Error())
			return nil, err
		}
		item.retentionStr = s.ValueOf("retentions")
		item.retentions, err = ParseRetentionDefs(item.retentionStr)

		p, err := strconv.ParseInt(s.ValueOf("priority"), 10, 0)
		if err != nil {
			return nil, err
		}
		item.priority = int64(p)<<32 - int64(index) // for sort records with same priority
		// item.priority = (s.ValueOf("priority"))
		logrus.Debugf("adding schema [%s] pattern = %s retentions = %s",
			item.name, s.ValueOf("pattern"), item.retentionStr)

		result.Data = append(result.Data, item)
	}

	sort.Sort(whisperSchemaItemByPriority(result.Data))

	return result, nil
}

// Match find schema for metric
func (s *WhisperSchemas) match(metric string) *whisperSchemaItem {
	for _, s := range s.Data {
		if s.pattern.MatchString(metric) {
			return s
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package whm

import "github.com/letsencrypt-cpanel/cpanelgo"

func (a WhmApi) InstallServiceSslCertificate(service, crt, key, cabundle string) (BaseWhmApiResponse, error) {
	var out BaseWhmApiResponse

	err := a.WHMAPI1("install_service_ssl_certificate", cpanelgo.Args{
		"service":  service,
		"crt":      crt,
		"key":      key,
		"cabundle": cabundle,
	}, &out)
	if err == nil {
		err = out.Error()
	}

	return out, err
}

type FetchServiceSslComponentsAPIResponse struct {
	BaseWhmApiResponse
	Data struct {
		Services []struct {
			Service string `json:"service"`
		} `json:"services"`
	} `json:"data"`
}

func (r FetchServiceSslComponentsAPIResponse) Services() []string {
	out := []string{}
	for _, v := range r.Data.Services {
		out = append(out, v.Service)
	}
	return out
}

func (a WhmApi) FetchServiceSslComponents() (FetchServiceSslComponentsAPIResponse, error) {
	var out FetchServiceSslComponentsAPIResponse

	err := a.WHMAPI1("fetch_service_ssl_components", cpanelgo.Args{}, &out)
	if err == nil {
		err = out.Error()
	}

	return out, err
}
<commit_msg>Include more information in FetchServiceSslComponentsAPIResponse<commit_after>package whm

import "github.com/letsencrypt-cpanel/cpanelgo"

func (a WhmApi) InstallServiceSslCertificate(service, crt, key, cabundle string) (BaseWhmApiResponse, error) {
	var out BaseWhmApiResponse

	err := a.WHMAPI1("install_service_ssl_certificate", cpanelgo.Args{
		"service":  service,
		"crt":      crt,
		"key":      key,
		"cabundle": cabundle,
	}, &out)
	if err == nil {
		err = out.Error()
	}

	return out, err
}

type FetchServiceSslComponentsAPIResponse struct {
	BaseWhmApiResponse
	Data struct {
		Services []struct {
			Service         string `json:"service"`
			Certificate     string `json:"certificate"`
			CertificateInfo struct {
				IsSelfSigned int   `json:"is_self_signed"`
				NotAfter     int64 `json:"not_after"`
			} `json:"certificate_info"`
		} `json:"services"`
	} `json:"data"`
}

func (r FetchServiceSslComponentsAPIResponse) Services() []string {
	out := []string{}
	for _, v := range r.Data.Services {
		out = append(out, v.Service)
	}
	return out
}

func (a WhmApi) FetchServiceSslComponents() (FetchServiceSslComponentsAPIResponse, error) {
	var out FetchServiceSslComponentsAPIResponse

	err := a.WHMAPI1("fetch_service_ssl_components", cpanelgo.Args{}, &out)
	if err == nil {
		err = out.Error()
	}

	return out, err
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"strings"

	"gopkg.in/yaml.v2"

	"github.com/lxc/lxd"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/gnuflag"
	"github.com/lxc/lxd/shared/i18n"
)

type infoCmd struct {
	showLog bool
}

func (c *infoCmd) showByDefault() bool {
	return true
}

func (c *infoCmd) usage() string {
	return i18n.G(
		`List information on LXD servers and containers.

For a container:
 lxc info [<remote>:]container [--show-log]

For a server:
 lxc info [<remote>:]`)
}

func (c *infoCmd) flags() {
	gnuflag.BoolVar(&c.showLog, "show-log", false, i18n.G("Show the container's last 100 log lines?"))
}

func (c *infoCmd) run(config *lxd.Config, args []string) error {
	var remote string
	var cName string
	if len(args) == 1 {
		remote, cName = config.ParseRemoteAndContainer(args[0])
	} else {
		remote, cName = config.ParseRemoteAndContainer("")
	}

	d, err := lxd.NewClient(config, remote)
	if err != nil {
		return err
	}

	if cName == "" {
		return c.remoteInfo(d)
	} else {
		return c.containerInfo(d, cName, c.showLog)
	}
}

func (c *infoCmd) remoteInfo(d *lxd.Client) error {
	serverStatus, err := d.ServerStatus()
	if err != nil {
		return err
	}

	data, err := yaml.Marshal(&serverStatus)
	if err != nil {
		return err
	}

	fmt.Printf("%s", data)

	return nil
}

func (c *infoCmd) containerInfo(d *lxd.Client, name string, showLog bool) error {
	ct, err := d.ContainerInfo(name)
	if err != nil {
		return err
	}

	cs, err := d.ContainerState(name)
	if err != nil {
		return err
	}

	const layout = "2006/01/02 15:04 UTC"

	fmt.Printf(i18n.G("Name: %s")+"\n", ct.Name)
	if d.Remote != nil && d.Remote.Addr != "" {
		fmt.Printf(i18n.G("Remote: %s")+"\n", d.Remote.Addr)
	}
	fmt.Printf(i18n.G("Architecture: %s")+"\n", ct.Architecture)
	if ct.CreationDate.UTC().Unix() != 0 {
		fmt.Printf(i18n.G("Created: %s")+"\n", ct.CreationDate.UTC().Format(layout))
	}

	fmt.Printf(i18n.G("Status: %s")+"\n", ct.Status)
	if ct.Ephemeral {
		fmt.Printf(i18n.G("Type: ephemeral") + "\n")
	} else {
		fmt.Printf(i18n.G("Type: persistent") + "\n")
	}
	fmt.Printf(i18n.G("Profiles: %s")+"\n", strings.Join(ct.Profiles, ", "))
	if cs.Pid != 0 {
		fmt.Printf(i18n.G("Pid: %d")+"\n", cs.Pid)

		// IP addresses
		ipInfo := ""
		if cs.Network != nil {
			for netName, net := range cs.Network {
				vethStr := ""
				if net.HostName != "" {
					vethStr = fmt.Sprintf("\t%s", net.HostName)
				}

				for _, addr := range net.Addresses {
					ipInfo += fmt.Sprintf("  %s:\t%s\t%s%s\n", netName, addr.Family, addr.Address, vethStr)
				}
			}
		}

		if ipInfo != "" {
			fmt.Println(i18n.G("Ips:"))
			fmt.Printf(ipInfo)
		}
		fmt.Println(i18n.G("Resources:"))

		// Processes
		fmt.Printf("  "+i18n.G("Processes: %d")+"\n", cs.Processes)

		// Disk usage
		diskInfo := ""
		if cs.Disk != nil {
			for entry, disk := range cs.Disk {
				if disk.Usage != 0 {
					diskInfo += fmt.Sprintf("    %s: %s\n", entry, shared.GetByteSizeString(disk.Usage))
				}
			}
		}

		if diskInfo != "" {
			fmt.Println(i18n.G("  Disk usage:"))
			fmt.Printf(diskInfo)
		}

		// CPU usage
		cpuInfo := ""
		if cs.CPU.Usage != 0 {
			cpuInfo += fmt.Sprintf("    %s: %v\n", i18n.G("CPU usage (in seconds)"), cs.CPU.Usage/1000000000)
		}

		if cpuInfo != "" {
			fmt.Println(i18n.G("  CPU usage:"))
			fmt.Printf(cpuInfo)
		}

		// Memory usage
		memoryInfo := ""
		if cs.Memory.Usage != 0 {
			memoryInfo += fmt.Sprintf("    %s: %s\n", i18n.G("Memory (current)"), shared.GetByteSizeString(cs.Memory.Usage))
		}

		if cs.Memory.UsagePeak != 0 {
			memoryInfo += fmt.Sprintf("    %s: %s\n", i18n.G("Memory (peak)"), shared.GetByteSizeString(cs.Memory.UsagePeak))
		}

		if cs.Memory.SwapUsage != 0 {
			memoryInfo += fmt.Sprintf("    %s: %s\n", i18n.G("Swap (current)"), shared.GetByteSizeString(cs.Memory.SwapUsage))
		}

		if cs.Memory.SwapUsagePeak != 0 {
			memoryInfo += fmt.Sprintf("    %s: %s\n", i18n.G("Swap (peak)"), shared.GetByteSizeString(cs.Memory.SwapUsagePeak))
		}

		if memoryInfo != "" {
			fmt.Println(i18n.G("  Memory usage:"))
			fmt.Printf(memoryInfo)
		}

		// Network usage
		networkInfo := ""
		if cs.Network != nil {
			for netName, net := range cs.Network {
				networkInfo += fmt.Sprintf("    %s:\n", netName)
				networkInfo += fmt.Sprintf("      %s: %s\n", i18n.G("Bytes received"), shared.GetByteSizeString(net.Counters.BytesReceived))
				networkInfo += fmt.Sprintf("      %s: %s\n", i18n.G("Bytes sent"), shared.GetByteSizeString(net.Counters.BytesSent))
				networkInfo += fmt.Sprintf("      %s: %d\n", i18n.G("Packets received"), net.Counters.PacketsReceived)
				networkInfo += fmt.Sprintf("      %s: %d\n", i18n.G("Packets sent"), net.Counters.PacketsSent)
			}
		}

		if networkInfo != "" {
			fmt.Println(i18n.G("  Network usage:"))
			fmt.Printf(networkInfo)
		}
	}

	// List snapshots
	first_snapshot := true
	snaps, err := d.ListSnapshots(name)
	if err != nil {
		return nil
	}

	for _, snap := range snaps {
		if first_snapshot {
			fmt.Println(i18n.G("Snapshots:"))
		}

		fields := strings.Split(snap.Name, shared.SnapshotDelimiter)
		fmt.Printf("  %s", fields[len(fields)-1])

		if snap.CreationDate.UTC().Unix() != 0 {
			fmt.Printf(" ("+i18n.G("taken at %s")+")", snap.CreationDate.UTC().Format(layout))
		}

		if snap.Stateful {
			fmt.Printf(" (" + i18n.G("stateful") + ")")
		} else {
			fmt.Printf(" (" + i18n.G("stateless") + ")")
		}
		fmt.Printf("\n")

		first_snapshot = false
	}

	if showLog {
		log, err := d.GetLog(name, "lxc.log")
		if err != nil {
			return err
		}

		stuff, err := ioutil.ReadAll(log)
		if err != nil {
			return err
		}

		fmt.Printf("\n"+i18n.G("Log:")+"\n\n%s\n", string(stuff))
	}

	return nil
}
<commit_msg>info: Update help<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"strings"

	"gopkg.in/yaml.v2"

	"github.com/lxc/lxd"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/gnuflag"
	"github.com/lxc/lxd/shared/i18n"
)

type infoCmd struct {
	showLog bool
}

func (c *infoCmd) showByDefault() bool {
	return true
}

func (c *infoCmd) usage() string {
	return i18n.G(
		`List information on LXD servers and containers.

For a container:
    lxc info [<remote:>]<container> [--show-log]

For a server:
    lxc info [<remote:>]`)
}

func (c *infoCmd) flags() {
	gnuflag.BoolVar(&c.showLog, "show-log", false, i18n.G("Show the container's last 100 log lines?"))
}

func (c *infoCmd) run(config *lxd.Config, args []string) error {
	var remote string
	var cName string
	if len(args) == 1 {
		remote, cName = config.ParseRemoteAndContainer(args[0])
	} else {
		remote, cName = config.ParseRemoteAndContainer("")
	}

	d, err := lxd.NewClient(config, remote)
	if err != nil {
		return err
	}

	if cName == "" {
		return c.remoteInfo(d)
	} else {
		return c.containerInfo(d, cName, c.showLog)
	}
}

func (c *infoCmd) remoteInfo(d *lxd.Client) error {
	serverStatus, err := d.ServerStatus()
	if err != nil {
		return err
	}

	data, err := yaml.Marshal(&serverStatus)
	if err != nil {
		return err
	}

	fmt.Printf("%s", data)

	return nil
}

func (c *infoCmd) containerInfo(d *lxd.Client, name string, showLog bool) error {
	ct, err := d.ContainerInfo(name)
	if err != nil {
		return err
	}

	cs, err := d.ContainerState(name)
	if err != nil {
		return err
	}

	const layout = "2006/01/02 15:04 UTC"

	fmt.Printf(i18n.G("Name: %s")+"\n", ct.Name)
	if d.Remote != nil && d.Remote.Addr != "" {
		fmt.Printf(i18n.G("Remote: %s")+"\n", d.Remote.Addr)
	}
	fmt.Printf(i18n.G("Architecture: %s")+"\n", ct.Architecture)
	if ct.CreationDate.UTC().Unix() != 0 {
		fmt.Printf(i18n.G("Created: %s")+"\n", ct.CreationDate.UTC().Format(layout))
	}

	fmt.Printf(i18n.G("Status: %s")+"\n", ct.Status)
	if ct.Ephemeral {
		fmt.Printf(i18n.G("Type: ephemeral") + "\n")
	} else {
		fmt.Printf(i18n.G("Type: persistent") + "\n")
	}
	fmt.Printf(i18n.G("Profiles: %s")+"\n", strings.Join(ct.Profiles, ", "))
	if cs.Pid != 0 {
		fmt.Printf(i18n.G("Pid: %d")+"\n", cs.Pid)

		// IP addresses
		ipInfo := ""
		if cs.Network != nil {
			for netName, net := range cs.Network {
				vethStr := ""
				if net.HostName != "" {
					vethStr = fmt.Sprintf("\t%s", net.HostName)
				}

				for _, addr := range net.Addresses {
					ipInfo += fmt.Sprintf("  %s:\t%s\t%s%s\n", netName, addr.Family, addr.Address, vethStr)
				}
			}
		}

		if ipInfo != "" {
			fmt.Println(i18n.G("Ips:"))
			fmt.Printf(ipInfo)
		}
		fmt.Println(i18n.G("Resources:"))

		// Processes
		fmt.Printf("  "+i18n.G("Processes: %d")+"\n", cs.Processes)

		// Disk usage
		diskInfo := ""
		if cs.Disk != nil {
			for entry, disk := range cs.Disk {
				if disk.Usage != 0 {
					diskInfo += fmt.Sprintf("    %s: %s\n", entry, shared.GetByteSizeString(disk.Usage))
				}
			}
		}

		if diskInfo != "" {
			fmt.Println(i18n.G("  Disk usage:"))
			fmt.Printf(diskInfo)
		}

		// CPU usage
		cpuInfo := ""
		if cs.CPU.Usage != 0 {
			cpuInfo += fmt.Sprintf("    %s: %v\n", i18n.G("CPU usage (in seconds)"), cs.CPU.Usage/1000000000)
		}

		if cpuInfo != "" {
			fmt.Println(i18n.G("  CPU usage:"))
			fmt.Printf(cpuInfo)
		}

		// Memory usage
		memoryInfo := ""
		if cs.Memory.Usage != 0 {
			memoryInfo += fmt.Sprintf("    %s: %s\n", i18n.G("Memory (current)"), shared.GetByteSizeString(cs.Memory.Usage))
		}

		if cs.Memory.UsagePeak != 0 {
			memoryInfo += fmt.Sprintf("    %s: %s\n", i18n.G("Memory (peak)"), shared.GetByteSizeString(cs.Memory.UsagePeak))
		}

		if cs.Memory.SwapUsage != 0 {
			memoryInfo += fmt.Sprintf("    %s: %s\n", i18n.G("Swap (current)"), shared.GetByteSizeString(cs.Memory.SwapUsage))
		}

		if cs.Memory.SwapUsagePeak != 0 {
			memoryInfo += fmt.Sprintf("    %s: %s\n", i18n.G("Swap (peak)"), shared.GetByteSizeString(cs.Memory.SwapUsagePeak))
		}

		if memoryInfo != "" {
			fmt.Println(i18n.G("  Memory usage:"))
			fmt.Printf(memoryInfo)
		}

		// Network usage
		networkInfo := ""
		if cs.Network != nil {
			for netName, net := range cs.Network {
				networkInfo += fmt.Sprintf("    %s:\n", netName)
				networkInfo += fmt.Sprintf("      %s: %s\n", i18n.G("Bytes received"), shared.GetByteSizeString(net.Counters.BytesReceived))
				networkInfo += fmt.Sprintf("      %s: %s\n", i18n.G("Bytes sent"), shared.GetByteSizeString(net.Counters.BytesSent))
				networkInfo += fmt.Sprintf("      %s: %d\n", i18n.G("Packets received"), net.Counters.PacketsReceived)
				networkInfo += fmt.Sprintf("      %s: %d\n", i18n.G("Packets sent"), net.Counters.PacketsSent)
			}
		}

		if networkInfo != "" {
			fmt.Println(i18n.G("  Network usage:"))
			fmt.Printf(networkInfo)
		}
	}

	// List snapshots
	first_snapshot := true
	snaps, err := d.ListSnapshots(name)
	if err != nil {
		return nil
	}

	for _, snap := range snaps {
		if first_snapshot {
			fmt.Println(i18n.G("Snapshots:"))
		}

		fields := strings.Split(snap.Name, shared.SnapshotDelimiter)
		fmt.Printf("  %s", fields[len(fields)-1])

		if snap.CreationDate.UTC().Unix() != 0 {
			fmt.Printf(" ("+i18n.G("taken at %s")+")", snap.CreationDate.UTC().Format(layout))
		}

		if snap.Stateful {
			fmt.Printf(" (" + i18n.G("stateful") + ")")
		} else {
			fmt.Printf(" (" + i18n.G("stateless") + ")")
		}
		fmt.Printf("\n")

		first_snapshot = false
	}

	if showLog {
		log, err := d.GetLog(name, "lxc.log")
		if err != nil {
			return err
		}

		stuff, err := ioutil.ReadAll(log)
		if err != nil {
			return err
		}

		fmt.Printf("\n"+i18n.G("Log:")+"\n\n%s\n", string(stuff))
	}

	return nil
}
<|endoftext|>


<commit_before>/*
 * lxc_test.go: Go bindings for lxc
 *
 * Copyright © 2013, S.Çağlar Onur
 *
 * Authors:
 * S.Çağlar Onur <caglar@10ur.org>
 *
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2, as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

package lxc

import (
	"fmt"
	"strings"
	"testing"
)

const (
	CONTAINER_NAME = "rubik"
	CONFIG_FILE_NAME = "/var/lib/lxc/rubik/config"
)

func TestDefined_Negative(t *testing.T) {
	z := NewContainer(CONTAINER_NAME)

	if z.Defined() {
		t.Errorf("Defined_Negative failed...")
	}
}

func TestCreate(t *testing.T) {
	z := NewContainer(CONTAINER_NAME)

	fmt.Printf("Creating the container...\n")
	z.Create("ubuntu", []string{"amd64", "quantal"})

	if !z.Defined() {
		t.Errorf("Creating the container failed...")
	}
}

func TestGetConfigFileName(t *testing.T) {
	z := NewContainer(CONTAINER_NAME)
	if z.GetConfigFileName() != CONFIG_FILE_NAME {
		t.Errorf("GetConfigFileName failed...")
	}
}

func TestDefined_Positive(t *testing.T) {
	z := NewContainer(CONTAINER_NAME)

	if !z.Defined() {
		t.Errorf("Defined failed...")
	}
}

func TestInitPID_Negative(t *testing.T) {
   	z := NewContainer(CONTAINER_NAME)

	if z.GetInitPID() != -1 {
		t.Errorf("GetInitPID failed...")
	}
}

func TestStart(t *testing.T) {
	z := NewContainer(CONTAINER_NAME)

	fmt.Printf("Starting the container...\n")
	z.SetDaemonize()
	z.Start(false, nil)

	z.Wait(RUNNING, 5)
	if !z.Running() {
		t.Errorf("Starting the container failed...")
	}
}

func TestSetDaemonize(t *testing.T) {
        z := NewContainer(CONTAINER_NAME)

	z.SetDaemonize()
	if !z.GetDaemonize() {
		t.Errorf("GetDaemonize failed...")
	}
}

func TestInitPID_Positive(t *testing.T) {
   	z := NewContainer(CONTAINER_NAME)

	if z.GetInitPID() == -1 {
		t.Errorf("GetInitPID failed...")
	}
}

func TestGetName(t *testing.T) {
   	z := NewContainer(CONTAINER_NAME)

	if z.GetName() != CONTAINER_NAME {
		t.Errorf("GetName failed...")
	}
}

func TestFreeze(t *testing.T) {
	z := NewContainer(CONTAINER_NAME)

	fmt.Printf("Freezing the container...\n")
	z.Freeze()

	z.Wait(FROZEN, 5)
	if z.GetState() != "FROZEN" {
		t.Errorf("Freezing the container failed...")
	}
}

func TestUnfreeze(t *testing.T) {
	z := NewContainer(CONTAINER_NAME)

	fmt.Printf("Unfreezing the container...\n")
	z.Unfreeze()

	z.Wait(RUNNING, 5)
	if z.GetState() != "RUNNING" {
		t.Errorf("Unfreezing the container failed...")
	}
}

func TestLoadConfigFile(t *testing.T) {
	z := NewContainer(CONTAINER_NAME)

	if !z.LoadConfigFile(CONFIG_FILE_NAME) {
		t.Errorf("LoadConfigFile failed...")
	}
}

func TestSaveConfigFile(t *testing.T) {
	z := NewContainer(CONTAINER_NAME)

	if !z.SaveConfigFile(CONFIG_FILE_NAME) {
		t.Errorf("LoadConfigFile failed...")
	}
}

func TestGetConfigItem(t *testing.T) {
        z := NewContainer(CONTAINER_NAME)

	if z.GetConfigItem("lxc.utsname")[0] != CONTAINER_NAME {
		t.Errorf("GetConfigItem failed...")
	}
}

func TestSetConfigItem(t *testing.T) {
        z := NewContainer(CONTAINER_NAME)

	z.SetConfigItem("lxc.utsname", CONTAINER_NAME)
	if z.GetConfigItem("lxc.utsname")[0] != CONTAINER_NAME {
		t.Errorf("GetConfigItem failed...")
	}
}

func TestClearConfigItem(t *testing.T) {
        z := NewContainer(CONTAINER_NAME)

	z.ClearConfigItem("lxc.cap.drop")
	if z.GetConfigItem("lxc.cap.drop")[0] != "" {
		t.Errorf("ClearConfigItem failed...")
	}
}

func TestGetKeys(t *testing.T) {
	z := NewContainer(CONTAINER_NAME)

	keys := strings.Join(z.GetKeys("lxc.network.0"), " ")
	if !strings.Contains(keys, "mtu") {
		t.Errorf("GetKeys failed...")
	}
}

func TestShutdown(t *testing.T) {
	z := NewContainer(CONTAINER_NAME)

	fmt.Printf("Shutting down the container...\n")
	z.Shutdown(30)
	if z.Running() {
		t.Errorf("Shutting down the container failed...")
	}
}

func TestStop(t *testing.T) {
	z := NewContainer(CONTAINER_NAME)

	fmt.Printf("Stopping the container...\n")
	z.Stop()
	if z.Running() {
		t.Errorf("Stopping the container failed...")
	}
}

func TestDestroy(t *testing.T) {
	z := NewContainer(CONTAINER_NAME)

	fmt.Printf("Destroying the container...\n")
	z.Destroy()

	if z.Defined() {
		t.Errorf("Destroying the container failed...")
	}
}
<commit_msg>gofmt<commit_after>/*
 * lxc_test.go: Go bindings for lxc
 *
 * Copyright © 2013, S.Çağlar Onur
 *
 * Authors:
 * S.Çağlar Onur <caglar@10ur.org>
 *
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2, as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

package lxc

import (
	"fmt"
	"strings"
	"testing"
)

const (
	CONTAINER_NAME   = "rubik"
	CONFIG_FILE_NAME = "/var/lib/lxc/rubik/config"
)

func TestDefined_Negative(t *testing.T) {
	z := NewContainer(CONTAINER_NAME)

	if z.Defined() {
		t.Errorf("Defined_Negative failed...")
	}
}

func TestCreate(t *testing.T) {
	z := NewContainer(CONTAINER_NAME)

	fmt.Printf("Creating the container...\n")
	z.Create("ubuntu", []string{"amd64", "quantal"})

	if !z.Defined() {
		t.Errorf("Creating the container failed...")
	}
}

func TestGetConfigFileName(t *testing.T) {
	z := NewContainer(CONTAINER_NAME)
	if z.GetConfigFileName() != CONFIG_FILE_NAME {
		t.Errorf("GetConfigFileName failed...")
	}
}

func TestDefined_Positive(t *testing.T) {
	z := NewContainer(CONTAINER_NAME)

	if !z.Defined() {
		t.Errorf("Defined failed...")
	}
}

func TestInitPID_Negative(t *testing.T) {
	z := NewContainer(CONTAINER_NAME)

	if z.GetInitPID() != -1 {
		t.Errorf("GetInitPID failed...")
	}
}

func TestStart(t *testing.T) {
	z := NewContainer(CONTAINER_NAME)

	fmt.Printf("Starting the container...\n")
	z.SetDaemonize()
	z.Start(false, nil)

	z.Wait(RUNNING, 5)
	if !z.Running() {
		t.Errorf("Starting the container failed...")
	}
}

func TestSetDaemonize(t *testing.T) {
	z := NewContainer(CONTAINER_NAME)

	z.SetDaemonize()
	if !z.GetDaemonize() {
		t.Errorf("GetDaemonize failed...")
	}
}

func TestInitPID_Positive(t *testing.T) {
	z := NewContainer(CONTAINER_NAME)

	if z.GetInitPID() == -1 {
		t.Errorf("GetInitPID failed...")
	}
}

func TestGetName(t *testing.T) {
	z := NewContainer(CONTAINER_NAME)

	if z.GetName() != CONTAINER_NAME {
		t.Errorf("GetName failed...")
	}
}

func TestFreeze(t *testing.T) {
	z := NewContainer(CONTAINER_NAME)

	fmt.Printf("Freezing the container...\n")
	z.Freeze()

	z.Wait(FROZEN, 5)
	if z.GetState() != "FROZEN" {
		t.Errorf("Freezing the container failed...")
	}
}

func TestUnfreeze(t *testing.T) {
	z := NewContainer(CONTAINER_NAME)

	fmt.Printf("Unfreezing the container...\n")
	z.Unfreeze()

	z.Wait(RUNNING, 5)
	if z.GetState() != "RUNNING" {
		t.Errorf("Unfreezing the container failed...")
	}
}

func TestLoadConfigFile(t *testing.T) {
	z := NewContainer(CONTAINER_NAME)

	if !z.LoadConfigFile(CONFIG_FILE_NAME) {
		t.Errorf("LoadConfigFile failed...")
	}
}

func TestSaveConfigFile(t *testing.T) {
	z := NewContainer(CONTAINER_NAME)

	if !z.SaveConfigFile(CONFIG_FILE_NAME) {
		t.Errorf("LoadConfigFile failed...")
	}
}

func TestGetConfigItem(t *testing.T) {
	z := NewContainer(CONTAINER_NAME)

	if z.GetConfigItem("lxc.utsname")[0] != CONTAINER_NAME {
		t.Errorf("GetConfigItem failed...")
	}
}

func TestSetConfigItem(t *testing.T) {
	z := NewContainer(CONTAINER_NAME)

	z.SetConfigItem("lxc.utsname", CONTAINER_NAME)
	if z.GetConfigItem("lxc.utsname")[0] != CONTAINER_NAME {
		t.Errorf("GetConfigItem failed...")
	}
}

func TestClearConfigItem(t *testing.T) {
	z := NewContainer(CONTAINER_NAME)

	z.ClearConfigItem("lxc.cap.drop")
	if z.GetConfigItem("lxc.cap.drop")[0] != "" {
		t.Errorf("ClearConfigItem failed...")
	}
}

func TestGetKeys(t *testing.T) {
	z := NewContainer(CONTAINER_NAME)

	keys := strings.Join(z.GetKeys("lxc.network.0"), " ")
	if !strings.Contains(keys, "mtu") {
		t.Errorf("GetKeys failed...")
	}
}

func TestShutdown(t *testing.T) {
	z := NewContainer(CONTAINER_NAME)

	fmt.Printf("Shutting down the container...\n")
	z.Shutdown(30)
	if z.Running() {
		t.Errorf("Shutting down the container failed...")
	}
}

func TestStop(t *testing.T) {
	z := NewContainer(CONTAINER_NAME)

	fmt.Printf("Stopping the container...\n")
	z.Stop()
	if z.Running() {
		t.Errorf("Stopping the container failed...")
	}
}

func TestDestroy(t *testing.T) {
	z := NewContainer(CONTAINER_NAME)

	fmt.Printf("Destroying the container...\n")
	z.Destroy()

	if z.Defined() {
		t.Errorf("Destroying the container failed...")
	}
}
<|endoftext|>


<commit_before>// +build mage

package main

import (
	"fmt"
	"os"
	"os/exec"
	"runtime"
	"time"

	"github.com/magefile/mage/mg"
	"github.com/magefile/mage/sh"
)

// warning shown when at least one dependency is not installed
var missingDepsWarning = `Dependencies %v are missing. Please install them and try again.
To learn how, visit our contributors guide: https://github.com/getfider/fider/blob/master/CONTRIBUTING.md.
`

// required dependencies for building fider
var requiredDeps = []string{
	"air",
	"godotenv",
	"docker",
	"npm",
	"node",
	"mage",
	"golangci-lint",
}
var buildTime = time.Now().Format("2006.01.02.150405")
var buildNumber = os.Getenv("CIRCLE_BUILD_NUM")
var exeName = "fider"

var Aliases = map[string]interface{}{
	"build": Build.All,
	"test":  Test.All,
	"watch": Watch.All,
	"lint":  Lint.All,
}

func init() {
	os.Setenv("MAGEFILE_VERBOSE", "true")
	if runtime.GOOS == "windows" {
		exeName = "fider.exe"
	}

	missingDeps := missingDependencies()
	if len(missingDeps) > 0 {
		fmt.Printf(missingDepsWarning, missingDeps)
		os.Exit(1)
	}
}

func Run() error {
	return sh.Run("godotenv", "-f", ".env", "./"+exeName)
}

func Migrate() error {
	return sh.Run("godotenv", "-f", ".env", "./"+exeName, "migrate")
}

func Clean() error {
	os.RemoveAll("./dist")
	return os.Mkdir("./dist", 0777)
}

type Watch mg.Namespace

func (Watch) All() {
	Clean()
	Migrate()
	mg.Deps(Watch.Server, Watch.UI)
}

func (Watch) UI() error {
	return sh.Run("npx", "webpack", "-w")
}

func (Watch) Server() error {
	return sh.Run("air", "-c", "air.conf")
}

type Build mg.Namespace

func (Build) All() {
	mg.Deps(Build.Server, Build.UI)
}

func (Build) Docker() error {
	mg.Deps(Build.UI)
	if err := buildServer(map[string]string{
		"CGO_ENABLED": "0",
		"GOOS":        "linux",
		"GOARCH":      "amd64",
	}); err != nil {
		return err
	}

	return sh.Run("docker", "build", "-t", "getfider/fider", ".")
}

func (Build) Server() error {
	return buildServer(map[string]string{
		"GOOS":   runtime.GOOS,
		"GOARCH": runtime.GOARCH,
	})
}

func (Build) UI() error {
	mg.Deps(Clean)
	env := map[string]string{"NODE_ENV": "production"}
	return sh.RunWith(env, "npx", "webpack", "-p")
}

type Test mg.Namespace

func (Test) All() {
	mg.Deps(Test.Server, Test.UI)
}

func (Test) Coverage() error {
	mg.Deps(Build.Server)
	sh.Run("godotenv", "-f", ".test.env", "./"+exeName, "migrate")
	return sh.Run("godotenv", "-f", ".test.env", "go", "test", "./...", "-coverprofile=cover.out", "-coverpkg=all", "-p=8", "-race")
}

func (Test) Server() error {
	mg.Deps(Build.Server)
	sh.Run("godotenv", "-f", ".test.env", "./"+exeName, "migrate")
	return sh.Run("godotenv", "-f", ".test.env", "go", "test", "./...", "-race")
}

func (Test) UI() error {
	env := map[string]string{"TZ": "GMT"}
	return sh.RunWith(env, "npx", "jest", "./public")
}

type Lint mg.Namespace

func (Lint) All() {
	mg.Deps(Lint.Server, Lint.UI)
}

func (Lint) UI() error {
	return sh.Run("npx", "tslint", "-c", "tslint.json", "'public/**/*.{ts,tsx}'", "'tests/**/*.{ts,tsx}'")
}

func (Lint) Server() error {
	return sh.Run("golangci-lint", "run")
}

// Utils
func buildServer(env map[string]string) error {
	ldflags := "-s -w -X main.buildtime=" + buildTime + " -X main.buildnumber=" + buildNumber
	return sh.RunWith(env, "go", "build", "-ldflags", ldflags, "-o", exeName, ".")
}

func missingDependencies() []string {
	var missingDeps []string
	for _, dep := range requiredDeps {
		_, err := exec.LookPath(dep)
		if err != nil {
			missingDeps = append(missingDeps, dep)
		}
	}
	return missingDeps
}
<commit_msg>fix: wait for migration to complete before starting app (#799)<commit_after>// +build mage

package main

import (
	"fmt"
	"os"
	"os/exec"
	"runtime"
	"time"

	"github.com/magefile/mage/mg"
	"github.com/magefile/mage/sh"
)

// warning shown when at least one dependency is not installed
var missingDepsWarning = `Dependencies %v are missing. Please install them and try again.
To learn how, visit our contributors guide: https://github.com/getfider/fider/blob/master/CONTRIBUTING.md.
`

// required dependencies for building fider
var requiredDeps = []string{
	"air",
	"godotenv",
	"docker",
	"npm",
	"node",
	"mage",
	"golangci-lint",
}
var buildTime = time.Now().Format("2006.01.02.150405")
var buildNumber = os.Getenv("CIRCLE_BUILD_NUM")
var exeName = "fider"

var Aliases = map[string]interface{}{
	"build": Build.All,
	"test":  Test.All,
	"watch": Watch.All,
	"lint":  Lint.All,
}

func init() {
	os.Setenv("MAGEFILE_VERBOSE", "true")
	if runtime.GOOS == "windows" {
		exeName = "fider.exe"
	}

	missingDeps := missingDependencies()
	if len(missingDeps) > 0 {
		fmt.Printf(missingDepsWarning, missingDeps)
		os.Exit(1)
	}
}

func Run() error {
	return sh.Run("godotenv", "-f", ".env", "./"+exeName)
}

func Migrate() error {
	return sh.Run("godotenv", "-f", ".env", "./"+exeName, "migrate")
}

func Clean() error {
	os.RemoveAll("./dist")
	return os.Mkdir("./dist", 0777)
}

type Watch mg.Namespace

func (Watch) All() {
	mg.SerialDeps(Clean, Build.Server, Migrate)
	mg.Deps(Watch.Server, Watch.UI)
}

func (Watch) UI() error {
	return sh.Run("npx", "webpack", "-w")
}

func (Watch) Server() error {
	return sh.Run("air", "-c", "air.conf")
}

type Build mg.Namespace

func (Build) All() {
	mg.Deps(Build.Server, Build.UI)
}

func (Build) Docker() error {
	mg.Deps(Build.UI)
	if err := buildServer(map[string]string{
		"CGO_ENABLED": "0",
		"GOOS":        "linux",
		"GOARCH":      "amd64",
	}); err != nil {
		return err
	}

	return sh.Run("docker", "build", "-t", "getfider/fider", ".")
}

func (Build) Server() error {
	return buildServer(map[string]string{
		"GOOS":   runtime.GOOS,
		"GOARCH": runtime.GOARCH,
	})
}

func (Build) UI() error {
	mg.Deps(Clean)
	env := map[string]string{"NODE_ENV": "production"}
	return sh.RunWith(env, "npx", "webpack", "-p")
}

type Test mg.Namespace

func (Test) All() {
	mg.Deps(Test.Server, Test.UI)
}

func (Test) Coverage() error {
	mg.Deps(Build.Server)
	sh.Run("godotenv", "-f", ".test.env", "./"+exeName, "migrate")
	return sh.Run("godotenv", "-f", ".test.env", "go", "test", "./...", "-coverprofile=cover.out", "-coverpkg=all", "-p=8", "-race")
}

func (Test) Server() error {
	mg.Deps(Build.Server)
	sh.Run("godotenv", "-f", ".test.env", "./"+exeName, "migrate")
	return sh.Run("godotenv", "-f", ".test.env", "go", "test", "./...", "-race")
}

func (Test) UI() error {
	env := map[string]string{"TZ": "GMT"}
	return sh.RunWith(env, "npx", "jest", "./public")
}

type Lint mg.Namespace

func (Lint) All() {
	mg.Deps(Lint.Server, Lint.UI)
}

func (Lint) UI() error {
	return sh.Run("npx", "tslint", "-c", "tslint.json", "'public/**/*.{ts,tsx}'", "'tests/**/*.{ts,tsx}'")
}

func (Lint) Server() error {
	return sh.Run("golangci-lint", "run")
}

// Utils
func buildServer(env map[string]string) error {
	ldflags := "-s -w -X main.buildtime=" + buildTime + " -X main.buildnumber=" + buildNumber
	return sh.RunWith(env, "go", "build", "-ldflags", ldflags, "-o", exeName, ".")
}

func missingDependencies() []string {
	var missingDeps []string
	for _, dep := range requiredDeps {
		_, err := exec.LookPath(dep)
		if err != nil {
			missingDeps = append(missingDeps, dep)
		}
	}
	return missingDeps
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"flag"
	"fmt"
	"os"
	"os/exec"
	"strings"
)

const bindatafile = "bindata.go"

func isDebug(args []string) bool {
	flagset := flag.NewFlagSet("", flag.ContinueOnError)
	debug := flagset.Bool("debug", false, "")
	debugArgs := make([]string, 0)
	for _, arg := range args {
		if strings.HasPrefix(arg, "-debug") {
			debugArgs = append(debugArgs, arg)
		}
	}
	flagset.Parse(debugArgs)
	if debug == nil {
		return false
	}
	return *debug
}

func main() {
	if _, err := exec.LookPath("go-bindata"); err != nil {
		fmt.Println("Cannot find go-bindata executable in path")
		fmt.Println("Maybe you need: go get github.com/elazarl/go-bindata-assetfs/...")
		os.Exit(1)
	}
	cmd := exec.Command("go-bindata", os.Args[1:]...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	if err := cmd.Run(); err != nil {
		os.Exit(1)
	}
	in, err := os.Open(bindatafile)
	if err != nil {
		fmt.Fprintln(os.Stderr, "Cannot read", bindatafile, err)
		return
	}
	out, err := os.Create("bindata_assetfs.go")
	if err != nil {
		fmt.Fprintln(os.Stderr, "Cannot write 'bindata_assetfs.go'", err)
		return
	}
	debug := isDebug(os.Args[1:])
	r := bufio.NewReader(in)
	done := false
	for line, isPrefix, err := r.ReadLine(); err == nil; line, isPrefix, err = r.ReadLine() {
		if !isPrefix {
			line = append(line, '\n')
		}
		if _, err := out.Write(line); err != nil {
			fmt.Fprintln(os.Stderr, "Cannot write to 'bindata_assetfs.go'", err)
			return
		}
		if !done && !isPrefix && bytes.HasPrefix(line, []byte("import (")) {
			if debug {
				fmt.Fprintln(out, "\t\"net/http\"")
			} else {
				fmt.Fprintln(out, "\t\"github.com/elazarl/go-bindata-assetfs\"")
			}
			done = true
		}
	}
	if debug {
		fmt.Fprintln(out, `
func assetFS() http.FileSystem {
	for k := range _bintree.Children {
		return http.Dir(k)
	}
	panic("unreachable")
}`)
	} else {
		fmt.Fprintln(out, `
func assetFS() *assetfs.AssetFS {
	for k := range _bintree.Children {
		return &assetfs.AssetFS{Asset: Asset, AssetDir: AssetDir, AssetInfo: AssetInfo, Prefix: k}
	}
	panic("unreachable")
}`)
	}
	// Close files BEFORE remove calls (don't use defer).
	in.Close()
	out.Close()
	if err := os.Remove(bindatafile); err != nil {
		fmt.Fprintln(os.Stderr, "Cannot remove", bindatafile, err)
	}
}
<commit_msg>Parse the output location for bindatafile<commit_after>package main

import (
	"bufio"
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
)

func isDebug(args []string) bool {
	flagset := flag.NewFlagSet("", flag.ContinueOnError)
	debug := flagset.Bool("debug", false, "")
	debugArgs := make([]string, 0)
	for _, arg := range args {
		if strings.HasPrefix(arg, "-debug") {
			debugArgs = append(debugArgs, arg)
		}
	}
	flagset.Parse(debugArgs)
	if debug == nil {
		return false
	}
	return *debug
}

func getBinDataFile() (*os.File, *os.File, []string, error) {
	bindataArgs := make([]string, 0)
	outputLoc := "bindata.go"

	for i := 1; i < len(os.Args); i++ {
		if os.Args[i] == "-o" {
			outputLoc = os.Args[i+1]
			i++
		} else {
			bindataArgs = append(bindataArgs, os.Args[i])
		}
	}

	tempFile, err := ioutil.TempFile(os.TempDir(), "")
	if err != nil {
		return &os.File{}, &os.File{}, nil, err
	}

	outputFile, err := os.Create(outputLoc)
	if err != nil {
		return &os.File{}, &os.File{}, nil, err
	}

	bindataArgs = append([]string{"-o", tempFile.Name()}, bindataArgs...)
	return outputFile, tempFile, bindataArgs, nil
}

func main() {
	path, err := exec.LookPath("go-bindata")
	if err != nil {
		fmt.Println("Cannot find go-bindata executable in path")
		fmt.Println("Maybe you need: go get github.com/elazarl/go-bindata-assetfs/...")
		os.Exit(1)
	}
	out, in, args, err := getBinDataFile()
	if err != nil {
		fmt.Fprintln(os.Stderr, "Error: cannot create temporary file", err)
		os.Exit(1)
	}
	cmd := exec.Command(path, args...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	if err := cmd.Run(); err != nil {
		fmt.Fprintln(os.Stderr, "Error: go-bindata: ", err)
		os.Exit(1)
	}
	debug := isDebug(os.Args[1:])
	r := bufio.NewReader(in)
	done := false
	for line, isPrefix, err := r.ReadLine(); err == nil; line, isPrefix, err = r.ReadLine() {
		if !isPrefix {
			line = append(line, '\n')
		}
		if _, err := out.Write(line); err != nil {
			fmt.Fprintln(os.Stderr, "Cannot write to ", out.Name(), err)
			return
		}
		if !done && !isPrefix && bytes.HasPrefix(line, []byte("import (")) {
			if debug {
				fmt.Fprintln(out, "\t\"net/http\"")
			} else {
				fmt.Fprintln(out, "\t\"github.com/elazarl/go-bindata-assetfs\"")
			}
			done = true
		}
	}
	if debug {
		fmt.Fprintln(out, `
func assetFS() http.FileSystem {
	for k := range _bintree.Children {
		return http.Dir(k)
	}
	panic("unreachable")
}`)
	} else {
		fmt.Fprintln(out, `
func assetFS() *assetfs.AssetFS {
	for k := range _bintree.Children {
		return &assetfs.AssetFS{Asset: Asset, AssetDir: AssetDir, AssetInfo: AssetInfo, Prefix: k}
	}
	panic("unreachable")
}`)
	}
	// Close files BEFORE remove calls (don't use defer).
	in.Close()
	out.Close()
	if err := os.Remove(in.Name()); err != nil {
		fmt.Fprintln(os.Stderr, "Cannot remove", in.Name(), err)
	}
}
<|endoftext|>


<commit_before>package sentry

import (
	"errors"
	"fmt"
	"log"
	"net/http"
	"strings"
	"sync"
	"time"

	"github.com/mozilla-services/go-bouncer/bouncer"
)

// Sentry contains sentry operations
type Sentry struct {
	DB      *bouncer.DB
	Verbose bool

	locations   []*bouncer.LocationsActiveResult
	mirrors     []*bouncer.MirrorsActiveResult
	startTime   time.Time
	runLck      sync.Mutex
	locationSem chan bool
	mirrorSem   chan bool

	client *http.Client
}

// New returns a new Sentry
func New(db *bouncer.DB, checknow bool, mirror string, mirrorRoutines, locRoutines int) (*Sentry, error) {
	locations, err := db.LocationsActive(checknow)
	if err != nil {
		return nil, fmt.Errorf("db.LocationsActive: %v", err)
	}

	mirrors, err := db.MirrorsActive(mirror)
	if err != nil {
		return nil, fmt.Errorf("db.MirrorsActive: %v", err)
	}

	client := &http.Client{
		CheckRedirect: func(req *http.Request, via []*http.Request) error {
			if len(via) >= 1 {
				return errors.New("Stopped after 1 redirect")
			}
			return nil
		},
	}

	return &Sentry{
		DB:          db,
		locations:   locations,
		mirrors:     mirrors,
		locationSem: make(chan bool, locRoutines),
		mirrorSem:   make(chan bool, mirrorRoutines),
		client:      client,
	}, nil
}

// Run starts a full sentry run
func (s *Sentry) Run() error {
	s.runLck.Lock()
	defer s.runLck.Unlock()

	wg := sync.WaitGroup{}

	s.startTime = time.Now()
	for _, mirror := range s.mirrors {
		s.mirrorSem <- true
		wg.Add(1)
		go func(mirror *bouncer.MirrorsActiveResult) {
			defer func() {
				<-s.mirrorSem
				wg.Done()
			}()
			if err := s.checkMirror(mirror); err != nil {
				log.Printf("Error checking mirror: %s err: %s", mirror.BaseURL, err)
			}
		}(mirror)
	}

	wg.Wait()
	return nil
}

func boolToString(b bool) string {
	if b {
		return "1"
	}
	return "0"
}

func (s *Sentry) checkLocation(mirror *bouncer.MirrorsActiveResult, location *bouncer.LocationsActiveResult, runLog *lockedWriter) error {
	lang := "en-US"

	if strings.Contains(location.Path, "/firefox/") &&
		!strings.Contains(location.Path, "/namoroka/") &&
		!strings.Contains(location.Path, "/devpreview/") &&
		!strings.Contains(location.Path, "3.6b1") &&
		!strings.Contains(location.Path, "wince-arm") &&
		!strings.Contains(strings.ToLower(location.Path), "euballot") {

		lang = "zh-TW"
	} else if strings.Contains(location.Path, "/thunderbird/") {
		if strings.Contains(location.Path, "3.1a1") {
			lang = "tr"
		} else {
			lang = "zh-TW"
		}
	} else if strings.Contains(location.Path, "/seamonkey/") {
		if strings.Contains(location.Path, "2.0.5") || strings.Contains(location.Path, "2.0.6") {
			lang = "zh-CN"
		} else {
			lang = "tr"
		}
	} else if strings.Contains(strings.ToLower(location.Path), "-euballot") {
		lang = "sv-SE"
	}

	path := strings.Replace(location.Path, ":lang", lang, -1)
	url := mirror.BaseURL + path

	start := time.Now()
	active, healthy := true, false

	resp, err := s.HeadLocation(url)
	elapsed := time.Now().Sub(start)
	if err != nil {
		active, healthy = true, false
		runLog.Printf("%s TOOK=%v ERR=%v\n", url, elapsed, err)
	} else {
		if resp.StatusCode == 200 && !strings.Contains(resp.Header.Get("Content-Type"), "text/html") {
			active, healthy = true, true
		} else if resp.StatusCode == 404 || resp.StatusCode == 403 {
			active, healthy = false, false
		}

		runLog.Printf("%s TOOK=%v RC=%d\n", url, elapsed, resp.StatusCode)
	}

	return s.DB.MirrorLocationUpdate(location.ID, mirror.ID, boolToString(active), boolToString(healthy))
}

func (s *Sentry) checkMirror(mirror *bouncer.MirrorsActiveResult) error {
	runLog := newLockedWriter()
	runLog.Printf("Checking mirror %s ...\n", mirror.BaseURL)

	// Check overall mirror health
	err := s.HeadMirror(mirror)
	if err != nil {
		if dberr := s.DB.MirrorSetHealth(mirror.ID, "0"); dberr != nil {
			return fmt.Errorf("MirrorSetHealth: %v", dberr)
		}
		if dberr := s.DB.SentryLogInsert(s.startTime, mirror.ID, "0", mirror.Rating, err.Error()); dberr != nil {
			return fmt.Errorf("SentryLogInsert: %v", dberr)
		}
		return fmt.Errorf("HeadMirror: %v", err)
	}

	// Check locations
	wg := sync.WaitGroup{}
	for _, location := range s.locations {
		s.locationSem <- true
		wg.Add(1)
		go func(location *bouncer.LocationsActiveResult) {
			defer func() {
				<-s.locationSem
				wg.Done()
			}()

			if err := s.checkLocation(mirror, location, runLog); err != nil {
				runLog.Printf("Error checking mirror: %s, location: %s, err: %v\n", mirror.ID, location.ID, err)
				return
			}

		}(location)
	}

	wg.Wait()

	if err := s.DB.SentryLogInsert(s.startTime, mirror.ID, "1", mirror.Rating, runLog.String()); err != nil {
		log.Println(err)
	}

	if s.Verbose {
		log.Println(runLog.String())
	}

	return nil
}

// HeadMirror returns error if mirror is not healthy
func (s *Sentry) HeadMirror(mirror *bouncer.MirrorsActiveResult) error {
	// Check DNS?

	req, err := http.NewRequest("HEAD", mirror.BaseURL, nil)
	if err != nil {
		return err
	}

	resp, err := http.DefaultTransport.RoundTrip(req)
	if err != nil {
		return err
	}
	if resp.StatusCode >= 500 {
		return fmt.Errorf("Bad Response: %s", resp.Status)
	}
	return nil

}

// HeadLocation makes a HEAD request to url and returns the response
func (s *Sentry) HeadLocation(url string) (resp *http.Response, err error) {

	req, err := http.NewRequest("HEAD", url, nil)
	if err != nil {
		return nil, err
	}

	return s.client.Do(req)
}
<commit_msg>sentry: make roundtripper configurable<commit_after>package sentry

import (
	"errors"
	"fmt"
	"log"
	"net/http"
	"strings"
	"sync"
	"time"

	"github.com/mozilla-services/go-bouncer/bouncer"
)

// Sentry contains sentry operations
type Sentry struct {
	DB      *bouncer.DB
	Verbose bool

	locations   []*bouncer.LocationsActiveResult
	mirrors     []*bouncer.MirrorsActiveResult
	startTime   time.Time
	runLck      sync.Mutex
	locationSem chan bool
	mirrorSem   chan bool

	client       *http.Client
	roundTripper http.RoundTripper
}

// New returns a new Sentry
func New(db *bouncer.DB, checknow bool, mirror string, mirrorRoutines, locRoutines int) (*Sentry, error) {
	locations, err := db.LocationsActive(checknow)
	if err != nil {
		return nil, fmt.Errorf("db.LocationsActive: %v", err)
	}

	mirrors, err := db.MirrorsActive(mirror)
	if err != nil {
		return nil, fmt.Errorf("db.MirrorsActive: %v", err)
	}

	client := &http.Client{
		CheckRedirect: func(req *http.Request, via []*http.Request) error {
			if len(via) >= 1 {
				return errors.New("Stopped after 1 redirect")
			}
			return nil
		},
	}

	return &Sentry{
		DB:           db,
		locations:    locations,
		mirrors:      mirrors,
		locationSem:  make(chan bool, locRoutines),
		mirrorSem:    make(chan bool, mirrorRoutines),
		client:       client,
		roundTripper: http.DefaultTransport,
	}, nil
}

// Run starts a full sentry run
func (s *Sentry) Run() error {
	s.runLck.Lock()
	defer s.runLck.Unlock()

	wg := sync.WaitGroup{}

	s.startTime = time.Now()
	for _, mirror := range s.mirrors {
		s.mirrorSem <- true
		wg.Add(1)
		go func(mirror *bouncer.MirrorsActiveResult) {
			defer func() {
				<-s.mirrorSem
				wg.Done()
			}()
			if err := s.checkMirror(mirror); err != nil {
				log.Printf("Error checking mirror: %s err: %s", mirror.BaseURL, err)
			}
		}(mirror)
	}

	wg.Wait()
	return nil
}

func boolToString(b bool) string {
	if b {
		return "1"
	}
	return "0"
}

func (s *Sentry) checkLocation(mirror *bouncer.MirrorsActiveResult, location *bouncer.LocationsActiveResult, runLog *lockedWriter) error {
	lang := "en-US"

	if strings.Contains(location.Path, "/firefox/") &&
		!strings.Contains(location.Path, "/namoroka/") &&
		!strings.Contains(location.Path, "/devpreview/") &&
		!strings.Contains(location.Path, "3.6b1") &&
		!strings.Contains(location.Path, "wince-arm") &&
		!strings.Contains(strings.ToLower(location.Path), "euballot") {

		lang = "zh-TW"
	} else if strings.Contains(location.Path, "/thunderbird/") {
		if strings.Contains(location.Path, "3.1a1") {
			lang = "tr"
		} else {
			lang = "zh-TW"
		}
	} else if strings.Contains(location.Path, "/seamonkey/") {
		if strings.Contains(location.Path, "2.0.5") || strings.Contains(location.Path, "2.0.6") {
			lang = "zh-CN"
		} else {
			lang = "tr"
		}
	} else if strings.Contains(strings.ToLower(location.Path), "-euballot") {
		lang = "sv-SE"
	}

	path := strings.Replace(location.Path, ":lang", lang, -1)
	url := mirror.BaseURL + path

	start := time.Now()
	active, healthy := true, false

	resp, err := s.HeadLocation(url)
	elapsed := time.Now().Sub(start)
	if err != nil {
		active, healthy = true, false
		runLog.Printf("%s TOOK=%v ERR=%v\n", url, elapsed, err)
	} else {
		if resp.StatusCode == 200 && !strings.Contains(resp.Header.Get("Content-Type"), "text/html") {
			active, healthy = true, true
		} else if resp.StatusCode == 404 || resp.StatusCode == 403 {
			active, healthy = false, false
		}

		runLog.Printf("%s TOOK=%v RC=%d\n", url, elapsed, resp.StatusCode)
	}

	return s.DB.MirrorLocationUpdate(location.ID, mirror.ID, boolToString(active), boolToString(healthy))
}

func (s *Sentry) checkMirror(mirror *bouncer.MirrorsActiveResult) error {
	runLog := newLockedWriter()
	runLog.Printf("Checking mirror %s ...\n", mirror.BaseURL)

	// Check overall mirror health
	err := s.HeadMirror(mirror)
	if err != nil {
		if dberr := s.DB.MirrorSetHealth(mirror.ID, "0"); dberr != nil {
			return fmt.Errorf("MirrorSetHealth: %v", dberr)
		}
		if dberr := s.DB.SentryLogInsert(s.startTime, mirror.ID, "0", mirror.Rating, err.Error()); dberr != nil {
			return fmt.Errorf("SentryLogInsert: %v", dberr)
		}
		return fmt.Errorf("HeadMirror: %v", err)
	}

	// Check locations
	wg := sync.WaitGroup{}
	for _, location := range s.locations {
		s.locationSem <- true
		wg.Add(1)
		go func(location *bouncer.LocationsActiveResult) {
			defer func() {
				<-s.locationSem
				wg.Done()
			}()

			if err := s.checkLocation(mirror, location, runLog); err != nil {
				runLog.Printf("Error checking mirror: %s, location: %s, err: %v\n", mirror.ID, location.ID, err)
				return
			}

		}(location)
	}

	wg.Wait()

	if err := s.DB.SentryLogInsert(s.startTime, mirror.ID, "1", mirror.Rating, runLog.String()); err != nil {
		log.Println(err)
	}

	if s.Verbose {
		log.Println(runLog.String())
	}

	return nil
}

// HeadMirror returns error if mirror is not healthy
func (s *Sentry) HeadMirror(mirror *bouncer.MirrorsActiveResult) error {
	// Check DNS?

	req, err := http.NewRequest("HEAD", mirror.BaseURL, nil)
	if err != nil {
		return err
	}

	resp, err := s.roundTripper.RoundTrip(req)
	if err != nil {
		return err
	}
	if resp.StatusCode >= 500 {
		return fmt.Errorf("Bad Response: %s", resp.Status)
	}
	return nil

}

// HeadLocation makes a HEAD request to url and returns the response
func (s *Sentry) HeadLocation(url string) (resp *http.Response, err error) {

	req, err := http.NewRequest("HEAD", url, nil)
	if err != nil {
		return nil, err
	}

	return s.client.Do(req)
}
<|endoftext|>


<commit_before>package engine

import (
	"bytes"

	"github.com/agl/ed25519"
	"golang.org/x/crypto/nacl/box"
	"golang.org/x/crypto/scrypt"

	"github.com/keybase/client/go/libkb"
)

type BackupKeygenArg struct {
	Passphrase string
	SkipPush   bool
	Me         *libkb.User
	SigningKey libkb.GenericKey
}

// BackupKeygen is an engine.
type BackupKeygen struct {
	arg    *BackupKeygenArg
	sigKey libkb.GenericKey
	encKey libkb.GenericKey
	libkb.Contextified
}

// NewBackupKeygen creates a BackupKeygen engine.
func NewBackupKeygen(arg *BackupKeygenArg, g *libkb.GlobalContext) *BackupKeygen {
	return &BackupKeygen{
		arg:          arg,
		Contextified: libkb.NewContextified(g),
	}
}

// Name is the unique engine name.
func (e *BackupKeygen) Name() string {
	return "BackupKeygen"
}

// GetPrereqs returns the engine prereqs.
func (e *BackupKeygen) Prereqs() Prereqs {
	// only need session if pushing keys
	return Prereqs{
		Session: !e.arg.SkipPush,
	}
}

// RequiredUIs returns the required UIs.
func (e *BackupKeygen) RequiredUIs() []libkb.UIKind {
	return []libkb.UIKind{}
}

// SubConsumers returns the other UI consumers for this engine.
func (e *BackupKeygen) SubConsumers() []libkb.UIConsumer {
	return []libkb.UIConsumer{
		&DetKeyEngine{},
	}
}

func (e *BackupKeygen) SigKey() libkb.GenericKey {
	return e.sigKey
}

func (e *BackupKeygen) EncKey() libkb.GenericKey {
	return e.encKey
}

// Run starts the engine.
func (e *BackupKeygen) Run(ctx *Context) error {
	// make the passphrase stream
	key, err := scrypt.Key([]byte(e.arg.Passphrase), nil,
		libkb.BackupKeyScryptCost, libkb.BackupKeyScryptR, libkb.BackupKeyScryptP, libkb.BackupKeyScryptKeylen)
	if err != nil {
		return err
	}

	var gen libkb.PassphraseGeneration
	err = e.G().LoginState().Account(func(a *libkb.Account) {
		gen = a.GetStreamGeneration()
		if gen < 1 && !e.arg.SkipPush {
			e.G().Log.Warning("invalid passphrase generation: %d", gen)
		}
	}, "BackupKeygen - Run")
	if err != nil {
		return err
	}

	ppStream := libkb.NewPassphraseStream(key)
	ppStream.SetGeneration(gen)

	// make keys for the backup device
	if err := e.makeSigKey(ppStream.EdDSASeed()); err != nil {
		return err
	}
	if err := e.makeEncKey(ppStream.DHSeed()); err != nil {
		return err
	}

	// push everything to the server
	if err := e.push(ctx); err != nil {
		return err
	}

	return nil
}

func (e *BackupKeygen) makeSigKey(seed []byte) error {
	pub, priv, err := ed25519.GenerateKey(bytes.NewBuffer(seed))
	if err != nil {
		return err
	}

	var key libkb.NaclSigningKeyPair
	copy(key.Public[:], (*pub)[:])
	key.Private = &libkb.NaclSigningKeyPrivate{}
	copy(key.Private[:], (*priv)[:])

	e.sigKey = key

	return nil
}

func (e *BackupKeygen) makeEncKey(seed []byte) error {
	pub, priv, err := box.GenerateKey(bytes.NewBuffer(seed))
	if err != nil {
		return err
	}
	var key libkb.NaclDHKeyPair
	copy(key.Public[:], (*pub)[:])
	key.Private = &libkb.NaclDHKeyPrivate{}
	copy(key.Private[:], (*priv)[:])

	e.encKey = key

	return nil
}

func (e *BackupKeygen) push(ctx *Context) error {
	if e.arg.SkipPush {
		return nil
	}

	// create a new backup device
	dev, err := libkb.NewBackupDevice()
	if err != nil {
		return err
	}

	// create lks halves for this device.  Note that they aren't used for
	// local, encrypted storage of the backup keys, but just for recovery
	// purposes.

	var ppgen libkb.PassphraseGeneration
	var clientHalf []byte
	e.G().LoginState().Account(func(a *libkb.Account) {
		ppgen = a.PassphraseStreamCache().PassphraseStream().Generation()
		clientHalf = a.PassphraseStreamCache().PassphraseStream().LksClientHalf()
	}, "BackupKeygen - push")

	lks := libkb.NewLKSec(clientHalf, ppgen, e.arg.Me.GetUID(), e.G())
	if err := lks.GenerateServerHalf(); err != nil {
		return err
	}
	ctext, err := lks.EncryptClientHalfRecovery(e.encKey)
	if err != nil {
		return err
	}

	// post them to the server.
	if err := libkb.PostDeviceLKS(ctx.LoginContext, dev.ID, libkb.DeviceTypeBackup, lks.GetServerHalf(), lks.Generation(), ctext, e.encKey.GetKID()); err != nil {
		return err
	}

	// push the backup signing key
	sigDel := libkb.Delegator{
		NewKey:      e.sigKey,
		Sibkey:      true,
		Expire:      libkb.NaclEdDSAExpireIn,
		ExistingKey: e.arg.SigningKey,
		Me:          e.arg.Me,
		Device:      dev,
	}
	if err := sigDel.Run(ctx.LoginContext); err != nil {
		return err
	}

	// push the backup encryption key
	sigEnc := libkb.Delegator{
		NewKey:      e.encKey,
		Sibkey:      false,
		Expire:      libkb.NaclDHExpireIn,
		ExistingKey: e.sigKey,
		Me:          e.arg.Me,
		Device:      dev,
	}
	if err := sigEnc.Run(ctx.LoginContext); err != nil {
		return err
	}

	return nil
}
<commit_msg>removed SetGeneration call<commit_after>package engine

import (
	"bytes"

	"github.com/agl/ed25519"
	"golang.org/x/crypto/nacl/box"
	"golang.org/x/crypto/scrypt"

	"github.com/keybase/client/go/libkb"
)

type BackupKeygenArg struct {
	Passphrase string
	SkipPush   bool
	Me         *libkb.User
	SigningKey libkb.GenericKey
}

// BackupKeygen is an engine.
type BackupKeygen struct {
	arg    *BackupKeygenArg
	sigKey libkb.GenericKey
	encKey libkb.GenericKey
	libkb.Contextified
}

// NewBackupKeygen creates a BackupKeygen engine.
func NewBackupKeygen(arg *BackupKeygenArg, g *libkb.GlobalContext) *BackupKeygen {
	return &BackupKeygen{
		arg:          arg,
		Contextified: libkb.NewContextified(g),
	}
}

// Name is the unique engine name.
func (e *BackupKeygen) Name() string {
	return "BackupKeygen"
}

// GetPrereqs returns the engine prereqs.
func (e *BackupKeygen) Prereqs() Prereqs {
	// only need session if pushing keys
	return Prereqs{
		Session: !e.arg.SkipPush,
	}
}

// RequiredUIs returns the required UIs.
func (e *BackupKeygen) RequiredUIs() []libkb.UIKind {
	return []libkb.UIKind{}
}

// SubConsumers returns the other UI consumers for this engine.
func (e *BackupKeygen) SubConsumers() []libkb.UIConsumer {
	return []libkb.UIConsumer{
		&DetKeyEngine{},
	}
}

func (e *BackupKeygen) SigKey() libkb.GenericKey {
	return e.sigKey
}

func (e *BackupKeygen) EncKey() libkb.GenericKey {
	return e.encKey
}

// Run starts the engine.
func (e *BackupKeygen) Run(ctx *Context) error {
	// make the passphrase stream
	key, err := scrypt.Key([]byte(e.arg.Passphrase), nil,
		libkb.BackupKeyScryptCost, libkb.BackupKeyScryptR, libkb.BackupKeyScryptP, libkb.BackupKeyScryptKeylen)
	if err != nil {
		return err
	}

	ppStream := libkb.NewPassphraseStream(key)

	// make keys for the backup device
	if err := e.makeSigKey(ppStream.EdDSASeed()); err != nil {
		return err
	}
	if err := e.makeEncKey(ppStream.DHSeed()); err != nil {
		return err
	}

	// push everything to the server
	if err := e.push(ctx); err != nil {
		return err
	}

	return nil
}

func (e *BackupKeygen) makeSigKey(seed []byte) error {
	pub, priv, err := ed25519.GenerateKey(bytes.NewBuffer(seed))
	if err != nil {
		return err
	}

	var key libkb.NaclSigningKeyPair
	copy(key.Public[:], (*pub)[:])
	key.Private = &libkb.NaclSigningKeyPrivate{}
	copy(key.Private[:], (*priv)[:])

	e.sigKey = key

	return nil
}

func (e *BackupKeygen) makeEncKey(seed []byte) error {
	pub, priv, err := box.GenerateKey(bytes.NewBuffer(seed))
	if err != nil {
		return err
	}
	var key libkb.NaclDHKeyPair
	copy(key.Public[:], (*pub)[:])
	key.Private = &libkb.NaclDHKeyPrivate{}
	copy(key.Private[:], (*priv)[:])

	e.encKey = key

	return nil
}

func (e *BackupKeygen) push(ctx *Context) error {
	if e.arg.SkipPush {
		return nil
	}

	// create a new backup device
	dev, err := libkb.NewBackupDevice()
	if err != nil {
		return err
	}

	// create lks halves for this device.  Note that they aren't used for
	// local, encrypted storage of the backup keys, but just for recovery
	// purposes.

	var ppgen libkb.PassphraseGeneration
	var clientHalf []byte
	e.G().LoginState().Account(func(a *libkb.Account) {
		ppgen = a.PassphraseStreamCache().PassphraseStream().Generation()
		clientHalf = a.PassphraseStreamCache().PassphraseStream().LksClientHalf()
	}, "BackupKeygen - push")

	lks := libkb.NewLKSec(clientHalf, ppgen, e.arg.Me.GetUID(), e.G())
	if err := lks.GenerateServerHalf(); err != nil {
		return err
	}
	ctext, err := lks.EncryptClientHalfRecovery(e.encKey)
	if err != nil {
		return err
	}

	// post them to the server.
	if err := libkb.PostDeviceLKS(ctx.LoginContext, dev.ID, libkb.DeviceTypeBackup, lks.GetServerHalf(), lks.Generation(), ctext, e.encKey.GetKID()); err != nil {
		return err
	}

	// push the backup signing key
	sigDel := libkb.Delegator{
		NewKey:      e.sigKey,
		Sibkey:      true,
		Expire:      libkb.NaclEdDSAExpireIn,
		ExistingKey: e.arg.SigningKey,
		Me:          e.arg.Me,
		Device:      dev,
	}
	if err := sigDel.Run(ctx.LoginContext); err != nil {
		return err
	}

	// push the backup encryption key
	sigEnc := libkb.Delegator{
		NewKey:      e.encKey,
		Sibkey:      false,
		Expire:      libkb.NaclDHExpireIn,
		ExistingKey: e.sigKey,
		Me:          e.arg.Me,
		Device:      dev,
	}
	if err := sigEnc.Run(ctx.LoginContext); err != nil {
		return err
	}

	return nil
}
<|endoftext|>


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

// Package redirect provides hooks to register HTTP handlers that redirect old
// godoc paths to their new equivalents and assist in accessing the issue
// tracker, wiki, code review system, etc.
package redirect

import (
	"net/http"
	"regexp"
)

// Register registers HTTP handlers that redirect old godoc paths to their new
// equivalents and assist in accessing the issue tracker, wiki, code review
// system, etc. If mux is nil it uses http.DefaultServeMux.
func Register(mux *http.ServeMux) {
	if mux == nil {
		mux = http.DefaultServeMux
	}
	handlePathRedirects(mux, pkgRedirects, "/pkg/")
	handlePathRedirects(mux, cmdRedirects, "/cmd/")
	for prefix, redirect := range prefixHelpers {
		p := "/" + prefix + "/"
		mux.Handle(p, PrefixHandler(p, redirect))
	}
	for path, redirect := range redirects {
		mux.Handle(path, Handler(redirect))
	}
}

func handlePathRedirects(mux *http.ServeMux, redirects map[string]string, prefix string) {
	for source, target := range redirects {
		h := Handler(prefix + target + "/")
		p := prefix + source
		mux.Handle(p, h)
		mux.Handle(p+"/", h)
	}
}

// Packages that were renamed between r60 and go1.
var pkgRedirects = map[string]string{
	"asn1":              "encoding/asn1",
	"big":               "math/big",
	"cmath":             "math/cmplx",
	"csv":               "encoding/csv",
	"exec":              "os/exec",
	"exp/template/html": "html/template",
	"gob":               "encoding/gob",
	"http":              "net/http",
	"http/cgi":          "net/http/cgi",
	"http/fcgi":         "net/http/fcgi",
	"http/httptest":     "net/http/httptest",
	"http/pprof":        "net/http/pprof",
	"json":              "encoding/json",
	"mail":              "net/mail",
	"rand":              "math/rand",
	"rpc":               "net/rpc",
	"rpc/jsonrpc":       "net/rpc/jsonrpc",
	"scanner":           "text/scanner",
	"smtp":              "net/smtp",
	"tabwriter":         "text/tabwriter",
	"template":          "text/template",
	"template/parse":    "text/template/parse",
	"url":               "net/url",
	"utf16":             "unicode/utf16",
	"utf8":              "unicode/utf8",
	"xml":               "encoding/xml",
}

// Commands that were renamed between r60 and go1.
var cmdRedirects = map[string]string{
	"gofix":     "fix",
	"goinstall": "go",
	"gopack":    "pack",
	"gotest":    "go",
	"govet":     "vet",
	"goyacc":    "yacc",
}

var redirects = map[string]string{
	"/blog":       "/blog/",
	"/build":      "http://build.golang.org",
	"/change":     "https://code.google.com/p/go/source/list",
	"/cl":         "https://gocodereview.appspot.com/",
	"/cmd/godoc/": "http://godoc.org/code.google.com/p/go.tools/cmd/godoc/",
	"/cmd/vet/":   "http://godoc.org/code.google.com/p/go.tools/cmd/vet/",
	"/issue":      "https://code.google.com/p/go/issues",
	"/issue/new":  "https://code.google.com/p/go/issues/entry",
	"/issues":     "https://code.google.com/p/go/issues",
	"/play":       "http://play.golang.org",

	// THESE DO NOT WORK FOR GO 1.1 SITES SUCH AS golang.org.
	// DO NOT RE-ENABLE.
	// "/ref":        "/doc/#references",
	// "/ref/":       "/doc/#references",
	// "/ref/mem":    "/doc/mem",
	// "/ref/spec":   "/doc/spec",

	// In fact, becuase golang.org pulls some pages from tip, there
	// are already links on the main golang.org page pointing at
	// the non-existent /doc/spec etc URLs. So redirect the other way.
	"/doc/mem":  "/ref/mem",
	"/doc/spec": "/ref/spec",

	"/talks": "http://talks.golang.org",
	"/tour":  "http://tour.golang.org",
	"/wiki":  "https://code.google.com/p/go-wiki/w/list",

	"/doc/articles/c_go_cgo.html":                    "/blog/c-go-cgo",
	"/doc/articles/concurrency_patterns.html":        "/blog/go-concurrency-patterns-timing-out-and",
	"/doc/articles/defer_panic_recover.html":         "/blog/defer-panic-and-recover",
	"/doc/articles/error_handling.html":              "/blog/error-handling-and-go",
	"/doc/articles/gobs_of_data.html":                "/blog/gobs-of-data",
	"/doc/articles/godoc_documenting_go_code.html":   "/blog/godoc-documenting-go-code",
	"/doc/articles/gos_declaration_syntax.html":      "/blog/gos-declaration-syntax",
	"/doc/articles/image_draw.html":                  "/blog/go-imagedraw-package",
	"/doc/articles/image_package.html":               "/blog/go-image-package",
	"/doc/articles/json_and_go.html":                 "/blog/json-and-go",
	"/doc/articles/json_rpc_tale_of_interfaces.html": "/blog/json-rpc-tale-of-interfaces",
	"/doc/articles/laws_of_reflection.html":          "/blog/laws-of-reflection",
	"/doc/articles/race_detector.html":               "/blog/race-detector",
	"/doc/articles/slices_usage_and_internals.html":  "/blog/go-slices-usage-and-internals",
	"/doc/go_for_cpp_programmers.html":               "https://code.google.com/p/go-wiki/wiki/GoForCPPProgrammers",
	"/doc/go_tutorial.html":                          "http://tour.golang.org/",
}

var prefixHelpers = map[string]string{
	"change": "https://code.google.com/p/go/source/detail?r=",
	"cl":     "https://codereview.appspot.com/",
	"issue":  "https://code.google.com/p/go/issues/detail?id=",
	"play":   "http://play.golang.org/",
	"talks":  "http://talks.golang.org/",
	"wiki":   "https://code.google.com/p/go-wiki/wiki/",
}

func Handler(target string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, target, http.StatusMovedPermanently)
	})
}

var validId = regexp.MustCompile(`^[A-Za-z0-9-]*$`)

func PrefixHandler(prefix, baseURL string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if p := r.URL.Path; p == prefix {
			// redirect /prefix/ to /prefix
			http.Redirect(w, r, p[:len(p)-1], http.StatusFound)
			return
		}
		id := r.URL.Path[len(prefix):]
		if !validId.MatchString(id) {
			http.Error(w, "Not found", http.StatusNotFound)
			return
		}
		target := baseURL + id
		http.Redirect(w, r, target, http.StatusFound)
	})
}
<commit_msg>go.tools/godoc/redirect: remove redundant redirect rules<commit_after>// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package redirect provides hooks to register HTTP handlers that redirect old
// godoc paths to their new equivalents and assist in accessing the issue
// tracker, wiki, code review system, etc.
package redirect

import (
	"net/http"
	"regexp"
)

// Register registers HTTP handlers that redirect old godoc paths to their new
// equivalents and assist in accessing the issue tracker, wiki, code review
// system, etc. If mux is nil it uses http.DefaultServeMux.
func Register(mux *http.ServeMux) {
	if mux == nil {
		mux = http.DefaultServeMux
	}
	handlePathRedirects(mux, pkgRedirects, "/pkg/")
	handlePathRedirects(mux, cmdRedirects, "/cmd/")
	for prefix, redirect := range prefixHelpers {
		p := "/" + prefix + "/"
		mux.Handle(p, PrefixHandler(p, redirect))
	}
	for path, redirect := range redirects {
		mux.Handle(path, Handler(redirect))
	}
}

func handlePathRedirects(mux *http.ServeMux, redirects map[string]string, prefix string) {
	for source, target := range redirects {
		h := Handler(prefix + target + "/")
		p := prefix + source
		mux.Handle(p, h)
		mux.Handle(p+"/", h)
	}
}

// Packages that were renamed between r60 and go1.
var pkgRedirects = map[string]string{
	"asn1":              "encoding/asn1",
	"big":               "math/big",
	"cmath":             "math/cmplx",
	"csv":               "encoding/csv",
	"exec":              "os/exec",
	"exp/template/html": "html/template",
	"gob":               "encoding/gob",
	"http":              "net/http",
	"http/cgi":          "net/http/cgi",
	"http/fcgi":         "net/http/fcgi",
	"http/httptest":     "net/http/httptest",
	"http/pprof":        "net/http/pprof",
	"json":              "encoding/json",
	"mail":              "net/mail",
	"rand":              "math/rand",
	"rpc":               "net/rpc",
	"rpc/jsonrpc":       "net/rpc/jsonrpc",
	"scanner":           "text/scanner",
	"smtp":              "net/smtp",
	"tabwriter":         "text/tabwriter",
	"template":          "text/template",
	"template/parse":    "text/template/parse",
	"url":               "net/url",
	"utf16":             "unicode/utf16",
	"utf8":              "unicode/utf8",
	"xml":               "encoding/xml",
}

// Commands that were renamed between r60 and go1.
var cmdRedirects = map[string]string{
	"gofix":     "fix",
	"goinstall": "go",
	"gopack":    "pack",
	"gotest":    "go",
	"govet":     "vet",
	"goyacc":    "yacc",
}

var redirects = map[string]string{
	"/blog":       "/blog/",
	"/build":      "http://build.golang.org",
	"/change":     "https://code.google.com/p/go/source/list",
	"/cl":         "https://gocodereview.appspot.com/",
	"/cmd/godoc/": "http://godoc.org/code.google.com/p/go.tools/cmd/godoc/",
	"/cmd/vet/":   "http://godoc.org/code.google.com/p/go.tools/cmd/vet/",
	"/issue":      "https://code.google.com/p/go/issues",
	"/issue/new":  "https://code.google.com/p/go/issues/entry",
	"/issues":     "https://code.google.com/p/go/issues",
	"/play":       "http://play.golang.org",

	// In Go 1.2 the references page is part of /doc/.
	"/ref": "/doc/#references",
	// This next rule clobbers /ref/spec and /ref/mem.
	// TODO(adg): figure out what to do here, if anything.
	// "/ref/": "/doc/#references",

	// Be nice to people who are looking in the wrong place.
	"/doc/mem":  "/ref/mem",
	"/doc/spec": "/ref/spec",

	"/talks": "http://talks.golang.org",
	"/tour":  "http://tour.golang.org",
	"/wiki":  "https://code.google.com/p/go-wiki/w/list",

	"/doc/articles/c_go_cgo.html":                    "/blog/c-go-cgo",
	"/doc/articles/concurrency_patterns.html":        "/blog/go-concurrency-patterns-timing-out-and",
	"/doc/articles/defer_panic_recover.html":         "/blog/defer-panic-and-recover",
	"/doc/articles/error_handling.html":              "/blog/error-handling-and-go",
	"/doc/articles/gobs_of_data.html":                "/blog/gobs-of-data",
	"/doc/articles/godoc_documenting_go_code.html":   "/blog/godoc-documenting-go-code",
	"/doc/articles/gos_declaration_syntax.html":      "/blog/gos-declaration-syntax",
	"/doc/articles/image_draw.html":                  "/blog/go-imagedraw-package",
	"/doc/articles/image_package.html":               "/blog/go-image-package",
	"/doc/articles/json_and_go.html":                 "/blog/json-and-go",
	"/doc/articles/json_rpc_tale_of_interfaces.html": "/blog/json-rpc-tale-of-interfaces",
	"/doc/articles/laws_of_reflection.html":          "/blog/laws-of-reflection",
	"/doc/articles/race_detector.html":               "/blog/race-detector",
	"/doc/articles/slices_usage_and_internals.html":  "/blog/go-slices-usage-and-internals",
	"/doc/go_for_cpp_programmers.html":               "https://code.google.com/p/go-wiki/wiki/GoForCPPProgrammers",
	"/doc/go_tutorial.html":                          "http://tour.golang.org/",
}

var prefixHelpers = map[string]string{
	"change": "https://code.google.com/p/go/source/detail?r=",
	"cl":     "https://codereview.appspot.com/",
	"issue":  "https://code.google.com/p/go/issues/detail?id=",
	"play":   "http://play.golang.org/",
	"talks":  "http://talks.golang.org/",
	"wiki":   "https://code.google.com/p/go-wiki/wiki/",
}

func Handler(target string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, target, http.StatusMovedPermanently)
	})
}

var validId = regexp.MustCompile(`^[A-Za-z0-9-]*$`)

func PrefixHandler(prefix, baseURL string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if p := r.URL.Path; p == prefix {
			// redirect /prefix/ to /prefix
			http.Redirect(w, r, p[:len(p)-1], http.StatusFound)
			return
		}
		id := r.URL.Path[len(prefix):]
		if !validId.MatchString(id) {
			http.Error(w, "Not found", http.StatusNotFound)
			return
		}
		target := baseURL + id
		http.Redirect(w, r, target, http.StatusFound)
	})
}
<|endoftext|>