<commit_before>/*
Copyright 2018 Google LLC

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 util

import (
	"io/ioutil"
	"os/exec"

	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

// DefaultExecCommand runs commands using exec.Cmd
var DefaultExecCommand Command = &Commander{}

// Command is an interface used to run commands. All packages should use this
// interface instead of calling exec.Cmd directly.
type Command interface {
	RunCmdOut(cmd *exec.Cmd) ([]byte, error)
	RunCmd(cmd *exec.Cmd) error
}

func RunCmdOut(cmd *exec.Cmd) ([]byte, error) {
	return DefaultExecCommand.RunCmdOut(cmd)
}

func RunCmd(cmd *exec.Cmd) error {
	return DefaultExecCommand.RunCmd(cmd)
}

// Commander is the exec.Cmd implementation of the Command interface
type Commander struct{}

// RunCmdOut runs an exec.Command and returns the stdout and error.
func (*Commander) RunCmdOut(cmd *exec.Cmd) ([]byte, error) {
	logrus.Infof("Executing: %s", cmd.Args)
	stdoutPipe, err := cmd.StdoutPipe()
	if err != nil {
		return nil, err
	}

	stderrPipe, err := cmd.StderrPipe()
	if err != nil {
		return nil, err
	}

	if err := cmd.Start(); err != nil {
		return nil, errors.Wrapf(err, "starting command %v", cmd)
	}

	stdout, err := ioutil.ReadAll(stdoutPipe)
	if err != nil {
		return nil, err
	}

	stderr, err := ioutil.ReadAll(stderrPipe)
	if err != nil {
		return nil, err
	}

	err = cmd.Wait()
	if err != nil {
		return stdout, errors.Wrapf(err, "Running %s: stdout %s, stderr: %s, err: %v", cmd.Args, stdout, stderr, err)
	}

	logrus.Debugf("Command output: stdout %s, stderr: %s", stdout, stderr)

	return stdout, nil
}

// RunCmd runs an exec.Command.
func (*Commander) RunCmd(cmd *exec.Cmd) error {
	logrus.Debugf("Running command: %s", cmd.Args)
	return cmd.Run()
}
<commit_msg>Also use .Infof for RunCmd()<commit_after>/*
Copyright 2018 Google LLC

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 util

import (
	"io/ioutil"
	"os/exec"

	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

// DefaultExecCommand runs commands using exec.Cmd
var DefaultExecCommand Command = &Commander{}

// Command is an interface used to run commands. All packages should use this
// interface instead of calling exec.Cmd directly.
type Command interface {
	RunCmdOut(cmd *exec.Cmd) ([]byte, error)
	RunCmd(cmd *exec.Cmd) error
}

func RunCmdOut(cmd *exec.Cmd) ([]byte, error) {
	return DefaultExecCommand.RunCmdOut(cmd)
}

func RunCmd(cmd *exec.Cmd) error {
	return DefaultExecCommand.RunCmd(cmd)
}

// Commander is the exec.Cmd implementation of the Command interface
type Commander struct{}

// RunCmdOut runs an exec.Command and returns the stdout and error.
func (*Commander) RunCmdOut(cmd *exec.Cmd) ([]byte, error) {
	logrus.Infof("Executing: %s", cmd.Args)
	stdoutPipe, err := cmd.StdoutPipe()
	if err != nil {
		return nil, err
	}

	stderrPipe, err := cmd.StderrPipe()
	if err != nil {
		return nil, err
	}

	if err := cmd.Start(); err != nil {
		return nil, errors.Wrapf(err, "starting command %v", cmd)
	}

	stdout, err := ioutil.ReadAll(stdoutPipe)
	if err != nil {
		return nil, err
	}

	stderr, err := ioutil.ReadAll(stderrPipe)
	if err != nil {
		return nil, err
	}

	err = cmd.Wait()
	if err != nil {
		return stdout, errors.Wrapf(err, "Running %s: stdout %s, stderr: %s, err: %v", cmd.Args, stdout, stderr, err)
	}

	logrus.Debugf("Command output: stdout %s, stderr: %s", stdout, stderr)

	return stdout, nil
}

// RunCmd runs an exec.Command.
func (*Commander) RunCmd(cmd *exec.Cmd) error {
	logrus.Infof("Executing: %s", cmd.Args)
	return cmd.Run()
}
<|endoftext|>


<commit_before>package rkedialerfactory

import (
	"fmt"
	"net"
	"strings"

	"net/http"

	"github.com/rancher/norman/types/slice"
	"github.com/rancher/rancher/pkg/ref"
	"github.com/rancher/rke/hosts"
	"github.com/rancher/rke/k8s"
	"github.com/rancher/types/apis/management.cattle.io/v3"
	"github.com/rancher/types/config/dialer"
)

type RKEDialerFactory struct {
	Factory dialer.Factory
	Docker  bool
}

func (t *RKEDialerFactory) Build(h *hosts.Host) (func(network, address string) (net.Conn, error), error) {
	if h.NodeName == "" {
		return hosts.SSHFactory(h)
	}

	parts := strings.SplitN(h.NodeName, ":", 2)
	if len(parts) != 2 {
		return nil, fmt.Errorf("invalid name reference %s", h.NodeName)
	}

	if t.Docker {
		return t.Factory.DockerDialer(parts[0], parts[1])
	}
	return t.Factory.NodeDialer(parts[0], parts[1])
}

func (t *RKEDialerFactory) WrapTransport(config *v3.RancherKubernetesEngineConfig) k8s.WrapTransport {
	for _, node := range config.Nodes {
		if !slice.ContainsString(node.Role, "controlplane") {
			continue
		}

		ns, n := ref.Parse(node.NodeName)
		dialer, err := t.Factory.NodeDialer(ns, n)
		if dialer == nil || err != nil {
			continue
		}

		return func(rt http.RoundTripper) http.RoundTripper {
			if ht, ok := rt.(*http.Transport); ok {
				ht.MaxIdleConnsPerHost = 1
				ht.DialContext = nil
				ht.DialTLS = nil
				ht.Dial = dialer
			}
			return rt
		}
	}

	return nil
}
<commit_msg>Don't limit idle connects on rke dialer<commit_after>package rkedialerfactory

import (
	"fmt"
	"net"
	"strings"

	"net/http"

	"github.com/rancher/norman/types/slice"
	"github.com/rancher/rancher/pkg/ref"
	"github.com/rancher/rke/hosts"
	"github.com/rancher/rke/k8s"
	"github.com/rancher/types/apis/management.cattle.io/v3"
	"github.com/rancher/types/config/dialer"
)

type RKEDialerFactory struct {
	Factory dialer.Factory
	Docker  bool
}

func (t *RKEDialerFactory) Build(h *hosts.Host) (func(network, address string) (net.Conn, error), error) {
	if h.NodeName == "" {
		return hosts.SSHFactory(h)
	}

	parts := strings.SplitN(h.NodeName, ":", 2)
	if len(parts) != 2 {
		return nil, fmt.Errorf("invalid name reference %s", h.NodeName)
	}

	if t.Docker {
		return t.Factory.DockerDialer(parts[0], parts[1])
	}
	return t.Factory.NodeDialer(parts[0], parts[1])
}

func (t *RKEDialerFactory) WrapTransport(config *v3.RancherKubernetesEngineConfig) k8s.WrapTransport {
	for _, node := range config.Nodes {
		if !slice.ContainsString(node.Role, "controlplane") {
			continue
		}

		ns, n := ref.Parse(node.NodeName)
		dialer, err := t.Factory.NodeDialer(ns, n)
		if dialer == nil || err != nil {
			continue
		}

		return func(rt http.RoundTripper) http.RoundTripper {
			if ht, ok := rt.(*http.Transport); ok {
				ht.DialContext = nil
				ht.DialTLS = nil
				ht.Dial = dialer
			}
			return rt
		}
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2013 Google. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd

/*
Package github provides a client for using the GitHub API.

Access different parts of the GitHub API using the various services on a GitHub
Client:

	client := github.NewClient(nil)

	// list all organizations for user "willnorris"
	orgs, err := client.Organizations.List("willnorris", nil)

Set optional parameters for an API method by passing an Options object.

	// list recently updated repositories for org "github"
	opt := &github.RepositoryListByOrgOptions{Sort: "updated"}
	repos, err := client.Repositories.ListByOrg("github", opt)

Make authenticated API calls by constructing a GitHub client using an OAuth
capable http.Client:

	import "code.google.com/p/goauth2/oauth"

	// simple OAuth transport if you already have an access token;
	// see goauth2 library for full usage
	t := &oauth.Transport{
		Token: &oauth.Token{AccessToken: "..."},
	}

	client := github.NewClient(t.Client())

	// list all repositories for the authenticated user
	repos, err := client.Repositories.List(nil)

Note that when using an authenticated Client, all calls made by the client will
include the specified OAuth token. Therefore, authenticated clients should
almost never be shared between different users.

The full GitHub API is documented at http://developer.github.com/v3/.
*/
package github

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
)

const (
	libraryVersion = "0.1"
	defaultBaseURL = "https://api.github.com/"
	userAgent      = "go-github/" + libraryVersion
)

// A Client manages communication with the GitHub API.
type Client struct {
	// HTTP client used to communicate with the API.
	client *http.Client

	// Base URL for API requests.  Defaults to the public GitHub API, but can be
	// set to a domain endpoint to use with GitHub Enterprise.  BaseURL should
	// always be specified with a trailing slash.
	BaseURL *url.URL

	// User agent used when communicating with the GitHub API.
	UserAgent string

	// Services used for talking to different parts of the API

	Organizations *OrganizationsService
	Repositories  *RepositoriesService
	Users         *UsersService
}

// ListOptions specifies the optional parameters to various List methods that
// support pagination.
type ListOptions struct {
	// For paginated result sets, page of results to retrieve.
	Page int
}

// NewClient returns a new GitHub API client.  If a nil httpClient is
// provided, http.DefaultClient will be used.  To use API methods which require
// authentication, provide an http.Client that will perform the authentication
// for you (such as that provided by the goauth2 library).
func NewClient(httpClient *http.Client) *Client {
	if httpClient == nil {
		httpClient = http.DefaultClient
	}
	baseURL, _ := url.Parse(defaultBaseURL)

	c := &Client{client: httpClient, BaseURL: baseURL, UserAgent: userAgent}
	c.Organizations = &OrganizationsService{client: c}
	c.Repositories = &RepositoriesService{client: c}
	c.Users = &UsersService{client: c}
	return c
}

// NewRequest creates an API request. A relative URL can be provided in urlStr,
// in which case it is resolved relative to the BaseURL of the Client.
// Relative URLs should always be specified without a preceding slash.  If
// specified, the value pointed to by body is JSON encoded and included as the
// request body.
func (c *Client) NewRequest(method, urlStr string, body interface{}) (*http.Request, error) {
	rel, err := url.Parse(urlStr)
	if err != nil {
		return nil, err
	}

	u := c.BaseURL.ResolveReference(rel)

	buf := new(bytes.Buffer)
	if body != nil {
		err := json.NewEncoder(buf).Encode(body)
		if err != nil {
			return nil, err
		}
	}

	req, err := http.NewRequest(method, u.String(), buf)
	if err != nil {
		return nil, err
	}

	req.Header.Add("User-Agent", c.UserAgent)
	return req, nil
}

// Do sends an API request and returns the API response.  The API response is
// decoded and stored in the value pointed to by v, or returned as an error if
// an API error has occurred.
func (c *Client) Do(req *http.Request, v interface{}) (*http.Response, error) {
	resp, err := c.client.Do(req)
	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()

	err = CheckResponse(resp)
	if err != nil {
		return resp, err
	}

	if v != nil {
		err = json.NewDecoder(resp.Body).Decode(v)
	}
	return resp, err
}

/*
An ErrorResponse reports one or more errors caused by an API request.

GitHub API docs: http://developer.github.com/v3/#client-errors
*/
type ErrorResponse struct {
	Response *http.Response // HTTP response that caused this error
	Message  string         `json:message` // error message
	Errors   []Error        `json:errors`  // more detail on individual errors
}

func (r *ErrorResponse) Error() string {
	return fmt.Sprintf("%v %v: %d %v",
		r.Response.Request.Method, r.Response.Request.URL,
		r.Response.StatusCode, r.Message)
}

/*
An Error reports more details on an individual error in an ErrorResponse.
These are the possible validation error codes:

    missing:
        resource does not exist
    missing_field:
        a required field on a resource has not been set
    invalid:
        the formatting of a field is invalid
    already_exists:
        another resource has the same valid as this field

GitHub API docs: http://developer.github.com/v3/#client-errors
*/
type Error struct {
	Resource string `json:resource` // resource on which the error occurred
	Field    string `json:field`    // field on which the error occurred
	Code     string `json:code`     // validation error code
}

func (e *Error) Error() string {
	return fmt.Sprintf("%v error caused by %v field on %v resource",
		e.Code, e.Field, e.Resource)
}

// CheckResponse checks the API response for errors, and returns them if
// present.  A response is considered an error if it has a status code outside
// the 200 range.  API error responses are expected to have either no response
// body, or a JSON response body that maps to ErrorResponse.  Any other
// response body will be silently ignored.
func CheckResponse(r *http.Response) error {
	if c := r.StatusCode; 200 <= c && c <= 299 {
		return nil
	}
	errorResponse := &ErrorResponse{Response: r}
	data, err := ioutil.ReadAll(r.Body)
	if err == nil && data != nil {
		json.Unmarshal(data, errorResponse)
	}
	return errorResponse
}

// parseBoolResponse determines the boolean result from a GitHub API response.
// Several GitHub API methods return boolean responses indicated by the HTTP
// status code in the response (true indicated by a 204, false indicated by a
// 404).  This helper function will determine that result and hide the 404
// error if present.  Any other error will be returned through as-is.
func parseBoolResponse(err error) (bool, error) {
	if err == nil {
		return true, nil
	}

	if err, ok := err.(*ErrorResponse); ok && err.Response.StatusCode == http.StatusNotFound {
		// Simply false.  In this one case, we do not pass the error through.
		return false, nil
	}

	// some other real error occurred
	return false, err
}

// API response wrapper to a rate limit request.
type rateResponse struct {
	Rate *Rate `json:rate`
}

// Rate represents the rate limit for the current client.  Unauthenticated
// requests are limited to 60 per hour.  Authenticated requests are limited to
// 5,000 per hour.
type Rate struct {
	// The number of requests per hour the client is currently limited to.
	Limit int `json:limit`

	// The number of remaining requests the client can make this hour.
	Remaining int `json:remaining`
}

// RateLimit returns the rate limit for the current client.
func (c *Client) RateLimit() (*Rate, error) {
	req, err := c.NewRequest("GET", "rate_limit", nil)
	if err != nil {
		return nil, err
	}

	response := new(rateResponse)
	_, err = c.Do(req, response)
	return response.Rate, err
}

/*
UnauthenticatedRateLimitedTransport allows you to make unauthenticated calls
that need to use a higher rate limit associated with your OAuth application.

	t := &github.UnauthenticatedRateLimitedTransport{
		ClientID:     "your app's client ID",
		ClientSecret: "your app's client secret",
	}
	client := github.NewClient(t.Client())

This will append the querystring params client_id=xxx&client_secret=yyy to all
requests.

See http://developer.github.com/v3/#unauthenticated-rate-limited-requests for
more information.
*/
type UnauthenticatedRateLimitedTransport struct {
	// ClientID is the GitHub OAuth client ID of the current application, which
	// can be found by selecting its entry in the list at
	// https://github.com/settings/applications.
	ClientID string

	// ClientSecret is the GitHub OAuth client secret of the current
	// application.
	ClientSecret string

	// Transport is the underlying HTTP transport to use when making requests.
	// It will default to http.DefaultTransport if nil.
	Transport http.RoundTripper
}

func (t *UnauthenticatedRateLimitedTransport) RoundTrip(req *http.Request) (*http.Response, error) {
	if t.ClientID == "" {
		return nil, errors.New("ClientID is empty")
	}
	if t.ClientSecret == "" {
		return nil, errors.New("ClientSecret is empty")
	}

	// To set extra querystring params, we must make a copy of the Request so
	// that we don't modify the Request we were given. This is required by the
	// specification of http.RoundTripper.
	req = cloneRequest(req)
	q := req.URL.Query()
	q.Set("client_id", t.ClientID)
	q.Set("client_secret", t.ClientSecret)
	req.URL.RawQuery = q.Encode()

	// Make the HTTP request.
	return t.transport().RoundTrip(req)
}

// Client returns an *http.Client that makes requests which are subject to the
// rate limit of your OAuth application.
func (t *UnauthenticatedRateLimitedTransport) Client() *http.Client {
	return &http.Client{Transport: t}
}

func (t *UnauthenticatedRateLimitedTransport) transport() http.RoundTripper {
	if t.Transport != nil {
		return t.Transport
	}
	return http.DefaultTransport
}

// cloneRequest returns a clone of the provided *http.Request. The clone is a
// shallow copy of the struct and its Header map.
func cloneRequest(r *http.Request) *http.Request {
	// shallow copy of the struct
	r2 := new(http.Request)
	*r2 = *r
	// deep copy of the Header
	r2.Header = make(http.Header)
	for k, s := range r.Header {
		r2.Header[k] = s
	}
	return r2
}
<commit_msg>add comment for RoundTrip<commit_after>// Copyright 2013 Google. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd

/*
Package github provides a client for using the GitHub API.

Access different parts of the GitHub API using the various services on a GitHub
Client:

	client := github.NewClient(nil)

	// list all organizations for user "willnorris"
	orgs, err := client.Organizations.List("willnorris", nil)

Set optional parameters for an API method by passing an Options object.

	// list recently updated repositories for org "github"
	opt := &github.RepositoryListByOrgOptions{Sort: "updated"}
	repos, err := client.Repositories.ListByOrg("github", opt)

Make authenticated API calls by constructing a GitHub client using an OAuth
capable http.Client:

	import "code.google.com/p/goauth2/oauth"

	// simple OAuth transport if you already have an access token;
	// see goauth2 library for full usage
	t := &oauth.Transport{
		Token: &oauth.Token{AccessToken: "..."},
	}

	client := github.NewClient(t.Client())

	// list all repositories for the authenticated user
	repos, err := client.Repositories.List(nil)

Note that when using an authenticated Client, all calls made by the client will
include the specified OAuth token. Therefore, authenticated clients should
almost never be shared between different users.

The full GitHub API is documented at http://developer.github.com/v3/.
*/
package github

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
)

const (
	libraryVersion = "0.1"
	defaultBaseURL = "https://api.github.com/"
	userAgent      = "go-github/" + libraryVersion
)

// A Client manages communication with the GitHub API.
type Client struct {
	// HTTP client used to communicate with the API.
	client *http.Client

	// Base URL for API requests.  Defaults to the public GitHub API, but can be
	// set to a domain endpoint to use with GitHub Enterprise.  BaseURL should
	// always be specified with a trailing slash.
	BaseURL *url.URL

	// User agent used when communicating with the GitHub API.
	UserAgent string

	// Services used for talking to different parts of the API

	Organizations *OrganizationsService
	Repositories  *RepositoriesService
	Users         *UsersService
}

// ListOptions specifies the optional parameters to various List methods that
// support pagination.
type ListOptions struct {
	// For paginated result sets, page of results to retrieve.
	Page int
}

// NewClient returns a new GitHub API client.  If a nil httpClient is
// provided, http.DefaultClient will be used.  To use API methods which require
// authentication, provide an http.Client that will perform the authentication
// for you (such as that provided by the goauth2 library).
func NewClient(httpClient *http.Client) *Client {
	if httpClient == nil {
		httpClient = http.DefaultClient
	}
	baseURL, _ := url.Parse(defaultBaseURL)

	c := &Client{client: httpClient, BaseURL: baseURL, UserAgent: userAgent}
	c.Organizations = &OrganizationsService{client: c}
	c.Repositories = &RepositoriesService{client: c}
	c.Users = &UsersService{client: c}
	return c
}

// NewRequest creates an API request. A relative URL can be provided in urlStr,
// in which case it is resolved relative to the BaseURL of the Client.
// Relative URLs should always be specified without a preceding slash.  If
// specified, the value pointed to by body is JSON encoded and included as the
// request body.
func (c *Client) NewRequest(method, urlStr string, body interface{}) (*http.Request, error) {
	rel, err := url.Parse(urlStr)
	if err != nil {
		return nil, err
	}

	u := c.BaseURL.ResolveReference(rel)

	buf := new(bytes.Buffer)
	if body != nil {
		err := json.NewEncoder(buf).Encode(body)
		if err != nil {
			return nil, err
		}
	}

	req, err := http.NewRequest(method, u.String(), buf)
	if err != nil {
		return nil, err
	}

	req.Header.Add("User-Agent", c.UserAgent)
	return req, nil
}

// Do sends an API request and returns the API response.  The API response is
// decoded and stored in the value pointed to by v, or returned as an error if
// an API error has occurred.
func (c *Client) Do(req *http.Request, v interface{}) (*http.Response, error) {
	resp, err := c.client.Do(req)
	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()

	err = CheckResponse(resp)
	if err != nil {
		return resp, err
	}

	if v != nil {
		err = json.NewDecoder(resp.Body).Decode(v)
	}
	return resp, err
}

/*
An ErrorResponse reports one or more errors caused by an API request.

GitHub API docs: http://developer.github.com/v3/#client-errors
*/
type ErrorResponse struct {
	Response *http.Response // HTTP response that caused this error
	Message  string         `json:message` // error message
	Errors   []Error        `json:errors`  // more detail on individual errors
}

func (r *ErrorResponse) Error() string {
	return fmt.Sprintf("%v %v: %d %v",
		r.Response.Request.Method, r.Response.Request.URL,
		r.Response.StatusCode, r.Message)
}

/*
An Error reports more details on an individual error in an ErrorResponse.
These are the possible validation error codes:

    missing:
        resource does not exist
    missing_field:
        a required field on a resource has not been set
    invalid:
        the formatting of a field is invalid
    already_exists:
        another resource has the same valid as this field

GitHub API docs: http://developer.github.com/v3/#client-errors
*/
type Error struct {
	Resource string `json:resource` // resource on which the error occurred
	Field    string `json:field`    // field on which the error occurred
	Code     string `json:code`     // validation error code
}

func (e *Error) Error() string {
	return fmt.Sprintf("%v error caused by %v field on %v resource",
		e.Code, e.Field, e.Resource)
}

// CheckResponse checks the API response for errors, and returns them if
// present.  A response is considered an error if it has a status code outside
// the 200 range.  API error responses are expected to have either no response
// body, or a JSON response body that maps to ErrorResponse.  Any other
// response body will be silently ignored.
func CheckResponse(r *http.Response) error {
	if c := r.StatusCode; 200 <= c && c <= 299 {
		return nil
	}
	errorResponse := &ErrorResponse{Response: r}
	data, err := ioutil.ReadAll(r.Body)
	if err == nil && data != nil {
		json.Unmarshal(data, errorResponse)
	}
	return errorResponse
}

// parseBoolResponse determines the boolean result from a GitHub API response.
// Several GitHub API methods return boolean responses indicated by the HTTP
// status code in the response (true indicated by a 204, false indicated by a
// 404).  This helper function will determine that result and hide the 404
// error if present.  Any other error will be returned through as-is.
func parseBoolResponse(err error) (bool, error) {
	if err == nil {
		return true, nil
	}

	if err, ok := err.(*ErrorResponse); ok && err.Response.StatusCode == http.StatusNotFound {
		// Simply false.  In this one case, we do not pass the error through.
		return false, nil
	}

	// some other real error occurred
	return false, err
}

// API response wrapper to a rate limit request.
type rateResponse struct {
	Rate *Rate `json:rate`
}

// Rate represents the rate limit for the current client.  Unauthenticated
// requests are limited to 60 per hour.  Authenticated requests are limited to
// 5,000 per hour.
type Rate struct {
	// The number of requests per hour the client is currently limited to.
	Limit int `json:limit`

	// The number of remaining requests the client can make this hour.
	Remaining int `json:remaining`
}

// RateLimit returns the rate limit for the current client.
func (c *Client) RateLimit() (*Rate, error) {
	req, err := c.NewRequest("GET", "rate_limit", nil)
	if err != nil {
		return nil, err
	}

	response := new(rateResponse)
	_, err = c.Do(req, response)
	return response.Rate, err
}

/*
UnauthenticatedRateLimitedTransport allows you to make unauthenticated calls
that need to use a higher rate limit associated with your OAuth application.

	t := &github.UnauthenticatedRateLimitedTransport{
		ClientID:     "your app's client ID",
		ClientSecret: "your app's client secret",
	}
	client := github.NewClient(t.Client())

This will append the querystring params client_id=xxx&client_secret=yyy to all
requests.

See http://developer.github.com/v3/#unauthenticated-rate-limited-requests for
more information.
*/
type UnauthenticatedRateLimitedTransport struct {
	// ClientID is the GitHub OAuth client ID of the current application, which
	// can be found by selecting its entry in the list at
	// https://github.com/settings/applications.
	ClientID string

	// ClientSecret is the GitHub OAuth client secret of the current
	// application.
	ClientSecret string

	// Transport is the underlying HTTP transport to use when making requests.
	// It will default to http.DefaultTransport if nil.
	Transport http.RoundTripper
}

// RoundTrip implements the RoundTripper interface.
func (t *UnauthenticatedRateLimitedTransport) RoundTrip(req *http.Request) (*http.Response, error) {
	if t.ClientID == "" {
		return nil, errors.New("ClientID is empty")
	}
	if t.ClientSecret == "" {
		return nil, errors.New("ClientSecret is empty")
	}

	// To set extra querystring params, we must make a copy of the Request so
	// that we don't modify the Request we were given. This is required by the
	// specification of http.RoundTripper.
	req = cloneRequest(req)
	q := req.URL.Query()
	q.Set("client_id", t.ClientID)
	q.Set("client_secret", t.ClientSecret)
	req.URL.RawQuery = q.Encode()

	// Make the HTTP request.
	return t.transport().RoundTrip(req)
}

// Client returns an *http.Client that makes requests which are subject to the
// rate limit of your OAuth application.
func (t *UnauthenticatedRateLimitedTransport) Client() *http.Client {
	return &http.Client{Transport: t}
}

func (t *UnauthenticatedRateLimitedTransport) transport() http.RoundTripper {
	if t.Transport != nil {
		return t.Transport
	}
	return http.DefaultTransport
}

// cloneRequest returns a clone of the provided *http.Request. The clone is a
// shallow copy of the struct and its Header map.
func cloneRequest(r *http.Request) *http.Request {
	// shallow copy of the struct
	r2 := new(http.Request)
	*r2 = *r
	// deep copy of the Header
	r2.Header = make(http.Header)
	for k, s := range r.Header {
		r2.Header[k] = s
	}
	return r2
}
<|endoftext|>


<commit_before>package aws

import (
	"errors"
	"fmt"
	"log"
	"testing"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/iam"
	"github.com/hashicorp/go-multierror"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
	"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)

func init() {
	resource.AddTestSweepers("aws_iam_group", &resource.Sweeper{
		Name: "aws_iam_group",
		F:    testSweepIamGroups,
		Dependencies: []string{
			"aws_iam_user",
		},
	})
}

func testSweepIamGroups(region string) error {
	client, err := sharedClientForRegion(region)

	if err != nil {
		return fmt.Errorf("error getting client: %w", err)
	}

	conn := client.(*AWSClient).iamconn
	input := &iam.ListGroupsInput{}
	var sweeperErrs *multierror.Error

	err = conn.ListGroupsPages(input, func(page *iam.ListGroupsOutput, isLast bool) bool {
		if page == nil {
			return !isLast
		}

		for _, group := range page.Groups {
			input := &iam.DeleteGroupInput{
				GroupName: group.GroupName,
			}
			name := aws.StringValue(group.GroupName)

			if name == "Admin" || name == "TerraformAccTests" {
				continue
			}

			log.Printf("[INFO] Deleting IAM Group: %s", name)

			if err := deleteAwsIamGroupPolicyAttachments(conn, name); err != nil {
				sweeperErr := fmt.Errorf("error deleting IAM Group (%s) policy attachments: %w", name, err)
				log.Printf("[ERROR] %s", sweeperErr)
				sweeperErrs = multierror.Append(sweeperErrs, sweeperErr)
				continue
			}

			if err := deleteAwsIamGroupPolicies(conn, name); err != nil {
				sweeperErr := fmt.Errorf("error deleting IAM Group (%s) policies: %w", name, err)
				log.Printf("[ERROR] %s", sweeperErr)
				sweeperErrs = multierror.Append(sweeperErrs, sweeperErr)
				continue
			}

			_, err := conn.DeleteGroup(input)

			if isAWSErr(err, iam.ErrCodeNoSuchEntityException, "") {
				continue
			}

			if err != nil {
				sweeperErr := fmt.Errorf("error deleting IAM Group (%s): %w", name, err)
				log.Printf("[ERROR] %s", sweeperErr)
				sweeperErrs = multierror.Append(sweeperErrs, sweeperErr)
				continue
			}
		}

		return !isLast
	})

	if testSweepSkipSweepError(err) {
		log.Printf("[WARN] Skipping IAM Group sweep for %s: %s", region, err)
		return sweeperErrs.ErrorOrNil()
	}

	if err != nil {
		sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error retrieving IAM Groups: %w", err))
	}

	return sweeperErrs.ErrorOrNil()
}

func TestAccAWSIAMGroup_basic(t *testing.T) {
	var conf iam.GetGroupOutput
	resourceName := "aws_iam_group.test"
	resourceName2 := "aws_iam_group.test2"
	rString := acctest.RandString(8)
	groupName := fmt.Sprintf("tf-acc-group-basic-%s", rString)
	groupName2 := fmt.Sprintf("tf-acc-group-basic-2-%s", rString)

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAWSGroupDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAWSGroupConfig(groupName),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSGroupExists(resourceName, &conf),
					testAccCheckAWSGroupAttributes(&conf, groupName, "/"),
				),
			},
			{
				ResourceName:      resourceName,
				ImportState:       true,
				ImportStateVerify: true,
			},
			{
				Config: testAccAWSGroupConfig2(groupName2),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSGroupExists(resourceName2, &conf),
					testAccCheckAWSGroupAttributes(&conf, groupName2, "/funnypath/"),
				),
			},
		},
	})
}

func TestAccAWSIAMGroup_nameChange(t *testing.T) {
	var conf iam.GetGroupOutput
	resourceName := "aws_iam_group.test"
	rString := acctest.RandString(8)
	groupName := fmt.Sprintf("tf-acc-group-basic-%s", rString)
	groupName2 := fmt.Sprintf("tf-acc-group-basic-2-%s", rString)

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAWSGroupDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAWSGroupConfig(groupName),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSGroupExists(resourceName, &conf),
					testAccCheckAWSGroupAttributes(&conf, groupName, "/"),
				),
			},
			{
				Config: testAccAWSGroupConfig(groupName2),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSGroupExists(resourceName, &conf),
					testAccCheckAWSGroupAttributes(&conf, groupName2, "/"),
				),
			},
		},
	})
}

func testAccCheckAWSGroupDestroy(s *terraform.State) error {
	iamconn := testAccProvider.Meta().(*AWSClient).iamconn

	for _, rs := range s.RootModule().Resources {
		if rs.Type != "aws_iam_group" {
			continue
		}

		// Try to get group
		_, err := iamconn.GetGroup(&iam.GetGroupInput{
			GroupName: aws.String(rs.Primary.ID),
		})
		if err == nil {
			return errors.New("still exist.")
		}

		// Verify the error is what we want
		ec2err, ok := err.(awserr.Error)
		if !ok {
			return err
		}
		if ec2err.Code() != "NoSuchEntity" {
			return err
		}
	}

	return nil
}

func testAccCheckAWSGroupExists(n string, res *iam.GetGroupOutput) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[n]
		if !ok {
			return fmt.Errorf("Not found: %s", n)
		}

		if rs.Primary.ID == "" {
			return errors.New("No Group name is set")
		}

		iamconn := testAccProvider.Meta().(*AWSClient).iamconn

		resp, err := iamconn.GetGroup(&iam.GetGroupInput{
			GroupName: aws.String(rs.Primary.ID),
		})
		if err != nil {
			return err
		}

		*res = *resp

		return nil
	}
}

func testAccCheckAWSGroupAttributes(group *iam.GetGroupOutput, name string, path string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		if *group.Group.GroupName != name {
			return fmt.Errorf("Bad name: %s when %s was expected", *group.Group.GroupName, name)
		}

		if *group.Group.Path != path {
			return fmt.Errorf("Bad path: %s when %s was expected", *group.Group.Path, path)
		}

		return nil
	}
}

func testAccAWSGroupConfig(groupName string) string {
	return fmt.Sprintf(`
resource "aws_iam_group" "test" {
  name = "%s"
  path = "/"
}
`, groupName)
}

func testAccAWSGroupConfig2(groupName string) string {
	return fmt.Sprintf(`
resource "aws_iam_group" "test2" {
  name = "%s"
  path = "/funnypath/"
}
`, groupName)
}
<commit_msg>tests/resource/aws_iam_group: Prevent sweeper error with user membership in group (#15714)<commit_after>package aws

import (
	"errors"
	"fmt"
	"log"
	"testing"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/iam"
	"github.com/hashicorp/aws-sdk-go-base/tfawserr"
	"github.com/hashicorp/go-multierror"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
	"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)

func init() {
	resource.AddTestSweepers("aws_iam_group", &resource.Sweeper{
		Name: "aws_iam_group",
		F:    testSweepIamGroups,
		Dependencies: []string{
			"aws_iam_user",
		},
	})
}

func testSweepIamGroups(region string) error {
	client, err := sharedClientForRegion(region)

	if err != nil {
		return fmt.Errorf("error getting client: %w", err)
	}

	conn := client.(*AWSClient).iamconn
	input := &iam.ListGroupsInput{}
	var sweeperErrs *multierror.Error

	err = conn.ListGroupsPages(input, func(page *iam.ListGroupsOutput, isLast bool) bool {
		if page == nil {
			return !isLast
		}

		for _, group := range page.Groups {
			name := aws.StringValue(group.GroupName)

			if name == "Admin" || name == "TerraformAccTests" {
				continue
			}

			log.Printf("[INFO] Deleting IAM Group: %s", name)

			getGroupInput := &iam.GetGroupInput{
				GroupName: group.GroupName,
			}

			getGroupOutput, err := conn.GetGroup(getGroupInput)

			if tfawserr.ErrCodeEquals(err, iam.ErrCodeNoSuchEntityException) {
				continue
			}

			if err != nil {
				sweeperErr := fmt.Errorf("error reading IAM Group (%s): %w", name, err)
				log.Printf("[ERROR] %s", sweeperErr)
				sweeperErrs = multierror.Append(sweeperErrs, sweeperErr)
				continue
			}

			if getGroupOutput != nil {
				for _, user := range getGroupOutput.Users {
					username := aws.StringValue(user.UserName)

					log.Printf("[INFO] Removing IAM User (%s) from Group: %s", username, name)

					input := &iam.RemoveUserFromGroupInput{
						UserName:  user.UserName,
						GroupName: group.GroupName,
					}

					_, err := conn.RemoveUserFromGroup(input)

					if tfawserr.ErrCodeEquals(err, iam.ErrCodeNoSuchEntityException) {
						continue
					}

					if err != nil {
						sweeperErr := fmt.Errorf("error removing IAM User (%s) from IAM Group (%s): %w", username, name, err)
						log.Printf("[ERROR] %s", sweeperErr)
						sweeperErrs = multierror.Append(sweeperErrs, sweeperErr)
						continue
					}
				}
			}

			input := &iam.DeleteGroupInput{
				GroupName: group.GroupName,
			}

			if err := deleteAwsIamGroupPolicyAttachments(conn, name); err != nil {
				sweeperErr := fmt.Errorf("error deleting IAM Group (%s) policy attachments: %w", name, err)
				log.Printf("[ERROR] %s", sweeperErr)
				sweeperErrs = multierror.Append(sweeperErrs, sweeperErr)
				continue
			}

			if err := deleteAwsIamGroupPolicies(conn, name); err != nil {
				sweeperErr := fmt.Errorf("error deleting IAM Group (%s) policies: %w", name, err)
				log.Printf("[ERROR] %s", sweeperErr)
				sweeperErrs = multierror.Append(sweeperErrs, sweeperErr)
				continue
			}

			_, err = conn.DeleteGroup(input)

			if tfawserr.ErrCodeEquals(err, iam.ErrCodeNoSuchEntityException) {
				continue
			}

			if err != nil {
				sweeperErr := fmt.Errorf("error deleting IAM Group (%s): %w", name, err)
				log.Printf("[ERROR] %s", sweeperErr)
				sweeperErrs = multierror.Append(sweeperErrs, sweeperErr)
				continue
			}
		}

		return !isLast
	})

	if testSweepSkipSweepError(err) {
		log.Printf("[WARN] Skipping IAM Group sweep for %s: %s", region, err)
		return sweeperErrs.ErrorOrNil()
	}

	if err != nil {
		sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error retrieving IAM Groups: %w", err))
	}

	return sweeperErrs.ErrorOrNil()
}

func TestAccAWSIAMGroup_basic(t *testing.T) {
	var conf iam.GetGroupOutput
	resourceName := "aws_iam_group.test"
	resourceName2 := "aws_iam_group.test2"
	rString := acctest.RandString(8)
	groupName := fmt.Sprintf("tf-acc-group-basic-%s", rString)
	groupName2 := fmt.Sprintf("tf-acc-group-basic-2-%s", rString)

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAWSGroupDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAWSGroupConfig(groupName),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSGroupExists(resourceName, &conf),
					testAccCheckAWSGroupAttributes(&conf, groupName, "/"),
				),
			},
			{
				ResourceName:      resourceName,
				ImportState:       true,
				ImportStateVerify: true,
			},
			{
				Config: testAccAWSGroupConfig2(groupName2),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSGroupExists(resourceName2, &conf),
					testAccCheckAWSGroupAttributes(&conf, groupName2, "/funnypath/"),
				),
			},
		},
	})
}

func TestAccAWSIAMGroup_nameChange(t *testing.T) {
	var conf iam.GetGroupOutput
	resourceName := "aws_iam_group.test"
	rString := acctest.RandString(8)
	groupName := fmt.Sprintf("tf-acc-group-basic-%s", rString)
	groupName2 := fmt.Sprintf("tf-acc-group-basic-2-%s", rString)

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAWSGroupDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAWSGroupConfig(groupName),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSGroupExists(resourceName, &conf),
					testAccCheckAWSGroupAttributes(&conf, groupName, "/"),
				),
			},
			{
				Config: testAccAWSGroupConfig(groupName2),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSGroupExists(resourceName, &conf),
					testAccCheckAWSGroupAttributes(&conf, groupName2, "/"),
				),
			},
		},
	})
}

func testAccCheckAWSGroupDestroy(s *terraform.State) error {
	iamconn := testAccProvider.Meta().(*AWSClient).iamconn

	for _, rs := range s.RootModule().Resources {
		if rs.Type != "aws_iam_group" {
			continue
		}

		// Try to get group
		_, err := iamconn.GetGroup(&iam.GetGroupInput{
			GroupName: aws.String(rs.Primary.ID),
		})
		if err == nil {
			return errors.New("still exist.")
		}

		// Verify the error is what we want
		ec2err, ok := err.(awserr.Error)
		if !ok {
			return err
		}
		if ec2err.Code() != "NoSuchEntity" {
			return err
		}
	}

	return nil
}

func testAccCheckAWSGroupExists(n string, res *iam.GetGroupOutput) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[n]
		if !ok {
			return fmt.Errorf("Not found: %s", n)
		}

		if rs.Primary.ID == "" {
			return errors.New("No Group name is set")
		}

		iamconn := testAccProvider.Meta().(*AWSClient).iamconn

		resp, err := iamconn.GetGroup(&iam.GetGroupInput{
			GroupName: aws.String(rs.Primary.ID),
		})
		if err != nil {
			return err
		}

		*res = *resp

		return nil
	}
}

func testAccCheckAWSGroupAttributes(group *iam.GetGroupOutput, name string, path string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		if *group.Group.GroupName != name {
			return fmt.Errorf("Bad name: %s when %s was expected", *group.Group.GroupName, name)
		}

		if *group.Group.Path != path {
			return fmt.Errorf("Bad path: %s when %s was expected", *group.Group.Path, path)
		}

		return nil
	}
}

func testAccAWSGroupConfig(groupName string) string {
	return fmt.Sprintf(`
resource "aws_iam_group" "test" {
  name = "%s"
  path = "/"
}
`, groupName)
}

func testAccAWSGroupConfig2(groupName string) string {
	return fmt.Sprintf(`
resource "aws_iam_group" "test2" {
  name = "%s"
  path = "/funnypath/"
}
`, groupName)
}
<|endoftext|>


<commit_before>package itest

import (
	"testing"

	"github.com/ligato/cn-infra/core"
	"github.com/ligato/cn-infra/flavors/generic"
	"github.com/ligato/cn-infra/flavors/local"
	"github.com/ligato/cn-infra/httpmux"
	"github.com/ligato/cn-infra/httpmux/mock"
	"github.com/onsi/gomega"
)

type suiteGenericFlavor struct {
	T *testing.T
	AgentT
	Given
	When
	Then
	mock.HttpMock
}

func MockGenericFlavor(mock *mock.HttpMock) *generic.FlavorGeneric {
	return &generic.FlavorGeneric{
		HTTP: *httpmux.FromExistingServer(mock.SetHandler),
	}
}

// TC01 asserts that injection works fine and agent starts & stops
func (t *suiteGenericFlavor) TC01StartStop() {
	flavor := MockGenericFlavor(&t.HttpMock)
	t.Setup(flavor, t.T)

	gomega.Expect(t.agent).ShouldNot(gomega.BeNil(), "agent is not initialized")

	defer t.Teardown()
}

// TC03 check that status check in flavor works
func (t *suiteGenericFlavor) TC03StatusCheck() {
	flavor := &local.FlavorLocal{}
	t.Setup(flavor, t.T)

	tstPlugin := core.PluginName("tstPlugin")
	flavor.StatusCheck.Register(tstPlugin, nil)
	flavor.StatusCheck.ReportStateChange(tstPlugin, "tst", nil)

	t.HttpMock.NewRequest("GET", flavor.ServiceLabel.GetAgentPrefix()+
		"/check/status/v1/agent", nil)
	//TODO assert flavor.StatusCheck using IDX map???

	defer t.Teardown()
}
<commit_msg> ODPM-361 http response assertion for generic flavor status check TC<commit_after>package itest

import (
	"testing"

	"github.com/ligato/cn-infra/core"
	"github.com/ligato/cn-infra/flavors/generic"
	"github.com/ligato/cn-infra/flavors/local"
	"github.com/ligato/cn-infra/httpmux"
	"github.com/ligato/cn-infra/httpmux/mock"
	"github.com/onsi/gomega"
)

type suiteGenericFlavor struct {
	T *testing.T
	AgentT
	Given
	When
	Then
	mock.HttpMock
}

// MockGenericFlavor initializes generic flavor with HTTP mock
func MockGenericFlavor(mock *mock.HttpMock) *generic.FlavorGeneric {
	return &generic.FlavorGeneric{
		HTTP: *httpmux.FromExistingServer(mock.SetHandler),
	}
}

// TC01 asserts that injection works fine and agent starts & stops
func (t *suiteGenericFlavor) TC01StartStop() {
	flavor := MockGenericFlavor(&t.HttpMock)
	t.Setup(flavor, t.T)

	gomega.Expect(t.agent).ShouldNot(gomega.BeNil(), "agent is not initialized")

	defer t.Teardown()
}

// TC03 check that status check in flavor works
func (t *suiteGenericFlavor) TC03StatusCheck() {
	flavor := &local.FlavorLocal{}
	t.Setup(flavor, t.T)

	tstPlugin := core.PluginName("tstPlugin")
	flavor.StatusCheck.Register(tstPlugin, nil)
	flavor.StatusCheck.ReportStateChange(tstPlugin, "tst", nil)

	result, err := t.HttpMock.NewRequest("GET", flavor.ServiceLabel.GetAgentPrefix()+
		"/check/status/v1/agent", nil)
	gomega.Expect(err).Should(gomega.BeNil(), "logger is not initialized")
	gomega.Expect(result).ShouldNot(gomega.BeNil(), "http result is not initialized")
	gomega.Expect(result).Should(gomega.BeEquivalentTo(200))

	defer t.Teardown()
}
<|endoftext|>


<commit_before>package v2v3action_test

import (
	"errors"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gstruct"

	"code.cloudfoundry.org/cli/actor/v2action"
	. "code.cloudfoundry.org/cli/actor/v2v3action"
	"code.cloudfoundry.org/cli/actor/v2v3action/v2v3actionfakes"
	"code.cloudfoundry.org/cli/actor/v3action"
	"code.cloudfoundry.org/cli/types"
	"code.cloudfoundry.org/cli/util/manifest"
)

var _ = Describe("Manifest", func() {
	var (
		actor       *Actor
		fakeV2Actor *v2v3actionfakes.FakeV2Actor
		fakeV3Actor *v2v3actionfakes.FakeV3Actor

		appName  string
		appSpace string

		manifestApp manifest.Application
		warnings    Warnings
		executeErr  error
	)

	BeforeEach(func() {
		fakeV2Actor = new(v2v3actionfakes.FakeV2Actor)
		fakeV3Actor = new(v2v3actionfakes.FakeV3Actor)

		actor = NewActor(fakeV2Actor, fakeV3Actor)

		appName = "some-app-name"
		appSpace = "some-space-GUID"
	})

	JustBeforeEach(func() {
		manifestApp, warnings, executeErr = actor.CreateApplicationManifestByNameAndSpace(appName, appSpace)
	})

	It("calls v2Actor.CreateManifestApplication with the appName and appSpace", func() {
		Expect(fakeV2Actor.CreateApplicationManifestByNameAndSpaceCallCount()).To(Equal(1))
		appNameArg, appSpaceArg := fakeV2Actor.CreateApplicationManifestByNameAndSpaceArgsForCall(0)
		Expect(appNameArg).To(Equal(appName))
		Expect(appSpaceArg).To(Equal(appSpace))
	})

	Context("when v2Actor.CreateManifestApplication succeeds", func() {
		BeforeEach(func() {
			// This only needs to test v2 specific attributes
			v2Application := manifest.Application{
				Buildpack: types.FilteredString{IsSet: true, Value: "some-buildpack"},
			}

			fakeV2Actor.CreateApplicationManifestByNameAndSpaceReturns(v2Application, v2action.Warnings{"v2-action-warnings"}, nil)
		})

		PContext("when the cc returns an invalid semver", func() {
			BeforeEach(func() {
				fakeV3Actor.CloudControllerAPIVersionReturns("i am invalid")
			})

			It("returns a semver error", func() {
				Expect(executeErr).To(MatchError("No Major.Minor.Patch elements found"))
				Expect(warnings).To(ConsistOf("v2-action-warnings"))
			})

		})

		PContext("when the cc has a v3 buildpacks endpoint ( >= v3.25)", func() {
			BeforeEach(func() {
				fakeV3Actor.CloudControllerAPIVersionReturns("3.25.0")
			})

			It("Calls the v3actor.GetApplicationByNameAndSpace with the appName and appSpace", func() {
				Expect(fakeV3Actor.GetApplicationByNameAndSpaceCallCount()).To(Equal(1))
				appNameArg, appSpaceArg := fakeV3Actor.GetApplicationByNameAndSpaceArgsForCall(0)
				Expect(appNameArg).To(Equal(appName))
				Expect(appSpaceArg).To(Equal(appSpace))
			})

			Context("when the v3Actor.GetApplicationByNameAndSpace succeeds", func() {
				BeforeEach(func() {
					v3Application := v3action.Application{LifecycleBuildpacks: []string{"some-buildpack"}}
					fakeV3Actor.GetApplicationByNameAndSpaceReturns(v3Application, v3action.Warnings{"v3-action-warnings"}, nil)
				})

				It("should return an application with v3 specific attributes", func() {
					Expect(executeErr).ToNot(HaveOccurred())
					Expect(warnings).To(ConsistOf("v2-action-warnings", "v3-action-warnings"))
					Expect(manifestApp).To(MatchFields(IgnoreExtras, Fields{
						"Buildpack": Equal(types.FilteredString{}),
						// "Buildpacks": ConsistOf("some-buildpack"),
					}))
				})
			})

			Context("when the v3Actor.GetApplicationByNameAndSpace fails", func() {
				BeforeEach(func() {
					fakeV3Actor.GetApplicationByNameAndSpaceReturns(v3action.Application{}, v3action.Warnings{"v3-action-warnings"}, errors.New("i'm a v3 error"))
				})

				It("it raises the error", func() {
					Expect(executeErr).To(MatchError("i'm a v3 error"))
					Expect(warnings).To(ConsistOf("v2-action-warnings", "v3-action-warnings"))
				})
			})
		})

		Context("when the cc does not have a v3 buildpacks endpoint ( < v3.25)", func() {
			BeforeEach(func() {
				fakeV3Actor.CloudControllerAPIVersionReturns("3.24.0")
			})

			It("does not call the v3actor.GetApplicationByNameAndSpace", func() {
				Expect(fakeV3Actor.GetApplicationByNameAndSpaceCallCount()).To(Equal(0))
			})

			It("returns the v2 only version of a manifest application", func() {
				Expect(executeErr).ToNot(HaveOccurred())
				Expect(warnings).To(ConsistOf("v2-action-warnings"))
				Expect(manifestApp).To(MatchFields(IgnoreExtras, Fields{
					"Buildpack": Equal(types.FilteredString{IsSet: true, Value: "some-buildpack"}),
					// "Buildpacks": BeNil(),
				}))
			})
		})
	})

	Context("when v2Actor.CreateManifestApplication fails", func() {
		BeforeEach(func() {
			fakeV2Actor.CreateApplicationManifestByNameAndSpaceReturns(manifest.Application{}, v2action.Warnings{"v2-action-warnings"}, errors.New("spaghetti"))
		})

		It("returns warnings and the error", func() {
			Expect(executeErr).To(MatchError(errors.New("spaghetti")))
			Expect(warnings).To(ConsistOf("v2-action-warnings"))
		})
	})
})
<commit_msg>Revert "pend multiple buildpacks manifest tests"<commit_after>package v2v3action_test

import (
	"errors"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gstruct"

	"code.cloudfoundry.org/cli/actor/v2action"
	. "code.cloudfoundry.org/cli/actor/v2v3action"
	"code.cloudfoundry.org/cli/actor/v2v3action/v2v3actionfakes"
	"code.cloudfoundry.org/cli/actor/v3action"
	"code.cloudfoundry.org/cli/types"
	"code.cloudfoundry.org/cli/util/manifest"
)

var _ = Describe("Manifest", func() {
	var (
		actor       *Actor
		fakeV2Actor *v2v3actionfakes.FakeV2Actor
		fakeV3Actor *v2v3actionfakes.FakeV3Actor

		appName  string
		appSpace string

		manifestApp manifest.Application
		warnings    Warnings
		executeErr  error
	)

	BeforeEach(func() {
		fakeV2Actor = new(v2v3actionfakes.FakeV2Actor)
		fakeV3Actor = new(v2v3actionfakes.FakeV3Actor)

		actor = NewActor(fakeV2Actor, fakeV3Actor)

		appName = "some-app-name"
		appSpace = "some-space-GUID"
	})

	JustBeforeEach(func() {
		manifestApp, warnings, executeErr = actor.CreateApplicationManifestByNameAndSpace(appName, appSpace)
	})

	It("calls v2Actor.CreateManifestApplication with the appName and appSpace", func() {
		Expect(fakeV2Actor.CreateApplicationManifestByNameAndSpaceCallCount()).To(Equal(1))
		appNameArg, appSpaceArg := fakeV2Actor.CreateApplicationManifestByNameAndSpaceArgsForCall(0)
		Expect(appNameArg).To(Equal(appName))
		Expect(appSpaceArg).To(Equal(appSpace))
	})

	Context("when v2Actor.CreateManifestApplication succeeds", func() {
		BeforeEach(func() {
			// This only needs to test v2 specific attributes
			v2Application := manifest.Application{
				Buildpack: types.FilteredString{IsSet: true, Value: "some-buildpack"},
			}

			fakeV2Actor.CreateApplicationManifestByNameAndSpaceReturns(v2Application, v2action.Warnings{"v2-action-warnings"}, nil)
		})

		Context("when the cc returns an invalid semver", func() {
			BeforeEach(func() {
				fakeV3Actor.CloudControllerAPIVersionReturns("i am invalid")
			})

			It("returns a semver error", func() {
				Expect(executeErr).To(MatchError("No Major.Minor.Patch elements found"))
				Expect(warnings).To(ConsistOf("v2-action-warnings"))
			})

		})

		Context("when the cc has a v3 buildpacks endpoint ( >= v3.25)", func() {
			BeforeEach(func() {
				fakeV3Actor.CloudControllerAPIVersionReturns("3.25.0")
			})

			It("Calls the v3actor.GetApplicationByNameAndSpace with the appName and appSpace", func() {
				Expect(fakeV3Actor.GetApplicationByNameAndSpaceCallCount()).To(Equal(1))
				appNameArg, appSpaceArg := fakeV3Actor.GetApplicationByNameAndSpaceArgsForCall(0)
				Expect(appNameArg).To(Equal(appName))
				Expect(appSpaceArg).To(Equal(appSpace))
			})

			Context("when the v3Actor.GetApplicationByNameAndSpace succeeds", func() {
				BeforeEach(func() {
					v3Application := v3action.Application{LifecycleBuildpacks: []string{"some-buildpack"}}
					fakeV3Actor.GetApplicationByNameAndSpaceReturns(v3Application, v3action.Warnings{"v3-action-warnings"}, nil)
				})

				It("should return an application with v3 specific attributes", func() {
					Expect(executeErr).ToNot(HaveOccurred())
					Expect(warnings).To(ConsistOf("v2-action-warnings", "v3-action-warnings"))
					Expect(manifestApp).To(MatchFields(IgnoreExtras, Fields{
						"Buildpack": Equal(types.FilteredString{}),
						// "Buildpacks": ConsistOf("some-buildpack"),
					}))
				})
			})

			Context("when the v3Actor.GetApplicationByNameAndSpace fails", func() {
				BeforeEach(func() {
					fakeV3Actor.GetApplicationByNameAndSpaceReturns(v3action.Application{}, v3action.Warnings{"v3-action-warnings"}, errors.New("i'm a v3 error"))
				})

				It("it raises the error", func() {
					Expect(executeErr).To(MatchError("i'm a v3 error"))
					Expect(warnings).To(ConsistOf("v2-action-warnings", "v3-action-warnings"))
				})
			})
		})

		Context("when the cc does not have a v3 buildpacks endpoint ( < v3.25)", func() {
			BeforeEach(func() {
				fakeV3Actor.CloudControllerAPIVersionReturns("3.24.0")
			})

			It("does not call the v3actor.GetApplicationByNameAndSpace", func() {
				Expect(fakeV3Actor.GetApplicationByNameAndSpaceCallCount()).To(Equal(0))
			})

			It("returns the v2 only version of a manifest application", func() {
				Expect(executeErr).ToNot(HaveOccurred())
				Expect(warnings).To(ConsistOf("v2-action-warnings"))
				Expect(manifestApp).To(MatchFields(IgnoreExtras, Fields{
					"Buildpack": Equal(types.FilteredString{IsSet: true, Value: "some-buildpack"}),
					// "Buildpacks": BeNil(),
				}))
			})
		})
	})

	Context("when v2Actor.CreateManifestApplication fails", func() {
		BeforeEach(func() {
			fakeV2Actor.CreateApplicationManifestByNameAndSpaceReturns(manifest.Application{}, v2action.Warnings{"v2-action-warnings"}, errors.New("spaghetti"))
		})

		It("returns warnings and the error", func() {
			Expect(executeErr).To(MatchError(errors.New("spaghetti")))
			Expect(warnings).To(ConsistOf("v2-action-warnings"))
		})
	})
})
<|endoftext|>


<commit_before>package extra

import (
	"regexp"
	"strings"
	"unicode"

	"github.com/belak/go-seabird"
	"github.com/belak/nut"
	"github.com/go-irc/irc"
)

func init() {
	seabird.RegisterPlugin("karma", newKarmaPlugin)
}

type karmaPlugin struct {
	db *nut.DB
}

// KarmaTarget represents an item with a karma count
type KarmaTarget struct {
	Name  string
	Score int
}

var regex = regexp.MustCompile(`([\w]{2,}|".+?")(\+\++|--+)(?:\s|$)`)

func newKarmaPlugin(b *seabird.Bot, m *seabird.BasicMux, cm *seabird.CommandMux, db *nut.DB) error {
	p := &karmaPlugin{db: db}

	err := p.db.EnsureBucket("karma")
	if err != nil {
		return err
	}

	cm.Event("karma", p.karmaCallback, &seabird.HelpInfo{
		Usage:       "<nick>",
		Description: "Displays karma for given user",
	})

	/*
		cm.Event("topkarma", p.topKarmaCallback, &seabird.HelpInfo{
			Description: "Reports the user with the most karma",
		})

		cm.Event("bottomkarma", p.bottomKarmaCallback, &seabird.HelpInfo{
			Description: "Reports the user with the least karma",
		})
	*/

	m.Event("PRIVMSG", p.callback)

	return nil
}

func (p *karmaPlugin) cleanedName(name string) string {
	return strings.TrimFunc(strings.ToLower(name), unicode.IsSpace)
}

// GetKarmaFor returns the karma for the given name.
func (p *karmaPlugin) GetKarmaFor(name string) int {
	out := &KarmaTarget{Name: p.cleanedName(name)}

	_ = p.db.View(func(tx *nut.Tx) error {
		bucket := tx.Bucket("karma")
		return bucket.Get(out.Name, out)
	})

	return out.Score
}

// UpdateKarma will update the karma for a given name and return the new karma value.
func (p *karmaPlugin) UpdateKarma(name string, diff int) int {
	out := &KarmaTarget{Name: p.cleanedName(name)}

	_ = p.db.Update(func(tx *nut.Tx) error {
		bucket := tx.Bucket("karma")
		bucket.Get(out.Name, out)
		out.Score += diff
		return bucket.Put(out.Name, out)
	})

	return out.Score
}

func (p *karmaPlugin) karmaCallback(b *seabird.Bot, m *irc.Message) {
	term := strings.TrimSpace(m.Trailing())

	// If we don't provide a term, search for the current nick
	if term == "" {
		term = m.Prefix.Name
	}

	b.MentionReply(m, "%s's karma is %d", term, p.GetKarmaFor(term))
}

/*
func (p *karmaPlugin) karmaCheck(b *seabird.Bot, m *irc.Message, msg string, sort string) {
	res := &KarmaTarget{}
	p.db.Order("score " + sort).First(res)
	b.MentionReply(m, "%s has the %s karma with %d", res.Name, msg, res.Score)
}
func (p *karmaPlugin) topKarmaCallback(b *seabird.Bot, m *irc.Message) {
	p.karmaCheck(b, m, "top", "DESC")
}

func (p *karmaPlugin) bottomKarmaCallback(b *seabird.Bot, m *irc.Message) {
	p.karmaCheck(b, m, "bottom", "ASC")
}
*/

func (p *karmaPlugin) callback(b *seabird.Bot, m *irc.Message) {
	if len(m.Params) < 2 || !m.FromChannel() {
		return
	}

	var buzzkillTriggered bool

	matches := regex.FindAllStringSubmatch(m.Trailing(), -1)
	if len(matches) > 0 {
		for _, v := range matches {
			// If it starts with a ", we know it also ends with a quote so we
			// can chop them off.
			if strings.HasPrefix(v[1], "\"") {
				v[1] = v[1][1 : len(v[1])-1]
			}

			diff := len(v[2]) - 1
			name := strings.ToLower(v[1])

			if diff > 5 {
				buzzkillTriggered = true
				diff = 5
			}

			// If it's negative, or positive and someone is trying to change
			// their own karma we need to reverse the sign.
			if v[2][0] == '-' || name == m.Prefix.Name {
				diff *= -1
			}

			b.Reply(m, "%s's karma is now %d", v[1], p.UpdateKarma(name, diff))
		}
	}

	if buzzkillTriggered {
		b.Reply(m, "Buzzkill Mode (tm) enforced a maximum karma change of 5")
	}
}
<commit_msg>Batch karma changes when possible<commit_after>package extra

import (
	"regexp"
	"strings"
	"unicode"

	"github.com/belak/go-seabird"
	"github.com/belak/nut"
	"github.com/go-irc/irc"
)

func init() {
	seabird.RegisterPlugin("karma", newKarmaPlugin)
}

type karmaPlugin struct {
	db *nut.DB
}

// KarmaTarget represents an item with a karma count
type KarmaTarget struct {
	Name  string
	Score int
}

var regex = regexp.MustCompile(`([\w]{2,}|".+?")(\+\++|--+)(?:\s|$)`)

func newKarmaPlugin(b *seabird.Bot, m *seabird.BasicMux, cm *seabird.CommandMux, db *nut.DB) error {
	p := &karmaPlugin{db: db}

	err := p.db.EnsureBucket("karma")
	if err != nil {
		return err
	}

	cm.Event("karma", p.karmaCallback, &seabird.HelpInfo{
		Usage:       "<nick>",
		Description: "Displays karma for given user",
	})

	/*
		cm.Event("topkarma", p.topKarmaCallback, &seabird.HelpInfo{
			Description: "Reports the user with the most karma",
		})

		cm.Event("bottomkarma", p.bottomKarmaCallback, &seabird.HelpInfo{
			Description: "Reports the user with the least karma",
		})
	*/

	m.Event("PRIVMSG", p.callback)

	return nil
}

func (p *karmaPlugin) cleanedName(name string) string {
	return strings.TrimFunc(strings.ToLower(name), unicode.IsSpace)
}

// GetKarmaFor returns the karma for the given name.
func (p *karmaPlugin) GetKarmaFor(name string) int {
	out := &KarmaTarget{Name: p.cleanedName(name)}

	_ = p.db.View(func(tx *nut.Tx) error {
		bucket := tx.Bucket("karma")
		return bucket.Get(out.Name, out)
	})

	return out.Score
}

// UpdateKarma will update the karma for a given name and return the new karma value.
func (p *karmaPlugin) UpdateKarma(name string, diff int) int {
	out := &KarmaTarget{Name: p.cleanedName(name)}

	_ = p.db.Update(func(tx *nut.Tx) error {
		bucket := tx.Bucket("karma")
		bucket.Get(out.Name, out)
		out.Score += diff
		return bucket.Put(out.Name, out)
	})

	return out.Score
}

func (p *karmaPlugin) karmaCallback(b *seabird.Bot, m *irc.Message) {
	term := strings.TrimSpace(m.Trailing())

	// If we don't provide a term, search for the current nick
	if term == "" {
		term = m.Prefix.Name
	}

	b.MentionReply(m, "%s's karma is %d", term, p.GetKarmaFor(term))
}

/*
func (p *karmaPlugin) karmaCheck(b *seabird.Bot, m *irc.Message, msg string, sort string) {
	res := &KarmaTarget{}
	p.db.Order("score " + sort).First(res)
	b.MentionReply(m, "%s has the %s karma with %d", res.Name, msg, res.Score)
}
func (p *karmaPlugin) topKarmaCallback(b *seabird.Bot, m *irc.Message) {
	p.karmaCheck(b, m, "top", "DESC")
}

func (p *karmaPlugin) bottomKarmaCallback(b *seabird.Bot, m *irc.Message) {
	p.karmaCheck(b, m, "bottom", "ASC")
}
*/

func (p *karmaPlugin) callback(b *seabird.Bot, m *irc.Message) {
	if len(m.Params) < 2 || !m.FromChannel() {
		return
	}

	var buzzkillTriggered bool
	var changes = make(map[string]int)

	matches := regex.FindAllStringSubmatch(m.Trailing(), -1)
	if len(matches) > 0 {
		for _, v := range matches {
			// If it starts with a ", we know it also ends with a quote so we
			// can chop them off.
			if strings.HasPrefix(v[1], "\"") {
				v[1] = v[1][1 : len(v[1])-1]
			}

			diff := len(v[2]) - 1
			cleanedName := p.cleanedName(v[1])
			cleanedNick := p.cleanedName(m.Prefix.Name)

			if diff > 5 {
				buzzkillTriggered = true
				diff = 5
			}

			// If it's negative, or positive and someone is trying to change
			// their own karma we need to reverse the sign.
			if v[2][0] == '-' || cleanedName == cleanedNick {
				diff *= -1
			}

			changes[v[1]] = changes[v[1]] + diff
		}
	}

	for name, diff := range changes {
		b.Reply(m, "%s's karma is now %d", name, p.UpdateKarma(name, diff))
	}

	if buzzkillTriggered {
		b.Reply(m, "Buzzkill Mode (tm) enforced a maximum karma change of 5")
	}
}
<|endoftext|>


<commit_before>package ds

import (
	"context"
	"math/rand"
	"sort"
	"testing"
	"time"

	"cloud.google.com/go/datastore"
	assert "github.com/stretchr/testify/require"
	"go.skia.org/infra/go/testutils"
)

const TEST_KIND = Kind("DS_TEST_KIND")

type testEntity struct {
	Key      *datastore.Key `datastore:"__key__"`
	Random   int64
	Sortable int64
}

func TestDeleteAll(t *testing.T) {
	testutils.LargeTest(t)

	assert.NoError(t, InitForTesting("test-project", "test-namespace"))
	client := DS

	nEntries := 1200
	maxID := int64(nEntries * 10)

	// Ignore the cleanup-call returned by addRandEntities since we are
	// calling DeleteAll in this function anyway.
	_, _ = addRandEntities(t, client, nEntries, maxID)
	_, err := DeleteAll(client, TEST_KIND, true)
	assert.NoError(t, err)

	count, err := client.Count(context.TODO(), NewQuery(TEST_KIND))
	assert.NoError(t, err)
	assert.Equal(t, 0, count)
}

func TestMigrateData(t *testing.T) {
	testutils.LargeTest(t)
	ctx := context.TODO()

	// Create the source project.
	assert.NoError(t, InitForTesting("src-project", "test-namespace"))
	srcClient := DS

	// Populate the source.
	nEntries := 1200
	maxID := int64(nEntries * 10)
	entitiesSrc, cleanupSrc := addRandEntities(t, srcClient, nEntries, maxID)
	defer cleanupSrc()
	srcCount, err := srcClient.Count(ctx, NewQuery(TEST_KIND))
	assert.NoError(t, err)
	assert.Equal(t, nEntries, srcCount)

	// Create the destination project.
	assert.NoError(t, InitForTesting("dest-project", "test-namespace"))
	destClient := DS
	defer func() {
		_, err := DeleteAll(destClient, TEST_KIND, true)
		assert.NoError(t, err)
	}()
	destCountEmpty, err := destClient.Count(ctx, NewQuery(TEST_KIND))
	assert.NoError(t, err)
	assert.Equal(t, 0, destCountEmpty)

	// Migrate from source to destination reusing the old keys.
	assert.NoError(t, MigrateData(ctx, srcClient, destClient, TEST_KIND, false /* createNewKey */))
	wait(t, destClient, TEST_KIND, nEntries)
	destCountPopulated, err := destClient.Count(ctx, NewQuery(TEST_KIND))
	assert.NoError(t, err)
	assert.Equal(t, nEntries, destCountPopulated)
	// Spot check to make sure source and destination data match.
	for _, entitySrc := range []*testEntity{entitiesSrc[0], entitiesSrc[10], entitiesSrc[nEntries-1]} {
		entityDest := &testEntity{}
		assert.NoError(t, destClient.Get(ctx, entitySrc.Key, entityDest))
		assert.Equal(t, entitySrc.Key, entityDest.Key)
		assert.Equal(t, entitySrc.Random, entityDest.Random)
		assert.Equal(t, entitySrc.Sortable, entityDest.Sortable)
	}
	// Cleanup.
	_, err = DeleteAll(destClient, TEST_KIND, true)
	assert.NoError(t, err)

	// Migrate from source to destination by creating new keys.
	assert.NoError(t, MigrateData(ctx, srcClient, destClient, TEST_KIND, true /* createNewKey */))
	wait(t, destClient, TEST_KIND, nEntries)
	destCountPopulated, err = destClient.Count(ctx, NewQuery(TEST_KIND))
	assert.NoError(t, err)
	assert.Equal(t, nEntries, destCountPopulated)
}

func TestIterKeys(t *testing.T) {
	testutils.LargeTest(t)

	nEntries := 1200
	maxID := int64(nEntries / 2)
	assert.NoError(t, InitForTesting("test-project", "test-namespace"))
	client := DS
	exp, cleanup := addRandEntities(t, client, nEntries, maxID)
	defer cleanup()

	// Iterate over the type and collect the instances
	iterCh, err := IterKeys(client, TEST_KIND, 10)
	assert.NoError(t, err)
	ctx := context.TODO()
	var found []*testEntity

	for item := range iterCh {
		assert.NoError(t, item.Err)
		keySlice := item.Keys
		target := make([]*testEntity, len(keySlice))
		assert.NoError(t, client.GetMulti(ctx, keySlice, target))
		found = append(found, target...)
	}
	assert.Equal(t, exp, found)
}

func addRandEntities(t *testing.T, client *datastore.Client, nEntries int, maxID int64) ([]*testEntity, func()) {
	_, err := DeleteAll(client, TEST_KIND, true)
	assert.NoError(t, err)

	cleanup := func() {
		_, err := DeleteAll(client, TEST_KIND, true)
		assert.NoError(t, err)
	}

	// Create a test type and fill it with random values
	exp := make([]*testEntity, 0, nEntries)
	ctx := context.TODO()
	for i := 0; i < nEntries; i++ {
		newEntry := &testEntity{
			Random:   rand.Int63(),
			Sortable: (rand.Int63() % maxID) + 1,
		}
		newEntry.Key, err = client.Put(ctx, NewKey(TEST_KIND), newEntry)
		assert.NoError(t, err)
		exp = append(exp, newEntry)
	}

	sort.Slice(exp, func(i, j int) bool { return exp[i].Key.ID < exp[j].Key.ID })
	wait(t, client, TEST_KIND, nEntries)
	assert.Equal(t, nEntries, len(exp))
	return exp, cleanup
}

func wait(t *testing.T, client *datastore.Client, kind Kind, expectedCount int) {
	for {
		count, err := client.Count(context.TODO(), NewQuery(kind))
		assert.NoError(t, err)
		if count == expectedCount {
			return
		}
		time.Sleep(500 * time.Millisecond)
	}
}
<commit_msg>Disable Flaky Test TestMigrateData<commit_after>package ds

import (
	"context"
	"math/rand"
	"sort"
	"testing"
	"time"

	"cloud.google.com/go/datastore"
	assert "github.com/stretchr/testify/require"
	"go.skia.org/infra/go/testutils"
)

const TEST_KIND = Kind("DS_TEST_KIND")

type testEntity struct {
	Key      *datastore.Key `datastore:"__key__"`
	Random   int64
	Sortable int64
}

func TestDeleteAll(t *testing.T) {
	testutils.LargeTest(t)

	assert.NoError(t, InitForTesting("test-project", "test-namespace"))
	client := DS

	nEntries := 1200
	maxID := int64(nEntries * 10)

	// Ignore the cleanup-call returned by addRandEntities since we are
	// calling DeleteAll in this function anyway.
	_, _ = addRandEntities(t, client, nEntries, maxID)
	_, err := DeleteAll(client, TEST_KIND, true)
	assert.NoError(t, err)

	count, err := client.Count(context.TODO(), NewQuery(TEST_KIND))
	assert.NoError(t, err)
	assert.Equal(t, 0, count)
}

func TestMigrateData(t *testing.T) {
	// disabled: https://bugs.chromium.org/p/skia/issues/detail?id=9061
	testutils.ManualTest(t)
	ctx := context.TODO()

	// Create the source project.
	assert.NoError(t, InitForTesting("src-project", "test-namespace"))
	srcClient := DS

	// Populate the source.
	nEntries := 1200
	maxID := int64(nEntries * 10)
	entitiesSrc, cleanupSrc := addRandEntities(t, srcClient, nEntries, maxID)
	defer cleanupSrc()
	srcCount, err := srcClient.Count(ctx, NewQuery(TEST_KIND))
	assert.NoError(t, err)
	assert.Equal(t, nEntries, srcCount)

	// Create the destination project.
	assert.NoError(t, InitForTesting("dest-project", "test-namespace"))
	destClient := DS
	defer func() {
		_, err := DeleteAll(destClient, TEST_KIND, true)
		assert.NoError(t, err)
	}()
	destCountEmpty, err := destClient.Count(ctx, NewQuery(TEST_KIND))
	assert.NoError(t, err)
	assert.Equal(t, 0, destCountEmpty)

	// Migrate from source to destination reusing the old keys.
	assert.NoError(t, MigrateData(ctx, srcClient, destClient, TEST_KIND, false /* createNewKey */))
	wait(t, destClient, TEST_KIND, nEntries)
	destCountPopulated, err := destClient.Count(ctx, NewQuery(TEST_KIND))
	assert.NoError(t, err)
	assert.Equal(t, nEntries, destCountPopulated)
	// Spot check to make sure source and destination data match.
	for _, entitySrc := range []*testEntity{entitiesSrc[0], entitiesSrc[10], entitiesSrc[nEntries-1]} {
		entityDest := &testEntity{}
		assert.NoError(t, destClient.Get(ctx, entitySrc.Key, entityDest))
		assert.Equal(t, entitySrc.Key, entityDest.Key)
		assert.Equal(t, entitySrc.Random, entityDest.Random)
		assert.Equal(t, entitySrc.Sortable, entityDest.Sortable)
	}
	// Cleanup.
	_, err = DeleteAll(destClient, TEST_KIND, true)
	assert.NoError(t, err)

	// Migrate from source to destination by creating new keys.
	assert.NoError(t, MigrateData(ctx, srcClient, destClient, TEST_KIND, true /* createNewKey */))
	wait(t, destClient, TEST_KIND, nEntries)
	destCountPopulated, err = destClient.Count(ctx, NewQuery(TEST_KIND))
	assert.NoError(t, err)
	assert.Equal(t, nEntries, destCountPopulated)
}

func TestIterKeys(t *testing.T) {
	testutils.LargeTest(t)

	nEntries := 1200
	maxID := int64(nEntries / 2)
	assert.NoError(t, InitForTesting("test-project", "test-namespace"))
	client := DS
	exp, cleanup := addRandEntities(t, client, nEntries, maxID)
	defer cleanup()

	// Iterate over the type and collect the instances
	iterCh, err := IterKeys(client, TEST_KIND, 10)
	assert.NoError(t, err)
	ctx := context.TODO()
	var found []*testEntity

	for item := range iterCh {
		assert.NoError(t, item.Err)
		keySlice := item.Keys
		target := make([]*testEntity, len(keySlice))
		assert.NoError(t, client.GetMulti(ctx, keySlice, target))
		found = append(found, target...)
	}
	assert.Equal(t, exp, found)
}

func addRandEntities(t *testing.T, client *datastore.Client, nEntries int, maxID int64) ([]*testEntity, func()) {
	_, err := DeleteAll(client, TEST_KIND, true)
	assert.NoError(t, err)

	cleanup := func() {
		_, err := DeleteAll(client, TEST_KIND, true)
		assert.NoError(t, err)
	}

	// Create a test type and fill it with random values
	exp := make([]*testEntity, 0, nEntries)
	ctx := context.TODO()
	for i := 0; i < nEntries; i++ {
		newEntry := &testEntity{
			Random:   rand.Int63(),
			Sortable: (rand.Int63() % maxID) + 1,
		}
		newEntry.Key, err = client.Put(ctx, NewKey(TEST_KIND), newEntry)
		assert.NoError(t, err)
		exp = append(exp, newEntry)
	}

	sort.Slice(exp, func(i, j int) bool { return exp[i].Key.ID < exp[j].Key.ID })
	wait(t, client, TEST_KIND, nEntries)
	assert.Equal(t, nEntries, len(exp))
	return exp, cleanup
}

func wait(t *testing.T, client *datastore.Client, kind Kind, expectedCount int) {
	for {
		count, err := client.Count(context.TODO(), NewQuery(kind))
		assert.NoError(t, err)
		if count == expectedCount {
			return
		}
		time.Sleep(500 * time.Millisecond)
	}
}
<|endoftext|>


<commit_before>// Copyright 2016-2017 Authors of Cilium
//
// 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 client

import (
	"bytes"
	"fmt"
	"io"
	"net"
	"net/http"
	"net/url"
	"os"
	"strings"

	clientapi "github.com/cilium/cilium/api/v1/client"
	"github.com/cilium/cilium/api/v1/models"
	"github.com/cilium/cilium/daemon/defaults"

	runtime_client "github.com/go-openapi/runtime/client"
	"github.com/go-openapi/strfmt"
)

type Client struct {
	clientapi.Cilium
}

func configureTransport(tr *http.Transport, proto, addr string) *http.Transport {
	if tr == nil {
		tr = &http.Transport{}
	}

	if proto == "unix" {
		// No need for compression in local communications.
		tr.DisableCompression = true
		tr.Dial = func(_, _ string) (net.Conn, error) {
			return net.Dial(proto, addr)
		}
	} else {
		tr.Proxy = http.ProxyFromEnvironment
		tr.Dial = (&net.Dialer{}).Dial
	}

	return tr
}

// NewDefaultClient creates a client with default parameters connecting to UNIX domain socket.
func NewDefaultClient() (*Client, error) {
	return NewClient("")
}

// NewClient creates a client for the given `host`.
func NewClient(host string) (*Client, error) {
	if host == "" {
		// Check if environment variable points to socket
		e := os.Getenv(defaults.SockPathEnv)
		if e == "" {
			// If unset, fall back to default value
			e = defaults.SockPath
		}
		host = "unix://" + e
	}
	tmp := strings.SplitN(host, "://", 2)
	if len(tmp) != 2 {
		return nil, fmt.Errorf("invalid host format '%s'", host)
	}

	switch tmp[0] {
	case "tcp":
		if _, err := url.Parse("tcp://" + tmp[1]); err != nil {
			return nil, err
		}
		host = "http://" + tmp[1]
	case "unix":
		host = tmp[1]
	}

	transport := configureTransport(nil, tmp[0], host)
	httpClient := &http.Client{Transport: transport}
	clientTrans := runtime_client.NewWithClient(host, clientapi.DefaultBasePath,
		clientapi.DefaultSchemes, httpClient)
	return &Client{*clientapi.New(clientTrans, strfmt.Default)}, nil
}

// Hint tries to improve the error message displayed to the user.
func Hint(err error) error {
	if err == nil {
		return err
	}
	e, _ := url.PathUnescape(err.Error())
	if strings.Contains(err.Error(), defaults.SockPath) {
		return fmt.Errorf("%s\nIs the agent running?", e)
	}
	return fmt.Errorf("%s", e)
}

func formatNodeAddress(w io.Writer, elem *models.NodeAddressingElement, primary bool, prefix string) bool {
	if elem.Enabled || !primary {
		if primary {
			fmt.Fprintf(w, "%sPrimary Address:\t%s\n", prefix, elem.IP)
		} else {
			fmt.Fprintf(w, "%s%s:\n", prefix, elem.IP)
		}
		fmt.Fprintf(w, "%s Type:\t%s\n", prefix, elem.AddressType)
		if elem.AllocRange != "" {
			fmt.Fprintf(w, "%sAllocRange:\t%s\n", prefix, elem.AllocRange)
		}

		return true
	}

	return false
}

// FormatStatusResponse writes a StatusResponse as a string to the writer
func FormatStatusResponse(w io.Writer, sr *models.StatusResponse) {
	if sr.Kvstore != nil {
		fmt.Fprintf(w, "KVStore:\t%s\t%s\n", sr.Kvstore.State, sr.Kvstore.Msg)
	}
	if sr.ContainerRuntime != nil {
		fmt.Fprintf(w, "ContainerRuntime:\t%s\t%s\n",
			sr.ContainerRuntime.State, sr.ContainerRuntime.Msg)
	}
	if sr.Kubernetes != nil {
		fmt.Fprintf(w, "Kubernetes:\t%s\t%s\n", sr.Kubernetes.State, sr.Kubernetes.Msg)
		fmt.Fprintf(w, "Kubernetes APIs:\t[\"%s\"]\n", strings.Join(sr.Kubernetes.K8sAPIVersions, "\", \""))
	}
	if sr.Cilium != nil {
		fmt.Fprintf(w, "Cilium:\t%s\t%s\n", sr.Cilium.State, sr.Cilium.Msg)
	}

	if nm := sr.NodeMonitor; nm != nil {
		fmt.Fprintf(w, "NodeMonitor:\tListening for events on %d CPUs with %dx%d of shared memory\n",
			nm.Cpus, nm.Npages, nm.Pagesize)
		if nm.Lost != 0 || nm.Unknown != 0 {
			fmt.Fprintf(w, "\t%d events lost, %d unknown notifications\n", nm.Lost, nm.Unknown)
		}
	} else {
		fmt.Fprintf(w, "NodeMonitor:\tDisabled\n")
	}

	if sr.IPAM != nil {
		fmt.Fprintf(w, "Allocated IPv4 addresses:\n")
		for _, ipv4 := range sr.IPAM.IPV4 {
			fmt.Fprintf(w, " %s\n", ipv4)

		}
		fmt.Fprintf(w, "Allocated IPv6 addresses:\n")
		for _, ipv6 := range sr.IPAM.IPV6 {
			fmt.Fprintf(w, " %s\n", ipv6)
		}
	}

	if sr.Cluster != nil {
		fmt.Fprintf(w, "Known cluster nodes:\n")
		for _, node := range sr.Cluster.Nodes {
			localStr := ""
			if node.Name == sr.Cluster.Self {
				localStr = " (localhost)"
			}
			fmt.Fprintf(w, " %s%s:\n", node.Name, localStr)
			formatNodeAddress(w, node.PrimaryAddress.IPV4, true, "  ")
			formatNodeAddress(w, node.PrimaryAddress.IPV6, true, "  ")

			buf := new(bytes.Buffer)
			secondary := false
			fmt.Fprintf(buf, "  Secondary Addresses:\n")
			for _, elem := range node.SecondaryAddresses {
				if formatNodeAddress(buf, elem, false, "   ") {
					secondary = true
				}
			}
			if secondary {
				fmt.Fprintf(w, "%s", buf.String())
			}
		}
	}
}
<commit_msg>client: Fix connecting to TCP servers<commit_after>// Copyright 2016-2017 Authors of Cilium
//
// 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 client

import (
	"bytes"
	"fmt"
	"io"
	"net"
	"net/http"
	"net/url"
	"os"
	"strings"

	clientapi "github.com/cilium/cilium/api/v1/client"
	"github.com/cilium/cilium/api/v1/models"
	"github.com/cilium/cilium/daemon/defaults"

	runtime_client "github.com/go-openapi/runtime/client"
	"github.com/go-openapi/strfmt"
)

type Client struct {
	clientapi.Cilium
}

func configureTransport(tr *http.Transport, proto, addr string) *http.Transport {
	if tr == nil {
		tr = &http.Transport{}
	}

	if proto == "unix" {
		// No need for compression in local communications.
		tr.DisableCompression = true
		tr.Dial = func(_, _ string) (net.Conn, error) {
			return net.Dial(proto, addr)
		}
	} else {
		tr.Proxy = http.ProxyFromEnvironment
		tr.Dial = (&net.Dialer{}).Dial
	}

	return tr
}

// NewDefaultClient creates a client with default parameters connecting to UNIX domain socket.
func NewDefaultClient() (*Client, error) {
	return NewClient("")
}

// NewClient creates a client for the given `host`.
func NewClient(host string) (*Client, error) {
	if host == "" {
		// Check if environment variable points to socket
		e := os.Getenv(defaults.SockPathEnv)
		if e == "" {
			// If unset, fall back to default value
			e = defaults.SockPath
		}
		host = "unix://" + e
	}
	tmp := strings.SplitN(host, "://", 2)
	if len(tmp) != 2 {
		return nil, fmt.Errorf("invalid host format '%s'", host)
	}

	switch tmp[0] {
	case "tcp":
		if _, err := url.Parse("tcp://" + tmp[1]); err != nil {
			return nil, err
		}
		host = "http://" + tmp[1]
	case "unix":
		host = tmp[1]
	}

	transport := configureTransport(nil, tmp[0], host)
	httpClient := &http.Client{Transport: transport}
	clientTrans := runtime_client.NewWithClient(tmp[1], clientapi.DefaultBasePath,
		clientapi.DefaultSchemes, httpClient)
	return &Client{*clientapi.New(clientTrans, strfmt.Default)}, nil
}

// Hint tries to improve the error message displayed to the user.
func Hint(err error) error {
	if err == nil {
		return err
	}
	e, _ := url.PathUnescape(err.Error())
	if strings.Contains(err.Error(), defaults.SockPath) {
		return fmt.Errorf("%s\nIs the agent running?", e)
	}
	return fmt.Errorf("%s", e)
}

func formatNodeAddress(w io.Writer, elem *models.NodeAddressingElement, primary bool, prefix string) bool {
	if elem.Enabled || !primary {
		if primary {
			fmt.Fprintf(w, "%sPrimary Address:\t%s\n", prefix, elem.IP)
		} else {
			fmt.Fprintf(w, "%s%s:\n", prefix, elem.IP)
		}
		fmt.Fprintf(w, "%s Type:\t%s\n", prefix, elem.AddressType)
		if elem.AllocRange != "" {
			fmt.Fprintf(w, "%sAllocRange:\t%s\n", prefix, elem.AllocRange)
		}

		return true
	}

	return false
}

// FormatStatusResponse writes a StatusResponse as a string to the writer
func FormatStatusResponse(w io.Writer, sr *models.StatusResponse) {
	if sr.Kvstore != nil {
		fmt.Fprintf(w, "KVStore:\t%s\t%s\n", sr.Kvstore.State, sr.Kvstore.Msg)
	}
	if sr.ContainerRuntime != nil {
		fmt.Fprintf(w, "ContainerRuntime:\t%s\t%s\n",
			sr.ContainerRuntime.State, sr.ContainerRuntime.Msg)
	}
	if sr.Kubernetes != nil {
		fmt.Fprintf(w, "Kubernetes:\t%s\t%s\n", sr.Kubernetes.State, sr.Kubernetes.Msg)
		fmt.Fprintf(w, "Kubernetes APIs:\t[\"%s\"]\n", strings.Join(sr.Kubernetes.K8sAPIVersions, "\", \""))
	}
	if sr.Cilium != nil {
		fmt.Fprintf(w, "Cilium:\t%s\t%s\n", sr.Cilium.State, sr.Cilium.Msg)
	}

	if nm := sr.NodeMonitor; nm != nil {
		fmt.Fprintf(w, "NodeMonitor:\tListening for events on %d CPUs with %dx%d of shared memory\n",
			nm.Cpus, nm.Npages, nm.Pagesize)
		if nm.Lost != 0 || nm.Unknown != 0 {
			fmt.Fprintf(w, "\t%d events lost, %d unknown notifications\n", nm.Lost, nm.Unknown)
		}
	} else {
		fmt.Fprintf(w, "NodeMonitor:\tDisabled\n")
	}

	if sr.IPAM != nil {
		fmt.Fprintf(w, "Allocated IPv4 addresses:\n")
		for _, ipv4 := range sr.IPAM.IPV4 {
			fmt.Fprintf(w, " %s\n", ipv4)

		}
		fmt.Fprintf(w, "Allocated IPv6 addresses:\n")
		for _, ipv6 := range sr.IPAM.IPV6 {
			fmt.Fprintf(w, " %s\n", ipv6)
		}
	}

	if sr.Cluster != nil {
		fmt.Fprintf(w, "Known cluster nodes:\n")
		for _, node := range sr.Cluster.Nodes {
			localStr := ""
			if node.Name == sr.Cluster.Self {
				localStr = " (localhost)"
			}
			fmt.Fprintf(w, " %s%s:\n", node.Name, localStr)
			formatNodeAddress(w, node.PrimaryAddress.IPV4, true, "  ")
			formatNodeAddress(w, node.PrimaryAddress.IPV6, true, "  ")

			buf := new(bytes.Buffer)
			secondary := false
			fmt.Fprintf(buf, "  Secondary Addresses:\n")
			for _, elem := range node.SecondaryAddresses {
				if formatNodeAddress(buf, elem, false, "   ") {
					secondary = true
				}
			}
			if secondary {
				fmt.Fprintf(w, "%s", buf.String())
			}
		}
	}
}
<|endoftext|>


<commit_before>package nodejs

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

	"github.com/blang/semver"
	"github.com/markelog/archive"
	"github.com/markelog/cprf"
	"gopkg.in/cavaliercoder/grab.v1"

	"github.com/markelog/eclectica/io"
	"github.com/markelog/eclectica/variables"
)

var (
	minimalForYarn, _ = semver.Make("6.0.0")
	version           = "1.13.0"
	yarnURL           = fmt.Sprintf(
		"https://yarnpkg.com/downloads/%s/yarn-v%s.tar.gz",
		version,
		version,
	)
)

func (node Node) download(path string) (err error) {
	_, err = grab.Get(path, yarnURL)
	if err != nil {
		return
	}

	return
}

func (node Node) isYarnPossible() bool {
	version, _ := semver.Make(node.Version)

	return version.GTE(minimalForYarn)
}

// Yarn does everything that needs to be done to install yarn
func (node Node) Yarn() (ok bool, err error) {
	var (
		path       = variables.Path("node", node.Version)
		modules    = filepath.Join(path, "lib/node_modules")
		archived   = filepath.Join(variables.TempDir(), "yarn-archived")
		unarchived = filepath.Join(variables.TempDir(), "yarn-unarchived")
		from       = filepath.Join(unarchived, fmt.Sprintf("yarn-v%s/", version))
		dest       = filepath.Join(modules, "yarn")
	)

	if node.isYarnPossible() == false {
		return true, errors.New("\"" + node.Version + "\" version is not supported by yarn")
	}

	if _, statErr := os.Stat(unarchived); statErr != nil {
		err = node.download(archived)
		if err != nil {
			return
		}

		err = archive.Extract(archived, unarchived)
		if err != nil {
			return
		}
	}

	err = cprf.Copy(from+"/", dest)
	if err != nil {
		return
	}

	os.RemoveAll(archived)

	current := filepath.Join(modules, "yarn/bin/yarn.js")
	base := filepath.Join(path, "bin/yarn")

	err = io.Symlink(base, current)
	if err != nil {
		return
	}

	return true, nil
}
<commit_msg>Bump version of default yarn installation<commit_after>package nodejs

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

	"github.com/blang/semver"
	"github.com/markelog/archive"
	"github.com/markelog/cprf"
	"gopkg.in/cavaliercoder/grab.v1"

	"github.com/markelog/eclectica/io"
	"github.com/markelog/eclectica/variables"
)

var (
	minimalForYarn, _ = semver.Make("6.0.0")
	version           = "1.16.0"
	yarnURL           = fmt.Sprintf(
		"https://yarnpkg.com/downloads/%s/yarn-v%s.tar.gz",
		version,
		version,
	)
)

func (node Node) download(path string) (err error) {
	_, err = grab.Get(path, yarnURL)
	if err != nil {
		return
	}

	return
}

func (node Node) isYarnPossible() bool {
	version, _ := semver.Make(node.Version)

	return version.GTE(minimalForYarn)
}

// Yarn does everything that needs to be done to install yarn
func (node Node) Yarn() (ok bool, err error) {
	var (
		path       = variables.Path("node", node.Version)
		modules    = filepath.Join(path, "lib/node_modules")
		archived   = filepath.Join(variables.TempDir(), "yarn-archived")
		unarchived = filepath.Join(variables.TempDir(), "yarn-unarchived")
		from       = filepath.Join(unarchived, fmt.Sprintf("yarn-v%s/", version))
		dest       = filepath.Join(modules, "yarn")
	)

	if node.isYarnPossible() == false {
		return true, errors.New("\"" + node.Version + "\" version is not supported by yarn")
	}

	if _, statErr := os.Stat(unarchived); statErr != nil {
		err = node.download(archived)
		if err != nil {
			return
		}

		err = archive.Extract(archived, unarchived)
		if err != nil {
			return
		}
	}

	err = cprf.Copy(from+"/", dest)
	if err != nil {
		return
	}

	os.RemoveAll(archived)

	current := filepath.Join(modules, "yarn/bin/yarn.js")
	base := filepath.Join(path, "bin/yarn")

	err = io.Symlink(base, current)
	if err != nil {
		return
	}

	return true, nil
}
<|endoftext|>


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

package main

import (
	"fmt"
	"github.com/osrg/gobgp/api"
	"github.com/spf13/cobra"
	"golang.org/x/net/context"
	"io"
	"net"
	"os"
)

func NewMonitorCmd() *cobra.Command {
	ribCmd := &cobra.Command{
		Use: CMD_RIB,
		Run: func(cmd *cobra.Command, args []string) {
			rt, err := checkAddressFamily(net.IP{})
			if err != nil {
				fmt.Println(err)
				os.Exit(1)
			}
			arg := &api.Arguments{
				Resource: api.Resource_GLOBAL,
				Af:       rt,
			}

			stream, err := client.MonitorBestChanged(context.Background(), arg)
			if err != nil {
				fmt.Println(err)
				os.Exit(1)
			}
			for {
				p, err := stream.Recv()
				if err == io.EOF {
					break
				} else if err != nil {
					fmt.Println(err)
					os.Exit(1)
				}
				showRoute([]*api.Path{p}, false, false, true)
			}

		},
	}

	globalCmd := &cobra.Command{
		Use: CMD_GLOBAL,
	}
	globalCmd.AddCommand(ribCmd)

	neighborCmd := &cobra.Command{
		Use: CMD_NEIGHBOR,
		Run: func(cmd *cobra.Command, args []string) {
			var arg *api.Arguments
			if len(args) > 0 {
				arg = &api.Arguments{
					RouterId: args[0],
				}
			} else {
				arg = &api.Arguments{}
			}

			stream, err := client.MonitorPeerState(context.Background(), arg)
			if err != nil {
				fmt.Println(err)
				os.Exit(1)
			}
			for {
				s, err := stream.Recv()
				if err == io.EOF {
					break
				} else if err != nil {
					fmt.Println(err)
					os.Exit(1)
				}
				fmt.Printf("[NEIGH] %s fsm: %s admin: %s\n", s.Conf.RemoteIp, s.Info.BgpState, s.Info.AdminState)
			}
		},
	}

	monitorCmd := &cobra.Command{
		Use: CMD_MONITOR,
	}
	monitorCmd.AddCommand(globalCmd)
	monitorCmd.AddCommand(neighborCmd)

	return monitorCmd
}
<commit_msg>cli: handle json option for monitor commands<commit_after>// Copyright (C) 2015 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"encoding/json"
	"fmt"
	"github.com/osrg/gobgp/api"
	"github.com/spf13/cobra"
	"golang.org/x/net/context"
	"io"
	"net"
	"os"
)

func NewMonitorCmd() *cobra.Command {
	ribCmd := &cobra.Command{
		Use: CMD_RIB,
		Run: func(cmd *cobra.Command, args []string) {
			rt, err := checkAddressFamily(net.IP{})
			if err != nil {
				fmt.Println(err)
				os.Exit(1)
			}
			arg := &api.Arguments{
				Resource: api.Resource_GLOBAL,
				Af:       rt,
			}

			stream, err := client.MonitorBestChanged(context.Background(), arg)
			if err != nil {
				fmt.Println(err)
				os.Exit(1)
			}
			for {
				p, err := stream.Recv()
				if err == io.EOF {
					break
				} else if err != nil {
					fmt.Println(err)
					os.Exit(1)
				}
				if globalOpts.Json {
					j, _ := json.Marshal(p)
					fmt.Println(string(j))
				} else {
					showRoute([]*api.Path{p}, false, false, true)
				}
			}

		},
	}

	globalCmd := &cobra.Command{
		Use: CMD_GLOBAL,
	}
	globalCmd.AddCommand(ribCmd)

	neighborCmd := &cobra.Command{
		Use: CMD_NEIGHBOR,
		Run: func(cmd *cobra.Command, args []string) {
			var arg *api.Arguments
			if len(args) > 0 {
				arg = &api.Arguments{
					RouterId: args[0],
				}
			} else {
				arg = &api.Arguments{}
			}

			stream, err := client.MonitorPeerState(context.Background(), arg)
			if err != nil {
				fmt.Println(err)
				os.Exit(1)
			}
			for {
				s, err := stream.Recv()
				if err == io.EOF {
					break
				} else if err != nil {
					fmt.Println(err)
					os.Exit(1)
				}
				if globalOpts.Json {
					j, _ := json.Marshal(s)
					fmt.Println(string(j))
				} else {
					fmt.Printf("[NEIGH] %s fsm: %s admin: %s\n", s.Conf.RemoteIp, s.Info.BgpState, s.Info.AdminState)
				}
			}
		},
	}

	monitorCmd := &cobra.Command{
		Use: CMD_MONITOR,
	}
	monitorCmd.AddCommand(globalCmd)
	monitorCmd.AddCommand(neighborCmd)

	return monitorCmd
}
<|endoftext|>