<commit_before>package service

import (
	"fmt"
	"strings"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/fatih/color"
	"github.com/stormcat24/ecs-formation/client"
	"github.com/stormcat24/ecs-formation/logger"
	"github.com/stormcat24/ecs-formation/service/types"
)

type ELBSwitcher interface {
	Apply(clusterService ClusterService, bgplan *types.BlueGreenPlan, nodeploy bool) error
}

func NewELBSwitcher(awscli client.AWSClient, bgplan *types.BlueGreenPlan) ELBSwitcher {
	if bgplan.ElbV2 != nil && len(bgplan.ElbV2.TargetGroups) > 0 {
		return &ELBV2Switcher{
			awsCli: client.AWSCli,
		}
	} else {
		return &ELBV1Switcher{
			awsCli: client.AWSCli,
		}
	}
}

type ELBV1Switcher struct {
	awsCli client.AWSClient
}

type ELBV2Switcher struct {
	awsCli client.AWSClient
}

func (s ELBV1Switcher) Apply(clusterService ClusterService, bgplan *types.BlueGreenPlan, nodeploy bool) error {

	var targetGreen bool
	for _, lb := range bgplan.Blue.AutoScalingGroup.LoadBalancerNames {
		if *lb == bgplan.PrimaryElb {
			targetGreen = true
		}
	}

	var currentLabel string
	var nextLabel string
	var current *types.ServiceSet
	var next *types.ServiceSet
	primaryLb := bgplan.PrimaryElb
	standbyLb := bgplan.StandbyElb
	if targetGreen {
		current = bgplan.Blue
		next = bgplan.Green
		currentLabel = color.CyanString("blue")
		nextLabel = color.GreenString("green")
	} else {
		current = bgplan.Green
		next = bgplan.Blue
		currentLabel = color.GreenString("green")
		nextLabel = color.CyanString("blue")
	}

	primaryGroup := []string{primaryLb}
	standbyGroup := []string{standbyLb}
	for _, entry := range bgplan.ChainElb {
		primaryGroup = append(primaryGroup, entry.PrimaryElb)
		standbyGroup = append(standbyGroup, entry.StandbyElb)
	}

	logger.Main.Infof("Current status is '%s'", currentLabel)
	logger.Main.Infof("Start Blue-Green Deployment: %s to %s ...", currentLabel, nextLabel)
	if nodeploy {
		logger.Main.Infof("Without deployment. It only replaces load balancers.")
	} else {
		// deploy service
		logger.Main.Infof("Updating %s@%s service at %s ...", next.NewService.Service, next.NewService.Cluster, nextLabel)
		if err := clusterService.ApplyServicePlan(next.ClusterUpdatePlan); err != nil {
			return err
		}
	}

	// attach next group to primary lb
	if err := s.awsCli.Autoscaling.AttachLoadBalancers(*next.AutoScalingGroup.AutoScalingGroupName, primaryGroup); err != nil {
		return err
	}
	for _, e := range primaryGroup {
		logger.Main.Infof("Attached to attach %s group to %s(primary).", nextLabel, e)
	}

	if err := s.waitLoadBalancer(*next.AutoScalingGroup.AutoScalingGroupName, primaryLb); err != nil {
		return err
	}
	logger.Main.Infof("Added %s group to primary", nextLabel)

	// detach current group from primary lb
	if err := s.awsCli.Autoscaling.DetachLoadBalancers(*current.AutoScalingGroup.AutoScalingGroupName, primaryGroup); err != nil {
		return err
	}
	for _, e := range primaryGroup {
		logger.Main.Infof("Detached %s group from %s(primary).", currentLabel, e)
	}

	// detach next group from standby lb
	if err := s.awsCli.Autoscaling.DetachLoadBalancers(*next.AutoScalingGroup.AutoScalingGroupName, standbyGroup); err != nil {
		return err
	}
	for _, e := range standbyGroup {
		logger.Main.Infof("Detached %s group from %s(standby).", nextLabel, e)
	}

	// attach current group to standby lb
	if err := s.awsCli.Autoscaling.AttachLoadBalancers(*current.AutoScalingGroup.AutoScalingGroupName, standbyGroup); err != nil {
		return err
	}
	for _, e := range standbyGroup {
		logger.Main.Infof("Attached %s group to %s(standby).", currentLabel, e)
	}

	return nil
}

func (s ELBV1Switcher) waitLoadBalancer(group string, lb string) error {

	for {
		time.Sleep(5 * time.Second)

		result, err := s.awsCli.Autoscaling.DescribeLoadBalancerState(group)
		if err != nil {
			return err
		}

		if lbs, ok := result[lb]; ok {

			// *** LoadbalancerState
			// Adding - The instances in the group are being registered with the load balancer.
			// Added - All instances in the group are registered with the load balancer.
			// InService - At least one instance in the group passed an ELB health check.
			// Removing - The instances are being deregistered from the load balancer. If connection draining is enabled, Elastic Load Balancing waits for in-flight requests to complete before deregistering the instances.
			if *lbs.State == "Added" || *lbs.State == "InService" {
				return nil
			}

		} else {
			return fmt.Errorf("cannot get load balanracer '%s'", lb)
		}

	}

}

func (s ELBV2Switcher) Apply(clusterService ClusterService, bgplan *types.BlueGreenPlan, nodeploy bool) error {

	var targetGreen bool
	for _, tg := range bgplan.Blue.AutoScalingGroup.TargetGroupARNs {
		topTg := bgplan.ElbV2.TargetGroups[0]
		// TODO name check
		if strings.Contains(*tg, topTg.PrimaryGroup) {
			targetGreen = true
		}
	}

	var currentLabel string
	var nextLabel string
	var current *types.ServiceSet
	var next *types.ServiceSet

	topGroup := bgplan.ElbV2.TargetGroups[0]

	primaryTg := topGroup.PrimaryGroup
	if targetGreen {
		current = bgplan.Blue
		next = bgplan.Green
		currentLabel = color.CyanString("blue")
		nextLabel = color.GreenString("green")
	} else {
		current = bgplan.Green
		next = bgplan.Blue
		currentLabel = color.GreenString("green")
		nextLabel = color.CyanString("blue")
	}

	allGroup := []string{}
	primaryGroup := []string{}
	standbyGroup := []string{}
	for _, tg := range bgplan.ElbV2.TargetGroups {
		primaryGroup = append(primaryGroup, tg.PrimaryGroup)
		standbyGroup = append(standbyGroup, tg.StandbyGroup)
		allGroup = append(allGroup, tg.PrimaryGroup)
		allGroup = append(allGroup, tg.StandbyGroup)
	}

	tgmap, err := s.awsCli.ELBV2.DescribeTargetGroup(allGroup)
	if err != nil {
		return err
	}

	primaryGroupARNs := []string{}
	standbyGroupARNs := []string{}
	for name, tg := range tgmap {
		for _, pg := range primaryGroup {
			if pg == name {
				primaryGroupARNs = append(primaryGroupARNs, *tg.TargetGroupArn)
			}
		}

		for _, sg := range standbyGroup {
			if sg == name {
				standbyGroupARNs = append(standbyGroupARNs, *tg.TargetGroupArn)
			}
		}
	}

	logger.Main.Infof("Current status is '%s'", currentLabel)
	logger.Main.Infof("Start Blue-Green Deployment: %s to %s ...", currentLabel, nextLabel)
	if nodeploy {
		logger.Main.Infof("Without deployment. It only replaces load balancers.")
	} else {
		// deploy service
		logger.Main.Infof("Updating %s@%s service at %s ...", next.NewService.Service, next.NewService.Cluster, nextLabel)
		if err := clusterService.ApplyServicePlan(next.ClusterUpdatePlan); err != nil {
			return err
		}
	}

	// attach next group to primary target group
	if err := s.awsCli.Autoscaling.AttachLoadBalancerTargetGroups(*next.AutoScalingGroup.AutoScalingGroupName, aws.StringSlice(primaryGroupARNs)); err != nil {
		return err
	}
	for _, e := range primaryGroup {
		logger.Main.Infof("Attached to attach %s group to %s(primary).", nextLabel, e)
	}

	if err := s.waitTargetGroup(*next.AutoScalingGroup.AutoScalingGroupName, primaryTg); err != nil {
		return err
	}
	logger.Main.Infof("Added %s group to primary", nextLabel)

	time.Sleep(5 * time.Second)

	// detach current group from primary target group
	if err := s.awsCli.Autoscaling.DetachLoadBalancerTargetGroups(*current.AutoScalingGroup.AutoScalingGroupName, aws.StringSlice(primaryGroupARNs)); err != nil {
		return err
	}
	for _, e := range primaryGroup {
		logger.Main.Infof("Detached %s group from %s(primary).", currentLabel, e)
	}

	// detach next group from standby lb
	if err := s.awsCli.Autoscaling.DetachLoadBalancerTargetGroups(*next.AutoScalingGroup.AutoScalingGroupName, aws.StringSlice(standbyGroupARNs)); err != nil {
		return err
	}
	for _, e := range standbyGroup {
		logger.Main.Infof("Detached %s group from %s(standby).", nextLabel, e)
	}

	// attach current group to standby lb
	if err := s.awsCli.Autoscaling.AttachLoadBalancerTargetGroups(*current.AutoScalingGroup.AutoScalingGroupName, aws.StringSlice(standbyGroupARNs)); err != nil {
		return err
	}
	for _, e := range standbyGroup {
		logger.Main.Infof("Attached %s group to %s(standby).", currentLabel, e)
	}

	return nil
}

func (s ELBV2Switcher) waitTargetGroup(group string, tg string) error {
	for {
		time.Sleep(5 * time.Second)
		targetGroups, err := s.awsCli.Autoscaling.DescribeLoadBalancerTargetGroups(group)
		if err != nil {
			return err
		}

		// *** LoadBalancerTargetGroupState
		//    Adding - The Auto Scaling instances are being registered with the target group.
		//    Added - All Auto Scaling instances are registered with the target group.
		//    InService - At least one Auto Scaling instance passed an ELB health check.
		//    Removing - The Auto Scaling instances are being deregistered from the
		// target group. If connection draining is enabled, Elastic Load Balancing waits
		// for in-flight requests to complete before deregistering the instances.
		//    Removed - All Auto Scaling instances are deregistered from the target group.

		if len(targetGroups) == 0 {
			return fmt.Errorf("cannot get target group %s at ", tg, group)
		}

		for _, targetGroup := range targetGroups {
			if strings.Contains(*targetGroup.LoadBalancerTargetGroupARN, tg) {
				state := *targetGroup.State
				if state == "Added" || state == "InService" {
					return nil
				}
			}
		}

		return nil
	}
}
<commit_msg>fix build<commit_after>package service

import (
	"fmt"
	"strings"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/fatih/color"
	"github.com/stormcat24/ecs-formation/client"
	"github.com/stormcat24/ecs-formation/logger"
	"github.com/stormcat24/ecs-formation/service/types"
)

type ELBSwitcher interface {
	Apply(clusterService ClusterService, bgplan *types.BlueGreenPlan, nodeploy bool) error
}

func NewELBSwitcher(awscli client.AWSClient, bgplan *types.BlueGreenPlan) ELBSwitcher {
	if bgplan.ElbV2 != nil && len(bgplan.ElbV2.TargetGroups) > 0 {
		return &ELBV2Switcher{
			awsCli: client.AWSCli,
		}
	} else {
		return &ELBV1Switcher{
			awsCli: client.AWSCli,
		}
	}
}

type ELBV1Switcher struct {
	awsCli client.AWSClient
}

type ELBV2Switcher struct {
	awsCli client.AWSClient
}

func (s ELBV1Switcher) Apply(clusterService ClusterService, bgplan *types.BlueGreenPlan, nodeploy bool) error {

	var targetGreen bool
	for _, lb := range bgplan.Blue.AutoScalingGroup.LoadBalancerNames {
		if *lb == bgplan.PrimaryElb {
			targetGreen = true
		}
	}

	var currentLabel string
	var nextLabel string
	var current *types.ServiceSet
	var next *types.ServiceSet
	primaryLb := bgplan.PrimaryElb
	standbyLb := bgplan.StandbyElb
	if targetGreen {
		current = bgplan.Blue
		next = bgplan.Green
		currentLabel = color.CyanString("blue")
		nextLabel = color.GreenString("green")
	} else {
		current = bgplan.Green
		next = bgplan.Blue
		currentLabel = color.GreenString("green")
		nextLabel = color.CyanString("blue")
	}

	primaryGroup := []string{primaryLb}
	standbyGroup := []string{standbyLb}
	for _, entry := range bgplan.ChainElb {
		primaryGroup = append(primaryGroup, entry.PrimaryElb)
		standbyGroup = append(standbyGroup, entry.StandbyElb)
	}

	logger.Main.Infof("Current status is '%s'", currentLabel)
	logger.Main.Infof("Start Blue-Green Deployment: %s to %s ...", currentLabel, nextLabel)
	if nodeploy {
		logger.Main.Infof("Without deployment. It only replaces load balancers.")
	} else {
		// deploy service
		logger.Main.Infof("Updating %s@%s service at %s ...", next.NewService.Service, next.NewService.Cluster, nextLabel)
		if err := clusterService.ApplyServicePlan(next.ClusterUpdatePlan); err != nil {
			return err
		}
	}

	// attach next group to primary lb
	if err := s.awsCli.Autoscaling.AttachLoadBalancers(*next.AutoScalingGroup.AutoScalingGroupName, primaryGroup); err != nil {
		return err
	}
	for _, e := range primaryGroup {
		logger.Main.Infof("Attached to attach %s group to %s(primary).", nextLabel, e)
	}

	if err := s.waitLoadBalancer(*next.AutoScalingGroup.AutoScalingGroupName, primaryLb); err != nil {
		return err
	}
	logger.Main.Infof("Added %s group to primary", nextLabel)

	// detach current group from primary lb
	if err := s.awsCli.Autoscaling.DetachLoadBalancers(*current.AutoScalingGroup.AutoScalingGroupName, primaryGroup); err != nil {
		return err
	}
	for _, e := range primaryGroup {
		logger.Main.Infof("Detached %s group from %s(primary).", currentLabel, e)
	}

	// detach next group from standby lb
	if err := s.awsCli.Autoscaling.DetachLoadBalancers(*next.AutoScalingGroup.AutoScalingGroupName, standbyGroup); err != nil {
		return err
	}
	for _, e := range standbyGroup {
		logger.Main.Infof("Detached %s group from %s(standby).", nextLabel, e)
	}

	// attach current group to standby lb
	if err := s.awsCli.Autoscaling.AttachLoadBalancers(*current.AutoScalingGroup.AutoScalingGroupName, standbyGroup); err != nil {
		return err
	}
	for _, e := range standbyGroup {
		logger.Main.Infof("Attached %s group to %s(standby).", currentLabel, e)
	}

	return nil
}

func (s ELBV1Switcher) waitLoadBalancer(group string, lb string) error {

	for {
		time.Sleep(5 * time.Second)

		result, err := s.awsCli.Autoscaling.DescribeLoadBalancerState(group)
		if err != nil {
			return err
		}

		if lbs, ok := result[lb]; ok {

			// *** LoadbalancerState
			// Adding - The instances in the group are being registered with the load balancer.
			// Added - All instances in the group are registered with the load balancer.
			// InService - At least one instance in the group passed an ELB health check.
			// Removing - The instances are being deregistered from the load balancer. If connection draining is enabled, Elastic Load Balancing waits for in-flight requests to complete before deregistering the instances.
			if *lbs.State == "Added" || *lbs.State == "InService" {
				return nil
			}

		} else {
			return fmt.Errorf("cannot get load balanracer '%s'", lb)
		}

	}

}

func (s ELBV2Switcher) Apply(clusterService ClusterService, bgplan *types.BlueGreenPlan, nodeploy bool) error {

	var targetGreen bool
	for _, tg := range bgplan.Blue.AutoScalingGroup.TargetGroupARNs {
		topTg := bgplan.ElbV2.TargetGroups[0]
		// TODO name check
		if strings.Contains(*tg, topTg.PrimaryGroup) {
			targetGreen = true
		}
	}

	var currentLabel string
	var nextLabel string
	var current *types.ServiceSet
	var next *types.ServiceSet

	topGroup := bgplan.ElbV2.TargetGroups[0]

	primaryTg := topGroup.PrimaryGroup
	if targetGreen {
		current = bgplan.Blue
		next = bgplan.Green
		currentLabel = color.CyanString("blue")
		nextLabel = color.GreenString("green")
	} else {
		current = bgplan.Green
		next = bgplan.Blue
		currentLabel = color.GreenString("green")
		nextLabel = color.CyanString("blue")
	}

	allGroup := []string{}
	primaryGroup := []string{}
	standbyGroup := []string{}
	for _, tg := range bgplan.ElbV2.TargetGroups {
		primaryGroup = append(primaryGroup, tg.PrimaryGroup)
		standbyGroup = append(standbyGroup, tg.StandbyGroup)
		allGroup = append(allGroup, tg.PrimaryGroup)
		allGroup = append(allGroup, tg.StandbyGroup)
	}

	tgmap, err := s.awsCli.ELBV2.DescribeTargetGroup(allGroup)
	if err != nil {
		return err
	}

	primaryGroupARNs := []string{}
	standbyGroupARNs := []string{}
	for name, tg := range tgmap {
		for _, pg := range primaryGroup {
			if pg == name {
				primaryGroupARNs = append(primaryGroupARNs, *tg.TargetGroupArn)
			}
		}

		for _, sg := range standbyGroup {
			if sg == name {
				standbyGroupARNs = append(standbyGroupARNs, *tg.TargetGroupArn)
			}
		}
	}

	logger.Main.Infof("Current status is '%s'", currentLabel)
	logger.Main.Infof("Start Blue-Green Deployment: %s to %s ...", currentLabel, nextLabel)
	if nodeploy {
		logger.Main.Infof("Without deployment. It only replaces load balancers.")
	} else {
		// deploy service
		logger.Main.Infof("Updating %s@%s service at %s ...", next.NewService.Service, next.NewService.Cluster, nextLabel)
		if err := clusterService.ApplyServicePlan(next.ClusterUpdatePlan); err != nil {
			return err
		}
	}

	// attach next group to primary target group
	if err := s.awsCli.Autoscaling.AttachLoadBalancerTargetGroups(*next.AutoScalingGroup.AutoScalingGroupName, aws.StringSlice(primaryGroupARNs)); err != nil {
		return err
	}
	for _, e := range primaryGroup {
		logger.Main.Infof("Attached to attach %s group to %s(primary).", nextLabel, e)
	}

	if err := s.waitTargetGroup(*next.AutoScalingGroup.AutoScalingGroupName, primaryTg); err != nil {
		return err
	}
	logger.Main.Infof("Added %s group to primary", nextLabel)

	time.Sleep(5 * time.Second)

	// detach current group from primary target group
	if err := s.awsCli.Autoscaling.DetachLoadBalancerTargetGroups(*current.AutoScalingGroup.AutoScalingGroupName, aws.StringSlice(primaryGroupARNs)); err != nil {
		return err
	}
	for _, e := range primaryGroup {
		logger.Main.Infof("Detached %s group from %s(primary).", currentLabel, e)
	}

	// detach next group from standby lb
	if err := s.awsCli.Autoscaling.DetachLoadBalancerTargetGroups(*next.AutoScalingGroup.AutoScalingGroupName, aws.StringSlice(standbyGroupARNs)); err != nil {
		return err
	}
	for _, e := range standbyGroup {
		logger.Main.Infof("Detached %s group from %s(standby).", nextLabel, e)
	}

	// attach current group to standby lb
	if err := s.awsCli.Autoscaling.AttachLoadBalancerTargetGroups(*current.AutoScalingGroup.AutoScalingGroupName, aws.StringSlice(standbyGroupARNs)); err != nil {
		return err
	}
	for _, e := range standbyGroup {
		logger.Main.Infof("Attached %s group to %s(standby).", currentLabel, e)
	}

	return nil
}

func (s ELBV2Switcher) waitTargetGroup(group string, tg string) error {
	for {
		time.Sleep(5 * time.Second)
		targetGroups, err := s.awsCli.Autoscaling.DescribeLoadBalancerTargetGroups(group)
		if err != nil {
			return err
		}

		// *** LoadBalancerTargetGroupState
		//    Adding - The Auto Scaling instances are being registered with the target group.
		//    Added - All Auto Scaling instances are registered with the target group.
		//    InService - At least one Auto Scaling instance passed an ELB health check.
		//    Removing - The Auto Scaling instances are being deregistered from the
		// target group. If connection draining is enabled, Elastic Load Balancing waits
		// for in-flight requests to complete before deregistering the instances.
		//    Removed - All Auto Scaling instances are deregistered from the target group.

		if len(targetGroups) == 0 {
			return fmt.Errorf("cannot get target group %s at %s", tg, group)
		}

		for _, targetGroup := range targetGroups {
			if strings.Contains(*targetGroup.LoadBalancerTargetGroupARN, tg) {
				state := *targetGroup.State
				if state == "Added" || state == "InService" {
					return nil
				}
			}
		}

		return nil
	}
}
<|endoftext|>


<commit_before>package middleware

import (
	"strconv"
	"strings"

	"github.com/Unknwon/macaron"
	"github.com/macaron-contrib/session"

	"github.com/grafana/grafana/pkg/bus"
	"github.com/grafana/grafana/pkg/components/apikeygen"
	"github.com/grafana/grafana/pkg/log"
	m "github.com/grafana/grafana/pkg/models"
	"github.com/grafana/grafana/pkg/setting"
)

type Context struct {
	*macaron.Context
	*m.SignedInUser

	Session session.Store

	IsSignedIn     bool
	AllowAnonymous bool
}

func GetContextHandler() macaron.Handler {
	return func(c *macaron.Context, sess session.Store) {
		ctx := &Context{
			Context:        c,
			Session:        sess,
			SignedInUser:   &m.SignedInUser{},
			IsSignedIn:     false,
			AllowAnonymous: false,
		}

		// try get account id from request
		if userId := getRequestUserId(ctx); userId != 0 {
			query := m.GetSignedInUserQuery{UserId: userId}
			if err := bus.Dispatch(&query); err != nil {
				log.Error(3, "Failed to get user by id, %v, %v", userId, err)
			} else {
				ctx.SignedInUser = query.Result
				ctx.IsSignedIn = true
			}
		} else if keyString := getApiKey(ctx); keyString != "" {
			// base64 decode key
			decoded, err := apikeygen.Decode(keyString)
			if err != nil {
				ctx.JsonApiErr(401, "Invalid API key", err)
				return
			}
			// fetch key
			keyQuery := m.GetApiKeyByNameQuery{KeyName: decoded.Name, OrgId: decoded.OrgId}
			if err := bus.Dispatch(&keyQuery); err != nil {
				ctx.JsonApiErr(401, "Invalid API key", err)
				return
			} else {
				apikey := keyQuery.Result

				// validate api key
				if !apikeygen.IsValid(decoded, apikey.Key) {
					ctx.JsonApiErr(401, "Invalid API key", err)
					return
				}

				ctx.IsSignedIn = true
				ctx.SignedInUser = &m.SignedInUser{}

				// TODO: fix this
				ctx.OrgRole = apikey.Role
				ctx.ApiKeyId = apikey.Id
				ctx.OrgId = apikey.OrgId
			}
		} else if setting.AnonymousEnabled {
			orgQuery := m.GetOrgByNameQuery{Name: setting.AnonymousOrgName}
			if err := bus.Dispatch(&orgQuery); err != nil {
				log.Error(3, "Anonymous access organization error", nil)
			} else {
				ctx.IsSignedIn = false
				ctx.AllowAnonymous = true
				ctx.SignedInUser = &m.SignedInUser{}
				ctx.OrgRole = m.RoleType(setting.AnonymousOrgRole)
				ctx.OrgId = orgQuery.Result.Id
				ctx.OrgName = orgQuery.Result.Name
			}
		}

		c.Map(ctx)
	}
}

// Handle handles and logs error by given status.
func (ctx *Context) Handle(status int, title string, err error) {
	if err != nil {
		log.Error(4, "%s: %v", title, err)
		if setting.Env != setting.PROD {
			ctx.Data["ErrorMsg"] = err
		}
	}

	ctx.Data["Title"] = title
	ctx.HTML(status, strconv.Itoa(status))
}

func (ctx *Context) JsonOK(message string) {
	resp := make(map[string]interface{})

	resp["message"] = message

	ctx.JSON(200, resp)
}

func (ctx *Context) IsApiRequest() bool {
	return strings.HasPrefix(ctx.Req.URL.Path, "/api")
}

func (ctx *Context) JsonApiErr(status int, message string, err error) {
	resp := make(map[string]interface{})

	if err != nil {
		log.Error(4, "%s: %v", message, err)
		if setting.Env != setting.PROD {
			resp["error"] = err.Error()
		}
	}

	switch status {
	case 404:
		resp["message"] = "Not Found"
	case 500:
		resp["message"] = "Internal Server Error"
	}

	if message != "" {
		resp["message"] = message
	}

	ctx.JSON(status, resp)
}
<commit_msg>Log more descriptive error when anonymous org is not found<commit_after>package middleware

import (
	"strconv"
	"strings"

	"github.com/Unknwon/macaron"
	"github.com/macaron-contrib/session"

	"github.com/grafana/grafana/pkg/bus"
	"github.com/grafana/grafana/pkg/components/apikeygen"
	"github.com/grafana/grafana/pkg/log"
	m "github.com/grafana/grafana/pkg/models"
	"github.com/grafana/grafana/pkg/setting"
)

type Context struct {
	*macaron.Context
	*m.SignedInUser

	Session session.Store

	IsSignedIn     bool
	AllowAnonymous bool
}

func GetContextHandler() macaron.Handler {
	return func(c *macaron.Context, sess session.Store) {
		ctx := &Context{
			Context:        c,
			Session:        sess,
			SignedInUser:   &m.SignedInUser{},
			IsSignedIn:     false,
			AllowAnonymous: false,
		}

		// try get account id from request
		if userId := getRequestUserId(ctx); userId != 0 {
			query := m.GetSignedInUserQuery{UserId: userId}
			if err := bus.Dispatch(&query); err != nil {
				log.Error(3, "Failed to get user by id, %v, %v", userId, err)
			} else {
				ctx.SignedInUser = query.Result
				ctx.IsSignedIn = true
			}
		} else if keyString := getApiKey(ctx); keyString != "" {
			// base64 decode key
			decoded, err := apikeygen.Decode(keyString)
			if err != nil {
				ctx.JsonApiErr(401, "Invalid API key", err)
				return
			}
			// fetch key
			keyQuery := m.GetApiKeyByNameQuery{KeyName: decoded.Name, OrgId: decoded.OrgId}
			if err := bus.Dispatch(&keyQuery); err != nil {
				ctx.JsonApiErr(401, "Invalid API key", err)
				return
			} else {
				apikey := keyQuery.Result

				// validate api key
				if !apikeygen.IsValid(decoded, apikey.Key) {
					ctx.JsonApiErr(401, "Invalid API key", err)
					return
				}

				ctx.IsSignedIn = true
				ctx.SignedInUser = &m.SignedInUser{}

				// TODO: fix this
				ctx.OrgRole = apikey.Role
				ctx.ApiKeyId = apikey.Id
				ctx.OrgId = apikey.OrgId
			}
		} else if setting.AnonymousEnabled {
			orgQuery := m.GetOrgByNameQuery{Name: setting.AnonymousOrgName}
			if err := bus.Dispatch(&orgQuery); err != nil {
				log.Error(3, "Anonymous access organization error: '%s': %s", setting.AnonymousOrgName, err)
			} else {
				ctx.IsSignedIn = false
				ctx.AllowAnonymous = true
				ctx.SignedInUser = &m.SignedInUser{}
				ctx.OrgRole = m.RoleType(setting.AnonymousOrgRole)
				ctx.OrgId = orgQuery.Result.Id
				ctx.OrgName = orgQuery.Result.Name
			}
		}

		c.Map(ctx)
	}
}

// Handle handles and logs error by given status.
func (ctx *Context) Handle(status int, title string, err error) {
	if err != nil {
		log.Error(4, "%s: %v", title, err)
		if setting.Env != setting.PROD {
			ctx.Data["ErrorMsg"] = err
		}
	}

	ctx.Data["Title"] = title
	ctx.HTML(status, strconv.Itoa(status))
}

func (ctx *Context) JsonOK(message string) {
	resp := make(map[string]interface{})

	resp["message"] = message

	ctx.JSON(200, resp)
}

func (ctx *Context) IsApiRequest() bool {
	return strings.HasPrefix(ctx.Req.URL.Path, "/api")
}

func (ctx *Context) JsonApiErr(status int, message string, err error) {
	resp := make(map[string]interface{})

	if err != nil {
		log.Error(4, "%s: %v", message, err)
		if setting.Env != setting.PROD {
			resp["error"] = err.Error()
		}
	}

	switch status {
	case 404:
		resp["message"] = "Not Found"
	case 500:
		resp["message"] = "Internal Server Error"
	}

	if message != "" {
		resp["message"] = message
	}

	ctx.JSON(status, resp)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"html/template"
	"io/ioutil"
	"net"
	"net/http"
	"os"

	"github.com/semanticize/st/internal/storage"
	"github.com/semanticize/st/linking"
)

var infoTemplate = template.Must(template.New("info").Parse(`
<title>Semanticizest</title>

Semanticizest

      Serving {{.Dumpname}}
      with maximum n-gram length {{.MaxNGram}}.

Endpoints take data via POST requests and produce JSON:

          /all
          gives all candidate entities occurring anywhere in a string

          /bestpath gives the entities according to a
          Viterbi algorithm

          /exactmatch
          gives all candidate entities for a string (but not its substrings)

© 2015 Netherlands eScience Center/University of Amsterdam.

`))

func info(w http.ResponseWriter, settings *storage.Settings) {
	infoTemplate.Execute(w, settings)
}

type allHandler struct{ *linking.Semanticizer }

func (h allHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	serveEntities(w, req, h.All)
}

type bestPathHandler struct{ *linking.Semanticizer }

func (h bestPathHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	serveEntities(w, req, h.BestPath)
}

type stringHandler struct{ *linking.Semanticizer }

func (h stringHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	serveEntities(w, req, h.ExactMatch)
}

func serveEntities(w http.ResponseWriter, req *http.Request,
	method func(string) ([]linking.Entity, error)) {

	text, err := ioutil.ReadAll(req.Body)
	if len(text) == 0 {
		err = errors.New("received no data")
	}
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	cands, err := method(string(text))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	if cands == nil {
		// Report "[]" to caller, not "null".
		cands = make([]linking.Entity, 0)
	}

	json.NewEncoder(w).Encode(cands)
}

// Determine actual port used by l and write it to path (followed by a newline).
//
// This is useful for random ports, as assigned when using port number 0.
func writePort(l net.Listener, path string) (err error) {
	f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0644)
	if err != nil {
		return
	}
	defer f.Close()

	_, port, err := net.SplitHostPort(l.Addr().String())
	if err != nil {
		return
	}
	fmt.Fprintln(f, port)
	return
}

func restServer(addr, portfile string, sem *linking.Semanticizer,
	s *storage.Settings) (err error) {

	http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
		info(w, s)
	})
	http.Handle("/all", allHandler{sem})
	http.Handle("/bestpath", bestPathHandler{sem})
	http.Handle("/exactmatch", stringHandler{sem})

	l, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}
	defer l.Close()

	if portfile != "" {
		writePort(l, portfile)
	}

	return http.Serve(l, nil)
}
<commit_msg>check errors when opening portfile<commit_after>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"html/template"
	"io/ioutil"
	"net"
	"net/http"
	"os"

	"github.com/semanticize/st/internal/storage"
	"github.com/semanticize/st/linking"
)

var infoTemplate = template.Must(template.New("info").Parse(`
<title>Semanticizest</title>

Semanticizest

      Serving {{.Dumpname}}
      with maximum n-gram length {{.MaxNGram}}.

Endpoints take data via POST requests and produce JSON:

          /all
          gives all candidate entities occurring anywhere in a string

          /bestpath gives the entities according to a
          Viterbi algorithm

          /exactmatch
          gives all candidate entities for a string (but not its substrings)

© 2015 Netherlands eScience Center/University of Amsterdam.

`))

func info(w http.ResponseWriter, settings *storage.Settings) {
	infoTemplate.Execute(w, settings)
}

type allHandler struct{ *linking.Semanticizer }

func (h allHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	serveEntities(w, req, h.All)
}

type bestPathHandler struct{ *linking.Semanticizer }

func (h bestPathHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	serveEntities(w, req, h.BestPath)
}

type stringHandler struct{ *linking.Semanticizer }

func (h stringHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	serveEntities(w, req, h.ExactMatch)
}

func serveEntities(w http.ResponseWriter, req *http.Request,
	method func(string) ([]linking.Entity, error)) {

	text, err := ioutil.ReadAll(req.Body)
	if len(text) == 0 {
		err = errors.New("received no data")
	}
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	cands, err := method(string(text))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	if cands == nil {
		// Report "[]" to caller, not "null".
		cands = make([]linking.Entity, 0)
	}

	json.NewEncoder(w).Encode(cands)
}

// Determine actual port used by l and write it to path (followed by a newline).
//
// This is useful for random ports, as assigned when using port number 0.
func writePort(l net.Listener, path string) (err error) {
	f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0644)
	if err != nil {
		return
	}
	defer f.Close()

	_, port, err := net.SplitHostPort(l.Addr().String())
	if err != nil {
		return
	}
	fmt.Fprintln(f, port)
	return
}

func restServer(addr, portfile string, sem *linking.Semanticizer,
	s *storage.Settings) (err error) {

	http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
		info(w, s)
	})
	http.Handle("/all", allHandler{sem})
	http.Handle("/bestpath", bestPathHandler{sem})
	http.Handle("/exactmatch", stringHandler{sem})

	l, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}
	defer l.Close()

	if portfile != "" {
		if err = writePort(l, portfile); err != nil {
			return
		}
	}

	return http.Serve(l, nil)
}
<|endoftext|>


<commit_before>package network

import (
	//"encoding/json"
	"fmt"
	"net/http"
	// "net/http/httptest"
	//"net/url"
	//"os"
	//"strings"
)

func getBasicHeaders() map[string]string {
	return map[string]string{
		"x-amz-id-2":       "ef8yU9AS1ed4OpIszj7UDNEHGran",
		"x-amz-request-id": "318BC8BC143432E5",
		"x-amz-version-id": "3HL4kqtJlcpXroDTDmjVBH40Nrjfkd",
		"Date":             "Wed, 30 May 2018 22:32:00 GMT",
		"Last-Modified":    "Tue, 29 May 2018 12:00:00 GMT",
		"ETag":             `"fba9dede5f27731c9771645a39863328"`,
		"Content-Length":   "434234",
		"Content-Type":     "text/plain",
		"Connection":       "close",
		"Server":           "AmazonS3",
	}
}

func S3HeadHandler(w http.ResponseWriter, r *http.Request) {
	for key, value := range getBasicHeaders() {
		w.Header().Set(key, value)
	}
	fmt.Fprintln(w, "")
}

// Handles an S3 Head request and replies that a restore is already in progress.
func S3HeadRestoreInProgressHandler(w http.ResponseWriter, r *http.Request) {
	for key, value := range getBasicHeaders() {
		w.Header().Set(key, value)
	}
	w.Header().Set("x-amz-restore", `ongoing-request="true"`)
	fmt.Fprintln(w, "")
}

// Handles an S3 Head request and replies that a restore is complete.
func S3HeadRestoreCompletedHandler(w http.ResponseWriter, r *http.Request) {
	for key, value := range getBasicHeaders() {
		w.Header().Set(key, value)
	}
	w.Header().Set("x-amz-restore", `ongoing-request="false", expiry-date="Fri, 1 Jun 2018 04:00:00 GMT"`)
	fmt.Fprintln(w, "")
}

// Handles a request to restore a Glacier object to S3.
func S3RestoreHandler(w http.ResponseWriter, r *http.Request) {

}
<commit_msg>Working on mocks for S3 restore<commit_after>package network

import (
	//"encoding/json"
	"fmt"
	"net/http"
	// "net/http/httptest"
	//"net/url"
	//"os"
	//"strings"
)

func getBasicHeaders() map[string]string {
	return map[string]string{
		"x-amz-id-2":       "ef8yU9AS1ed4OpIszj7UDNEHGran",
		"x-amz-request-id": "318BC8BC143432E5",
		"x-amz-version-id": "3HL4kqtJlcpXroDTDmjVBH40Nrjfkd",
		"Date":             "Wed, 30 May 2018 22:32:00 GMT",
		"Last-Modified":    "Tue, 29 May 2018 12:00:00 GMT",
		"ETag":             `"fba9dede5f27731c9771645a39863328"`,
		"Content-Length":   "434234",
		"Content-Type":     "text/plain",
		"Connection":       "close",
		"Server":           "AmazonS3",
	}
}

func S3HeadHandler(w http.ResponseWriter, r *http.Request) {
	for key, value := range getBasicHeaders() {
		w.Header().Set(key, value)
	}
	fmt.Fprintln(w, "")
}

// Handles an S3 Head request and replies that a restore is already in progress.
func S3HeadRestoreInProgressHandler(w http.ResponseWriter, r *http.Request) {
	for key, value := range getBasicHeaders() {
		w.Header().Set(key, value)
	}
	w.Header().Set("x-amz-restore", `ongoing-request="true"`)
	fmt.Fprintln(w, "")
}

// Handles an S3 Head request and replies that a restore is complete.
func S3HeadRestoreCompletedHandler(w http.ResponseWriter, r *http.Request) {
	for key, value := range getBasicHeaders() {
		w.Header().Set(key, value)
	}
	w.Header().Set("x-amz-restore", `ongoing-request="false", expiry-date="Fri, 1 Jun 2018 04:00:00 GMT"`)
	fmt.Fprintln(w, "")
}

func getRestoreHeaders() map[string]string {
	return map[string]string{
		"x-amz-id-2":       "GFihv3y6+kE7KG11GEkQhU7/2/cHR3Yb2fCb2S04nxI423Dqwg2XiQ0B/UZlzYQvPiBlZNRcovw=",
		"x-amz-request-id": "9F341CD3C4BA79E0",
		"Date":             "Wed, 30 May 2018 22:32:00 GMT",
		"Content-Length":   "0",
		"Server":           "AmazonS3",
	}
}

// Handles a request to restore a Glacier object to S3.
func S3RestoreHandler(w http.ResponseWriter, r *http.Request) {
	for key, value := range getRestoreHeaders() {
		w.Header().Set(key, value)
	}
	// Must return 202 to indicate the request was accepted
	w.WriteHeader(http.StatusAccepted)
	fmt.Fprintln(w, "")
}

// Handles a request to restore a Glacier object to S3,
// and replies with a 409 to say the restoration is
// already in progress.
// See https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPOSTrestore.html
func S3RestoreInProgressHandler(w http.ResponseWriter, r *http.Request) {
	for key, value := range getRestoreHeaders() {
		w.Header().Set(key, value)
	}
	// Must return 409 to indicate the request conflicts
	// with one already in progress
	w.WriteHeader(http.StatusConflict)
	fmt.Fprintln(w, "")
}

// Handles a request to restore a Glacier object to S3,
// and replies with a 200 to say the restoration is
// already completed (item already restored to active tier)
func S3RestoreCompletedHandler(w http.ResponseWriter, r *http.Request) {
	for key, value := range getRestoreHeaders() {
		w.Header().Set(key, value)
	}
	// Must return 200 to indicate item has already
	// been restored to S3
	w.WriteHeader(http.StatusOK)
	fmt.Fprintln(w, "")
}
<|endoftext|>


<commit_before>package main

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

	"github.com/prometheus/client_golang/prometheus"
)

type collector struct {
	sources []*source
}

type source struct {
	URL       string
	Namespace string
	Subsystem string
	Labels    map[string]string
	Keys      map[string]struct {
		Skip           bool
		MapValue       map[string]float64
		UseKeysAsLabel string
	}
}

func main() {
	sourcesJSON := os.Getenv("SOURCES")
	if sourcesJSON == "" {
		log.Print("environemnt variable SOURCES is requred")
		return
	}

	var sources []*source
	if err := json.Unmarshal([]byte(sourcesJSON), &sources); err != nil {
		log.Print(err)
		return
	}

	prometheus.MustRegister(&collector{sources})
	http.Handle("/metrics", prometheus.Handler())

	addr := os.Getenv("HTTP_ADDR")
	if addr == "" {
		addr = ":8080"
	}
	fmt.Println("listening on " + addr)
	log.Print(http.ListenAndServe(addr, nil))
}

func (c *collector) Describe(descs chan<- *prometheus.Desc) {
	metrics := make(chan prometheus.Metric)
	done := make(chan struct{})
	go func() {
		for m := range metrics {
			descs <- m.Desc()
		}
		close(done)
	}()
	c.Collect(metrics)
	close(metrics)
	<-done
}

func (c *collector) Collect(metrics chan<- prometheus.Metric) {
	for _, s := range c.sources {
		resp, err := http.Get(s.URL)
		if err != nil {
			log.Print(err)
			continue
		}
		defer resp.Body.Close()

		var value interface{}
		if err := json.NewDecoder(resp.Body).Decode(&value); err != nil {
			log.Print(err)
			continue
		}

		var labelNames []string
		var labelValues []string
		for k, v := range s.Labels {
			labelNames = append(labelNames, k)
			labelValues = append(labelValues, v)
		}
		s.processValue(nil, labelNames, labelValues, value, metrics)
	}
}

func (s *source) processValue(keys []string, labelNames, labelValues []string, value interface{}, metrics chan<- prometheus.Metric) {
	switch value := value.(type) {
	case map[string]interface{}:
		for k2, v2 := range value {
			d := s.Keys[k2]
			if d.Skip {
				continue
			}
			if d.MapValue != nil {
				s.processValue(append(keys, strings.Trim(k2, "_")), labelNames, labelValues, d.MapValue[v2.(string)], metrics)
				continue
			}
			if d.UseKeysAsLabel != "" {
				for k3, v3 := range v2.(map[string]interface{}) {
					s.processValue(append(keys, strings.Trim(k2, "_")), append(labelNames, d.UseKeysAsLabel), append(labelValues, k3), v3, metrics)
				}
				continue
			}
			s.processValue(append(keys, strings.Trim(k2, "_")), labelNames, labelValues, v2, metrics)
		}
	case float64:
		if value == 0 {
			return
		}
		labels := make(prometheus.Labels)
		for i, name := range labelNames {
			labels[name] = labelValues[i]
		}
		g := prometheus.NewGauge(prometheus.GaugeOpts{
			Namespace:   s.Namespace,
			Subsystem:   s.Subsystem,
			Name:        strings.Join(keys, "_"),
			Help:        strings.Join(keys, "."),
			ConstLabels: labels,
		})
		g.Set(value)
		metrics <- g
	}
}
<commit_msg>added root page<commit_after>package main

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

	"github.com/prometheus/client_golang/prometheus"
)

type collector struct {
	sources []*source
}

type source struct {
	URL       string
	Namespace string
	Subsystem string
	Labels    map[string]string
	Keys      map[string]struct {
		Skip           bool
		MapValue       map[string]float64
		UseKeysAsLabel string
	}
}

func main() {
	sourcesJSON := os.Getenv("SOURCES")
	if sourcesJSON == "" {
		log.Print("environemnt variable SOURCES is requred")
		return
	}

	var sources []*source
	if err := json.Unmarshal([]byte(sourcesJSON), &sources); err != nil {
		log.Print(err)
		return
	}

	prometheus.MustRegister(&collector{sources})
	http.Handle("/", http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
		resp.Write([]byte(`<html><head><title>json2prom</title></head><body><h1>json2prom</h1><p><a href="/metrics">Metrics</a></p></body></html>`))
	}))
	http.Handle("/metrics", prometheus.Handler())

	addr := os.Getenv("HTTP_ADDR")
	if addr == "" {
		addr = ":8080"
	}
	fmt.Println("listening on " + addr)
	log.Print(http.ListenAndServe(addr, nil))
}

func (c *collector) Describe(descs chan<- *prometheus.Desc) {
	metrics := make(chan prometheus.Metric)
	done := make(chan struct{})
	go func() {
		for m := range metrics {
			descs <- m.Desc()
		}
		close(done)
	}()
	c.Collect(metrics)
	close(metrics)
	<-done
}

func (c *collector) Collect(metrics chan<- prometheus.Metric) {
	for _, s := range c.sources {
		resp, err := http.Get(s.URL)
		if err != nil {
			log.Print(err)
			continue
		}
		defer resp.Body.Close()

		var value interface{}
		if err := json.NewDecoder(resp.Body).Decode(&value); err != nil {
			log.Print(err)
			continue
		}

		var labelNames []string
		var labelValues []string
		for k, v := range s.Labels {
			labelNames = append(labelNames, k)
			labelValues = append(labelValues, v)
		}
		s.processValue(nil, labelNames, labelValues, value, metrics)
	}
}

func (s *source) processValue(keys []string, labelNames, labelValues []string, value interface{}, metrics chan<- prometheus.Metric) {
	switch value := value.(type) {
	case map[string]interface{}:
		for k2, v2 := range value {
			d := s.Keys[k2]
			if d.Skip {
				continue
			}
			if d.MapValue != nil {
				s.processValue(append(keys, strings.Trim(k2, "_")), labelNames, labelValues, d.MapValue[v2.(string)], metrics)
				continue
			}
			if d.UseKeysAsLabel != "" {
				for k3, v3 := range v2.(map[string]interface{}) {
					s.processValue(append(keys, strings.Trim(k2, "_")), append(labelNames, d.UseKeysAsLabel), append(labelValues, k3), v3, metrics)
				}
				continue
			}
			s.processValue(append(keys, strings.Trim(k2, "_")), labelNames, labelValues, v2, metrics)
		}
	case float64:
		if value == 0 {
			return
		}
		labels := make(prometheus.Labels)
		for i, name := range labelNames {
			labels[name] = labelValues[i]
		}
		g := prometheus.NewGauge(prometheus.GaugeOpts{
			Namespace:   s.Namespace,
			Subsystem:   s.Subsystem,
			Name:        strings.Join(keys, "_"),
			Help:        strings.Join(keys, "."),
			ConstLabels: labels,
		})
		g.Set(value)
		metrics <- g
	}
}
<|endoftext|>


<commit_before>package bulk_query_gen

import (
	"fmt"
	"sync"
)

type Query interface {
	Release()
	HumanLabelName() []byte
	HumanDescriptionName() []byte
	fmt.Stringer
}

var HTTPQueryPool sync.Pool = sync.Pool{
	New: func() interface{} {
		return &HTTPQuery{
			HumanLabel:       []byte{},
			HumanDescription: []byte{},
			Method:           []byte{},
			Path:             []byte{},
			Body:             []byte{},
			StartTimestamp:   0,
			EndTimestamp:     0,
		}
	},
}

// HTTPQuery encodes an HTTP request. This will typically by serialized for use
// by the query_benchmarker program.
type HTTPQuery struct {
	HumanLabel       []byte
	HumanDescription []byte
	Method           []byte
	Path             []byte
	Body             []byte
	StartTimestamp   int64
	EndTimestamp     int64
}

func NewHTTPQuery() *HTTPQuery {
	return HTTPQueryPool.Get().(*HTTPQuery)
}

// String produces a debug-ready description of a Query.
func (q *HTTPQuery) String() string {
	return fmt.Sprintf("HumanLabel: \"%s\", HumanDescription: \"%s\", Method: \"%s\", Path: \"%s\", Body: \"%s\"", q.HumanLabel, q.HumanDescription, q.Method, q.Path, q.Body)
}

func (q *HTTPQuery) HumanLabelName() []byte {
	return q.HumanLabel
}
func (q *HTTPQuery) HumanDescriptionName() []byte {
	return q.HumanDescription
}

func (q *HTTPQuery) Release() {
	q.HumanLabel = q.HumanLabel[:0]
	q.HumanDescription = q.HumanDescription[:0]
	q.Method = q.Method[:0]
	q.Path = q.Path[:0]
	q.Body = q.Body[:0]
	q.StartTimestamp = 0
	q.EndTimestamp = 0

	HTTPQueryPool.Put(q)
}
<commit_msg>Added default query window<commit_after>package bulk_query_gen

import (
	"fmt"
	"sync"
	"time"
)

const DefaultQueryInterval = time.Hour * 24 * 180

type Query interface {
	Release()
	HumanLabelName() []byte
	HumanDescriptionName() []byte
	fmt.Stringer
}

var HTTPQueryPool sync.Pool = sync.Pool{
	New: func() interface{} {
		return &HTTPQuery{
			HumanLabel:       []byte{},
			HumanDescription: []byte{},
			Method:           []byte{},
			Path:             []byte{},
			Body:             []byte{},
			StartTimestamp:   0,
			EndTimestamp:     0,
		}
	},
}

// HTTPQuery encodes an HTTP request. This will typically by serialized for use
// by the query_benchmarker program.
type HTTPQuery struct {
	HumanLabel       []byte
	HumanDescription []byte
	Method           []byte
	Path             []byte
	Body             []byte
	StartTimestamp   int64
	EndTimestamp     int64
}

func NewHTTPQuery() *HTTPQuery {
	return HTTPQueryPool.Get().(*HTTPQuery)
}

// String produces a debug-ready description of a Query.
func (q *HTTPQuery) String() string {
	return fmt.Sprintf("HumanLabel: \"%s\", HumanDescription: \"%s\", Method: \"%s\", Path: \"%s\", Body: \"%s\"", q.HumanLabel, q.HumanDescription, q.Method, q.Path, q.Body)
}

func (q *HTTPQuery) HumanLabelName() []byte {
	return q.HumanLabel
}
func (q *HTTPQuery) HumanDescriptionName() []byte {
	return q.HumanDescription
}

func (q *HTTPQuery) Release() {
	q.HumanLabel = q.HumanLabel[:0]
	q.HumanDescription = q.HumanDescription[:0]
	q.Method = q.Method[:0]
	q.Path = q.Path[:0]
	q.Body = q.Body[:0]
	q.StartTimestamp = 0
	q.EndTimestamp = 0

	HTTPQueryPool.Put(q)
}
<|endoftext|>


<commit_before>// Copyright 2012 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 race_test

import (
	"runtime"
	"sync"
	"testing"
	"time"
)

func TestNoRaceFin(t *testing.T) {
	c := make(chan bool)
	go func() {
		x := new(int)
		runtime.SetFinalizer(x, func(x *int) {
			*x = 42
		})
		*x = 66
		c <- true
	}()
	<-c
	runtime.GC()
	time.Sleep(1e8)
}

var finVar struct {
	sync.Mutex
	cnt int
}

func TestNoRaceFinGlobal(t *testing.T) {
	c := make(chan bool)
	go func() {
		x := new(int)
		runtime.SetFinalizer(x, func(x *int) {
			finVar.Lock()
			finVar.cnt++
			finVar.Unlock()
		})
		c <- true
	}()
	<-c
	runtime.GC()
	time.Sleep(1e8)
	finVar.Lock()
	finVar.cnt++
	finVar.Unlock()
}

func TestRaceFin(t *testing.T) {
	c := make(chan bool)
	y := 0
	go func() {
		x := new(int)
		runtime.SetFinalizer(x, func(x *int) {
			y = 42
		})
		c <- true
	}()
	<-c
	runtime.GC()
	time.Sleep(1e8)
	y = 66
}
<commit_msg>runtime/race: fix finalizer tests After "runtime: combine small NoScan allocations" finalizers for small objects run more non deterministically. TestRaceFin episodically fails on my darwin/amd64.<commit_after>// Copyright 2012 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 race_test

import (
	"runtime"
	"sync"
	"testing"
	"time"
)

func TestNoRaceFin(t *testing.T) {
	c := make(chan bool)
	go func() {
		x := new(string)
		runtime.SetFinalizer(x, func(x *string) {
			*x = "foo"
		})
		*x = "bar"
		c <- true
	}()
	<-c
	runtime.GC()
	time.Sleep(100 * time.Millisecond)
}

var finVar struct {
	sync.Mutex
	cnt int
}

func TestNoRaceFinGlobal(t *testing.T) {
	c := make(chan bool)
	go func() {
		x := new(string)
		runtime.SetFinalizer(x, func(x *string) {
			finVar.Lock()
			finVar.cnt++
			finVar.Unlock()
		})
		c <- true
	}()
	<-c
	runtime.GC()
	time.Sleep(100 * time.Millisecond)
	finVar.Lock()
	finVar.cnt++
	finVar.Unlock()
}

func TestRaceFin(t *testing.T) {
	c := make(chan bool)
	y := 0
	go func() {
		x := new(string)
		runtime.SetFinalizer(x, func(x *string) {
			y = 42
		})
		c <- true
	}()
	<-c
	runtime.GC()
	time.Sleep(100 * time.Millisecond)
	y = 66
}
<|endoftext|>


<commit_before>// patcher.go
// 修复从手机端导出的缓存优酷MP4文件只能在优酷播放器播放的问题
// 优酷对MP4源文件进行了简单的加密处理，导致只能在优酷播放器里播放
// 修复后的MP4文件可以在任意播放器里播放
// fix youku mp4 file.
// https://github.com/Hell0wor1d
package main

import (
	"fmt"
	"github.com/cheggaaa/pb"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path"
	"strings"
)

const (
	FILE_EXT    = ".mp4"
	FILE_BUFFER = 1024
)

func main() {
	argsWithoutProg := os.Args[1:]
	if len(argsWithoutProg) <= 0 {
		fmt.Println("Please input a directory or file path.")
		return
	}
	target, err := os.Stat(argsWithoutProg[0])
	if os.IsNotExist(err) {
		fmt.Printf("No such file or directory: %s", argsWithoutProg[0])
		return
	}

	//process directory
	if target.IsDir() {
		files, _ := ioutil.ReadDir(argsWithoutProg[0])
		for _, file := range files {
			if file.IsDir() {
				continue
			} else {
				filePath := path.Join(argsWithoutProg[0], file.Name())
				if path.Ext(filePath) == FILE_EXT {
					PatchFile(filePath)
				}
			}
		}
	} else {
		if path.Ext(argsWithoutProg[0]) == FILE_EXT {
			PatchFile(argsWithoutProg[0])
		}
	}
}

func PatchFile(fName string) {
	srcFile, err := os.Open(fName) // For read access.
	if err != nil {
		log.Fatal(err)
	}

	// close srcFile on exit and check for its returned error
	defer func() {
		if err := srcFile.Close(); err != nil {
			log.Fatal(err)
		}
	}()

	stat, err := srcFile.Stat()
	if err != nil {
		log.Fatal(err)
	}
	srcFileSize := stat.Size()
	srcFile.Seek(srcFileSize-8, 0)
	data := make([]byte, 8)
	count, err := srcFile.Read(data)
	if err != nil {
		log.Fatal(err)
	}
	flat := string(data[:count])
	if strings.Contains(flat, "ftyp") {
		fNameInfo := strings.Split(fName, ".")
		newFileName := fNameInfo[0] + "_patched." + fNameInfo[1]

		// equivalent to Python's `if os.path.exists(filename)`
		if _, err := os.Stat(newFileName); err == nil {
			//log.Println("Patched file exists.", newFileName)
			return
		}
		newFile, err := os.Create(newFileName)
		if err != nil {
			log.Fatal(err)
		}

		// close newFile on exit and check for its returned error
		defer func() {
			if err := newFile.Close(); err != nil {
				log.Fatal(err)
			}
		}()

		newFile.Write(data)
		// make a buffer to keep chunks that are read
		buf := make([]byte, FILE_BUFFER)
		srcFile.Seek(8, 0)
		bar := pb.StartNew(int(srcFileSize) - 8)
		bar.ShowCounters = false
		var readLength int64 = 0
		for {
			n, err := srcFile.Read(buf)
			readLength += int64(n)

			if err != nil && err != io.EOF {
				log.Fatal(err)
			}

			if n == 0 {
				break
			}

			if readLength >= (srcFileSize - 8) {
				n = n - 8
			}
			bar.Add(n)
			// write a chunk
			if _, err := newFile.Write(buf[:n]); err != nil {
				log.Fatal(err)
			}
		}
		bar.FinishPrint("The srcFile" + fName + " has been patched successfully.")
	} else {
		log.Println("The file dose not need to patch.", fName)
	}
}
<commit_msg>fix screen print info<commit_after>// patcher.go
// 修复从手机端导出的缓存优酷MP4文件只能在优酷播放器播放的问题
// 优酷对MP4源文件进行了简单的加密处理，导致只能在优酷播放器里播放
// 修复后的MP4文件可以在任意播放器里播放
// fix youku mp4 file.
// https://github.com/Hell0wor1d
package main

import (
	"fmt"
	"github.com/cheggaaa/pb"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path"
	"strings"
)

const (
	FILE_EXT    = ".mp4"
	FILE_BUFFER = 1024
)

func main() {
	argsWithoutProg := os.Args[1:]
	if len(argsWithoutProg) <= 0 {
		fmt.Println("Please input a directory or file path.")
		return
	}
	target, err := os.Stat(argsWithoutProg[0])
	if os.IsNotExist(err) {
		fmt.Printf("No such file or directory: %s", argsWithoutProg[0])
		return
	}

	//process directory
	if target.IsDir() {
		files, _ := ioutil.ReadDir(argsWithoutProg[0])
		for _, file := range files {
			if file.IsDir() {
				continue
			} else {
				filePath := path.Join(argsWithoutProg[0], file.Name())
				if path.Ext(filePath) == FILE_EXT {
					PatchFile(filePath)
				}
			}
		}
	} else {
		if path.Ext(argsWithoutProg[0]) == FILE_EXT {
			PatchFile(argsWithoutProg[0])
		}
	}
}

func PatchFile(fName string) {
	srcFile, err := os.Open(fName) // For read access.
	if err != nil {
		log.Fatal(err)
	}

	// close srcFile on exit and check for its returned error
	defer func() {
		if err := srcFile.Close(); err != nil {
			log.Fatal(err)
		}
	}()

	stat, err := srcFile.Stat()
	if err != nil {
		log.Fatal(err)
	}
	srcFileSize := stat.Size()
	srcFile.Seek(srcFileSize-8, 0)
	data := make([]byte, 8)
	count, err := srcFile.Read(data)
	if err != nil {
		log.Fatal(err)
	}
	flat := string(data[:count])
	if strings.Contains(flat, "ftyp") {
		fNameInfo := strings.Split(fName, ".")
		newFileName := fNameInfo[0] + "_patched." + fNameInfo[1]

		// equivalent to Python's `if os.path.exists(filename)`
		if _, err := os.Stat(newFileName); err == nil {
			//log.Println("Patched file exists.", newFileName)
			return
		}
		newFile, err := os.Create(newFileName)
		if err != nil {
			log.Fatal(err)
		}

		// close newFile on exit and check for its returned error
		defer func() {
			if err := newFile.Close(); err != nil {
				log.Fatal(err)
			}
		}()

		newFile.Write(data)
		// make a buffer to keep chunks that are read
		buf := make([]byte, FILE_BUFFER)
		srcFile.Seek(8, 0)
		bar := pb.StartNew(int(srcFileSize) - 8)
		bar.ShowCounters = false
		var readLength int64 = 0
		for {
			n, err := srcFile.Read(buf)
			readLength += int64(n)

			if err != nil && err != io.EOF {
				log.Fatal(err)
			}

			if n == 0 {
				break
			}

			if readLength >= (srcFileSize - 8) {
				n = n - 8
			}
			bar.Add(n)
			// write a chunk
			if _, err := newFile.Write(buf[:n]); err != nil {
				log.Fatal(err)
			}
		}
		bar.FinishPrint("The srcFile " + fName + " has been patched successfully.")
	} else {
		log.Println("The file dose not need to patch.", fName)
	}
}
<|endoftext|>


<commit_before>package browser

import (
	"github.com/PuerkitoBio/goquery"
	"github.com/headzoo/surf/errors"
	"net/url"
	"strings"
)

// Submittable represents an element that may be submitted, such as a form.
type Submittable interface {
	Method() string
	Action() string
	Input(name, value string) error
	Click(button string) error
	Submit() error
	Dom() *goquery.Selection
}

// Form is the default form element.
type Form struct {
	bow           Browsable
	selection     *goquery.Selection
	method        string
	action        string
	definedFields []string
	fields        url.Values
	buttons       url.Values
}

// NewForm creates and returns a *Form type.
func NewForm(bow Browsable, s *goquery.Selection) *Form {
	definedFields, fields, buttons := serializeForm(s)
	method, action := formAttributes(bow, s)

	return &Form{
		bow:           bow,
		selection:     s,
		method:        method,
		action:        action,
		definedFields: definedFields,
		fields:        fields,
		buttons:       buttons,
	}
}

// Method returns the form method, eg "GET" or "POST".
func (f *Form) Method() string {
	return f.method
}

// Action returns the form action URL.
// The URL will always be absolute.
func (f *Form) Action() string {
	return f.action
}

// stringInSlice judges wheter slice has the given string.
// Original: http://stackoverflow.com/questions/15323767/how-to-if-x-in-array-in-golang
func stringInSlice(a string, list []string) bool {
	for _, b := range list {
		if b == a {
			return true
		}
	}
	return false
}

// Input sets the value of a form field.
func (f *Form) Input(name, value string) error {
	if stringInSlice(name, f.definedFields) {
		f.fields.Set(name, value)
		return nil
	}
	return errors.NewElementNotFound(
		"No input found with name '%s'.", name)
}

// Submit submits the form.
// Clicks the first button in the form, or submits the form without using
// any button when the form does not contain any buttons.
func (f *Form) Submit() error {
	if len(f.buttons) > 0 {
		for name := range f.buttons {
			return f.Click(name)
		}
	}
	return f.send("", "")
}

// Click submits the form by clicking the button with the given name.
func (f *Form) Click(button string) error {
	if _, ok := f.buttons[button]; !ok {
		return errors.NewInvalidFormValue(
			"Form does not contain a button with the name '%s'.", button)
	}
	return f.send(button, f.buttons[button][0])
}

// Dom returns the inner *goquery.Selection.
func (f *Form) Dom() *goquery.Selection {
	return f.selection
}

// send submits the form.
func (f *Form) send(buttonName, buttonValue string) error {
	method, ok := f.selection.Attr("method")
	if !ok {
		method = "GET"
	}
	action, ok := f.selection.Attr("action")
	if !ok {
		action = f.bow.Url().String()
	}
	aurl, err := url.Parse(action)
	if err != nil {
		return err
	}
	aurl = f.bow.ResolveUrl(aurl)

	values := make(url.Values, len(f.fields)+1)
	for name, vals := range f.fields {
		values[name] = vals
	}
	if buttonName != "" {
		values.Set(buttonName, buttonValue)
	}

	if strings.ToUpper(method) == "GET" {
		return f.bow.OpenForm(aurl.String(), values)
	} else {
		return f.bow.PostForm(aurl.String(), values)
	}

	return nil
}

// Serialize converts the form fields into a url.Values type.
// Returns two url.Value types. The first is the form field values, and the
// second is the form button values.
func serializeForm(sel *goquery.Selection) ([]string, url.Values, url.Values) {
	input := sel.Find("input,button")
	var definedfields []string
	fields := make(url.Values)
	buttons := make(url.Values)

	input.Each(func(_ int, s *goquery.Selection) {
		name, ok := s.Attr("name")
		if ok {
			typ, ok := s.Attr("type")
			if ok {
				if typ == "submit" {
					val, ok := s.Attr("value")
					if ok {
						buttons.Add(name, val)
					} else {
						buttons.Add(name, "")
					}
				} else if typ == "radio" || typ == "checkbox" {
					definedfields = append(definedfields, name)
					_, ok := s.Attr("checked")
					if ok {
						val, ok := s.Attr("value")
						if ok {
							fields.Add(name, val)
						}
					}
				} else {
					definedfields = append(definedfields, name)
					val, ok := s.Attr("value")
					if ok {
						fields.Add(name, val)
					}
				}
			}
		}
	})

	selec := sel.Find("select")

	selec.Each(func(_ int, s *goquery.Selection) {
		name, ok := s.Attr("name")
		if !ok {
			return
		}
		definedfields = append(definedfields, name)
		s.Find("option[selected]").Each(func(_ int, so *goquery.Selection) {
			val, ok := so.Attr("value")
			if ok {
				fields.Add(name, val)
			}
		})
	})

	textarea := sel.Find("textarea")
	textarea.Each(func(_ int, s *goquery.Selection) {
		name, ok := s.Attr("name")
		if !ok {
			return
		}
		definedfields = append(definedfields, name)
		fields.Add(name, s.Text())
	})

	return definedfields, fields, buttons
}

func formAttributes(bow Browsable, s *goquery.Selection) (string, string) {
	method, ok := s.Attr("method")
	if !ok {
		method = "GET"
	}
	action, ok := s.Attr("action")
	if !ok {
		action = bow.Url().String()
	}
	aurl, err := url.Parse(action)
	if err != nil {
		return "", ""
	}
	aurl = bow.ResolveUrl(aurl)

	return strings.ToUpper(method), aurl.String()
}
<commit_msg>Use map[string]bool type for defiledFields.<commit_after>package browser

import (
	"github.com/PuerkitoBio/goquery"
	"github.com/headzoo/surf/errors"
	"net/url"
	"strings"
)

// Submittable represents an element that may be submitted, such as a form.
type Submittable interface {
	Method() string
	Action() string
	Input(name, value string) error
	Click(button string) error
	Submit() error
	Dom() *goquery.Selection
}

// Form is the default form element.
type Form struct {
	bow           Browsable
	selection     *goquery.Selection
	method        string
	action        string
	definedFields map[string]bool
	fields        url.Values
	buttons       url.Values
}

// NewForm creates and returns a *Form type.
func NewForm(bow Browsable, s *goquery.Selection) *Form {
	definedFields, fields, buttons := serializeForm(s)
	method, action := formAttributes(bow, s)

	return &Form{
		bow:           bow,
		selection:     s,
		method:        method,
		action:        action,
		definedFields: definedFields,
		fields:        fields,
		buttons:       buttons,
	}
}

// Method returns the form method, eg "GET" or "POST".
func (f *Form) Method() string {
	return f.method
}

// Action returns the form action URL.
// The URL will always be absolute.
func (f *Form) Action() string {
	return f.action
}

// Input sets the value of a form field.
func (f *Form) Input(name, value string) error {
	if f.definedFields[name] {
		f.fields.Set(name, value)
		return nil
	}
	return errors.NewElementNotFound(
		"No input found with name '%s'.", name)
}

// Submit submits the form.
// Clicks the first button in the form, or submits the form without using
// any button when the form does not contain any buttons.
func (f *Form) Submit() error {
	if len(f.buttons) > 0 {
		for name := range f.buttons {
			return f.Click(name)
		}
	}
	return f.send("", "")
}

// Click submits the form by clicking the button with the given name.
func (f *Form) Click(button string) error {
	if _, ok := f.buttons[button]; !ok {
		return errors.NewInvalidFormValue(
			"Form does not contain a button with the name '%s'.", button)
	}
	return f.send(button, f.buttons[button][0])
}

// Dom returns the inner *goquery.Selection.
func (f *Form) Dom() *goquery.Selection {
	return f.selection
}

// send submits the form.
func (f *Form) send(buttonName, buttonValue string) error {
	method, ok := f.selection.Attr("method")
	if !ok {
		method = "GET"
	}
	action, ok := f.selection.Attr("action")
	if !ok {
		action = f.bow.Url().String()
	}
	aurl, err := url.Parse(action)
	if err != nil {
		return err
	}
	aurl = f.bow.ResolveUrl(aurl)

	values := make(url.Values, len(f.fields)+1)
	for name, vals := range f.fields {
		values[name] = vals
	}
	if buttonName != "" {
		values.Set(buttonName, buttonValue)
	}

	if strings.ToUpper(method) == "GET" {
		return f.bow.OpenForm(aurl.String(), values)
	} else {
		return f.bow.PostForm(aurl.String(), values)
	}

	return nil
}

// Serialize converts the form fields into a url.Values type.
// Returns two url.Value types. The first is the form field values, and the
// second is the form button values.
func serializeForm(sel *goquery.Selection) (map[string]bool, url.Values, url.Values) {
	input := sel.Find("input,button")
	definedFields := map[string]bool{}
	fields := make(url.Values)
	buttons := make(url.Values)

	input.Each(func(_ int, s *goquery.Selection) {
		name, ok := s.Attr("name")
		if ok {
			typ, ok := s.Attr("type")
			if ok {
				if typ == "submit" {
					val, ok := s.Attr("value")
					if ok {
						buttons.Add(name, val)
					} else {
						buttons.Add(name, "")
					}
				} else if typ == "radio" || typ == "checkbox" {
					definedFields[name] = true
					_, ok := s.Attr("checked")
					if ok {
						val, ok := s.Attr("value")
						if ok {
							fields.Add(name, val)
						}
					}
				} else {
					definedFields[name] = true
					val, ok := s.Attr("value")
					if ok {
						fields.Add(name, val)
					}
				}
			}
		}
	})

	selec := sel.Find("select")

	selec.Each(func(_ int, s *goquery.Selection) {
		name, ok := s.Attr("name")
		if !ok {
			return
		}
		definedFields[name] = true
		s.Find("option[selected]").Each(func(_ int, so *goquery.Selection) {
			val, ok := so.Attr("value")
			if ok {
				fields.Add(name, val)
			}
		})
	})

	textarea := sel.Find("textarea")
	textarea.Each(func(_ int, s *goquery.Selection) {
		name, ok := s.Attr("name")
		if !ok {
			return
		}
		definedFields[name] = true
		fields.Add(name, s.Text())
	})

	return definedFields, fields, buttons
}

func formAttributes(bow Browsable, s *goquery.Selection) (string, string) {
	method, ok := s.Attr("method")
	if !ok {
		method = "GET"
	}
	action, ok := s.Attr("action")
	if !ok {
		action = bow.Url().String()
	}
	aurl, err := url.Parse(action)
	if err != nil {
		return "", ""
	}
	aurl = bow.ResolveUrl(aurl)

	return strings.ToUpper(method), aurl.String()
}
<|endoftext|>


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

//go:build plan9
// +build plan9

// Mount mounts servename on old, with an optional keypattern spec
//
// Synopsis:
//	 mount [ option ... ] servename old [ spec ]
//
// Description:
//	Mount modifies the name space of the current
//	process and other processes in the same name space group
//	(see https://9p.io/magic/man2html/1/bind).
//
// Options:
//	–b:	Both files must be directories. Add the new directory to the beginning of the union directory represented by the old file.
//	–a:	Both files must be directories. Add the new directory to the end of the union directory represented by the old file.
//	–c:	This can be used in addition to any of the above to permit creation in a union directory.
//		When a new file is created in a union directory, it is placed in the first element of the union that has been bound or mounted with the –c flag.
//		If that directory does not have write permission, the create fails.
//	-C:	By default, file contents are always retrieved from the server.
//		With this option, the kernel may instead use a local cache to satisfy read(5) requests for files accessible through this mount point.
package main

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

	"github.com/u-root/u-root/pkg/namespace"
)

func main() {
	if len(os.Args) == 1 {
		n := fmt.Sprintf("/proc/%d/ns", os.Getpid())
		if b, err := os.ReadFile(n); err == nil {
			fmt.Print(string(b))
			os.Exit(0)
		}
		log.Fatalf("Could not read %s to get namespace", n)
	}
	flag.Parse()
	mod, err := namespace.ParseArgs(flag.Args())
	if err != nil {
		log.Fatal(err)
	}
	if err := mod.Modify(namespace.DefaultNamespace, &namespace.Builder{}); err != nil {
		log.Fatal(err)
	}
}
<commit_msg>Fix how we pass arguments to the namespace package in Plan 9 mount<commit_after>// Copyright 2012-2020 the u-root Authors. All rights reserved
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build plan9
// +build plan9

// Mount mounts servename on old, with an optional keypattern spec
//
// Synopsis:
//	 mount [ option ... ] servename old [ spec ]
//
// Description:
//	Mount modifies the name space of the current
//	process and other processes in the same name space group
//	(see https://9p.io/magic/man2html/1/bind).
//
// Options:
//	–b:	Both files must be directories. Add the new directory to the beginning of the union directory represented by the old file.
//	–a:	Both files must be directories. Add the new directory to the end of the union directory represented by the old file.
//	–c:	This can be used in addition to any of the above to permit creation in a union directory.
//		When a new file is created in a union directory, it is placed in the first element of the union that has been bound or mounted with the –c flag.
//		If that directory does not have write permission, the create fails.
//	-C:	By default, file contents are always retrieved from the server.
//		With this option, the kernel may instead use a local cache to satisfy read(5) requests for files accessible through this mount point.
package main

import (
	"fmt"
	"log"
	"os"

	"github.com/u-root/u-root/pkg/namespace"
)

func main() {
	if len(os.Args) == 1 {
		n := fmt.Sprintf("/proc/%d/ns", os.Getpid())
		if b, err := os.ReadFile(n); err == nil {
			fmt.Print(string(b))
			os.Exit(0)
		}
		log.Fatalf("Could not read %s to get namespace", n)
	}
	mod, err := namespace.ParseArgs(os.Args)
	if err != nil {
		log.Fatal(err)
	}
	if err := mod.Modify(namespace.DefaultNamespace, &namespace.Builder{}); err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package helm

import (
	"fmt"
	"github.com/Aptomi/aptomi/pkg/event"
	"github.com/Aptomi/aptomi/pkg/util"
	"github.com/Aptomi/aptomi/pkg/util/retry"
	"io/ioutil"
	"k8s.io/helm/cmd/helm/installer"
	"k8s.io/helm/pkg/helm"
	"k8s.io/helm/pkg/helm/portforwarder"
	"k8s.io/helm/pkg/kube"
	"k8s.io/helm/pkg/repo"
	"strings"
)

func getHelmReleaseInfo(params util.NestedParameterMap) (repository, name, version string, err error) {
	repository, ok := params["chartRepo"].(string)
	if !ok {
		err = fmt.Errorf("chartRepo is a mandatory paraneter")
		return
	}

	name, ok = params["chartName"].(string)
	if !ok {
		err = fmt.Errorf("chartName is a mandatory paraneter")
		return
	}

	version = params["chartVersion"].(string)

	return
}

func getHelmReleaseName(deployName string) string {
	return strings.ToLower(util.EscapeName(deployName))
}

func findHelmRelease(helmClient *helm.Client, name string) (bool, error) {
	// todo(slukjanov): use release list filter
	resp, err := helmClient.ListReleases()
	if err != nil {
		return false, err
	}

	for _, release := range resp.Releases {
		if release.Name == name {
			return true, nil
		}
	}

	return false, nil
}

func (cache *clusterCache) newHelmClient(eventLog *event.Log) (*helm.Client, error) {
	return helm.NewClient(helm.Host(cache.tillerHost)), nil
}

func (cache *clusterCache) ensureTillerTunnel(eventLog *event.Log) error {
	if len(cache.tillerHost) > 0 {
		// todo(slukjanov): verify that tunnel is still alive??
		// connection already set up, skip
		return nil
	}

	var tunnelErr error
	ok := retry.Do(120, 5, func() bool {
		cache.tillerTunnel, tunnelErr = cache.newTillerTunnel()

		if tunnelErr != nil {
			if strings.Contains(tunnelErr.Error(), "could not find tiller") {
				err := cache.setupTiller(eventLog)
				if err != nil {
					tunnelErr = err
					return false
				}
			}

			return false
		}

		port := cache.tillerTunnel.Local
		cache.tillerHost = fmt.Sprintf("localhost:%d", port)
		eventLog.WithFields(event.Fields{}).Debugf("Created k8s tunnel using local port: %d", port)

		return true
	})

	if !ok {
		if tunnelErr != nil {
			return tunnelErr
		}

		return fmt.Errorf("tiller tunnel creation timeout for cluster: %s", cache.cluster.Name)
	}

	return nil
}

func (cache *clusterCache) newTillerTunnel() (*kube.Tunnel, error) {
	client, err := cache.newKubeClient()
	if err != nil {
		return nil, err
	}

	return portforwarder.New(cache.tillerNamespace, client, cache.kubeConfig)
}

func (cache *clusterCache) setupTiller(eventLog *event.Log) error {
	client, err := cache.newKubeClient()
	if err != nil {
		return err
	}

	eventLog.WithFields(event.Fields{}).Debugf("Setting up tiller in cluster %s namespace %s", cache.cluster.Name, cache.tillerNamespace)

	err = cache.ensureKubeNamespace(client, cache.tillerNamespace)
	if err != nil {
		return err
	}

	err = cache.createKubeServiceAccount(client, cache.tillerNamespace)
	if err != nil {
		return err
	}

	err = cache.createKubeClusterRoleBinding(client, cache.tillerNamespace)
	if err != nil {
		return err
	}

	// todo wait until tiller available
	return installer.Install(client, &installer.Options{
		Namespace:      cache.tillerNamespace,
		ImageSpec:      "gcr.io/kubernetes-helm/tiller:v2.6.2",
		ServiceAccount: "tiller-" + cache.tillerNamespace,
	})
}

func (plugin *Plugin) fetchChart(repository, name, version string) (string, error) {
	chartURL, err := repo.FindChartInRepoURL(
		repository, name, version,
		"", "", "",
		newGetterProviders(),
	)
	if err != nil {
		return "", fmt.Errorf("error while getting chart url in repo: %s", err)
	}

	chartFile, err := ioutil.TempFile("", name)
	if err != nil {
		return "", fmt.Errorf("error while creating temp file for downloading chart: %s", err)
	}

	chartGetter, err := newHTTPGetter(chartURL, "", "", "")
	if err != nil {
		return "", fmt.Errorf("error while creating chart downloader: %s", err)
	}

	resp, err := chartGetter.Get(chartURL)
	if err != nil {
		return "", fmt.Errorf("error while downloading chart: %s", err)
	}

	_, err = chartFile.Write(resp.Bytes())
	if err != nil {
		return "", fmt.Errorf("error while writing downloaded chart to the temp file")
	}

	return chartFile.Name(), nil
}
<commit_msg>Remove no more needed findHelmRelease util<commit_after>package helm

import (
	"fmt"
	"github.com/Aptomi/aptomi/pkg/event"
	"github.com/Aptomi/aptomi/pkg/util"
	"github.com/Aptomi/aptomi/pkg/util/retry"
	"io/ioutil"
	"k8s.io/helm/cmd/helm/installer"
	"k8s.io/helm/pkg/helm"
	"k8s.io/helm/pkg/helm/portforwarder"
	"k8s.io/helm/pkg/kube"
	"k8s.io/helm/pkg/repo"
	"strings"
)

func getHelmReleaseInfo(params util.NestedParameterMap) (repository, name, version string, err error) {
	repository, ok := params["chartRepo"].(string)
	if !ok {
		err = fmt.Errorf("chartRepo is a mandatory paraneter")
		return
	}

	name, ok = params["chartName"].(string)
	if !ok {
		err = fmt.Errorf("chartName is a mandatory paraneter")
		return
	}

	version = params["chartVersion"].(string)

	return
}

func getHelmReleaseName(deployName string) string {
	return strings.ToLower(util.EscapeName(deployName))
}

func (cache *clusterCache) newHelmClient(eventLog *event.Log) (*helm.Client, error) {
	return helm.NewClient(helm.Host(cache.tillerHost)), nil
}

func (cache *clusterCache) ensureTillerTunnel(eventLog *event.Log) error {
	if len(cache.tillerHost) > 0 {
		// todo(slukjanov): verify that tunnel is still alive??
		// connection already set up, skip
		return nil
	}

	var tunnelErr error
	ok := retry.Do(120, 5, func() bool {
		cache.tillerTunnel, tunnelErr = cache.newTillerTunnel()

		if tunnelErr != nil {
			if strings.Contains(tunnelErr.Error(), "could not find tiller") {
				err := cache.setupTiller(eventLog)
				if err != nil {
					tunnelErr = err
					return false
				}
			}

			return false
		}

		port := cache.tillerTunnel.Local
		cache.tillerHost = fmt.Sprintf("localhost:%d", port)
		eventLog.WithFields(event.Fields{}).Debugf("Created k8s tunnel using local port: %d", port)

		return true
	})

	if !ok {
		if tunnelErr != nil {
			return tunnelErr
		}

		return fmt.Errorf("tiller tunnel creation timeout for cluster: %s", cache.cluster.Name)
	}

	return nil
}

func (cache *clusterCache) newTillerTunnel() (*kube.Tunnel, error) {
	client, err := cache.newKubeClient()
	if err != nil {
		return nil, err
	}

	return portforwarder.New(cache.tillerNamespace, client, cache.kubeConfig)
}

func (cache *clusterCache) setupTiller(eventLog *event.Log) error {
	client, err := cache.newKubeClient()
	if err != nil {
		return err
	}

	eventLog.WithFields(event.Fields{}).Debugf("Setting up tiller in cluster %s namespace %s", cache.cluster.Name, cache.tillerNamespace)

	err = cache.ensureKubeNamespace(client, cache.tillerNamespace)
	if err != nil {
		return err
	}

	err = cache.createKubeServiceAccount(client, cache.tillerNamespace)
	if err != nil {
		return err
	}

	err = cache.createKubeClusterRoleBinding(client, cache.tillerNamespace)
	if err != nil {
		return err
	}

	// todo wait until tiller available
	return installer.Install(client, &installer.Options{
		Namespace:      cache.tillerNamespace,
		ImageSpec:      "gcr.io/kubernetes-helm/tiller:v2.6.2",
		ServiceAccount: "tiller-" + cache.tillerNamespace,
	})
}

func (plugin *Plugin) fetchChart(repository, name, version string) (string, error) {
	chartURL, err := repo.FindChartInRepoURL(
		repository, name, version,
		"", "", "",
		newGetterProviders(),
	)
	if err != nil {
		return "", fmt.Errorf("error while getting chart url in repo: %s", err)
	}

	chartFile, err := ioutil.TempFile("", name)
	if err != nil {
		return "", fmt.Errorf("error while creating temp file for downloading chart: %s", err)
	}

	chartGetter, err := newHTTPGetter(chartURL, "", "", "")
	if err != nil {
		return "", fmt.Errorf("error while creating chart downloader: %s", err)
	}

	resp, err := chartGetter.Get(chartURL)
	if err != nil {
		return "", fmt.Errorf("error while downloading chart: %s", err)
	}

	_, err = chartFile.Write(resp.Bytes())
	if err != nil {
		return "", fmt.Errorf("error while writing downloaded chart to the temp file")
	}

	return chartFile.Name(), nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/mgadzhi/slack-pechkin/reddit"
	"github.com/nlopes/slack"
	"io/ioutil"
	"strings"
)

func getSlackToken() string {
	dat, err := ioutil.ReadFile("slack-token")
	if err != nil {
		fmt.Println("Cannot read slack token")
		panic(err)
	}
	return strings.TrimSpace(string(dat))
}

func main() {
	r := reddit.NewReddit()
	submissions := r.GetLastSubmissions("programming")

    slackChannel := "prostokvashino"
	slackToken := getSlackToken()
	fmt.Println(slackToken)
	api := slack.New(slackToken)
	fmt.Println(api)
	postParams := slack.PostMessageParameters{
		AsUser: true,
	}
	for i, s := range submissions {
		fmt.Println(i, s)
		channelID, timestamp, err := api.PostMessage(slackChannel, s, postParams)
		fmt.Println(channelID, timestamp, err)
	}

}
<commit_msg>First version of RTM<commit_after>package main

import (
	"fmt"
	// "github.com/mgadzhi/slack-pechkin/reddit"
	"github.com/nlopes/slack"
	"io/ioutil"
	"log"
	"os"
	"strings"
)

func getSlackToken() string {
	dat, err := ioutil.ReadFile("slack-token")
	if err != nil {
		fmt.Println("Cannot read slack token")
		panic(err)
	}
	return strings.TrimSpace(string(dat))
}

func main() {
	// r := reddit.NewReddit()
	// submissions := r.GetLastSubmissions("programming")

	slackChannel := "prostokvashino"
	slackToken := getSlackToken()
	fmt.Println(slackToken)
	api := slack.New(slackToken)
	fmt.Println(api)

	logger := log.New(os.Stderr, "Pechkin: ", log.Lshortfile|log.LstdFlags)
	slack.SetLogger(logger)
	api.SetDebug(true)

	rtm := api.NewRTM()
	go rtm.ManageConnection()

	for {
		select {
		case msg := <-rtm.IncomingEvents:
			fmt.Println("Event received:")
			switch ev := msg.Data.(type) {
			case *slack.HelloEvent:

			case *slack.ConnectedEvent:
				fmt.Println(ev.Info)
				rtm.NewOutgoingMessage("Privet!", slackChannel)
			case *slack.MessageEvent:
				newMsg := rtm.NewOutgoingMessage(":padazzhi:", "C3SAHQACF")
				fmt.Printf("%d %s %s %s", newMsg.ID, newMsg.Channel, newMsg.Text, newMsg.Type)
				rtm.SendMessage(newMsg)
			case *slack.InvalidAuthEvent:
				return
			default:

			}
		}
	}
}
<|endoftext|>


<commit_before>package keryxplib

import (
	"encoding/json"
	"io/ioutil"
	"os"

	"github.com/MediaMath/keryxlib/filters"
	"github.com/MediaMath/keryxlib/message"
	"github.com/MediaMath/keryxlib/pg"
	"github.com/MediaMath/keryxlib/streams"
)

//TransactionChannel sets up a keryx stream and schema reader with the provided configuration and returns
//it as a channel
func TransactionChannel(serverVersion string, kc *Config) (<-chan *message.Transaction, error) {

	schemaReader, err := pg.NewSchemaReader(kc.PGConnStrings, "postgres", 255)
	if err != nil {
		return nil, err
	}

	bufferWorkingDirectory, err := kc.GetBufferDirectoryOrTemp()
	if err != nil {
		return nil, err
	}

	f := filters.Exclusive(schemaReader, kc.ExcludeRelations)
	if len(kc.IncludeRelations) > 0 {
		f = filters.Inclusive(schemaReader, kc.IncludeRelations)
	}

	stream := NewKeryxStream(schemaReader)
	return stream.StartKeryxStream(serverVersion, f, kc.DataDir, bufferWorkingDirectory)
}

//Config contains necessary information to start a keryx stream
type Config struct {
	DataDir          string              `json:"data_dir"`
	PGConnStrings    []string            `json:"pg_conn_strings"`
	BufferMax        int                 `json:"buffer_max"`
	ExcludeRelations map[string][]string `json:"exclude,omitempty"`
	IncludeRelations map[string][]string `json:"include,omitempty"`
	BufferDirectory  string              `json:"buffer_directory"`
}

//BufferDirectoryDefaultBase is the root directory to attempt to create buffers files in if
//nothing else is specified
const BufferDirectoryDefaultBase = "/var/tmp/keryx"

//GetBufferDirectoryOrTemp gets the buffer directory out of the config file. If it isnt defined it creates it in BufferDirectoryDefaultBase
func (c *Config) GetBufferDirectoryOrTemp() (bufferWorkingDirectory string, err error) {
	bufferWorkingDirectory = c.BufferDirectory
	if bufferWorkingDirectory == "" {
		err = os.MkdirAll(BufferDirectoryDefaultBase, 0700)
		if err == nil {
			bufferWorkingDirectory, err = ioutil.TempDir(BufferDirectoryDefaultBase, "buffer")
		}
	}
	return
}

//ConfigFromFile loads a config object from a json file
func ConfigFromFile(path string) (*Config, error) {
	file, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}

	config := new(Config)
	err = json.Unmarshal(file, config)
	if err != nil {
		return nil, err
	}

	return config, nil
}

//FullStream is a facade around the full process of taking WAL entries and publishing them as txn messages.
type FullStream struct {
	walStream       *streams.WalStream
	sr              *pg.SchemaReader
	MaxMessageCount int
}

//NewKeryxStream takes a schema reader and returns a FullStream
func NewKeryxStream(sr *pg.SchemaReader, maxMessageCount int) *FullStream {
	return &FullStream{nil, sr, maxMessageCount}
}

//Stop will end the reading on the WAL log and subsequent streams will therefore end.
func (fs *FullStream) Stop() {
	if fs.walStream != nil {
		fs.walStream.Stop()
	}
}

//StartKeryxStream will start all the streams necessary to go from WAL entries to txn messages.
func (fs *FullStream) StartKeryxStream(serverVersion string, filters filters.MessageFilter, dataDir string, bufferWorkingDirectory string) (<-chan *message.Transaction, error) {
	walStream, err := streams.NewWalStream(dataDir)
	if err != nil {
		return nil, err
	}
	fs.walStream = walStream

	wal, err := fs.walStream.Start()
	if err != nil {
		return nil, err
	}

	txnBuffer := &streams.TxnBuffer{Filters: filters, WorkingDirectory: bufferWorkingDirectory}
	buffered, err := txnBuffer.Start(wal)
	if err != nil {
		fs.Stop()
		return nil, err
	}

	populated := &streams.PopulatedMessageStream{Filter: filters, SchemaReader: fs.sr, MaxMessageCount: fs.MaxMessageCount}
	keryx, err := populated.Start(serverVersion, buffered)
	if err != nil {
		fs.Stop()
		return nil, err
	}

	return keryx, nil
}
<commit_msg>add max count to config<commit_after>package keryxplib

import (
	"encoding/json"
	"io/ioutil"
	"os"

	"github.com/MediaMath/keryxlib/filters"
	"github.com/MediaMath/keryxlib/message"
	"github.com/MediaMath/keryxlib/pg"
	"github.com/MediaMath/keryxlib/streams"
)

//TransactionChannel sets up a keryx stream and schema reader with the provided configuration and returns
//it as a channel
func TransactionChannel(serverVersion string, kc *Config) (<-chan *message.Transaction, error) {

	schemaReader, err := pg.NewSchemaReader(kc.PGConnStrings, "postgres", 255)
	if err != nil {
		return nil, err
	}

	bufferWorkingDirectory, err := kc.GetBufferDirectoryOrTemp()
	if err != nil {
		return nil, err
	}

	f := filters.Exclusive(schemaReader, kc.ExcludeRelations)
	if len(kc.IncludeRelations) > 0 {
		f = filters.Inclusive(schemaReader, kc.IncludeRelations)
	}

	stream := NewKeryxStream(schemaReader, kc.MaxMessagePerTxn)
	return stream.StartKeryxStream(serverVersion, f, kc.DataDir, bufferWorkingDirectory)
}

//Config contains necessary information to start a keryx stream
type Config struct {
	DataDir          string              `json:"data_dir"`
	PGConnStrings    []string            `json:"pg_conn_strings"`
	BufferMax        int                 `json:"buffer_max"`
	ExcludeRelations map[string][]string `json:"exclude,omitempty"`
	IncludeRelations map[string][]string `json:"include,omitempty"`
	BufferDirectory  string              `json:"buffer_directory"`
	MaxMessagePerTxn int                 `json:"max_message_per_txn"`
}

//BufferDirectoryDefaultBase is the root directory to attempt to create buffers files in if
//nothing else is specified
const BufferDirectoryDefaultBase = "/var/tmp/keryx"

//GetBufferDirectoryOrTemp gets the buffer directory out of the config file. If it isnt defined it creates it in BufferDirectoryDefaultBase
func (c *Config) GetBufferDirectoryOrTemp() (bufferWorkingDirectory string, err error) {
	bufferWorkingDirectory = c.BufferDirectory
	if bufferWorkingDirectory == "" {
		err = os.MkdirAll(BufferDirectoryDefaultBase, 0700)
		if err == nil {
			bufferWorkingDirectory, err = ioutil.TempDir(BufferDirectoryDefaultBase, "buffer")
		}
	}
	return
}

//ConfigFromFile loads a config object from a json file
func ConfigFromFile(path string) (*Config, error) {
	file, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}

	config := new(Config)
	err = json.Unmarshal(file, config)
	if err != nil {
		return nil, err
	}

	return config, nil
}

//FullStream is a facade around the full process of taking WAL entries and publishing them as txn messages.
type FullStream struct {
	walStream       *streams.WalStream
	sr              *pg.SchemaReader
	MaxMessageCount int
}

//NewKeryxStream takes a schema reader and returns a FullStream
func NewKeryxStream(sr *pg.SchemaReader, maxMessageCount int) *FullStream {
	return &FullStream{nil, sr, maxMessageCount}
}

//Stop will end the reading on the WAL log and subsequent streams will therefore end.
func (fs *FullStream) Stop() {
	if fs.walStream != nil {
		fs.walStream.Stop()
	}
}

//StartKeryxStream will start all the streams necessary to go from WAL entries to txn messages.
func (fs *FullStream) StartKeryxStream(serverVersion string, filters filters.MessageFilter, dataDir string, bufferWorkingDirectory string) (<-chan *message.Transaction, error) {
	walStream, err := streams.NewWalStream(dataDir)
	if err != nil {
		return nil, err
	}
	fs.walStream = walStream

	wal, err := fs.walStream.Start()
	if err != nil {
		return nil, err
	}

	txnBuffer := &streams.TxnBuffer{Filters: filters, WorkingDirectory: bufferWorkingDirectory}
	buffered, err := txnBuffer.Start(wal)
	if err != nil {
		fs.Stop()
		return nil, err
	}

	populated := &streams.PopulatedMessageStream{Filter: filters, SchemaReader: fs.sr, MaxMessageCount: fs.MaxMessageCount}
	keryx, err := populated.Start(serverVersion, buffered)
	if err != nil {
		fs.Stop()
		return nil, err
	}

	return keryx, nil
}
<|endoftext|>


<commit_before>package resource

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

// Resource is the interface type for resources
type Resource interface {
	// ResourceID returns the unique identifier of a resource
	ID() string

	// Returns the resources before which this resource shoud be processed
	WantBefore() []string

	// Returns the resources after which this resource should be processed
	WantAfter() []string

	// Evaluates the resource
	Evaluate() (State, error)

	// Creates the resource
	Create() error

	// Deletes the resource
	Delete() error

	// Updates the resource
	Update() error
}

// Config type contains various settings used by the resources
type Config struct {
	// The site repo which contains module and data files
	SiteRepo string

	// Writer used by the resources to log events
	Writer io.Writer
}

// DefaultConfig is the default configuration used by the resources
var DefaultConfig = &Config{
	Writer: os.Stdout,
}

// BaseResource is the base resource type for all resources
// The purpose of this type is to be embedded into other resources
// Partially implements the Resource interface
type BaseResource struct {
	// Type of the resource
	Type string `luar:"-"`

	// Name of the resource
	Name string `luar:"-"`

	// Resource configuration settings
	Config *Config `luar:"-"`

	// Desired state of the resource
	State string `luar:"state"`

	// Resources before which this resource should be processed
	Before []string `luar:"before"`

	// Resources after which this resource should be processed
	After []string `luar:"require"`
}

// ID returns the unique resource id
func (br *BaseResource) ID() string {
	return fmt.Sprintf("%s[%s]", br.Type, br.Name)
}

// WantBefore returns the resources before which this resource
// should be processed
func (br *BaseResource) WantBefore() []string {
	return br.Before
}

// WantAfter returns the resources after which this resource
// should be processed
func (br *BaseResource) WantAfter() []string {
	return br.After
}

// Log works just like fmt.Printf except that it writes to the
// default config writer object and prepends the resource id to the output
func (br *BaseResource) Log(format string, a ...interface{}) (int, error) {
	fmt.Fprintf(DefaultConfig.Writer, "%s ", br.ID())

	return fmt.Fprintf(DefaultConfig.Writer, format, a...)
}
<commit_msg>resource: Update DefaultConfig<commit_after>package resource

import (
	"fmt"
	"io"
)

// Resource is the interface type for resources
type Resource interface {
	// ResourceID returns the unique identifier of a resource
	ID() string

	// Returns the resources before which this resource shoud be processed
	WantBefore() []string

	// Returns the resources after which this resource should be processed
	WantAfter() []string

	// Evaluates the resource
	Evaluate() (State, error)

	// Creates the resource
	Create() error

	// Deletes the resource
	Delete() error

	// Updates the resource
	Update() error
}

// Config type contains various settings used by the resources
type Config struct {
	// The site repo which contains module and data files
	SiteRepo string

	// Writer used by the resources to log events
	Writer io.Writer
}

// DefaultConfig is the default configuration used by the resources
var DefaultConfig = &Config{}

// BaseResource is the base resource type for all resources
// The purpose of this type is to be embedded into other resources
// Partially implements the Resource interface
type BaseResource struct {
	// Type of the resource
	Type string `luar:"-"`

	// Name of the resource
	Name string `luar:"-"`

	// Resource configuration settings
	Config *Config `luar:"-"`

	// Desired state of the resource
	State string `luar:"state"`

	// Resources before which this resource should be processed
	Before []string `luar:"before"`

	// Resources after which this resource should be processed
	After []string `luar:"require"`
}

// ID returns the unique resource id
func (br *BaseResource) ID() string {
	return fmt.Sprintf("%s[%s]", br.Type, br.Name)
}

// WantBefore returns the resources before which this resource
// should be processed
func (br *BaseResource) WantBefore() []string {
	return br.Before
}

// WantAfter returns the resources after which this resource
// should be processed
func (br *BaseResource) WantAfter() []string {
	return br.After
}

// Log works just like fmt.Printf except that it writes to the
// default config writer object and prepends the resource id to the output
func (br *BaseResource) Log(format string, a ...interface{}) (int, error) {
	fmt.Fprintf(DefaultConfig.Writer, "%s ", br.ID())

	return fmt.Fprintf(DefaultConfig.Writer, format, a...)
}
<|endoftext|>