<commit_before>package buildkite

import (
	"fmt"
	"time"
)

// BuildsService handles communication with the build related
// methods of the buildkite API.
//
// buildkite API docs: https://buildkite.com/docs/api/builds
type BuildsService struct {
	client *Client
}

// Author of a commit (used in CreateBuild)
type Author struct {
	Name  string `json:"name,omitempty" yaml:"name,omitempty"`
	Email string `json:"email,omitempty" yaml:"email,omitempty"`
}

// CreateBuild - Create a build.
type CreateBuild struct {
	Commit  string `json:"commit" yaml:"commit"`
	Branch  string `json:"branch" yaml:"branch"`
	Message string `json:"message" yaml:"message"`

	// Optional fields
	Author                      Author            `json:"author,omitempty" yaml:"author,omitempty"`
	Env                         map[string]string `json:"env,omitempty" yaml:"env,omitempty"`
	MetaData                    map[string]string `json:"meta_data,omitempty" yaml:"meta_data,omitempty"`
	IgnorePipelineBranchFilters bool              `json:"ignore_pipeline_branch_filters,omitempty" yaml:"ignore_pipeline_branch_filters,omitempty"`
	PullRequestBaseBranch       string            `json:"pull_request_base_branch,omitempty" yaml:"pull_request_base_branch,omitempty"`
	PullRequestID               int64             `json:"pull_request_id,omitempty" yaml:"pull_request_id,omitempty"`
	PullRequestRepository       string            `json:"pull_request_repository,omitempty" yaml:"pull_request_repository,omitempty"`
}

// Creator represents who created a build
type Creator struct {
	AvatarURL string     `json:"avatar_url" yaml:"avatar_url"`
	CreatedAt *Timestamp `json:"created_at" yaml:"created_at"`
	Email     string     `json:"email" yaml:"email"`
	ID        string     `json:"id" yaml:"id"`
	Name      string     `json:"name" yaml:"name"`
}

// PullRequest represents a Github PR
type PullRequest struct {
	ID         *string `json:"id,omitempty" yaml:"id,omitempty"`
	Base       *string `json:"base,omitempty" yaml:"base,omitempty"`
	Repository *string `json:"repository,omitempty" yaml:"repository,omitempty"`
}

// Build represents a build which has run in buildkite
type Build struct {
	ID          *string                `json:"id,omitempty" yaml:"id,omitempty"`
	URL         *string                `json:"url,omitempty" yaml:"url,omitempty"`
	WebURL      *string                `json:"web_url,omitempty" yaml:"web_url,omitempty"`
	Number      *int                   `json:"number,omitempty" yaml:"number,omitempty"`
	State       *string                `json:"state,omitempty" yaml:"state,omitempty"`
	Blocked     *bool                  `json:"blocked,omitempty" yaml:"blocked,omitempty"`
	Message     *string                `json:"message,omitempty" yaml:"message,omitempty"`
	Commit      *string                `json:"commit,omitempty" yaml:"commit,omitempty"`
	Branch      *string                `json:"branch,omitempty" yaml:"branch,omitempty"`
	Env         map[string]interface{} `json:"env,omitempty" yaml:"env,omitempty"`
	CreatedAt   *Timestamp             `json:"created_at,omitempty" yaml:"created_at,omitempty"`
	ScheduledAt *Timestamp             `json:"scheduled_at,omitempty" yaml:"scheduled_at,omitempty"`
	StartedAt   *Timestamp             `json:"started_at,omitempty" yaml:"started_at,omitempty"`
	FinishedAt  *Timestamp             `json:"finished_at,omitempty" yaml:"finished_at,omitempty"`
	MetaData    interface{}            `json:"meta_data,omitempty" yaml:"meta_data,omitempty"`
	Creator     *Creator               `json:"creator,omitempty" yaml:"creator,omitempty"`
	Source      *string                `json:"source,omitempty" yaml:"source,omitempty"`

	// jobs run during the build
	Jobs []*Job `json:"jobs,omitempty" yaml:"jobs,omitempty"`

	// the pipeline this build is associated with
	Pipeline *Pipeline `json:"pipeline,omitempty" yaml:"pipeline,omitempty"`

	// the pull request this build is associated with
	PullRequest *PullRequest `json:"pull_request,omitempty" yaml:"pull_request,omitempty"`
}

// BuildsListOptions specifies the optional parameters to the
// BuildsService.List method.
type BuildsListOptions struct {

	// Filters the results by the user who created the build
	Creator string `url:"creator,omitempty"`

	// Filters the results by builds created on or after the given time
	CreatedFrom time.Time `url:"created_from,omitempty"`

	// Filters the results by builds created before the given time
	CreatedTo time.Time `url:"created_to,omitempty"`

	// Filters the results by builds finished on or after the given time
	FinishedFrom time.Time `url:"finished_from,omitempty"`

	// State of builds to list.  Possible values are: running, scheduled, passed,
	// failed, canceled, skipped and not_run. Default is "".
	State []string `url:"state,brackets,omitempty"`

	// Branch filter by the name of the branch. Default is "".
	Branch string `url:"branch,omitempty"`

	// Filters the results by builds for the specific commit SHA (full, not shortened). Default is "".
	Commit string `url:"commit,omitempty"`

	// Include all retried jobs in each build’s jobs list
	IncludeRetriedJobs bool `url:"include_retried_jobs,omitempty"`

	ListOptions
}

// Cancel - Trigger a cancel for the target build
//
// buildkite API docs: https://buildkite.com/docs/apis/rest-api/builds#cancel-a-build
func (bs *BuildsService) Cancel(org, pipeline, build string) (*Build, error) {
	u := fmt.Sprintf("v2/organizations/%s/pipelines/%s/builds/%s/cancel", org, pipeline, build)
	req, err := bs.client.NewRequest("PUT", u, nil)
	if err != nil {
		return nil, err
	}
	result := Build{}
	_, err = bs.client.Do(req, &result)
	if err != nil {
		return nil, err
	}
	return &result, nil
}

// Create - Create a pipeline
//
// buildkite API docs: https://buildkite.com/docs/api/builds#create-a-build
func (bs *BuildsService) Create(org string, pipeline string, b *CreateBuild) (*Build, *Response, error) {
	u := fmt.Sprintf("v2/organizations/%s/pipelines/%s/builds", org, pipeline)

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

	build := new(Build)
	resp, err := bs.client.Do(req, build)
	if err != nil {
		return nil, resp, err
	}

	return build, resp, err
}

// Get fetches a build.
//
// buildkite API docs: https://buildkite.com/docs/api/builds#get-a-build
func (bs *BuildsService) Get(org string, pipeline string, id string, opt *BuildsListOptions) (*Build, *Response, error) {
	u := fmt.Sprintf("v2/organizations/%s/pipelines/%s/builds/%s", org, pipeline, id)

	u, err := addOptions(u, opt)
	if err != nil {
		return nil, nil, err
	}

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

	build := new(Build)
	resp, err := bs.client.Do(req, build)
	if err != nil {
		return nil, resp, err
	}

	return build, resp, err
}

// List the builds for the current user.
//
// buildkite API docs: https://buildkite.com/docs/api/builds#list-all-builds
func (bs *BuildsService) List(opt *BuildsListOptions) ([]Build, *Response, error) {
	var u string

	u = fmt.Sprintf("v2/builds")

	u, err := addOptions(u, opt)
	if err != nil {
		return nil, nil, err
	}

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

	orgs := new([]Build)
	resp, err := bs.client.Do(req, orgs)
	if err != nil {
		return nil, resp, err
	}

	return *orgs, resp, err
}

// ListByOrg lists the builds within the specified orginisation.
//
// buildkite API docs: https://buildkite.com/docs/api/builds#list-builds-for-an-organization
func (bs *BuildsService) ListByOrg(org string, opt *BuildsListOptions) ([]Build, *Response, error) {
	var u string

	u = fmt.Sprintf("v2/organizations/%s/builds", org)

	u, err := addOptions(u, opt)
	if err != nil {
		return nil, nil, err
	}

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

	orgs := new([]Build)
	resp, err := bs.client.Do(req, orgs)
	if err != nil {
		return nil, resp, err
	}

	return *orgs, resp, err
}

// ListByPipeline lists the builds for a pipeline within the specified originisation.
//
// buildkite API docs: https://buildkite.com/docs/api/builds#list-builds-for-a-pipeline
func (bs *BuildsService) ListByPipeline(org string, pipeline string, opt *BuildsListOptions) ([]Build, *Response, error) {
	var u string

	u = fmt.Sprintf("v2/organizations/%s/pipelines/%s/builds", org, pipeline)

	u, err := addOptions(u, opt)
	if err != nil {
		return nil, nil, err
	}

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

	orgs := new([]Build)
	resp, err := bs.client.Do(req, orgs)
	if err != nil {
		return nil, resp, err
	}

	return *orgs, resp, err
}

// Rebuild triggers a rebuild for the target build
//
// buildkite API docs: https://buildkite.com/docs/apis/rest-api/builds#rebuild-a-build
func (bs *BuildsService) Rebuild(org, pipeline, build string) (*Build, error) {
	u := fmt.Sprintf("v2/organizations/%s/pipelines/%s/builds/%s/rebuild", org, pipeline, build)
	req, err := bs.client.NewRequest("PUT", u, nil)
	if err != nil {
		return nil, err
	}
	result := Build{}
	_, err = bs.client.Do(req, &result)
	if err != nil {
		return nil, err
	}
	return &result, nil
}
<commit_msg>Add Author filed to Builds<commit_after>package buildkite

import (
	"fmt"
	"time"
)

// BuildsService handles communication with the build related
// methods of the buildkite API.
//
// buildkite API docs: https://buildkite.com/docs/api/builds
type BuildsService struct {
	client *Client
}

// Author of a commit (used in CreateBuild)
type Author struct {
	Name  string `json:"name,omitempty" yaml:"name,omitempty"`
	Email string `json:"email,omitempty" yaml:"email,omitempty"`
}

// CreateBuild - Create a build.
type CreateBuild struct {
	Commit  string `json:"commit" yaml:"commit"`
	Branch  string `json:"branch" yaml:"branch"`
	Message string `json:"message" yaml:"message"`

	// Optional fields
	Author                      Author            `json:"author,omitempty" yaml:"author,omitempty"`
	Env                         map[string]string `json:"env,omitempty" yaml:"env,omitempty"`
	MetaData                    map[string]string `json:"meta_data,omitempty" yaml:"meta_data,omitempty"`
	IgnorePipelineBranchFilters bool              `json:"ignore_pipeline_branch_filters,omitempty" yaml:"ignore_pipeline_branch_filters,omitempty"`
	PullRequestBaseBranch       string            `json:"pull_request_base_branch,omitempty" yaml:"pull_request_base_branch,omitempty"`
	PullRequestID               int64             `json:"pull_request_id,omitempty" yaml:"pull_request_id,omitempty"`
	PullRequestRepository       string            `json:"pull_request_repository,omitempty" yaml:"pull_request_repository,omitempty"`
}

// Creator represents who created a build
type Creator struct {
	AvatarURL string     `json:"avatar_url" yaml:"avatar_url"`
	CreatedAt *Timestamp `json:"created_at" yaml:"created_at"`
	Email     string     `json:"email" yaml:"email"`
	ID        string     `json:"id" yaml:"id"`
	Name      string     `json:"name" yaml:"name"`
}

// PullRequest represents a Github PR
type PullRequest struct {
	ID         *string `json:"id,omitempty" yaml:"id,omitempty"`
	Base       *string `json:"base,omitempty" yaml:"base,omitempty"`
	Repository *string `json:"repository,omitempty" yaml:"repository,omitempty"`
}

// Build represents a build which has run in buildkite
type Build struct {
	ID          *string                `json:"id,omitempty" yaml:"id,omitempty"`
	URL         *string                `json:"url,omitempty" yaml:"url,omitempty"`
	WebURL      *string                `json:"web_url,omitempty" yaml:"web_url,omitempty"`
	Number      *int                   `json:"number,omitempty" yaml:"number,omitempty"`
	State       *string                `json:"state,omitempty" yaml:"state,omitempty"`
	Blocked     *bool                  `json:"blocked,omitempty" yaml:"blocked,omitempty"`
	Message     *string                `json:"message,omitempty" yaml:"message,omitempty"`
	Commit      *string                `json:"commit,omitempty" yaml:"commit,omitempty"`
	Branch      *string                `json:"branch,omitempty" yaml:"branch,omitempty"`
	Author      *Author                `json:"author,omitempty" yaml:"author,omitempty"`
	Env         map[string]interface{} `json:"env,omitempty" yaml:"env,omitempty"`
	CreatedAt   *Timestamp             `json:"created_at,omitempty" yaml:"created_at,omitempty"`
	ScheduledAt *Timestamp             `json:"scheduled_at,omitempty" yaml:"scheduled_at,omitempty"`
	StartedAt   *Timestamp             `json:"started_at,omitempty" yaml:"started_at,omitempty"`
	FinishedAt  *Timestamp             `json:"finished_at,omitempty" yaml:"finished_at,omitempty"`
	MetaData    interface{}            `json:"meta_data,omitempty" yaml:"meta_data,omitempty"`
	Creator     *Creator               `json:"creator,omitempty" yaml:"creator,omitempty"`
	Source      *string                `json:"source,omitempty" yaml:"source,omitempty"`

	// jobs run during the build
	Jobs []*Job `json:"jobs,omitempty" yaml:"jobs,omitempty"`

	// the pipeline this build is associated with
	Pipeline *Pipeline `json:"pipeline,omitempty" yaml:"pipeline,omitempty"`

	// the pull request this build is associated with
	PullRequest *PullRequest `json:"pull_request,omitempty" yaml:"pull_request,omitempty"`
}

// BuildsListOptions specifies the optional parameters to the
// BuildsService.List method.
type BuildsListOptions struct {

	// Filters the results by the user who created the build
	Creator string `url:"creator,omitempty"`

	// Filters the results by builds created on or after the given time
	CreatedFrom time.Time `url:"created_from,omitempty"`

	// Filters the results by builds created before the given time
	CreatedTo time.Time `url:"created_to,omitempty"`

	// Filters the results by builds finished on or after the given time
	FinishedFrom time.Time `url:"finished_from,omitempty"`

	// State of builds to list.  Possible values are: running, scheduled, passed,
	// failed, canceled, skipped and not_run. Default is "".
	State []string `url:"state,brackets,omitempty"`

	// Branch filter by the name of the branch. Default is "".
	Branch string `url:"branch,omitempty"`

	// Filters the results by builds for the specific commit SHA (full, not shortened). Default is "".
	Commit string `url:"commit,omitempty"`

	// Include all retried jobs in each build’s jobs list
	IncludeRetriedJobs bool `url:"include_retried_jobs,omitempty"`

	ListOptions
}

// Cancel - Trigger a cancel for the target build
//
// buildkite API docs: https://buildkite.com/docs/apis/rest-api/builds#cancel-a-build
func (bs *BuildsService) Cancel(org, pipeline, build string) (*Build, error) {
	u := fmt.Sprintf("v2/organizations/%s/pipelines/%s/builds/%s/cancel", org, pipeline, build)
	req, err := bs.client.NewRequest("PUT", u, nil)
	if err != nil {
		return nil, err
	}
	result := Build{}
	_, err = bs.client.Do(req, &result)
	if err != nil {
		return nil, err
	}
	return &result, nil
}

// Create - Create a pipeline
//
// buildkite API docs: https://buildkite.com/docs/api/builds#create-a-build
func (bs *BuildsService) Create(org string, pipeline string, b *CreateBuild) (*Build, *Response, error) {
	u := fmt.Sprintf("v2/organizations/%s/pipelines/%s/builds", org, pipeline)

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

	build := new(Build)
	resp, err := bs.client.Do(req, build)
	if err != nil {
		return nil, resp, err
	}

	return build, resp, err
}

// Get fetches a build.
//
// buildkite API docs: https://buildkite.com/docs/api/builds#get-a-build
func (bs *BuildsService) Get(org string, pipeline string, id string, opt *BuildsListOptions) (*Build, *Response, error) {
	u := fmt.Sprintf("v2/organizations/%s/pipelines/%s/builds/%s", org, pipeline, id)

	u, err := addOptions(u, opt)
	if err != nil {
		return nil, nil, err
	}

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

	build := new(Build)
	resp, err := bs.client.Do(req, build)
	if err != nil {
		return nil, resp, err
	}

	return build, resp, err
}

// List the builds for the current user.
//
// buildkite API docs: https://buildkite.com/docs/api/builds#list-all-builds
func (bs *BuildsService) List(opt *BuildsListOptions) ([]Build, *Response, error) {
	var u string

	u = fmt.Sprintf("v2/builds")

	u, err := addOptions(u, opt)
	if err != nil {
		return nil, nil, err
	}

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

	orgs := new([]Build)
	resp, err := bs.client.Do(req, orgs)
	if err != nil {
		return nil, resp, err
	}

	return *orgs, resp, err
}

// ListByOrg lists the builds within the specified orginisation.
//
// buildkite API docs: https://buildkite.com/docs/api/builds#list-builds-for-an-organization
func (bs *BuildsService) ListByOrg(org string, opt *BuildsListOptions) ([]Build, *Response, error) {
	var u string

	u = fmt.Sprintf("v2/organizations/%s/builds", org)

	u, err := addOptions(u, opt)
	if err != nil {
		return nil, nil, err
	}

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

	orgs := new([]Build)
	resp, err := bs.client.Do(req, orgs)
	if err != nil {
		return nil, resp, err
	}

	return *orgs, resp, err
}

// ListByPipeline lists the builds for a pipeline within the specified originisation.
//
// buildkite API docs: https://buildkite.com/docs/api/builds#list-builds-for-a-pipeline
func (bs *BuildsService) ListByPipeline(org string, pipeline string, opt *BuildsListOptions) ([]Build, *Response, error) {
	var u string

	u = fmt.Sprintf("v2/organizations/%s/pipelines/%s/builds", org, pipeline)

	u, err := addOptions(u, opt)
	if err != nil {
		return nil, nil, err
	}

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

	orgs := new([]Build)
	resp, err := bs.client.Do(req, orgs)
	if err != nil {
		return nil, resp, err
	}

	return *orgs, resp, err
}

// Rebuild triggers a rebuild for the target build
//
// buildkite API docs: https://buildkite.com/docs/apis/rest-api/builds#rebuild-a-build
func (bs *BuildsService) Rebuild(org, pipeline, build string) (*Build, error) {
	u := fmt.Sprintf("v2/organizations/%s/pipelines/%s/builds/%s/rebuild", org, pipeline, build)
	req, err := bs.client.NewRequest("PUT", u, nil)
	if err != nil {
		return nil, err
	}
	result := Build{}
	_, err = bs.client.Do(req, &result)
	if err != nil {
		return nil, err
	}
	return &result, nil
}
<|endoftext|>


<commit_before>/*
Copyright 2018 Gravitational, Inc.

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 web

import (
	"context"
	"net/http"

	"github.com/gravitational/teleport/lib/auth"
	"github.com/gravitational/teleport/lib/client"
	"github.com/gravitational/teleport/lib/reversetunnel"
	"github.com/gravitational/teleport/lib/services"
	"github.com/gravitational/teleport/lib/sshutils/scp"

	"github.com/gravitational/trace"
	"github.com/julienschmidt/httprouter"
)

// fileTransferRequest describes HTTP file transfer request
type fileTransferRequest struct {
	// Server describes a server to connect to (serverId|hostname[:port]).
	server string
	// Login is Linux username to connect as.
	login string
	// Namespace is node namespace.
	namespace string
	// Cluster is the name of the remote cluster to connect to.
	cluster string
	// remoteLocation is file remote location
	remoteLocation string
	// filename is a file name
	filename string
}

func (h *Handler) transferFile(w http.ResponseWriter, r *http.Request, p httprouter.Params, ctx *SessionContext, site reversetunnel.RemoteSite) (interface{}, error) {
	query := r.URL.Query()
	req := fileTransferRequest{
		login:          p.ByName("login"),
		namespace:      p.ByName("namespace"),
		server:         p.ByName("server"),
		remoteLocation: query.Get("location"),
		filename:       query.Get("filename"),
	}

	clt, err := ctx.GetUserClient(site)
	if err != nil {
		return nil, trace.Wrap(err)
	}

	ft := fileTransfer{
		ctx:           ctx,
		authClient:    clt,
		proxyHostPort: h.ProxyHostPort(),
	}

	isUpload := r.Method == http.MethodPost
	if isUpload {
		err = ft.upload(req, r)
	} else {
		err = ft.download(req, w)
	}

	if err != nil {
		return nil, trace.Wrap(err)
	}

	return ok(), nil
}

type fileTransfer struct {
	// ctx is a web session context for the currently logged in user.
	ctx           *SessionContext
	authClient    auth.ClientI
	proxyHostPort string
}

func (f *fileTransfer) download(req fileTransferRequest, w http.ResponseWriter) error {
	cmd, err := scp.CreateHTTPDownload(scp.HTTPTransferRequest{
		RemoteLocation: req.remoteLocation,
		HTTPResponse:   w,
		User:           f.ctx.GetUser(),
	})
	if err != nil {
		return trace.Wrap(err)
	}

	tc, err := f.createClient(req)
	if err != nil {
		return trace.Wrap(err)
	}

	err = tc.ExecuteSCP(context.TODO(), cmd)
	if err != nil {
		return trace.Wrap(err)
	}

	return nil
}

func (f *fileTransfer) upload(req fileTransferRequest, httpReq *http.Request) error {
	cmd, err := scp.CreateHTTPUpload(scp.HTTPTransferRequest{
		RemoteLocation: req.remoteLocation,
		FileName:       req.filename,
		HTTPRequest:    httpReq,
		User:           f.ctx.GetUser(),
	})
	if err != nil {
		return trace.Wrap(err)
	}

	tc, err := f.createClient(req)
	if err != nil {
		return trace.Wrap(err)
	}

	err = tc.ExecuteSCP(context.TODO(), cmd)
	if err != nil {
		return trace.Wrap(err)
	}

	return nil
}

func (f *fileTransfer) createClient(req fileTransferRequest) (*client.TeleportClient, error) {
	if !services.IsValidNamespace(req.namespace) {
		return nil, trace.BadParameter("invalid namespace %q", req.namespace)
	}

	if req.login == "" {
		return nil, trace.BadParameter("missing login")
	}

	servers, err := f.authClient.GetNodes(req.namespace)
	if err != nil {
		return nil, trace.Wrap(err)
	}

	hostName, hostPort, err := resolveServerHostPort(req.server, servers)
	if err != nil {
		return nil, trace.BadParameter("invalid server name %q: %v", req.server, err)
	}

	cfg, err := makeTeleportClientConfig(f.ctx)
	if err != nil {
		return nil, trace.Wrap(err)
	}

	cfg.HostLogin = req.login
	cfg.SiteName = req.cluster
	cfg.Namespace = req.namespace
	cfg.ParseProxyHost(f.proxyHostPort)
	cfg.Host = hostName
	cfg.HostPort = hostPort

	tc, err := client.NewClient(cfg)
	if err != nil {
		return nil, trace.BadParameter("failed to create client: %v", err)
	}

	return tc, nil
}
<commit_msg>Pass site name along in fileTransferRequest.<commit_after>/*
Copyright 2018 Gravitational, Inc.

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 web

import (
	"context"
	"net/http"

	"github.com/gravitational/teleport/lib/auth"
	"github.com/gravitational/teleport/lib/client"
	"github.com/gravitational/teleport/lib/reversetunnel"
	"github.com/gravitational/teleport/lib/services"
	"github.com/gravitational/teleport/lib/sshutils/scp"

	"github.com/gravitational/trace"
	"github.com/julienschmidt/httprouter"
)

// fileTransferRequest describes HTTP file transfer request
type fileTransferRequest struct {
	// Server describes a server to connect to (serverId|hostname[:port]).
	server string
	// Login is Linux username to connect as.
	login string
	// Namespace is node namespace.
	namespace string
	// Cluster is the name of the remote cluster to connect to.
	cluster string
	// remoteLocation is file remote location
	remoteLocation string
	// filename is a file name
	filename string
}

func (h *Handler) transferFile(w http.ResponseWriter, r *http.Request, p httprouter.Params, ctx *SessionContext, site reversetunnel.RemoteSite) (interface{}, error) {
	query := r.URL.Query()
	req := fileTransferRequest{
		cluster:        p.ByName("site"),
		login:          p.ByName("login"),
		namespace:      p.ByName("namespace"),
		server:         p.ByName("server"),
		remoteLocation: query.Get("location"),
		filename:       query.Get("filename"),
	}

	clt, err := ctx.GetUserClient(site)
	if err != nil {
		return nil, trace.Wrap(err)
	}

	ft := fileTransfer{
		ctx:           ctx,
		authClient:    clt,
		proxyHostPort: h.ProxyHostPort(),
	}

	isUpload := r.Method == http.MethodPost
	if isUpload {
		err = ft.upload(req, r)
	} else {
		err = ft.download(req, w)
	}

	if err != nil {
		return nil, trace.Wrap(err)
	}

	return ok(), nil
}

type fileTransfer struct {
	// ctx is a web session context for the currently logged in user.
	ctx           *SessionContext
	authClient    auth.ClientI
	proxyHostPort string
}

func (f *fileTransfer) download(req fileTransferRequest, w http.ResponseWriter) error {
	cmd, err := scp.CreateHTTPDownload(scp.HTTPTransferRequest{
		RemoteLocation: req.remoteLocation,
		HTTPResponse:   w,
		User:           f.ctx.GetUser(),
	})
	if err != nil {
		return trace.Wrap(err)
	}

	tc, err := f.createClient(req)
	if err != nil {
		return trace.Wrap(err)
	}

	err = tc.ExecuteSCP(context.TODO(), cmd)
	if err != nil {
		return trace.Wrap(err)
	}

	return nil
}

func (f *fileTransfer) upload(req fileTransferRequest, httpReq *http.Request) error {
	cmd, err := scp.CreateHTTPUpload(scp.HTTPTransferRequest{
		RemoteLocation: req.remoteLocation,
		FileName:       req.filename,
		HTTPRequest:    httpReq,
		User:           f.ctx.GetUser(),
	})
	if err != nil {
		return trace.Wrap(err)
	}

	tc, err := f.createClient(req)
	if err != nil {
		return trace.Wrap(err)
	}

	err = tc.ExecuteSCP(context.TODO(), cmd)
	if err != nil {
		return trace.Wrap(err)
	}

	return nil
}

func (f *fileTransfer) createClient(req fileTransferRequest) (*client.TeleportClient, error) {
	if !services.IsValidNamespace(req.namespace) {
		return nil, trace.BadParameter("invalid namespace %q", req.namespace)
	}

	if req.login == "" {
		return nil, trace.BadParameter("missing login")
	}

	servers, err := f.authClient.GetNodes(req.namespace)
	if err != nil {
		return nil, trace.Wrap(err)
	}

	hostName, hostPort, err := resolveServerHostPort(req.server, servers)
	if err != nil {
		return nil, trace.BadParameter("invalid server name %q: %v", req.server, err)
	}

	cfg, err := makeTeleportClientConfig(f.ctx)
	if err != nil {
		return nil, trace.Wrap(err)
	}

	cfg.HostLogin = req.login
	cfg.SiteName = req.cluster
	cfg.Namespace = req.namespace
	cfg.ParseProxyHost(f.proxyHostPort)
	cfg.Host = hostName
	cfg.HostPort = hostPort

	tc, err := client.NewClient(cfg)
	if err != nil {
		return nil, trace.BadParameter("failed to create client: %v", err)
	}

	return tc, nil
}
<|endoftext|>


<commit_before>package main

import (
	"time"

	"github.com/Shopify/sarama"
	"github.com/golang/glog"
	"github.com/wvanbergen/kazoo-go"
)

const (
	REGISTER_CONSUMER_GROUP_RETRY_TIME = 10 * time.Second
	GET_CONSUMER_LIST_RETRY_TIME       = 10 * time.Second
	RUN_PARTITION_MANAGER_RETRY_TIME   = 10 * time.Second
	CONSUMER_LIST_CHANGE_RELOAD_TIME   = 5 * time.Second
	WATCH_INSTANCE_CHANGE_DELAY_TIME   = 5 * time.Second
)

type CallbackManager struct {
	*StartStopControl
	Topics    []string
	GroupName string
	Url       string

	// config
	config          *CallbackItemConfig
	kafkaConfig     *sarama.Config
	zookeeperConfig *kazoo.Config

	// zk instances
	kazoo              *kazoo.Kazoo                 // ZK
	kazooGroup         *kazoo.Consumergroup         // ZK ConsumerGroup /consumers/<cgname>/ Object
	kazooGroupInstance *kazoo.ConsumergroupInstance // ZK ConsumerGroup /consumers/<cgname>/ids/<cginstance> Object

	// kafka sarama consumer
	kafkaConsumer sarama.Consumer

	// partition manager
	partitionManagers      []*PartitionManager
	partitionManagerRunner *ServiceRunner

	// offset manager
	offsetManager *OffsetManager
}

func NewCallbackManager() *CallbackManager {
	return &CallbackManager{
		StartStopControl: NewStartStopControl(),
	}
}

func (cm *CallbackManager) Init(config *CallbackItemConfig) error {
	var err error

	cm.config = config
	cm.Topics = config.Topics
	cm.Url = config.Url

	// set group as MD5(Url)
	cm.GroupName = getGroupName(cm.Url)
	cm.kafkaConfig = sarama.NewConfig()
	cm.zookeeperConfig = kazoo.NewConfig()
	cm.zookeeperConfig.Chroot = config.ZkPath
	cm.kafkaConfig.ClientID = cm.GroupName

	// init OffsetManager
	cm.offsetManager = NewOffsetManager()
	if err = cm.offsetManager.Init(config.OffsetConfig, cm); err != nil {
		return err
	}

	cm.partitionManagerRunner = NewServiceRunner()

	return nil
}

func (cm *CallbackManager) Run() error {
	// mark service as started
	if err := cm.ensureStart(); err != nil {
		return err
	}

	defer cm.markStop()

	// init zookeeper
	if err := cm.connectZookeeper(); err != nil {
		return err
	}

	// init kafka sarama consumer
	if err := cm.connectKafka(); err != nil {
		return err
	}

	go cm.offsetManager.Run()

callbackManagerFailoverLoop:
	for {
		if !cm.Running() {
			break callbackManagerFailoverLoop
		}

		if err := cm.registerConsumergroup(); err != nil {
			time.Sleep(REGISTER_CONSUMER_GROUP_RETRY_TIME)
			continue
		}

		glog.Infof("Waiting for %v to avoid consumer register rebalance herd",
			WATCH_INSTANCE_CHANGE_DELAY_TIME)
		time.Sleep(WATCH_INSTANCE_CHANGE_DELAY_TIME)

		consumers, consumerChanges, err := cm.kazooGroup.WatchInstances()

		if err != nil {
			glog.Errorf("Failed to get list of registered consumer instances [err:%s]", err)
			time.Sleep(GET_CONSUMER_LIST_RETRY_TIME)
			continue
		}

		glog.Infof("Currently registered consumers [totalConsumers:%d]", len(consumers))

		// get partitionConsuming assignments
		// start ServiceRunner of PartitionManager
		// TODO refactor this
		if err := cm.partitionRun(consumers); err != nil {
			glog.Errorf("Failed to init partition consumer [err:%s]", err)
			time.Sleep(RUN_PARTITION_MANAGER_RETRY_TIME)
			continue
		}

		select {
		case <-cm.WaitForCloseChannel():
			cm.partitionManagerRunner.Close()
			break callbackManagerFailoverLoop

		case <-consumerChanges:
			glog.Infof("Triggering rebalance due to consumer list change")
			cm.partitionManagerRunner.Close()
			glog.Infof("Waiting for %v to avoid consumer inflight rebalance herd",
				CONSUMER_LIST_CHANGE_RELOAD_TIME)
			time.Sleep(CONSUMER_LIST_CHANGE_RELOAD_TIME)
		case <-cm.partitionManagerRunner.WaitForExitChannel():
			glog.Warning("PartitionManager unexpectedly stopped")
		}

		// deregister Consumergroup instance from zookeeper
		if err := cm.kazooGroupInstance.Deregister(); err != nil {
			glog.Errorf("Failed deregistering consumer instance [err:%s]", err)
		} else {
			glog.Infof("Deregistered consumer instance [instanceId:%s]", cm.kazooGroupInstance.ID)
		}
	}

	// sync close offsetManager
	if err := cm.offsetManager.Close(); err != nil {
		glog.Errorf("Failed closing the offset manager [err:%s]", err)
	}

	// close sarama Consumer
	if err := cm.kafkaConsumer.Close(); err != nil {
		glog.Errorf("Failed closing the Sarama client [err:%s]", err)
	}

	// close zookeeper connection
	if err := cm.kazoo.Close(); err != nil {
		glog.Errorf("Failed closing the Zookeeper connection [err:%s]", err)
	}

	return nil
}

func (cm *CallbackManager) GetPartitionManagers() []*PartitionManager {
	return cm.partitionManagers
}

func (cm *CallbackManager) GetOffsetManager() *OffsetManager {
	return cm.offsetManager
}

func (cm *CallbackManager) GetKazooGroup() *kazoo.Consumergroup {
	return cm.kazooGroup
}

func (cm *CallbackManager) GetKazooGroupInstance() *kazoo.ConsumergroupInstance {
	return cm.kazooGroupInstance
}

func (cm *CallbackManager) GetKafkaConsumer() sarama.Consumer {
	return cm.kafkaConsumer
}

func (cm *CallbackManager) GetConfig() *CallbackItemConfig {
	return cm.config
}

func (cm *CallbackManager) connectZookeeper() error {
	var err error

	// zookeeper ConsumerGroup instance initialization
	if cm.kazoo, err = kazoo.NewKazoo(cm.config.Zookeepers, cm.zookeeperConfig); err != nil {
		return err
	}
	cm.kazooGroup = cm.kazoo.Consumergroup(cm.GroupName)
	cm.kazooGroupInstance = cm.kazooGroup.NewInstance()

	return nil
}

func (cm *CallbackManager) connectKafka() error {
	var err error

	// kafka consumer initialization
	brokers, err := cm.kazoo.BrokerList()
	if err != nil {
		return err
	}

	// connect kafka using sarama Consumer
	if cm.kafkaConsumer, err = sarama.NewConsumer(brokers, cm.kafkaConfig); err != nil {
		return err
	}

	return nil
}

func (cm *CallbackManager) registerConsumergroup() error {
	// Register Consumergroup zk node
	if exists, err := cm.kazooGroup.Exists(); err != nil {
		glog.Errorf("Failed to check for existence of consumergroup [err:%s]", err)
		return err
	} else if !exists {
		glog.Infof("Consumergroup does not yet exists, creating [consumergroup:%s] ", cm.GroupName)
		if err := cm.kazooGroup.Create(); err != nil {
			glog.Errorf("Failed to create consumergroup in zookeeper [err:%s]", err)
			return err
		}
	}

	// register new kazoo.ConsumerGroup instance
	if err := cm.kazooGroupInstance.Register(cm.Topics); err != nil {
		glog.Errorf("Failed to register consumer instance [err:%s]", err)
		return err
	} else {
		glog.Infof("Consumer instance registered [instanceId:%s]", cm.kazooGroupInstance.ID)
	}

	return nil
}

func (cm *CallbackManager) partitionRun(consumers kazoo.ConsumergroupInstanceList) error {
	cm.partitionManagers = make([]*PartitionManager, 0)

	for _, topic := range cm.Topics {
		// Fetch a list of partition IDs
		partitions, err := cm.kazoo.Topic(topic).Partitions()
		if err != nil {
			glog.Errorf("Failed to get list of partitions [topic:%s][err:%s]", cm.Topics[0], err)
			return err
		}

		partitionLeaders, err := retrievePartitionLeaders(partitions)
		if err != nil {
			glog.Errorf("Failed to get leaders of partitions [topic:%s][err:%s]", topic, err)
			return err
		}

		// divide partition for each callback manager instance
		dividedPartitions := dividePartitionsBetweenConsumers(consumers, partitionLeaders)
		myPartitions := dividedPartitions[cm.kazooGroupInstance.ID]

		for i := 0; i < len(myPartitions); i++ {
			partitionManager := NewPartitionManager()
			if err := partitionManager.Init(cm.config, topic, myPartitions[i].ID, cm); err != nil {
				glog.Fatalf("Init partition manager failed [url:%s][err:%s]", cm.Url, err)
				return err
			}
			cm.partitionManagers = append(cm.partitionManagers, partitionManager)
		}
	}

	cm.partitionManagerRunner.RetryTimes = len(cm.partitionManagers) * 3
	cm.partitionManagerRunner.Prepare()
	if _, err := cm.partitionManagerRunner.RunAsync(cm.partitionManagers); err != nil {
		return err
	}

	return nil
}
<commit_msg>Fix repeated rebalance bug in callback_manager.go<commit_after>package main

import (
	"time"

	"github.com/Shopify/sarama"
	"github.com/golang/glog"
	"github.com/wvanbergen/kazoo-go"
)

const (
	REGISTER_CONSUMER_GROUP_RETRY_TIME = 10 * time.Second
	GET_CONSUMER_LIST_RETRY_TIME       = 10 * time.Second
	RUN_PARTITION_MANAGER_RETRY_TIME   = 10 * time.Second
	CONSUMER_LIST_CHANGE_RELOAD_TIME   = 5 * time.Second
	WATCH_INSTANCE_CHANGE_DELAY_TIME   = 5 * time.Second
)

type CallbackManager struct {
	*StartStopControl
	Topics    []string
	GroupName string
	Url       string

	// config
	config          *CallbackItemConfig
	kafkaConfig     *sarama.Config
	zookeeperConfig *kazoo.Config

	// zk instances
	kazoo              *kazoo.Kazoo                 // ZK
	kazooGroup         *kazoo.Consumergroup         // ZK ConsumerGroup /consumers/<cgname>/ Object
	kazooGroupInstance *kazoo.ConsumergroupInstance // ZK ConsumerGroup /consumers/<cgname>/ids/<cginstance> Object

	// kafka sarama consumer
	kafkaConsumer sarama.Consumer

	// partition manager
	partitionManagers      []*PartitionManager
	partitionManagerRunner *ServiceRunner

	// offset manager
	offsetManager *OffsetManager
}

func NewCallbackManager() *CallbackManager {
	return &CallbackManager{
		StartStopControl: NewStartStopControl(),
	}
}

func (cm *CallbackManager) Init(config *CallbackItemConfig) error {
	var err error

	cm.config = config
	cm.Topics = config.Topics
	cm.Url = config.Url

	// set group as MD5(Url)
	cm.GroupName = getGroupName(cm.Url)
	cm.kafkaConfig = sarama.NewConfig()
	cm.zookeeperConfig = kazoo.NewConfig()
	cm.zookeeperConfig.Chroot = config.ZkPath
	cm.kafkaConfig.ClientID = cm.GroupName

	// init OffsetManager
	cm.offsetManager = NewOffsetManager()
	if err = cm.offsetManager.Init(config.OffsetConfig, cm); err != nil {
		return err
	}

	cm.partitionManagerRunner = NewServiceRunner()

	return nil
}

func (cm *CallbackManager) Run() error {
	// mark service as started
	if err := cm.ensureStart(); err != nil {
		return err
	}

	defer cm.markStop()

	// init zookeeper
	if err := cm.connectZookeeper(); err != nil {
		return err
	}

	// init kafka sarama consumer
	if err := cm.connectKafka(); err != nil {
		return err
	}

	go cm.offsetManager.Run()

callbackManagerFailoverLoop:
	for {
		if !cm.Running() {
			break callbackManagerFailoverLoop
		}

		if err := cm.registerConsumergroup(); err != nil {
			time.Sleep(REGISTER_CONSUMER_GROUP_RETRY_TIME)
			continue
		}

		glog.Infof("Waiting for %v to avoid consumer register rebalance herd",
			WATCH_INSTANCE_CHANGE_DELAY_TIME)
		time.Sleep(WATCH_INSTANCE_CHANGE_DELAY_TIME)

		consumers, consumerChanges, err := cm.kazooGroup.WatchInstances()

		if err != nil {
			glog.Errorf("Failed to get list of registered consumer instances [err:%s]", err)
			time.Sleep(GET_CONSUMER_LIST_RETRY_TIME)
			continue
		}

		glog.Infof("Currently registered consumers [totalConsumers:%d]", len(consumers))

		// get partitionConsuming assignments
		// start ServiceRunner of PartitionManager
		// TODO refactor this
		if err := cm.partitionRun(consumers); err != nil {
			glog.Errorf("Failed to init partition consumer [err:%s]", err)
			time.Sleep(RUN_PARTITION_MANAGER_RETRY_TIME)
			continue
		}

		select {
		case <-cm.WaitForCloseChannel():
			cm.partitionManagerRunner.Close()
			break callbackManagerFailoverLoop

		case <-consumerChanges:
			glog.Infof("Triggering rebalance due to consumer list change")
			cm.partitionManagerRunner.Close()
			glog.Infof("Waiting for %v to avoid consumer inflight rebalance herd",
				CONSUMER_LIST_CHANGE_RELOAD_TIME)
			time.Sleep(CONSUMER_LIST_CHANGE_RELOAD_TIME)
		case <-cm.partitionManagerRunner.WaitForExitChannel():
			glog.Warning("PartitionManager unexpectedly stopped")
		}
	}

	// deregister Consumergroup instance from zookeeper
	if err := cm.kazooGroupInstance.Deregister(); err != nil {
		glog.Errorf("Failed deregistering consumer instance [err:%s]", err)
	} else {
		glog.Infof("Deregistered consumer instance [instanceId:%s]", cm.kazooGroupInstance.ID)
	}

	// sync close offsetManager
	if err := cm.offsetManager.Close(); err != nil {
		glog.Errorf("Failed closing the offset manager [err:%s]", err)
	}

	// close sarama Consumer
	if err := cm.kafkaConsumer.Close(); err != nil {
		glog.Errorf("Failed closing the Sarama client [err:%s]", err)
	}

	// close zookeeper connection
	if err := cm.kazoo.Close(); err != nil {
		glog.Errorf("Failed closing the Zookeeper connection [err:%s]", err)
	}

	return nil
}

func (cm *CallbackManager) GetPartitionManagers() []*PartitionManager {
	return cm.partitionManagers
}

func (cm *CallbackManager) GetOffsetManager() *OffsetManager {
	return cm.offsetManager
}

func (cm *CallbackManager) GetKazooGroup() *kazoo.Consumergroup {
	return cm.kazooGroup
}

func (cm *CallbackManager) GetKazooGroupInstance() *kazoo.ConsumergroupInstance {
	return cm.kazooGroupInstance
}

func (cm *CallbackManager) GetKafkaConsumer() sarama.Consumer {
	return cm.kafkaConsumer
}

func (cm *CallbackManager) GetConfig() *CallbackItemConfig {
	return cm.config
}

func (cm *CallbackManager) connectZookeeper() error {
	var err error

	// zookeeper ConsumerGroup instance initialization
	if cm.kazoo, err = kazoo.NewKazoo(cm.config.Zookeepers, cm.zookeeperConfig); err != nil {
		return err
	}
	cm.kazooGroup = cm.kazoo.Consumergroup(cm.GroupName)
	cm.kazooGroupInstance = cm.kazooGroup.NewInstance()

	return nil
}

func (cm *CallbackManager) connectKafka() error {
	var err error

	// kafka consumer initialization
	brokers, err := cm.kazoo.BrokerList()
	if err != nil {
		return err
	}

	// connect kafka using sarama Consumer
	if cm.kafkaConsumer, err = sarama.NewConsumer(brokers, cm.kafkaConfig); err != nil {
		return err
	}

	return nil
}

func (cm *CallbackManager) registerConsumergroup() error {
	// Register Consumergroup zk node
	if exists, err := cm.kazooGroup.Exists(); err != nil {
		glog.Errorf("Failed to check for existence of consumergroup [err:%s]", err)
		return err
	} else if !exists {
		glog.Infof("Consumergroup does not yet exists, creating [consumergroup:%s] ", cm.GroupName)
		if err := cm.kazooGroup.Create(); err != nil {
			glog.Errorf("Failed to create consumergroup in zookeeper [err:%s]", err)
			return err
		}
	}

	// register new kazoo.ConsumerGroup instance
	err := cm.kazooGroupInstance.Register(cm.Topics)
	if err != nil && err != kazoo.ErrInstanceAlreadyRegistered {
		glog.Errorf("Failed to register consumer instance [err:%s]", err)
	} else {
		err = nil
		glog.Infof("Consumer instance registered [instanceId:%s]", cm.kazooGroupInstance.ID)
	}

	return err
}

func (cm *CallbackManager) partitionRun(consumers kazoo.ConsumergroupInstanceList) error {
	cm.partitionManagers = make([]*PartitionManager, 0)

	for _, topic := range cm.Topics {
		// Fetch a list of partition IDs
		partitions, err := cm.kazoo.Topic(topic).Partitions()
		if err != nil {
			glog.Errorf("Failed to get list of partitions [topic:%s][err:%s]", cm.Topics[0], err)
			return err
		}

		partitionLeaders, err := retrievePartitionLeaders(partitions)
		if err != nil {
			glog.Errorf("Failed to get leaders of partitions [topic:%s][err:%s]", topic, err)
			return err
		}

		// divide partition for each callback manager instance
		dividedPartitions := dividePartitionsBetweenConsumers(consumers, partitionLeaders)
		myPartitions := dividedPartitions[cm.kazooGroupInstance.ID]

		for i := 0; i < len(myPartitions); i++ {
			partitionManager := NewPartitionManager()
			if err := partitionManager.Init(cm.config, topic, myPartitions[i].ID, cm); err != nil {
				glog.Fatalf("Init partition manager failed [url:%s][err:%s]", cm.Url, err)
				return err
			}
			cm.partitionManagers = append(cm.partitionManagers, partitionManager)
		}
	}

	cm.partitionManagerRunner.RetryTimes = len(cm.partitionManagers) * 3
	cm.partitionManagerRunner.Prepare()
	if _, err := cm.partitionManagerRunner.RunAsync(cm.partitionManagers); err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"time"

	"github.com/TykTechnologies/logrus"
)

type InterfaceNotification struct {
	Type      string
	Message   string
	OrgID     string
	Payload   interface{}
	Timestamp time.Time
}

type RedisNotificationHandler struct {
	CacheStore *RedisClusterStorageManager
}

const (
	UIChanName = "dashboard.ui.messages"
)

func (u *RedisNotificationHandler) Start() {
	go u.StartUIPubSubConn()
}

func (u *RedisNotificationHandler) Notify(n InterfaceNotification) error {
	jsonError, err := json.Marshal(n)
	if err != nil {
		return err
	}

	if u.CacheStore != nil {
		u.CacheStore.Publish(UIChanName, string(jsonError))
	}

	return nil
}

func (u *RedisNotificationHandler) StartUIPubSubConn() {
	u.CacheStore = &RedisClusterStorageManager{KeyPrefix: "gateway-notifications:", HashKeys: false}
	u.CacheStore.Connect()
	// On message, synchronize
	for {
		err := u.CacheStore.StartPubSubHandler(UIChanName, u.HandleIncommingRedisEvent)
		if err != nil {
			log.WithFields(logrus.Fields{
				"prefix": "log-notifications",
				"err":    err,
			}).Error("Connection to Redis failed, reconnect in 10s")

			time.Sleep(10 * time.Second)
			log.WithFields(logrus.Fields{
				"prefix": "log-notifications",
			}).Warning("Reconnecting")

			u.CacheStore.Connect()
			u.CacheStore.StartPubSubHandler(UIChanName, u.HandleIncommingRedisEvent)
		}

	}
}

func (u *RedisNotificationHandler) HandleIncommingRedisEvent(v interface{}) {
	log.Debug("Inbound redis event received")
}
<commit_msg>redis: remove another duplicate pub/sub call<commit_after>package main

import (
	"encoding/json"
	"time"

	"github.com/TykTechnologies/logrus"
)

type InterfaceNotification struct {
	Type      string
	Message   string
	OrgID     string
	Payload   interface{}
	Timestamp time.Time
}

type RedisNotificationHandler struct {
	CacheStore *RedisClusterStorageManager
}

const (
	UIChanName = "dashboard.ui.messages"
)

func (u *RedisNotificationHandler) Start() {
	go u.StartUIPubSubConn()
}

func (u *RedisNotificationHandler) Notify(n InterfaceNotification) error {
	jsonError, err := json.Marshal(n)
	if err != nil {
		return err
	}

	if u.CacheStore != nil {
		u.CacheStore.Publish(UIChanName, string(jsonError))
	}

	return nil
}

func (u *RedisNotificationHandler) StartUIPubSubConn() {
	u.CacheStore = &RedisClusterStorageManager{KeyPrefix: "gateway-notifications:", HashKeys: false}
	u.CacheStore.Connect()
	// On message, synchronize
	for {
		err := u.CacheStore.StartPubSubHandler(UIChanName, u.HandleIncommingRedisEvent)
		if err != nil {
			log.WithFields(logrus.Fields{
				"prefix": "log-notifications",
				"err":    err,
			}).Error("Connection to Redis failed, reconnect in 10s")

			time.Sleep(10 * time.Second)
			log.WithFields(logrus.Fields{
				"prefix": "log-notifications",
			}).Warning("Reconnecting")
		}

	}
}

func (u *RedisNotificationHandler) HandleIncommingRedisEvent(v interface{}) {
	log.Debug("Inbound redis event received")
}
<|endoftext|>


<commit_before>package redisc

import "github.com/garyburd/redigo/redis"

func GetMembers(members []*ScoredMember) []string {
	keys := make([]string, len(members))
	for i, m := range members {
		keys[i] = m.Member
	}
	return keys
}

func (rc *RedisCache) ZAdd(key string, members []*ScoredMember) (int, error) {
	if len(members) == 0 {
		return 0, nil
	}

	if conn, err := rc.write(); err != nil {
		return 0, err
	} else {
		defer conn.Close()

		count := (len(members) * 2) + 1
		command := make([]interface{}, count)
		command[0] = key
		items := command[1:]

		for i := 0; i < len(members); i++ {
			j := i * 2
			items[j] = members[i].Score
			items[j+1] = members[i].Member
		}

		if added, err := redis.Int(conn.Do("ZADD", command...)); err != nil {
			rc.Log.Error("Redis ZADD fail", err)
			return 0, err
		} else {
			return added, nil
		}
	}
}

// ZRevRange returns a subset ordered in descending order
func (rc *RedisCache) ZRevRange(key string, start, stop int) ([]*ScoredMember, error) {
	if conn, err := rc.read(); err != nil {
		return nil, err
	} else {
		defer conn.Close()
		return rc.scoredMembers(conn.Do("ZREVRANGE", key, start, stop, "WITHSCORES"))
	}
}

func (rc *RedisCache) ZIncrBy(key string, amount int, member interface{}) (int, error) {
	if conn, err := rc.write(); err != nil {
		return 0, err
	} else {
		defer conn.Close()
		return redis.Int(conn.Do("ZINCRBY", key, amount, member))
	}
}

// ZCard returns the Cardinality (i.e. count) of the set
func (rc *RedisCache) ZCard(key string) (int, error) {
	if conn, err := rc.read(); err != nil {
		return 0, err
	} else {
		defer conn.Close()
		return redis.Int(conn.Do("ZCard", key))
	}
}

func (rc *RedisCache) scoredMembers(results interface{}, err error) ([]*ScoredMember, error) {
	if values, err := redis.Values(results, err); err != nil {
		return nil, err
	} else {
		result := make([]*ScoredMember, len(values)/2)
		for i := range result {
			j := i * 2

			score, _ := redis.Int(values[j+1], nil)
			mv, _ := redis.String(values[j], nil)
			member := &ScoredMember{
				Member: mv,
				Score:  score,
			}
			result[i] = member
		}
		return result, nil
	}
}
<commit_msg>clean up<commit_after>package redisc

import "github.com/garyburd/redigo/redis"

func GetMembers(members []*ScoredMember) []string {
	keys := make([]string, len(members))
	for i, m := range members {
		keys[i] = m.Member
	}
	return keys
}

func (rc *RedisCache) ZAdd(key string, members []*ScoredMember) (int, error) {
	if len(members) == 0 {
		return 0, nil
	}

	if conn, err := rc.write(); err != nil {
		return 0, err
	} else {
		defer conn.Close()

		count := (len(members) * 2) + 1
		command := make([]interface{}, count)
		command[0] = key
		items := command[1:]

		for i := 0; i < len(members); i++ {
			j := i * 2
			items[j] = members[i].Score
			items[j+1] = members[i].Member
		}

		if added, err := redis.Int(conn.Do("ZADD", command...)); err != nil {
			rc.Log.Error("Redis ZADD fail", err)
			return 0, err
		} else {
			return added, nil
		}
	}
}

// ZRevRange returns a subset ordered in descending order
func (rc *RedisCache) ZRevRange(key string, start, stop int) ([]*ScoredMember, error) {
	if conn, err := rc.read(); err != nil {
		return nil, err
	} else {
		defer conn.Close()
		return rc.scoredMembers(conn.Do("ZREVRANGE", key, start, stop, "WITHSCORES"))
	}
}

func (rc *RedisCache) ZIncrBy(key string, amount int, member interface{}) (int, error) {
	if conn, err := rc.write(); err != nil {
		return 0, err
	} else {
		defer conn.Close()
		return redis.Int(conn.Do("ZINCRBY", key, amount, member))
	}
}

// ZCard returns the Cardinality (i.e. count) of the set
func (rc *RedisCache) ZCard(key string) (int, error) {
	if conn, err := rc.read(); err != nil {
		return 0, err
	} else {
		defer conn.Close()
		return redis.Int(conn.Do("ZCard", key))
	}
}

func (rc *RedisCache) scoredMembers(results interface{}, err error) ([]*ScoredMember, error) {
	if values, err := redis.Values(results, err); err != nil {
		return nil, err
	} else {
		result := make([]*ScoredMember, len(values)/2)
		for i := range result {
			j := i * 2

			mv, _ := redis.String(values[j], nil)
			score, _ := redis.Int(values[j+1], nil)
			member := &ScoredMember{
				Member: mv,
				Score:  score,
			}
			result[i] = member
		}
		return result, nil
	}
}
<|endoftext|>


<commit_before>package gmetric_test

import (
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"os/exec"
	"testing"
	"text/template"
	"time"

	"github.com/daaku/go.freeport"
	"github.com/daaku/go.subset"

	"github.com/daaku/go.ganglia/gmetric"
	"github.com/daaku/go.ganglia/gmon"
)

const localhostIP = "127.0.0.1"

var configTemplate, configTemplateErr = template.New("config").Parse(`
globals {
  daemonize = no
  setuid = false
  debug_level = 0
  max_udp_msg_len = 1472
  mute = no
  deaf = no
  allow_extra_data = yes
  host_dmax = 864000
}

cluster {
  name = "gmetric_test"
  owner = "gmetric_test"
  latlong = "gmetric_test"
  url = "gmetric_test"
}

host {
  location = "gmetric_test"
}

udp_recv_channel {
  port = {{.Port}}
  family = inet4
}

udp_recv_channel {
  port = {{.Port}}
  family = inet6
}

tcp_accept_channel {
  port = {{.Port}}
}
`)

func init() {
	if configTemplateErr != nil {
		panic(configTemplateErr)
	}
}

type harness struct {
	Client     *gmetric.Client
	Port       int
	T          *testing.T
	ConfigPath string
	Cmd        *exec.Cmd
}

func (h *harness) Start() {
	var err error
	if h.Port == 0 {
		if h.Port, err = freeport.Get(); err != nil {
			h.T.Fatal(err)
		}
	}

	cf, err := ioutil.TempFile("", "gmetric_test_gmond_conf")
	if err != nil {
		h.T.Fatal(err)
	}
	h.ConfigPath = cf.Name()

	if err := configTemplate.Execute(cf, h); err != nil {
		h.T.Fatal(err)
	}

	if err := cf.Close(); err != nil {
		h.T.Fatal(err)
	}

	h.Cmd = exec.Command("gmond", "--conf", h.ConfigPath)
	h.Cmd.Stderr = os.Stderr
	h.Cmd.Stdout = os.Stdout
	if err := h.Cmd.Start(); err != nil {
		h.T.Fatal(err)
	}

	// Wait until TCP socket is active to ensure we don't progress until the
	// server is ready to accept.
	for {
		if c, err := net.Dial("tcp", fmt.Sprintf("%s:%d", localhostIP, h.Port)); err == nil {
			c.Close()
			break
		}
	}

	h.Client = &gmetric.Client{
		Addr: []*net.UDPAddr{
			&net.UDPAddr{IP: net.ParseIP(localhostIP), Port: h.Port},
		},
	}

	if err := h.Client.Start(); err != nil {
		h.T.Fatal(err)
	}
}

func (h *harness) Stop() {
	if err := h.Client.Stop(); err != nil {
		h.T.Fatal(err)
	}

	if err := h.Cmd.Process.Kill(); err != nil {
		h.T.Fatal(err)
	}

	if err := os.Remove(h.ConfigPath); err != nil {
		h.T.Fatal(err)
	}
}

func (h *harness) State() *gmon.Ganglia {
	addr := fmt.Sprintf("%s:%d", localhostIP, h.Port)
	ganglia, err := gmon.RemoteRead("tcp", addr)
	if err != nil {
		h.T.Fatal(err)
	}
	return ganglia
}

func (h *harness) ContainsMetric(m *gmon.Metric) {
	deadline := time.Now().Add(2 * time.Second)
	for {
		g := h.State()
		for _, cluster := range g.Clusters {
			for _, host := range cluster.Hosts {
				for _, metric := range host.Metrics {
					if subset.Check(m, &metric) {
						return
					}
				}
			}
		}

		if time.Now().After(deadline) {
			h.T.Fatalf("did not find metric %+v in\n%+v", m, g)
		}
	}
}

func newHarness(t *testing.T) *harness {
	h := &harness{T: t}
	h.Start()
	return h
}

func TestUint32Metric(t *testing.T) {
	t.Parallel()
	h := newHarness(t)
	defer h.Stop()

	m := &gmetric.Metric{
		Name:         "simple_metric",
		Host:         "localhost",
		ValueType:    gmetric.ValueUint32,
		Units:        "count",
		Slope:        gmetric.SlopeBoth,
		TickInterval: 20 * time.Second,
		Lifetime:     24 * time.Hour,
	}
	const val = 10

	if err := h.Client.SendMeta(m); err != nil {
		t.Fatal(err)
	}

	if err := h.Client.SendValue(m, val); err != nil {
		t.Fatal(err)
	}

	h.ContainsMetric(&gmon.Metric{
		Name:  m.Name,
		Value: fmt.Sprint(val),
		Unit:  m.Units,
		Tn:    1,
		Tmax:  20,
		Slope: "both",
	})
}

func TestStringMetric(t *testing.T) {
	t.Parallel()
	h := newHarness(t)
	defer h.Stop()

	m := &gmetric.Metric{
		Name:         "simple_metric",
		Host:         "localhost",
		ValueType:    gmetric.ValueString,
		Units:        "count",
		Slope:        gmetric.SlopeBoth,
		TickInterval: 20 * time.Second,
		Lifetime:     24 * time.Hour,
	}
	const val = "hello"

	if err := h.Client.SendMeta(m); err != nil {
		t.Fatal(err)
	}

	if err := h.Client.SendValue(m, val); err != nil {
		t.Fatal(err)
	}

	h.ContainsMetric(&gmon.Metric{
		Name:  m.Name,
		Unit:  m.Units,
		Value: val,
		Tn:    1,
		Tmax:  20,
		Slope: "both",
	})
}

func TestFloatMetric(t *testing.T) {
	t.Parallel()
	h := newHarness(t)
	defer h.Stop()

	m := &gmetric.Metric{
		Name:         "simple_metric",
		Host:         "localhost",
		ValueType:    gmetric.ValueFloat32,
		Units:        "count",
		Slope:        gmetric.SlopeBoth,
		TickInterval: 20 * time.Second,
		Lifetime:     24 * time.Hour,
	}

	if err := h.Client.SendMeta(m); err != nil {
		t.Fatal(err)
	}

	if err := h.Client.SendValue(m, 3.14); err != nil {
		t.Fatal(err)
	}

	h.ContainsMetric(&gmon.Metric{
		Name:  m.Name,
		Unit:  m.Units,
		Value: "3.140000",
		Tn:    1,
		Tmax:  20,
		Slope: "both",
	})
}

func TestExtras(t *testing.T) {
	t.Parallel()
	h := newHarness(t)
	defer h.Stop()

	m := &gmetric.Metric{
		Name:         "simple_metric",
		Spoof:        "127.0.0.1:localhost_spoof",
		Title:        "the simple title",
		Description:  "the simple description",
		Host:         "localhost",
		Group:        "simple_group",
		ValueType:    gmetric.ValueString,
		Units:        "count",
		Slope:        gmetric.SlopeBoth,
		TickInterval: 20 * time.Second,
		Lifetime:     24 * time.Hour,
	}
	const val = "hello"

	if err := h.Client.SendMeta(m); err != nil {
		t.Fatal(err)
	}

	if err := h.Client.SendValue(m, val); err != nil {
		t.Fatal(err)
	}

	h.ContainsMetric(&gmon.Metric{
		Name:  m.Name,
		Unit:  m.Units,
		Value: val,
		Tn:    1,
		Tmax:  20,
		Slope: "both",
		ExtraData: gmon.ExtraData{
			ExtraElements: []gmon.ExtraElement{
				gmon.ExtraElement{Name: "GROUP", Val: m.Group},
				gmon.ExtraElement{Name: "SPOOF_HOST", Val: m.Spoof},
				gmon.ExtraElement{Name: "DESC", Val: m.Description},
				gmon.ExtraElement{Name: "TITLE", Val: m.Title},
			},
		},
	})
}
<commit_msg>test nits<commit_after>package gmetric_test

import (
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"os/exec"
	"testing"
	"text/template"
	"time"

	"github.com/daaku/go.freeport"
	"github.com/daaku/go.subset"

	"github.com/daaku/go.ganglia/gmetric"
	"github.com/daaku/go.ganglia/gmon"
)

const localhostIP = "127.0.0.1"

var configTemplate, configTemplateErr = template.New("config").Parse(`
globals {
  daemonize = no
  setuid = false
  debug_level = 0
  max_udp_msg_len = 1472
  mute = no
  deaf = no
  allow_extra_data = yes
  host_dmax = 864000
}

cluster {
  name = "gmetric_test"
  owner = "gmetric_test"
  latlong = "gmetric_test"
  url = "gmetric_test"
}

host {
  location = "gmetric_test"
}

udp_recv_channel {
  port = {{.Port}}
  family = inet4
}

udp_recv_channel {
  port = {{.Port}}
  family = inet6
}

tcp_accept_channel {
  port = {{.Port}}
}
`)

func init() {
	if configTemplateErr != nil {
		panic(configTemplateErr)
	}
}

type harness struct {
	Client     *gmetric.Client
	Port       int
	T          *testing.T
	ConfigPath string
	Cmd        *exec.Cmd
}

func (h *harness) Start() {
	var err error
	if h.Port == 0 {
		if h.Port, err = freeport.Get(); err != nil {
			h.T.Fatal(err)
		}
	}

	cf, err := ioutil.TempFile("", "gmetric_test_gmond_conf")
	if err != nil {
		h.T.Fatal(err)
	}
	h.ConfigPath = cf.Name()

	if err := configTemplate.Execute(cf, h); err != nil {
		h.T.Fatal(err)
	}

	if err := cf.Close(); err != nil {
		h.T.Fatal(err)
	}

	h.Cmd = exec.Command("gmond", "--conf", h.ConfigPath)
	h.Cmd.Stderr = os.Stderr
	h.Cmd.Stdout = os.Stdout
	if err := h.Cmd.Start(); err != nil {
		h.T.Fatal(err)
	}

	// Wait until TCP socket is active to ensure we don't progress until the
	// server is ready to accept.
	for {
		if c, err := net.Dial("tcp", fmt.Sprintf("%s:%d", localhostIP, h.Port)); err == nil {
			c.Close()
			break
		}
	}

	h.Client = &gmetric.Client{
		Addr: []*net.UDPAddr{
			&net.UDPAddr{IP: net.ParseIP(localhostIP), Port: h.Port},
		},
	}

	if err := h.Client.Start(); err != nil {
		h.T.Fatal(err)
	}
}

func (h *harness) Stop() {
	if err := h.Client.Stop(); err != nil {
		h.T.Fatal(err)
	}

	if err := h.Cmd.Process.Kill(); err != nil {
		h.T.Fatal(err)
	}

	if err := os.Remove(h.ConfigPath); err != nil {
		h.T.Fatal(err)
	}
}

func (h *harness) State() *gmon.Ganglia {
	addr := fmt.Sprintf("%s:%d", localhostIP, h.Port)
	ganglia, err := gmon.RemoteRead("tcp", addr)
	if err != nil {
		h.T.Fatal(err)
	}
	return ganglia
}

func (h *harness) ContainsMetric(m *gmon.Metric) {
	deadline := time.Now().Add(5 * time.Second)
	for {
		g := h.State()
		for _, cluster := range g.Clusters {
			for _, host := range cluster.Hosts {
				for _, metric := range host.Metrics {
					if subset.Check(m, &metric) {
						return
					}
				}
			}
		}

		if time.Now().After(deadline) {
			h.T.Fatalf("did not find metric %+v in\n%+v", m, g)
		}
	}
}

func newHarness(t *testing.T) *harness {
	h := &harness{T: t}
	h.Start()
	return h
}

func TestUint32Metric(t *testing.T) {
	t.Parallel()
	h := newHarness(t)
	defer h.Stop()

	m := &gmetric.Metric{
		Name:         "uint32_metric",
		Host:         "localhost",
		ValueType:    gmetric.ValueUint32,
		Units:        "count",
		Slope:        gmetric.SlopeBoth,
		TickInterval: 20 * time.Second,
		Lifetime:     24 * time.Hour,
	}
	const val = 10

	if err := h.Client.SendMeta(m); err != nil {
		t.Fatal(err)
	}

	if err := h.Client.SendValue(m, val); err != nil {
		t.Fatal(err)
	}

	h.ContainsMetric(&gmon.Metric{
		Name:  m.Name,
		Value: fmt.Sprint(val),
		Unit:  m.Units,
		Tn:    1,
		Tmax:  20,
		Slope: "both",
	})
}

func TestStringMetric(t *testing.T) {
	t.Parallel()
	h := newHarness(t)
	defer h.Stop()

	m := &gmetric.Metric{
		Name:         "string_metric",
		Host:         "localhost",
		ValueType:    gmetric.ValueString,
		Units:        "count",
		Slope:        gmetric.SlopeBoth,
		TickInterval: 20 * time.Second,
		Lifetime:     24 * time.Hour,
	}
	const val = "hello"

	if err := h.Client.SendMeta(m); err != nil {
		t.Fatal(err)
	}

	if err := h.Client.SendValue(m, val); err != nil {
		t.Fatal(err)
	}

	h.ContainsMetric(&gmon.Metric{
		Name:  m.Name,
		Unit:  m.Units,
		Value: val,
		Tn:    1,
		Tmax:  20,
		Slope: "both",
	})
}

func TestFloatMetric(t *testing.T) {
	t.Parallel()
	h := newHarness(t)
	defer h.Stop()

	m := &gmetric.Metric{
		Name:         "float_metric",
		Host:         "localhost",
		ValueType:    gmetric.ValueFloat32,
		Units:        "count",
		Slope:        gmetric.SlopeBoth,
		TickInterval: 20 * time.Second,
		Lifetime:     24 * time.Hour,
	}

	if err := h.Client.SendMeta(m); err != nil {
		t.Fatal(err)
	}

	if err := h.Client.SendValue(m, 3.14); err != nil {
		t.Fatal(err)
	}

	h.ContainsMetric(&gmon.Metric{
		Name:  m.Name,
		Unit:  m.Units,
		Value: "3.140000",
		Tn:    1,
		Tmax:  20,
		Slope: "both",
	})
}

func TestExtras(t *testing.T) {
	t.Parallel()
	h := newHarness(t)
	defer h.Stop()

	m := &gmetric.Metric{
		Name:         "extras_metric",
		Spoof:        "127.0.0.1:localhost_spoof",
		Title:        "the simple title",
		Description:  "the simple description",
		Host:         "localhost",
		Group:        "simple_group",
		ValueType:    gmetric.ValueString,
		Units:        "count",
		Slope:        gmetric.SlopeBoth,
		TickInterval: 20 * time.Second,
		Lifetime:     24 * time.Hour,
	}
	const val = "hello"

	if err := h.Client.SendMeta(m); err != nil {
		t.Fatal(err)
	}

	if err := h.Client.SendValue(m, val); err != nil {
		t.Fatal(err)
	}

	h.ContainsMetric(&gmon.Metric{
		Name:  m.Name,
		Unit:  m.Units,
		Value: val,
		Tn:    1,
		Tmax:  20,
		Slope: "both",
		ExtraData: gmon.ExtraData{
			ExtraElements: []gmon.ExtraElement{
				gmon.ExtraElement{Name: "GROUP", Val: m.Group},
				gmon.ExtraElement{Name: "SPOOF_HOST", Val: m.Spoof},
				gmon.ExtraElement{Name: "DESC", Val: m.Description},
				gmon.ExtraElement{Name: "TITLE", Val: m.Title},
			},
		},
	})
}
<|endoftext|>


<commit_before>package sdees

import (
	"fmt"
	"io/ioutil"
	"path"
	"strings"
	"time"
)

func Run() {
	// Some variables to be set later
	filterBranch := ""

	// Check if cloning needs to occur
	logger.Debug("Current remote: %s", Remote)
	measureTime := time.Now()
	fmt.Print("Fetching latest")
	if !exists(RemoteFolder) {
		logger.Debug("Remote folder does not exist: %s", RemoteFolder)
		err := Clone(RemoteFolder, Remote)
		if err != nil {
			logger.Warn("Problems cloning remote '%s': %s", Remote, err.Error())
		}
	} else {
		errFetch := Fetch(RemoteFolder)
		if errFetch == nil {
			fmt.Print("...done")
		} else {
			fmt.Println("...unable to fetch:")
			fmt.Println(errFetch.Error())
		}
	}
	fmt.Printf(" (%s)\n", time.Since(measureTime).String())

	// List available documents to choose from
	availableFiles, encrypted := ListFiles(RemoteFolder)
	if len(InputDocument) == 0 {
		var editDocument string
		fmt.Printf("\nCurrently available documents: ")
		logger.Debug("Last documents was %s", CurrentDocument)
		for i, file := range availableFiles {
			fmt.Printf("\n- %s ", file)
			if encrypted[i] {
				fmt.Print("[encrypted] ")
			}
			if file == CurrentDocument {
				fmt.Print("(default) ")
			}
		}
		if len(CurrentDocument) == 0 {
			CurrentDocument = "notes.txt"
		}
		fmt.Printf("\n\nWhich document (press enter for '%s', or type name): ", CurrentDocument)
		fmt.Scanln(&editDocument)
		if len(editDocument) == 0 && len(CurrentDocument) > 0 {
			// Pass
		} else if len(editDocument) == 0 && len(availableFiles) > 0 {
			CurrentDocument = availableFiles[0]
		} else if len(CurrentDocument) == 0 && len(editDocument) == 0 && len(availableFiles) == 0 {
			CurrentDocument = "notes.txt"
		} else if len(editDocument) > 0 {
			CurrentDocument = editDocument
		}
	} else {
		branchList, _ := ListBranches(RemoteFolder)
		for _, branch := range branchList {
			if branch == InputDocument {
				doc, _ := ListFileOfOne(RemoteFolder, branch)
				logger.Debug("You've entered a branch %s which is in document %s", branch, doc)
				InputDocument = doc
				filterBranch = branch
			}
		}
		CurrentDocument = InputDocument
	}
	logger.Debug("Current document: %s", CurrentDocument)
	// Save choice of current document
	SaveConfiguration(Editor, Remote, CurrentDocument)

	// Check if encryption is needed
	isNew := true
	Encrypt = false
	for i, file := range availableFiles {
		if CurrentDocument == file {
			isNew = false
			Encrypt = encrypted[i]
			break
		}
	}
	if isNew {
		// Prompt whether encryption is wanted for new files
		var yesencryption string
		fmt.Print("\nDo you want to add encryption (default: y)? (y/n) ")
		fmt.Scanln(&yesencryption)
		if yesencryption == "n" {
			Encrypt = false
		} else {
			Encrypt = true
		}
	} else if !All && !Summarize && !Export && !DeleteDocument && len(DeleteEntry) == 0 && len(filterBranch) == 0 {
		// Prompt for whether to load whole document
		var yesnoall string
		fmt.Print("\nLoad all entries (press enter for 'n')? (y/n) ")
		fmt.Scanln(&yesnoall)
		if yesnoall == "y" {
			All = true
		}
	}

	// Prompt for passphrase if encrypted
	if Encrypt {
		Passphrase = PromptPassword(RemoteFolder, CurrentDocument)
	}

	// Update the cache using the passphrase if needed
	cache, _, err := UpdateCache(RemoteFolder, CurrentDocument, false)
	if err != nil {
		logger.Error("Error updating cache: %s", err.Error())
		return
	}

	// Do deletions
	if DeleteDocument {
		GoDeleteDocument(cache)
		return
	} else if len(DeleteEntry) > 0 {
		GoDeleteEntry(cache)
		return
	}

	// Load fulltext
	texts := []string{}
	textsBranch := []string{}
	var branchHashes map[string]string
	if All || Export || Summarize || len(Search) > 0 || len(filterBranch) > 0 {
		texts, textsBranch, branchHashes = CombineEntries(cache)
		// Conduct the search
		if len(Search) > 0 {
			searchWords := GetWordsFromText(Search)
			textFoo := []string{}
			for i := range texts {
				for _, searchWord := range searchWords {
					if strings.Contains(texts[i], searchWord) {
						textFoo = append(textFoo, texts[i])
						break
					}
				}
			}
			texts = textFoo
		}
		if len(filterBranch) > 0 {
			for i, branch := range textsBranch {
				if branch == filterBranch {
					logger.Debug("Filtering out everything but branch %s", filterBranch)
					texts = []string{texts[i]}
					textsBranch = []string{textsBranch[i]}
				}
			}
		}
	}

	// Case-switch for what to do with fulltext
	if Export {
		fmt.Println("Exporting to " + CurrentDocument)
		ioutil.WriteFile(CurrentDocument, []byte(strings.Join(texts, "\n\n")+"\n"), 0644)
		return
	} else if Summarize {
		fmt.Println("\nSummary:")
		fmt.Println(SummarizeEntries(texts, textsBranch))
		return
	} else {
		if len(filterBranch) == 0 {
			texts = append(texts, HeadMatter(GetCurrentDate(), MakeAlliteration()))
		} else {
			fmt.Printf("Loaded entry '%s' on document '%s'\n", filterBranch, CurrentDocument)
		}
		ioutil.WriteFile(path.Join(TempPath, "temp"), []byte(strings.Join(texts, "\n\n")+"\n"), 0644)
	}
	fulltext := WriteEntry()
	UpdateEntryFromText(fulltext, branchHashes)

	// Push new changes
	measureTime = time.Now()
	fmt.Print("Pushing changes")
	err = Push(RemoteFolder)
	if err == nil {
		fmt.Print("...done")
	} else {
		fmt.Print("...no internet, not pushing")
	}
	fmt.Printf(" (%s)\n", time.Since(measureTime).String())
}
<commit_msg>Fix #53<commit_after>package sdees

import (
	"fmt"
	"io/ioutil"
	"path"
	"strings"
	"time"
)

func Run() {
	// Some variables to be set later
	filterBranch := ""

	// Check if cloning needs to occur
	logger.Debug("Current remote: %s", Remote)
	measureTime := time.Now()
	fmt.Print("Fetching latest")
	if !exists(RemoteFolder) {
		logger.Debug("Remote folder does not exist: %s", RemoteFolder)
		err := Clone(RemoteFolder, Remote)
		if err != nil {
			logger.Warn("Problems cloning remote '%s': %s", Remote, err.Error())
		}
	} else {
		errFetch := Fetch(RemoteFolder)
		if errFetch == nil {
			fmt.Print("...done")
		} else {
			fmt.Println("...unable to fetch:")
			fmt.Println(errFetch.Error())
		}
	}
	fmt.Printf(" (%s)\n", time.Since(measureTime).String())

	// List available documents to choose from
	availableFiles, encrypted := ListFiles(RemoteFolder)
	if len(InputDocument) == 0 {
		var editDocument string
		fmt.Printf("\nCurrently available documents: ")
		logger.Debug("Last documents was %s", CurrentDocument)
		for i, file := range availableFiles {
			fmt.Printf("\n- %s ", file)
			if encrypted[i] {
				fmt.Print("[encrypted] ")
			}
			if file == CurrentDocument {
				fmt.Print("(default) ")
			}
		}
		if len(CurrentDocument) == 0 {
			CurrentDocument = "notes.txt"
		}
		fmt.Printf("\n\nWhich document (press enter for '%s', or type name): ", CurrentDocument)
		fmt.Scanln(&editDocument)
		if len(editDocument) == 0 && len(CurrentDocument) > 0 {
			// Pass
		} else if len(editDocument) == 0 && len(availableFiles) > 0 {
			CurrentDocument = availableFiles[0]
		} else if len(CurrentDocument) == 0 && len(editDocument) == 0 && len(availableFiles) == 0 {
			CurrentDocument = "notes.txt"
		} else if len(editDocument) > 0 {
			CurrentDocument = editDocument
		}
	} else {
		branchList, _ := ListBranches(RemoteFolder)
		for _, branch := range branchList {
			if branch == InputDocument {
				doc, _ := ListFileOfOne(RemoteFolder, branch)
				logger.Debug("You've entered a branch %s which is in document %s", branch, doc)
				InputDocument = doc
				filterBranch = branch
			}
		}
		CurrentDocument = InputDocument
	}
	logger.Debug("Current document: %s", CurrentDocument)
	// Save choice of current document
	SaveConfiguration(Editor, Remote, CurrentDocument)

	// Check if encryption is needed
	isNew := true
	Encrypt = false
	for i, file := range availableFiles {
		if CurrentDocument == file {
			isNew = false
			Encrypt = encrypted[i]
			break
		}
	}
	if isNew {
		// Prompt whether encryption is wanted for new files
		var yesencryption string
		fmt.Print("\nDo you want to add encryption (default: y)? (y/n) ")
		fmt.Scanln(&yesencryption)
		if yesencryption == "n" {
			Encrypt = false
		} else {
			Encrypt = true
		}
	} else if !All && !Summarize && !Export && !DeleteDocument && len(DeleteEntry) == 0 && len(filterBranch) == 0 && len(Search) == 0 {
		// Prompt for whether to load whole document
		var yesnoall string
		fmt.Print("\nLoad all entries (press enter for 'n')? (y/n) ")
		fmt.Scanln(&yesnoall)
		if yesnoall == "y" {
			All = true
		}
	}

	// Prompt for passphrase if encrypted
	if Encrypt {
		Passphrase = PromptPassword(RemoteFolder, CurrentDocument)
	}

	// Update the cache using the passphrase if needed
	cache, _, err := UpdateCache(RemoteFolder, CurrentDocument, false)
	if err != nil {
		logger.Error("Error updating cache: %s", err.Error())
		return
	}

	// Do deletions
	if DeleteDocument {
		GoDeleteDocument(cache)
		return
	} else if len(DeleteEntry) > 0 {
		GoDeleteEntry(cache)
		return
	}

	// Load fulltext
	texts := []string{}
	textsBranch := []string{}
	var branchHashes map[string]string
	if All || Export || Summarize || len(Search) > 0 || len(filterBranch) > 0 {
		texts, textsBranch, branchHashes = CombineEntries(cache)
		// Conduct the search
		if len(Search) > 0 {
			searchWords := GetWordsFromText(Search)
			textFoo := []string{}
			for i := range texts {
				for _, searchWord := range searchWords {
					if strings.Contains(strings.ToLower(texts[i]), strings.ToLower(searchWord)) {
						textFoo = append(textFoo, texts[i])
						break
					}
				}
			}
			texts = textFoo
		}
		if len(filterBranch) > 0 {
			for i, branch := range textsBranch {
				if branch == filterBranch {
					logger.Debug("Filtering out everything but branch %s", filterBranch)
					texts = []string{texts[i]}
					textsBranch = []string{textsBranch[i]}
				}
			}
		}
	}

	// Case-switch for what to do with fulltext
	if Export {
		fmt.Println("Exporting to " + CurrentDocument)
		ioutil.WriteFile(CurrentDocument, []byte(strings.Join(texts, "\n\n")+"\n"), 0644)
		return
	} else if Summarize {
		fmt.Println("\nSummary:")
		fmt.Println(SummarizeEntries(texts, textsBranch))
		return
	} else {
		if len(filterBranch) == 0 {
			texts = append(texts, HeadMatter(GetCurrentDate(), MakeAlliteration()))
		} else {
			fmt.Printf("Loaded entry '%s' on document '%s'\n", filterBranch, CurrentDocument)
		}
		ioutil.WriteFile(path.Join(TempPath, "temp"), []byte(strings.Join(texts, "\n\n")+"\n"), 0644)
	}
	fulltext := WriteEntry()
	UpdateEntryFromText(fulltext, branchHashes)

	// Push new changes
	measureTime = time.Now()
	fmt.Print("Pushing changes")
	err = Push(RemoteFolder)
	if err == nil {
		fmt.Print("...done")
	} else {
		fmt.Print("...no internet, not pushing")
	}
	fmt.Printf(" (%s)\n", time.Since(measureTime).String())
}
<|endoftext|>


<commit_before>package repository

import (
	"github.com/timeredbull/commandmocker"
	"github.com/timeredbull/tsuru/config"
	"github.com/timeredbull/tsuru/log"
	. "launchpad.net/gocheck"
	stdlog "log"
	"os"
	"os/exec"
	"path"
	"testing"
	"time"
)

func Test(t *testing.T) { TestingT(t) }

type S struct {
	git         *repository
	gitRoot     string
	gitosisBare string
	gitosisRepo string
	mngr        *gitosisManager
	logFile     *os.File
	repoPath    string
	tmpdir      string
}

var _ = Suite(&S{})

func (s *S) setUpGit(c *C) {
	s.repoPath = "/tmp/git" + time.Now().Format("20060102150405")
	err := os.MkdirAll(s.repoPath, 0755)
	c.Assert(err, IsNil)
	s.git = &repository{path: s.repoPath}
	_, err = s.git.run("init")
	c.Assert(err, IsNil)
}

func (s *S) tearDownGit(c *C) {
	err := os.RemoveAll(s.repoPath)
	c.Assert(err, IsNil)
}

func (s *S) SetUpSuite(c *C) {
	var err error
	s.tmpdir, err = commandmocker.Add("juju", "")
	c.Assert(err, IsNil)
	err = config.ReadConfigFile("../etc/tsuru.conf")
	c.Assert(err, IsNil)
	s.gitRoot = ".test/git"
	s.gitosisRepo = s.gitRoot + "/gitosis-admin"
	s.gitosisBare = s.gitosisRepo + ".git"
	config.Set("git:root", s.gitRoot)
	config.Set("git:gitosis-bare", s.gitosisBare)
	config.Set("git:gitosis-repo", s.gitosisRepo)
	err = os.RemoveAll(s.gitRoot)
	c.Assert(err, IsNil)
	err = os.MkdirAll(s.gitRoot, 0777)
	c.Assert(err, IsNil)
	err = exec.Command("git", "init", "--bare", s.gitosisBare).Run()
	c.Assert(err, IsNil)
	err = exec.Command("git", "clone", s.gitosisBare, s.gitosisRepo).Run()
	c.Assert(err, IsNil)
	s.logFile, err = os.Create("/tmp/tsuru-tests.log")
	c.Assert(err, IsNil)
	RunAgent()
	s.setUpGit(c)
	s.mngr, err = newGitosisManager()
	c.Assert(err, IsNil)
	log.Target = stdlog.New(s.logFile, "[tsuru-tests]", stdlog.LstdFlags|stdlog.Llongfile)
}

func (s *S) SetUpTest(c *C) {
	fpath := path.Join(s.gitosisRepo, "gitosis.conf")
	f, err := os.Create(fpath)
	c.Assert(err, IsNil)
	f.Close()
	err = s.mngr.git.commit("added gitosis test file")
	c.Assert(err, IsNil)
	err = s.mngr.git.push("origin", "master")
	c.Assert(err, IsNil)
}

func (s *S) TearDownSuite(c *C) {
	defer commandmocker.Remove(s.tmpdir)
	defer s.logFile.Close()
	defer s.tearDownGit(c)
	err := os.RemoveAll(s.gitRoot)
	c.Assert(err, IsNil)
}

func (s *S) TearDownTest(c *C) {
	_, err := s.mngr.git.run("rm", "gitosis.conf")
	c.Assert(err, IsNil)
	err = s.mngr.git.commit("removing test file")
	c.Assert(err, IsNil)
	err = s.mngr.git.push("origin", "master")
	c.Assert(err, IsNil)
}

func (s *S) TestGetGitServerPanicsIfTheConfigFileHasNoServer(c *C) {
	oldConfig, err := config.Get("git")
	c.Assert(err, IsNil)
	err = config.Unset("git")
	c.Assert(err, IsNil)
	defer config.Set("git", oldConfig)
	c.Assert(getGitServer, PanicMatches, "key git:server not found")
}

func (s *S) lastBareCommit(c *C) string {
	bareOutput, err := exec.Command("git", "--git-dir="+s.gitosisBare, "log", "-1", "--pretty=format:%s").CombinedOutput()
	c.Assert(err, IsNil)
	return string(bareOutput)
}
<commit_msg>repository: improving fixtures<commit_after>package repository

import (
	"github.com/timeredbull/commandmocker"
	"github.com/timeredbull/tsuru/config"
	"github.com/timeredbull/tsuru/log"
	. "launchpad.net/gocheck"
	stdlog "log"
	"os"
	"os/exec"
	"path"
	"testing"
	"time"
)

func Test(t *testing.T) { TestingT(t) }

type S struct {
	git         *repository
	gitRoot     string
	gitosisBare string
	gitosisRepo string
	mngr        *gitosisManager
	logFile     *os.File
	repoPath    string
	tmpdir      string
}

var _ = Suite(&S{})

func (s *S) setUpGit(c *C) {
	s.repoPath = "/tmp/git" + time.Now().Format("20060102150405")
	err := os.MkdirAll(s.repoPath, 0755)
	c.Assert(err, IsNil)
	s.git = &repository{path: s.repoPath}
	_, err = s.git.run("init")
	c.Assert(err, IsNil)
}

func (s *S) tearDownGit(c *C) {
	err := os.RemoveAll(s.repoPath)
	c.Assert(err, IsNil)
}

func (s *S) SetUpSuite(c *C) {
	var err error
	s.tmpdir, err = commandmocker.Add("juju", "")
	c.Assert(err, IsNil)
	err = config.ReadConfigFile("../etc/tsuru.conf")
	c.Assert(err, IsNil)
	s.gitRoot = ".test/git"
	s.gitosisRepo = s.gitRoot + "/gitosis-admin"
	s.gitosisBare = s.gitosisRepo + ".git"
	config.Set("git:root", s.gitRoot)
	config.Set("git:gitosis-bare", s.gitosisBare)
	config.Set("git:gitosis-repo", s.gitosisRepo)
	err = os.RemoveAll(s.gitRoot)
	c.Assert(err, IsNil)
	err = os.MkdirAll(s.gitRoot, 0777)
	c.Assert(err, IsNil)
	err = exec.Command("git", "init", "--bare", s.gitosisBare).Run()
	c.Assert(err, IsNil)
	err = exec.Command("git", "clone", s.gitosisBare, s.gitosisRepo).Run()
	c.Assert(err, IsNil)
	s.logFile, err = os.Create("/tmp/tsuru-tests.log")
	c.Assert(err, IsNil)
	RunAgent()
	s.setUpGit(c)
	s.mngr, err = newGitosisManager()
	c.Assert(err, IsNil)
	log.Target = stdlog.New(s.logFile, "[tsuru-tests]", stdlog.LstdFlags|stdlog.Llongfile)
}

func (s *S) SetUpTest(c *C) {
	fpath := path.Join(s.gitosisRepo, "gitosis.conf")
	f, err := os.Create(fpath)
	c.Assert(err, IsNil)
	f.Close()
	err = s.mngr.git.commit("added gitosis test file")
	c.Assert(err, IsNil)
	err = s.mngr.git.push("origin", "master")
	c.Assert(err, IsNil)
}

func (s *S) TearDownSuite(c *C) {
	defer commandmocker.Remove(s.tmpdir)
	defer s.logFile.Close()
	defer s.tearDownGit(c)
	err := os.RemoveAll(s.gitRoot)
	c.Assert(err, IsNil)
}

func (s *S) TearDownTest(c *C) {
	out, err := s.mngr.git.run("rm", "gitosis.conf")
	if err != nil {
		c.Error(out)
		c.FailNow()
	}
	c.Assert(err, IsNil)
	err = s.mngr.git.commit("removing test file")
	c.Assert(err, IsNil)
	err = s.mngr.git.push("origin", "master")
	c.Assert(err, IsNil)
}

func (s *S) TestGetGitServerPanicsIfTheConfigFileHasNoServer(c *C) {
	oldConfig, err := config.Get("git")
	c.Assert(err, IsNil)
	err = config.Unset("git")
	c.Assert(err, IsNil)
	defer config.Set("git", oldConfig)
	c.Assert(getGitServer, PanicMatches, "key git:server not found")
}

func (s *S) lastBareCommit(c *C) string {
	bareOutput, err := exec.Command("git", "--git-dir="+s.gitosisBare, "log", "-1", "--pretty=format:%s").CombinedOutput()
	c.Assert(err, IsNil)
	return string(bareOutput)
}
<|endoftext|>


<commit_before>package request

import (
	"encoding/json"
	"github.com/MatthewHartstonge/storage/client"
	"github.com/ory/fosite"
	"github.com/pborman/uuid"
	"github.com/pkg/errors"
	"log"
	"net/url"
	"time"
)

// MongoRequest is a concrete implementation of a fosite.Requester, extended to support the required data for
// OAuth2 and OpenID.
type MongoRequest struct {
	ID            string    `bson:"_id" json:"id"`
	RequestedAt   time.Time `bson:"requested_at" json:"requested_at"`
	Signature     string    `bson:"signature"`
	ClientID      string    `bson:"client_id" json:"client_id"`
	Scopes        []string  `bson:"scopes" json:"scopes"`
	GrantedScopes []string  `bson:"granted_scopes" json:"granted_scopes"`
	Form          string    `bson:"form_data" json:"form_data"`
	Session       []byte    `bson:"session_data"`
}

func NewRequest() *MongoRequest {
	return &MongoRequest{
		ID:            uuid.New(),
		RequestedAt:   time.Now(),
		Scopes:        []string{},
		GrantedScopes: []string{},
		Form:          "",
		Session:       []byte(""),
	}
}

// toRequest transforms a mongo database reference to a fosite request
func (m *MongoRequest) toRequest(session fosite.Session, cm client.Manager) (*fosite.Request, error) {
	if session != nil {
		if err := json.Unmarshal(m.Session, session); err != nil {
			return nil, errors.WithStack(err)
		}
	} else {
		log.Println("Got an empty session in toRequest")
	}

	c, err := cm.GetClient(nil, m.ClientID)
	if err != nil {
		return nil, err
	}

	val, err := url.ParseQuery(m.Form)
	if err != nil {
		return nil, errors.WithStack(err)
	}

	r := &fosite.Request{
		ID:            m.ID,
		RequestedAt:   m.RequestedAt,
		Client:        c,
		Scopes:        m.Scopes,
		GrantedScopes: m.GrantedScopes,
		Form:          val,
		Session:       session,
	}

	return r, nil
}
<commit_msg>:arrow_up: request: update marshalling to conform to camelcase as per idiomatic JS<commit_after>package request

import (
	"encoding/json"
	"github.com/MatthewHartstonge/storage/client"
	"github.com/ory/fosite"
	"github.com/pborman/uuid"
	"github.com/pkg/errors"
	"log"
	"net/url"
	"time"
)

// MongoRequest is a concrete implementation of a fosite.Requester, extended to support the required data for
// OAuth2 and OpenID.
type MongoRequest struct {
	ID            string    `bson:"_id" json:"id" xml:"id"`
	RequestedAt   time.Time `bson:"requestedAt" json:"requestedAt" xml:"requestedAt"`
	Signature     string    `bson:"signature" json:"signature" xml:"signature"`
	ClientID      string    `bson:"clientId" json:"clientId" xml:"clientId"`
	Scopes        []string  `bson:"scopes" json:"scopes" xml:"scopes"`
	GrantedScopes []string  `bson:"grantedScopes" json:"grantedScopes" xml:"grantedScopes"`
	Form          string    `bson:"formData" json:"formData" xml:"formData"`
	Session       []byte    `bson:"sessionData" json:"sessionData" xml:"sessionData"`
}

func NewRequest() *MongoRequest {
	return &MongoRequest{
		ID:            uuid.New(),
		RequestedAt:   time.Now(),
		Scopes:        []string{},
		GrantedScopes: []string{},
		Form:          "",
		Session:       []byte(""),
	}
}

// toRequest transforms a mongo database reference to a fosite request
func (m *MongoRequest) toRequest(session fosite.Session, cm client.Manager) (*fosite.Request, error) {
	if session != nil {
		if err := json.Unmarshal(m.Session, session); err != nil {
			return nil, errors.WithStack(err)
		}
	} else {
		log.Println("Got an empty session in toRequest")
	}

	c, err := cm.GetClient(nil, m.ClientID)
	if err != nil {
		return nil, err
	}

	val, err := url.ParseQuery(m.Form)
	if err != nil {
		return nil, errors.WithStack(err)
	}

	r := &fosite.Request{
		ID:            m.ID,
		RequestedAt:   m.RequestedAt,
		Client:        c,
		Scopes:        m.Scopes,
		GrantedScopes: m.GrantedScopes,
		Form:          val,
		Session:       session,
	}

	return r, nil
}
<|endoftext|>


<commit_before>// Copyright 2009 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.

// User ids etc.

package os

import (
	"syscall";
	"os";
	"unsafe";
)

// Getuid returns the numeric user id of the caller.
func Getuid() int {
	u, r2, e := syscall.Syscall(syscall.SYS_GETUID, 0, 0, 0);
	return int(u);
}

// Geteuid returns the numeric effective user id of the caller.
func Geteuid() int {
	u, r2, e := syscall.Syscall(syscall.SYS_GETEUID, 0, 0, 0);
	return int(u);
}

// Getgid returns the numeric group id of the caller.
func Getgid() int {
	g, r2, e := syscall.Syscall(syscall.SYS_GETGID, 0, 0, 0);
	return int(g);
}

// Getegid returns the numeric effective group id of the caller.
func Getegid() int {
	g, r2, e := syscall.Syscall(syscall.SYS_GETEGID, 0, 0, 0);
	return int(g);
}

// Getgroups returns a list of the numeric ids of groups that the caller belongs to.
func Getgroups() ([]int, os.Error) {
	// first call asks how many there are.
	r1, r2, err := syscall.Syscall(syscall.SYS_GETGROUPS, 0, 0, 0);
	if err != 0 {
		return nil, ErrnoToError(err);
	}

	if r1 < 0 || r1 > 1024 {	// the current max is 16; 1024 is a future-proof sanity check
		return nil, EINVAL;
	}
	a := make([]int, r1);
	if r1 > 0 {
		tmp := make([]uint32, r1);
		r1, r2, err = syscall.Syscall(syscall.SYS_GETGROUPS, r1, int64(uintptr(unsafe.Pointer(&tmp[0]))), 0);
		if err != 0 {
			return nil, ErrnoToError(err);
		}
		for i := 0; i < len(a); i++ {
			a[i] = int(tmp[i]);
		}
	}
	return a[0:r1], nil;
}
<commit_msg>Getgroups max on Linux is bigger than I thought.<commit_after>// Copyright 2009 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.

// User ids etc.

package os

import (
	"syscall";
	"os";
	"unsafe";
)

// Getuid returns the numeric user id of the caller.
func Getuid() int {
	u, r2, e := syscall.Syscall(syscall.SYS_GETUID, 0, 0, 0);
	return int(u);
}

// Geteuid returns the numeric effective user id of the caller.
func Geteuid() int {
	u, r2, e := syscall.Syscall(syscall.SYS_GETEUID, 0, 0, 0);
	return int(u);
}

// Getgid returns the numeric group id of the caller.
func Getgid() int {
	g, r2, e := syscall.Syscall(syscall.SYS_GETGID, 0, 0, 0);
	return int(g);
}

// Getegid returns the numeric effective group id of the caller.
func Getegid() int {
	g, r2, e := syscall.Syscall(syscall.SYS_GETEGID, 0, 0, 0);
	return int(g);
}

// Getgroups returns a list of the numeric ids of groups that the caller belongs to.
func Getgroups() ([]int, os.Error) {
	// first call asks how many there are.
	r1, r2, err := syscall.Syscall(syscall.SYS_GETGROUPS, 0, 0, 0);
	if err != 0 {
		return nil, ErrnoToError(err);
	}

	// Sanity check group count.
	// On Linux, max is 1<<16; on BSD, OS X, max is 16.
	if r1 < 0 || r1 > 1<<20 {
		return nil, EINVAL;
	}
	a := make([]int, r1);
	if r1 > 0 {
		tmp := make([]uint32, r1);
		r1, r2, err = syscall.Syscall(syscall.SYS_GETGROUPS, r1, int64(uintptr(unsafe.Pointer(&tmp[0]))), 0);
		if err != 0 {
			return nil, ErrnoToError(err);
		}
		for i := 0; i < len(a); i++ {
			a[i] = int(tmp[i]);
		}
	}
	return a[0:r1], nil;
}
<|endoftext|>


<commit_before>// Copyright 2009 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 strings

// Count UTF-8 sequences in s.
// Assumes s is well-formed.
export func utflen(s string) int {
	n := 0;
	for i := 0; i < len(s); i++ {
		if s[i]&0xC0 != 0x80 {
			n++
		}
	}
	return n
}

// Split string into array of UTF-8 sequences (still strings)
export func explode(s string) *[]string {
	a := new([]string, utflen(s));
	j := 0;
	for i := 0; i < len(a); i++ {
		ej := j;
		ej++;
		for ej < len(s) && (s[ej]&0xC0) == 0x80 {
			ej++
		}
		a[i] = s[j:ej];
		j = ej
	}
	return a
}

// Count non-overlapping instances of sep in s.
export func count(s, sep string) int {
	if sep == "" {
		return utflen(s)+1
	}
	c := sep[0];
	n := 0;
	for i := 0; i+len(sep) <= len(s); i++ {
		if s[i] == c && (len(sep) == 1 || s[i:i+len(sep)] == sep) {
			n++;
			i += len(sep)-1
		}
	}
	return n
}

// Return index of first instance of sep in s.
export func index(s, sep string) int {
	if sep == "" {
		return 0
	}
	c := sep[0];
	for i := 0; i+len(sep) <= len(s); i++ {
		if s[i] == c && (len(sep) == 1 || s[i:i+len(sep)] == sep) {
			return i
		}
	}
	return -1
}

// Split string into list of strings at separators
export func split(s, sep string) *[]string {
	if sep == "" {
		return explode(s)
	}
	c := sep[0];
	start := 0;
	n := count(s, sep)+1;
	a := new([]string, n);
	na := 0;
	for i := 0; i+len(sep) <= len(s); i++ {
		if s[i] == c && (len(sep) == 1 || s[i:i+len(sep)] == sep) {
			a[na] = s[start:i];
			na++;
			start = i+len(sep);
			i += len(sep)-1
		}
	}
	a[na] = s[start:len(s)];
	return a
}

// Join list of strings with separators between them.
export func join(a *[]string, sep string) string {
	if len(a) == 0 {
		return ""
	}
	if len(a) == 1 {
		return a[0]
	}
	n := len(sep) * (len(a)-1);
	for i := 0; i < len(a); i++ {
		n += len(a[i])
	}

	b := new([]byte, n);
	bp := 0;
	for i := 0; i < len(a); i++ {
		s := a[i];
		for j := 0; j < len(s); j++ {
			b[bp] = s[j];
			bp++
		}
		if i + 1 < len(a) {
			s = sep;
			for j := 0; j < len(s); j++ {
				b[bp] = s[j];
				bp++
			}
		}
	}
	return string(b)
}

// Convert decimal string to integer.
// TODO: Doesn't check for overflow.
export func atol(s string) (i int64, ok bool) {
	// empty string bad
	if len(s) == 0 {
		return 0, false
	}

	// pick off leading sign
	neg := false;
	if s[0] == '+' {
		s = s[1:len(s)]
	} else if s[0] == '-' {
		neg = true;
		s = s[1:len(s)]
	}

	// empty string bad
	if len(s) == 0 {
		return 0, false
	}

	// pick off zero
	if s == "0" {
		return 0, true
	}

	// otherwise, leading zero bad
	if s[0] == '0' {
		return 0, false
	}

	// parse number
	n := int64(0);
	for i := 0; i < len(s); i++ {
		if s[i] < '0' || s[i] > '9' {
			return 0, false
		}
		n = n*10 + int64(s[i] - '0')
	}
	if neg {
		n = -n
	}
	return n, true
}

export func atoi(s string) (i int, ok bool) {
	ii, okok := atol(s);
	i = int(ii);
	return i, okok
}

export func ltoa(i int64) string {
	if i == 0 {
		return "0"
	}

	neg := false;	// negative
	u := uint(i);
	if i < 0 {
		neg = true;
		u = -u;
	}

	// Assemble decimal in reverse order.
	var b [32]byte;
	bp := len(b);
	for ; u > 0; u /= 10 {
		bp--;
		b[bp] = byte(u%10) + '0'
	}
	if neg {	// add sign
		bp--;
		b[bp] = '-'
	}

	// BUG return string(b[bp:len(b)])
	return string((&b)[bp:len(b)])
}

export func itoa(i int) string {
	return ltoa(int64(i));
}

// Convert float64 to string.  No control over format.
// Result not great; only useful for simple debugging.
export func dtoa(v float64) string {
	var buf [20]byte;

	const n = 7;	// digits printed
	e := 0;	// exp
	var sign byte = '+';
	if(v != 0) {
		// sign
		if(v < 0) {
			v = -v;
			sign = '-';
		}

		// normalize
		for v >= 10 {
			e++;
			v /= 10;
		}
		for v < 1 {
			e--;
			v *= 10;
		}

		// round
		var h float64 = 5;
		for i := 0; i < n; i++ {
			h /= 10;
		}
		v += h;
		if v >= 10 {
			e++;
			v /= 10;
		}
	}

	// format +d.dddd+edd
	buf[0] = sign;
	for i := 0; i < n; i++ {
		s := int64(v);
		buf[i+2] = byte(s)+'0';
		v -= float64(s);
		v *= 10;
	}
	buf[1] = buf[2];
	buf[2] = '.';

	buf[n+2] = 'e';
	buf[n+3] = '+';
	if e < 0 {
		e = -e;
		buf[n+3] = '-';
	}

	// TODO: exponents > 99?
	buf[n+4] = byte((e/10) + '0');
	buf[n+5] = byte((e%10) + '0');
	return string(buf)[0:n+6];	// TODO: should be able to slice buf
}

export func ftoa(v float) string {
	return dtoa(float64(v));
}
<commit_msg>ascii to unsigned integer<commit_after>// Copyright 2009 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 strings

// Count UTF-8 sequences in s.
// Assumes s is well-formed.
export func utflen(s string) int {
	n := 0;
	for i := 0; i < len(s); i++ {
		if s[i]&0xC0 != 0x80 {
			n++
		}
	}
	return n
}

// Split string into array of UTF-8 sequences (still strings)
export func explode(s string) *[]string {
	a := new([]string, utflen(s));
	j := 0;
	for i := 0; i < len(a); i++ {
		ej := j;
		ej++;
		for ej < len(s) && (s[ej]&0xC0) == 0x80 {
			ej++
		}
		a[i] = s[j:ej];
		j = ej
	}
	return a
}

// Count non-overlapping instances of sep in s.
export func count(s, sep string) int {
	if sep == "" {
		return utflen(s)+1
	}
	c := sep[0];
	n := 0;
	for i := 0; i+len(sep) <= len(s); i++ {
		if s[i] == c && (len(sep) == 1 || s[i:i+len(sep)] == sep) {
			n++;
			i += len(sep)-1
		}
	}
	return n
}

// Return index of first instance of sep in s.
export func index(s, sep string) int {
	if sep == "" {
		return 0
	}
	c := sep[0];
	for i := 0; i+len(sep) <= len(s); i++ {
		if s[i] == c && (len(sep) == 1 || s[i:i+len(sep)] == sep) {
			return i
		}
	}
	return -1
}

// Split string into list of strings at separators
export func split(s, sep string) *[]string {
	if sep == "" {
		return explode(s)
	}
	c := sep[0];
	start := 0;
	n := count(s, sep)+1;
	a := new([]string, n);
	na := 0;
	for i := 0; i+len(sep) <= len(s); i++ {
		if s[i] == c && (len(sep) == 1 || s[i:i+len(sep)] == sep) {
			a[na] = s[start:i];
			na++;
			start = i+len(sep);
			i += len(sep)-1
		}
	}
	a[na] = s[start:len(s)];
	return a
}

// Join list of strings with separators between them.
export func join(a *[]string, sep string) string {
	if len(a) == 0 {
		return ""
	}
	if len(a) == 1 {
		return a[0]
	}
	n := len(sep) * (len(a)-1);
	for i := 0; i < len(a); i++ {
		n += len(a[i])
	}

	b := new([]byte, n);
	bp := 0;
	for i := 0; i < len(a); i++ {
		s := a[i];
		for j := 0; j < len(s); j++ {
			b[bp] = s[j];
			bp++
		}
		if i + 1 < len(a) {
			s = sep;
			for j := 0; j < len(s); j++ {
				b[bp] = s[j];
				bp++
			}
		}
	}
	return string(b)
}

// Convert decimal string to unsigned integer.
// TODO: Doesn't check for overflow.
export func atoui64(s string) (i uint64, ok bool) {
	// empty string bad
	if len(s) == 0 {
		return 0, false
	}

	// pick off zero
	if s == "0" {
		return 0, true
	}

	// otherwise, leading zero bad
	if s[0] == '0' {
		return 0, false
	}

	// parse number
	n := uint64(0);
	for i := 0; i < len(s); i++ {
		if s[i] < '0' || s[i] > '9' {
			return 0, false
		}
		n = n*10 + uint64(s[i] - '0')
	}
	return n, true
}

// Convert decimal string to integer.
// TODO: Doesn't check for overflow.
export func atoi64(s string) (i int64, ok bool) {
	// empty string bad
	if len(s) == 0 {
		return 0, false
	}

	// pick off leading sign
	neg := false;
	if s[0] == '+' {
		s = s[1:len(s)]
	} else if s[0] == '-' {
		neg = true;
		s = s[1:len(s)]
	}

	var un uint64;
	un, ok = atoui64(s);
	if !ok {
		return 0, false
	}
	n := int64(un);
	if neg {
		n = -n
	}
	return n, true
}

export func atoui(s string) (i uint, ok bool) {
	ii, okok := atoui64(s);
	i = uint(ii);
	return i, okok
}

export func atoi(s string) (i int, ok bool) {
	ii, okok := atoi64(s);
	i = int(ii);
	return i, okok
}

export func ltoa(i int64) string {
	if i == 0 {
		return "0"
	}

	neg := false;	// negative
	u := uint(i);
	if i < 0 {
		neg = true;
		u = -u;
	}

	// Assemble decimal in reverse order.
	var b [32]byte;
	bp := len(b);
	for ; u > 0; u /= 10 {
		bp--;
		b[bp] = byte(u%10) + '0'
	}
	if neg {	// add sign
		bp--;
		b[bp] = '-'
	}

	// BUG return string(b[bp:len(b)])
	return string((&b)[bp:len(b)])
}

export func itoa(i int) string {
	return ltoa(int64(i));
}

// Convert float64 to string.  No control over format.
// Result not great; only useful for simple debugging.
export func dtoa(v float64) string {
	var buf [20]byte;

	const n = 7;	// digits printed
	e := 0;	// exp
	var sign byte = '+';
	if(v != 0) {
		// sign
		if(v < 0) {
			v = -v;
			sign = '-';
		}

		// normalize
		for v >= 10 {
			e++;
			v /= 10;
		}
		for v < 1 {
			e--;
			v *= 10;
		}

		// round
		var h float64 = 5;
		for i := 0; i < n; i++ {
			h /= 10;
		}
		v += h;
		if v >= 10 {
			e++;
			v /= 10;
		}
	}

	// format +d.dddd+edd
	buf[0] = sign;
	for i := 0; i < n; i++ {
		s := int64(v);
		buf[i+2] = byte(s)+'0';
		v -= float64(s);
		v *= 10;
	}
	buf[1] = buf[2];
	buf[2] = '.';

	buf[n+2] = 'e';
	buf[n+3] = '+';
	if e < 0 {
		e = -e;
		buf[n+3] = '-';
	}

	// TODO: exponents > 99?
	buf[n+4] = byte((e/10) + '0');
	buf[n+5] = byte((e%10) + '0');
	return string(buf)[0:n+6];	// TODO: should be able to slice buf
}

export func ftoa(v float) string {
	return dtoa(float64(v));
}
<|endoftext|>


<commit_before>package server

import (
	"errors"
	"net"
	"os"
	"path/filepath"

	"github.com/hashicorp/serf/serf"
)

// ensurePath is used to make sure a path exists
func ensurePath(path string, dir bool) error {
	if !dir {
		path = filepath.Dir(path)
	}
	return os.MkdirAll(path, 0755)
}

// isKappaNode returns whether a node is a Kappa server as well as its cluster.
func isKappaNode(member serf.Member) (bool, string) {

	// Get role name
	if role, ok := member.Tags["role"]; !ok {
		return false, ""
	} else if role != "kappa" {
		return false, ""
	}

	// Get cluster name
	if name, ok := member.Tags["cluster"]; ok {
		return ok, name
	}
	return false, ""
}

// validateNode should validate all the Serf tags for the given member and returns
// NodeDetails and any that occured error.
func getKappaServer(serf.Member) (*NodeDetails, error) {
	return &NodeDetails{}, errors.New("Not implemented")
}

// NodeDetails stores details about a single serf.Member
type NodeDetails struct {
	Name      string
	Cluster   string
	SSHPort   int
	Bootstrap bool
	Addr      net.TCPAddr
	Expect    int
}
<commit_msg>Implement getKappaServer<commit_after>package server

import (
	"errors"
	"fmt"
	"net"
	"os"
	"path/filepath"

	"strconv"

	"github.com/hashicorp/serf/serf"
)

// ensurePath is used to make sure a path exists
func ensurePath(path string, dir bool) error {
	if !dir {
		path = filepath.Dir(path)
	}
	return os.MkdirAll(path, 0755)
}

// isKappaNode returns whether a node is a Kappa server as well as its cluster.
func isKappaNode(member serf.Member) (bool, string) {

	// Get role name
	if role, ok := member.Tags["role"]; !ok {
		return false, ""
	} else if role != "kappa" {
		return false, ""
	}

	// Get cluster name
	if name, ok := member.Tags["cluster"]; ok {
		return ok, name
	}
	return false, ""
}

// validateNode should validate all the Serf tags for the given member and returns
// NodeDetails and any that occured error.
func getKappaServer(m serf.Member) (n *NodeDetails, err error) {

	// Get node cluster
	cluster, ok := m.Tags["cluster"]
	if !ok {
		err = errors.New("error: member missing cluster tag")
		return
	}

	// Get node SSH port
	port, ok := m.Tags["port"]
	if !ok {
		err = errors.New("error: member missing ssh port")
		return
	}

	// Convert port to int
	p, err := strconv.Atoi(port)
	if err != nil {
		err = fmt.Errorf("error: member ssh port cannot be converted to string: '%s'", port)
		return
	}

	// Get node bootstrap
	// All nodes which have this tag are bootstrapped
	_, bootstrap := m.Tags["bootstrap"]

	// Get SSH addr
	addr := net.TCPAddr{IP: m.Addr, Port: p}

	n = &NodeDetails{}
	n.Name = m.Name
	n.Cluster = cluster
	n.SSHPort = p
	n.Bootstrap = bootstrap
	n.Addr = addr
	return
}

// NodeDetails stores details about a single serf.Member
type NodeDetails struct {
	Name      string
	Cluster   string
	SSHPort   int
	Bootstrap bool
	Addr      net.TCPAddr
	Expect    int
}

func (n NodeDetails) String() string {
	return fmt.Sprintf("%#v", n)
}
<|endoftext|>