<commit_before>/*
Copyright 2019 The xridge kubestone contributors.

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 sysbench

import (
	batchv1 "k8s.io/api/batch/v1"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	"github.com/firepear/qsplit"
	perfv1alpha1 "github.com/xridge/kubestone/api/v1alpha1"
)

// NewJob creates a sysbench benchmark job
func NewJob(cr *perfv1alpha1.Sysbench) *batchv1.Job {
	labels := map[string]string{
		"app":               "sysbench",
		"kubestone-cr-name": cr.Name,
	}
	for key, value := range cr.Spec.PodLabels {
		labels[key] = value
	}

	sysbenchCmdLineArgs := []string{}
	sysbenchCmdLineArgs = append(sysbenchCmdLineArgs, qsplit.ToStrings([]byte(cr.Spec.Options))...)
	sysbenchCmdLineArgs = append(sysbenchCmdLineArgs, cr.Spec.TestName, cr.Spec.Command)

	backoffLimit := int32(0)

	job := batchv1.Job{
		ObjectMeta: metav1.ObjectMeta{
			Name:      cr.Name,
			Namespace: cr.Namespace,
		},
		Spec: batchv1.JobSpec{
			Template: corev1.PodTemplateSpec{
				ObjectMeta: metav1.ObjectMeta{
					Labels: labels,
				},
				Spec: corev1.PodSpec{
					Containers: []corev1.Container{
						{
							Name:            "sysbench",
							Image:           cr.Spec.Image.Name,
							ImagePullPolicy: corev1.PullPolicy(cr.Spec.Image.PullPolicy),
							Args:            sysbenchCmdLineArgs,
						},
					},
					ImagePullSecrets: []corev1.LocalObjectReference{
						{
							Name: cr.Spec.Image.PullSecret,
						},
					},
					RestartPolicy: corev1.RestartPolicyNever,
					Affinity:      &cr.Spec.PodScheduling.Affinity,
					Tolerations:   cr.Spec.PodScheduling.Tolerations,
					NodeSelector:  cr.Spec.PodScheduling.NodeSelector,
					NodeName:      cr.Spec.PodScheduling.NodeName,
				},
			},
			BackoffLimit: &backoffLimit,
		},
	}

	return &job
}
<commit_msg>Add TODO item not to forget other pods attributes<commit_after>/*
Copyright 2019 The xridge kubestone contributors.

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 sysbench

import (
	batchv1 "k8s.io/api/batch/v1"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	"github.com/firepear/qsplit"
	perfv1alpha1 "github.com/xridge/kubestone/api/v1alpha1"
)

// NewJob creates a sysbench benchmark job
func NewJob(cr *perfv1alpha1.Sysbench) *batchv1.Job {
	labels := map[string]string{
		"app":               "sysbench",
		"kubestone-cr-name": cr.Name,
	}
	for key, value := range cr.Spec.PodLabels {
		labels[key] = value
	}

	sysbenchCmdLineArgs := []string{}
	sysbenchCmdLineArgs = append(sysbenchCmdLineArgs, qsplit.ToStrings([]byte(cr.Spec.Options))...)
	sysbenchCmdLineArgs = append(sysbenchCmdLineArgs, cr.Spec.TestName, cr.Spec.Command)

	backoffLimit := int32(0)

	job := batchv1.Job{
		ObjectMeta: metav1.ObjectMeta{
			Name:      cr.Name,
			Namespace: cr.Namespace,
		},
		Spec: batchv1.JobSpec{
			Template: corev1.PodTemplateSpec{
				ObjectMeta: metav1.ObjectMeta{
					Labels: labels,
				},
				Spec: corev1.PodSpec{
					Containers: []corev1.Container{
						{
							Name:            "sysbench",
							Image:           cr.Spec.Image.Name,
							ImagePullPolicy: corev1.PullPolicy(cr.Spec.Image.PullPolicy),
							Args:            sysbenchCmdLineArgs,
						},
					},
					ImagePullSecrets: []corev1.LocalObjectReference{
						{
							Name: cr.Spec.Image.PullSecret,
						},
					},
					// TODO: add more options here eg. resource requests/limits
					RestartPolicy: corev1.RestartPolicyNever,
					Affinity:      &cr.Spec.PodScheduling.Affinity,
					Tolerations:   cr.Spec.PodScheduling.Tolerations,
					NodeSelector:  cr.Spec.PodScheduling.NodeSelector,
					NodeName:      cr.Spec.PodScheduling.NodeName,
				},
			},
			BackoffLimit: &backoffLimit,
		},
	}

	return &job
}
<|endoftext|>


<commit_before>package v1

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"testing"
	"time"

	"github.com/freeusd/solebtc/Godeps/_workspace/src/github.com/gin-gonic/gin"
	. "github.com/freeusd/solebtc/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey"
	"github.com/freeusd/solebtc/errors"
	"github.com/freeusd/solebtc/models"
)

const (
	validBTCAddr   = "1EFJFaeATfp2442TGcHS5mgadXJjsSSP2T"
	invalidBTCAddr = "address"

	validEmail   = "valid@email.cc"
	invalidEmail = "invalid@.ee.cc"
)

func TestSignup(t *testing.T) {
	requestDataJSON := func(email string) []byte {
		raw, _ := json.Marshal(map[string]interface{}{
			"email":      email,
			"address":    "address",
			"referer_id": 2,
		})
		return raw
	}

	testdata := []struct {
		when        string
		requestData []byte
		code        int
		getUserByID dependencyGetUserByID
		createUser  dependencyCreateUser
	}{
		{
			"invalid json data",
			[]byte("huhu"),
			400,
			nil,
			nil,
		},
		{
			"invalid email",
			requestDataJSON(invalidEmail),
			400,
			nil,
			nil,
		},
		{
			"duplicate email",
			requestDataJSON(validEmail),
			409,
			mockGetUserByID(models.User{}, nil),
			mockCreateUser(errors.New(errors.ErrCodeDuplicateEmail)),
		},
		{
			"valid email, but create user unknown error",
			requestDataJSON(validEmail),
			500,
			mockGetUserByID(models.User{}, nil),
			mockCreateUser(errors.New(errors.ErrCodeUnknown)),
		},
		{
			"valid email",
			requestDataJSON(validEmail),
			200,
			mockGetUserByID(models.User{}, nil),
			mockCreateUser(nil),
		},
	}

	for _, v := range testdata {
		Convey("Given Signup controller", t, func() {
			handler := Signup(v.createUser, v.getUserByID)

			Convey(fmt.Sprintf("When request with %s", v.when), func() {
				route := "/users"
				_, resp, r := gin.CreateTestContext()
				r.POST(route, handler)
				req, _ := http.NewRequest("POST", route, bytes.NewBuffer(v.requestData))
				r.ServeHTTP(resp, req)

				Convey(fmt.Sprintf("Response code should be equal to %d", v.code), func() {
					So(resp.Code, ShouldEqual, v.code)
				})
			})
		})
	}
}

func TestVerifyEmail(t *testing.T) {
	Convey("Given verify email controller with expired session and errored getSessionByToken dependency", t, func() {
		getSessionByToken := mockGetSessionByToken(models.Session{}, errors.New(errors.ErrCodeUnknown))
		handler := VerifyEmail(getSessionByToken, nil, nil)

		Convey("When verify email", func() {
			route := "/users/1/status"
			_, resp, r := gin.CreateTestContext()
			r.PUT(route, handler)
			req, _ := http.NewRequest("PUT", route, nil)
			r.ServeHTTP(resp, req)

			Convey("Response code should be 401", func() {
				So(resp.Code, ShouldEqual, 401)
			})
		})
	})

	Convey("Given verify email controller with expired session and getSessionByToken dependency", t, func() {
		getSessionByToken := mockGetSessionByToken(models.Session{}, nil)
		handler := VerifyEmail(getSessionByToken, nil, nil)

		Convey("When verify email", func() {
			route := "/users/1/status"
			_, resp, r := gin.CreateTestContext()
			r.PUT(route, handler)
			req, _ := http.NewRequest("PUT", route, nil)
			r.ServeHTTP(resp, req)

			Convey("Response code should be 401", func() {
				So(resp.Code, ShouldEqual, 401)
			})
		})
	})

	Convey("Given verify email controller with errored getUserByID dependency", t, func() {
		getSessionByToken := mockGetSessionByToken(models.Session{UpdatedAt: time.Now()}, nil)
		getUserByID := mockGetUserByID(models.User{}, errors.New(errors.ErrCodeUnknown))
		handler := VerifyEmail(getSessionByToken, getUserByID, nil)

		Convey("When verify email", func() {
			route := "/users/1/status"
			_, resp, r := gin.CreateTestContext()
			r.PUT(route, handler)
			req, _ := http.NewRequest("PUT", route, nil)
			r.ServeHTTP(resp, req)

			Convey("Response code should be 500", func() {
				So(resp.Code, ShouldEqual, 500)
			})
		})
	})

	Convey("Given verify email controller with banned user status", t, func() {
		getSessionByToken := mockGetSessionByToken(models.Session{UpdatedAt: time.Now()}, nil)
		getUserByID := mockGetUserByID(models.User{Status: models.UserStatusBanned}, nil)
		handler := VerifyEmail(getSessionByToken, getUserByID, nil)

		Convey("When verify email", func() {
			route := "/users/1/status"
			_, resp, r := gin.CreateTestContext()
			r.PUT(route, handler)
			req, _ := http.NewRequest("PUT", route, nil)
			r.ServeHTTP(resp, req)

			Convey("Response code should be 403", func() {
				So(resp.Code, ShouldEqual, 403)
			})
		})
	})

	Convey("Given verify email controller with errored updateUser dependency", t, func() {
		getSessionByToken := mockGetSessionByToken(models.Session{UpdatedAt: time.Now()}, nil)
		getUserByID := mockGetUserByID(models.User{}, nil)
		updateUserStatus := mockUpdateUserStatus(errors.New(errors.ErrCodeUnknown))
		handler := VerifyEmail(getSessionByToken, getUserByID, updateUserStatus)

		Convey("When verify email", func() {
			route := "/users/1/status"
			_, resp, r := gin.CreateTestContext()
			r.PUT(route, handler)
			req, _ := http.NewRequest("PUT", route, nil)
			r.ServeHTTP(resp, req)

			Convey("Response code should be 500", func() {
				So(resp.Code, ShouldEqual, 500)
			})
		})
	})

	Convey("Given verify email controller with correct dependencies injected", t, func() {
		getSessionByToken := mockGetSessionByToken(models.Session{UpdatedAt: time.Now()}, nil)
		getUserByID := mockGetUserByID(models.User{}, nil)
		updateUserStatus := mockUpdateUserStatus(nil)
		handler := VerifyEmail(getSessionByToken, getUserByID, updateUserStatus)

		Convey("When verify email", func() {
			route := "/users/1/status"
			_, resp, r := gin.CreateTestContext()
			r.PUT(route, handler)
			req, _ := http.NewRequest("PUT", route, nil)
			r.ServeHTTP(resp, req)

			Convey("Response code should be 200", func() {
				So(resp.Code, ShouldEqual, 200)
			})
		})
	})
}

func TestGetUserInfo(t *testing.T) {
	Convey("Given get user info controller with errored getUserByID dependency", t, func() {
		getUserByID := mockGetUserByID(models.User{}, errors.New(errors.ErrCodeNotFound))
		handler := UserInfo(getUserByID)

		Convey("When get user info", func() {
			route := "/users"
			_, resp, r := gin.CreateTestContext()
			r.Use(func(c *gin.Context) {
				c.Set("auth_token", models.AuthToken{})
			})
			r.GET(route, handler)
			req, _ := http.NewRequest("GET", route, nil)
			r.ServeHTTP(resp, req)

			Convey("Response code should be 500", func() {
				So(resp.Code, ShouldEqual, 500)
			})
		})
	})

	Convey("Given get user info controller with correctly dependencies injected", t, func() {
		getUserByID := mockGetUserByID(models.User{}, nil)
		handler := UserInfo(getUserByID)

		Convey("When get user info", func() {
			route := "/users"
			_, resp, r := gin.CreateTestContext()
			r.Use(func(c *gin.Context) {
				c.Set("auth_token", models.AuthToken{})
			})
			r.GET(route, handler)
			req, _ := http.NewRequest("GET", route, nil)
			r.ServeHTTP(resp, req)

			Convey("Response code should be 200", func() {
				So(resp.Code, ShouldEqual, 200)
			})
		})
	})
}

func TestGetReferees(t *testing.T) {
	Convey("Given referee list controller", t, func() {
		handler := RefereeList(nil, nil)

		Convey("When get reward list with invalid limit", func() {
			route := "/users/referees"
			_, resp, r := gin.CreateTestContext()
			r.Use(func(c *gin.Context) {
				c.Set("auth_token", models.AuthToken{})
			})
			r.GET(route, handler)
			req, _ := http.NewRequest("GET", route+"?limit=3i", nil)
			r.ServeHTTP(resp, req)

			Convey("Response code should be 400", func() {
				So(resp.Code, ShouldEqual, 400)
			})
		})
	})

	Convey("Given referee list controller with errored getRefereesSinceID dependency", t, func() {
		since := mockGetRefereesSince(nil, errors.New(errors.ErrCodeUnknown))
		handler := RefereeList(since, nil)

		Convey("When get referee list", func() {
			route := "/users/referees"
			_, resp, r := gin.CreateTestContext()
			r.Use(func(c *gin.Context) {
				c.Set("auth_token", models.AuthToken{})
			})
			r.GET(route, handler)
			req, _ := http.NewRequest("GET", route+"?since=1234567890", nil)
			r.ServeHTTP(resp, req)

			Convey("Response code should be 500", func() {
				So(resp.Code, ShouldEqual, 500)
			})
		})
	})

	Convey("Given referee list controller with correct dependencies injected", t, func() {
		until := mockGetRefereesUntil(nil, nil)
		handler := RefereeList(nil, until)

		Convey("When get referee list", func() {
			route := "/users/referees"
			_, resp, r := gin.CreateTestContext()
			r.Use(func(c *gin.Context) {
				c.Set("auth_token", models.AuthToken{})
			})
			r.GET(route, handler)
			req, _ := http.NewRequest("GET", route+"?until=1234567890", nil)
			r.ServeHTTP(resp, req)

			Convey("Response code should be 200", func() {
				So(resp.Code, ShouldEqual, 200)
			})
		})
	})
}
<commit_msg>Do not convert between currencies, e.g btc <-> usd<commit_after>package v1

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"testing"
	"time"

	"github.com/freeusd/solebtc/Godeps/_workspace/src/github.com/gin-gonic/gin"
	. "github.com/freeusd/solebtc/Godeps/_workspace/src/github.com/smartystreets/goconvey/convey"
	"github.com/freeusd/solebtc/errors"
	"github.com/freeusd/solebtc/models"
)

const (
	validEmail   = "valid@email.cc"
	invalidEmail = "invalid@.ee.cc"
)

func TestSignup(t *testing.T) {
	requestDataJSON := func(email string) []byte {
		raw, _ := json.Marshal(map[string]interface{}{
			"email":      email,
			"address":    "address",
			"referer_id": 2,
		})
		return raw
	}

	testdata := []struct {
		when        string
		requestData []byte
		code        int
		getUserByID dependencyGetUserByID
		createUser  dependencyCreateUser
	}{
		{
			"invalid json data",
			[]byte("huhu"),
			400,
			nil,
			nil,
		},
		{
			"invalid email",
			requestDataJSON(invalidEmail),
			400,
			nil,
			nil,
		},
		{
			"duplicate email",
			requestDataJSON(validEmail),
			409,
			mockGetUserByID(models.User{}, nil),
			mockCreateUser(errors.New(errors.ErrCodeDuplicateEmail)),
		},
		{
			"valid email, but create user unknown error",
			requestDataJSON(validEmail),
			500,
			mockGetUserByID(models.User{}, nil),
			mockCreateUser(errors.New(errors.ErrCodeUnknown)),
		},
		{
			"valid email",
			requestDataJSON(validEmail),
			200,
			mockGetUserByID(models.User{}, nil),
			mockCreateUser(nil),
		},
	}

	for _, v := range testdata {
		Convey("Given Signup controller", t, func() {
			handler := Signup(v.createUser, v.getUserByID)

			Convey(fmt.Sprintf("When request with %s", v.when), func() {
				route := "/users"
				_, resp, r := gin.CreateTestContext()
				r.POST(route, handler)
				req, _ := http.NewRequest("POST", route, bytes.NewBuffer(v.requestData))
				r.ServeHTTP(resp, req)

				Convey(fmt.Sprintf("Response code should be equal to %d", v.code), func() {
					So(resp.Code, ShouldEqual, v.code)
				})
			})
		})
	}
}

func TestVerifyEmail(t *testing.T) {
	Convey("Given verify email controller with expired session and errored getSessionByToken dependency", t, func() {
		getSessionByToken := mockGetSessionByToken(models.Session{}, errors.New(errors.ErrCodeUnknown))
		handler := VerifyEmail(getSessionByToken, nil, nil)

		Convey("When verify email", func() {
			route := "/users/1/status"
			_, resp, r := gin.CreateTestContext()
			r.PUT(route, handler)
			req, _ := http.NewRequest("PUT", route, nil)
			r.ServeHTTP(resp, req)

			Convey("Response code should be 401", func() {
				So(resp.Code, ShouldEqual, 401)
			})
		})
	})

	Convey("Given verify email controller with expired session and getSessionByToken dependency", t, func() {
		getSessionByToken := mockGetSessionByToken(models.Session{}, nil)
		handler := VerifyEmail(getSessionByToken, nil, nil)

		Convey("When verify email", func() {
			route := "/users/1/status"
			_, resp, r := gin.CreateTestContext()
			r.PUT(route, handler)
			req, _ := http.NewRequest("PUT", route, nil)
			r.ServeHTTP(resp, req)

			Convey("Response code should be 401", func() {
				So(resp.Code, ShouldEqual, 401)
			})
		})
	})

	Convey("Given verify email controller with errored getUserByID dependency", t, func() {
		getSessionByToken := mockGetSessionByToken(models.Session{UpdatedAt: time.Now()}, nil)
		getUserByID := mockGetUserByID(models.User{}, errors.New(errors.ErrCodeUnknown))
		handler := VerifyEmail(getSessionByToken, getUserByID, nil)

		Convey("When verify email", func() {
			route := "/users/1/status"
			_, resp, r := gin.CreateTestContext()
			r.PUT(route, handler)
			req, _ := http.NewRequest("PUT", route, nil)
			r.ServeHTTP(resp, req)

			Convey("Response code should be 500", func() {
				So(resp.Code, ShouldEqual, 500)
			})
		})
	})

	Convey("Given verify email controller with banned user status", t, func() {
		getSessionByToken := mockGetSessionByToken(models.Session{UpdatedAt: time.Now()}, nil)
		getUserByID := mockGetUserByID(models.User{Status: models.UserStatusBanned}, nil)
		handler := VerifyEmail(getSessionByToken, getUserByID, nil)

		Convey("When verify email", func() {
			route := "/users/1/status"
			_, resp, r := gin.CreateTestContext()
			r.PUT(route, handler)
			req, _ := http.NewRequest("PUT", route, nil)
			r.ServeHTTP(resp, req)

			Convey("Response code should be 403", func() {
				So(resp.Code, ShouldEqual, 403)
			})
		})
	})

	Convey("Given verify email controller with errored updateUser dependency", t, func() {
		getSessionByToken := mockGetSessionByToken(models.Session{UpdatedAt: time.Now()}, nil)
		getUserByID := mockGetUserByID(models.User{}, nil)
		updateUserStatus := mockUpdateUserStatus(errors.New(errors.ErrCodeUnknown))
		handler := VerifyEmail(getSessionByToken, getUserByID, updateUserStatus)

		Convey("When verify email", func() {
			route := "/users/1/status"
			_, resp, r := gin.CreateTestContext()
			r.PUT(route, handler)
			req, _ := http.NewRequest("PUT", route, nil)
			r.ServeHTTP(resp, req)

			Convey("Response code should be 500", func() {
				So(resp.Code, ShouldEqual, 500)
			})
		})
	})

	Convey("Given verify email controller with correct dependencies injected", t, func() {
		getSessionByToken := mockGetSessionByToken(models.Session{UpdatedAt: time.Now()}, nil)
		getUserByID := mockGetUserByID(models.User{}, nil)
		updateUserStatus := mockUpdateUserStatus(nil)
		handler := VerifyEmail(getSessionByToken, getUserByID, updateUserStatus)

		Convey("When verify email", func() {
			route := "/users/1/status"
			_, resp, r := gin.CreateTestContext()
			r.PUT(route, handler)
			req, _ := http.NewRequest("PUT", route, nil)
			r.ServeHTTP(resp, req)

			Convey("Response code should be 200", func() {
				So(resp.Code, ShouldEqual, 200)
			})
		})
	})
}

func TestGetUserInfo(t *testing.T) {
	Convey("Given get user info controller with errored getUserByID dependency", t, func() {
		getUserByID := mockGetUserByID(models.User{}, errors.New(errors.ErrCodeNotFound))
		handler := UserInfo(getUserByID)

		Convey("When get user info", func() {
			route := "/users"
			_, resp, r := gin.CreateTestContext()
			r.Use(func(c *gin.Context) {
				c.Set("auth_token", models.AuthToken{})
			})
			r.GET(route, handler)
			req, _ := http.NewRequest("GET", route, nil)
			r.ServeHTTP(resp, req)

			Convey("Response code should be 500", func() {
				So(resp.Code, ShouldEqual, 500)
			})
		})
	})

	Convey("Given get user info controller with correctly dependencies injected", t, func() {
		getUserByID := mockGetUserByID(models.User{}, nil)
		handler := UserInfo(getUserByID)

		Convey("When get user info", func() {
			route := "/users"
			_, resp, r := gin.CreateTestContext()
			r.Use(func(c *gin.Context) {
				c.Set("auth_token", models.AuthToken{})
			})
			r.GET(route, handler)
			req, _ := http.NewRequest("GET", route, nil)
			r.ServeHTTP(resp, req)

			Convey("Response code should be 200", func() {
				So(resp.Code, ShouldEqual, 200)
			})
		})
	})
}

func TestGetReferees(t *testing.T) {
	Convey("Given referee list controller", t, func() {
		handler := RefereeList(nil, nil)

		Convey("When get reward list with invalid limit", func() {
			route := "/users/referees"
			_, resp, r := gin.CreateTestContext()
			r.Use(func(c *gin.Context) {
				c.Set("auth_token", models.AuthToken{})
			})
			r.GET(route, handler)
			req, _ := http.NewRequest("GET", route+"?limit=3i", nil)
			r.ServeHTTP(resp, req)

			Convey("Response code should be 400", func() {
				So(resp.Code, ShouldEqual, 400)
			})
		})
	})

	Convey("Given referee list controller with errored getRefereesSinceID dependency", t, func() {
		since := mockGetRefereesSince(nil, errors.New(errors.ErrCodeUnknown))
		handler := RefereeList(since, nil)

		Convey("When get referee list", func() {
			route := "/users/referees"
			_, resp, r := gin.CreateTestContext()
			r.Use(func(c *gin.Context) {
				c.Set("auth_token", models.AuthToken{})
			})
			r.GET(route, handler)
			req, _ := http.NewRequest("GET", route+"?since=1234567890", nil)
			r.ServeHTTP(resp, req)

			Convey("Response code should be 500", func() {
				So(resp.Code, ShouldEqual, 500)
			})
		})
	})

	Convey("Given referee list controller with correct dependencies injected", t, func() {
		until := mockGetRefereesUntil(nil, nil)
		handler := RefereeList(nil, until)

		Convey("When get referee list", func() {
			route := "/users/referees"
			_, resp, r := gin.CreateTestContext()
			r.Use(func(c *gin.Context) {
				c.Set("auth_token", models.AuthToken{})
			})
			r.GET(route, handler)
			req, _ := http.NewRequest("GET", route+"?until=1234567890", nil)
			r.ServeHTTP(resp, req)

			Convey("Response code should be 200", func() {
				So(resp.Code, ShouldEqual, 200)
			})
		})
	})
}
<|endoftext|>


<commit_before>// Copyright 2017 Tomas Machalek <tomas.machalek@gmail.com>
// Copyright 2017 Institute of the Czech National Corpus,
//                Faculty of Arts, Charles University
//
// 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 kontext

import (
	"encoding/json"
	"fmt"
	"net"
	"regexp"
	"strings"
	"time"

	"github.com/czcorpus/klogproc/conversion"
)

var (
	datetimeRegexp = regexp.MustCompile("^(\\d{4}-\\d{2}-\\d{2})(\\s|T)([012]\\d:[0-5]\\d:[0-5]\\d(\\.\\d+))")
)

func importDatetimeString(dateStr string) (string, error) {
	srch := datetimeRegexp.FindStringSubmatch(dateStr)
	if len(srch) > 0 {
		return fmt.Sprintf("%sT%s", srch[1], srch[3]), nil
	}
	return "", fmt.Errorf("Failed to import datetime \"%s\"", dateStr)
}

// ImportJSONLog parses original JSON record with some
// additional value corrections.
func ImportJSONLog(jsonLine []byte) (*InputRecord, error) {
	var record InputRecord
	err := json.Unmarshal(jsonLine, &record)
	if err != nil {
		return nil, err
	}
	dt, err := importDatetimeString(record.Date)
	if err != nil {
		return nil, err
	}
	record.Date = dt
	return &record, nil
}

// ------------------------------------------------------------

// Request is a simple representation of
// HTTP request metadata used in KonText logging
type Request struct {
	HTTPForwardedFor string `json:"HTTP_X_FORWARDED_FOR"`
	HTTPUserAgent    string `json:"HTTP_USER_AGENT"`
	HTTPRemoteAddr   string `json:"HTTP_REMOTE_ADDR"`
	RemoteAddr       string `json:"REMOTE_ADDR"`
}

// ------------------------------------------------------------

// ErrorRecord specifies a thrown error along with
// optional anchor for easier search within text file
// log
type ErrorRecord struct {
	Name   string `json:"name"`
	Anchor string `json:"anchor"`
}

// ------------------------------------------------------------

// InputRecord represents a parsed KonText record
type InputRecord struct {
	UserID   int                    `json:"user_id"`
	ProcTime float32                `json:"proc_time"`
	Date     string                 `json:"date"`
	Action   string                 `json:"action"`
	Request  Request                `json:"request"`
	Params   map[string]interface{} `json:"params"`
	PID      int                    `json:"pid"`
	Settings map[string]interface{} `json:"settings"`
	Error    ErrorRecord            `json:"error"`
}

// GetTime returns record's time as a Golang's Time
// instance. Please note that the value is truncated
// to seconds.
func (rec *InputRecord) GetTime() time.Time {
	return conversion.ConvertDatetimeString(rec.Date)
}

// GetClientIP returns a client IP no matter in which
// part of the record it was found
// (e.g. REMOTE_ADDR vs. HTTP_REMOTE_ADDR vs. HTTP_FORWARDED_FOR)
func (rec *InputRecord) GetClientIP() net.IP {
	if rec.Request.HTTPForwardedFor != "" {
		return net.ParseIP(rec.Request.HTTPForwardedFor)

	} else if rec.Request.HTTPRemoteAddr != "" {
		return net.ParseIP(rec.Request.HTTPRemoteAddr)

	} else if rec.Request.RemoteAddr != "" {
		return net.ParseIP(rec.Request.RemoteAddr)
	}
	return make([]byte, 0)
}

// GetUserAgent returns a raw HTTP user agent info as provided by the client
func (rec *InputRecord) GetUserAgent() string {
	return rec.Request.HTTPUserAgent
}

// IsProcessable returns true if there was no error in reading the record
func (rec *InputRecord) IsProcessable() bool {
	return true
}

// GetStringParam fetches a string parameter from
// a special "params" sub-object
func (rec *InputRecord) GetStringParam(name string) string {
	switch v := rec.Params[name].(type) {
	case string:
		return v
	}
	return ""
}

// GetIntParam fetches an integer parameter from
// a special "params" sub-object
func (rec *InputRecord) GetIntParam(name string) int {
	switch v := rec.Params[name].(type) {
	case int:
		return v
	}
	return -1
}

// GetAlignedCorpora fetches aligned corpora names from arguments
// found in record's "Params" attribute. It isolates
// user from miscellaneous idiosyncrasies of KonText/Bonito
// URL parameter handling (= it's not always that straightforward
// to detect aligned languages from raw URL).
func (rec *InputRecord) GetAlignedCorpora() []string {
	tmp := make(map[string]bool)
	for k := range rec.Params {
		if strings.HasPrefix(k, "queryselector_") {
			tmp[k[len("queryselector_"):]] = true
		}
		if strings.HasPrefix(k, "pcq_pos_neg_") {
			tmp[k[len("pcq_pos_neg_"):]] = true
		}
	}
	ans := make([]string, len(tmp))
	i := 0
	for k := range tmp {
		ans[i] = k
		i++
	}
	return ans
}
<commit_msg>Fix dt parsing<commit_after>// Copyright 2017 Tomas Machalek <tomas.machalek@gmail.com>
// Copyright 2017 Institute of the Czech National Corpus,
//                Faculty of Arts, Charles University
//
// 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 kontext

import (
	"encoding/json"
	"fmt"
	"net"
	"regexp"
	"strings"
	"time"

	"github.com/czcorpus/klogproc/conversion"
)

var (
	datetimeRegexp = regexp.MustCompile("^(\\d{4}-\\d{2}-\\d{2})(\\s|T)([012]\\d:[0-5]\\d:[0-5]\\d(\\.\\d+))")
)

func importDatetimeString(dateStr string) (string, error) {
	srch := datetimeRegexp.FindStringSubmatch(dateStr)
	if len(srch) > 0 {
		return fmt.Sprintf("%sT%s", srch[1], srch[3]), nil
	}
	return "", fmt.Errorf("Failed to import datetime \"%s\"", dateStr)
}

// ImportJSONLog parses original JSON record with some
// additional value corrections.
func ImportJSONLog(jsonLine []byte) (*InputRecord, error) {
	var record InputRecord
	err := json.Unmarshal(jsonLine, &record)
	if err != nil {
		return nil, err
	}
	dt, err := importDatetimeString(record.Date)
	if err != nil {
		return nil, err
	}
	record.Date = dt
	return &record, nil
}

// ------------------------------------------------------------

// Request is a simple representation of
// HTTP request metadata used in KonText logging
type Request struct {
	HTTPForwardedFor string `json:"HTTP_X_FORWARDED_FOR"`
	HTTPUserAgent    string `json:"HTTP_USER_AGENT"`
	HTTPRemoteAddr   string `json:"HTTP_REMOTE_ADDR"`
	RemoteAddr       string `json:"REMOTE_ADDR"`
}

// ------------------------------------------------------------

// ErrorRecord specifies a thrown error along with
// optional anchor for easier search within text file
// log
type ErrorRecord struct {
	Name   string `json:"name"`
	Anchor string `json:"anchor"`
}

// ------------------------------------------------------------

// InputRecord represents a parsed KonText record
type InputRecord struct {
	UserID   int                    `json:"user_id"`
	ProcTime float32                `json:"proc_time"`
	Date     string                 `json:"date"`
	Action   string                 `json:"action"`
	Request  Request                `json:"request"`
	Params   map[string]interface{} `json:"params"`
	PID      int                    `json:"pid"`
	Settings map[string]interface{} `json:"settings"`
	Error    ErrorRecord            `json:"error"`
}

// GetTime returns record's time as a Golang's Time
// instance. Please note that the value is truncated
// to seconds.
func (rec *InputRecord) GetTime() time.Time {
	return conversion.ConvertDatetimeStringWithMillisNoTZ(rec.Date)
}

// GetClientIP returns a client IP no matter in which
// part of the record it was found
// (e.g. REMOTE_ADDR vs. HTTP_REMOTE_ADDR vs. HTTP_FORWARDED_FOR)
func (rec *InputRecord) GetClientIP() net.IP {
	if rec.Request.HTTPForwardedFor != "" {
		return net.ParseIP(rec.Request.HTTPForwardedFor)

	} else if rec.Request.HTTPRemoteAddr != "" {
		return net.ParseIP(rec.Request.HTTPRemoteAddr)

	} else if rec.Request.RemoteAddr != "" {
		return net.ParseIP(rec.Request.RemoteAddr)
	}
	return make([]byte, 0)
}

// GetUserAgent returns a raw HTTP user agent info as provided by the client
func (rec *InputRecord) GetUserAgent() string {
	return rec.Request.HTTPUserAgent
}

// IsProcessable returns true if there was no error in reading the record
func (rec *InputRecord) IsProcessable() bool {
	return true
}

// GetStringParam fetches a string parameter from
// a special "params" sub-object
func (rec *InputRecord) GetStringParam(name string) string {
	switch v := rec.Params[name].(type) {
	case string:
		return v
	}
	return ""
}

// GetIntParam fetches an integer parameter from
// a special "params" sub-object
func (rec *InputRecord) GetIntParam(name string) int {
	switch v := rec.Params[name].(type) {
	case int:
		return v
	}
	return -1
}

// GetAlignedCorpora fetches aligned corpora names from arguments
// found in record's "Params" attribute. It isolates
// user from miscellaneous idiosyncrasies of KonText/Bonito
// URL parameter handling (= it's not always that straightforward
// to detect aligned languages from raw URL).
func (rec *InputRecord) GetAlignedCorpora() []string {
	tmp := make(map[string]bool)
	for k := range rec.Params {
		if strings.HasPrefix(k, "queryselector_") {
			tmp[k[len("queryselector_"):]] = true
		}
		if strings.HasPrefix(k, "pcq_pos_neg_") {
			tmp[k[len("pcq_pos_neg_"):]] = true
		}
	}
	ans := make([]string, len(tmp))
	i := 0
	for k := range tmp {
		ans[i] = k
		i++
	}
	return ans
}
<|endoftext|>


<commit_before>package worker

import (
	"fmt"
	"strings"
	"sync"
	"time"

	"github.com/funkygao/fae/servant/mysql"
	"github.com/funkygao/gafka/cmd/kateway/job"
	jm "github.com/funkygao/gafka/cmd/kateway/job/mysql"
	"github.com/funkygao/gafka/cmd/kateway/store"
	log "github.com/funkygao/log4go"
)

// Worker polls a single JobQueue and handle each Job.
type Worker struct {
	parentId       string // controller short id
	cluster, topic string
	mc             *mysql.MysqlCluster
	stopper        <-chan struct{}
	dueJobs        chan job.JobItem
	auditor        log.Logger

	// cached values
	appid string
	aid   int
	table string
	ident string
}

func New(parentId, cluster, topic string, mc *mysql.MysqlCluster,
	stopper <-chan struct{}, auditor log.Logger) *Worker {
	this := &Worker{
		parentId: parentId,
		cluster:  cluster,
		topic:    topic,
		mc:       mc,
		stopper:  stopper,
		dueJobs:  make(chan job.JobItem, 200),
		auditor:  auditor,
	}

	this.appid = topic[:strings.IndexByte(topic, '.')]
	this.aid = jm.App_id(this.appid)
	this.table = jm.JobTable(topic)
	this.ident = fmt.Sprintf("worker{cluster:%s app:%s aid:%d topic:%s table:%s}",
		this.cluster, this.appid, this.aid, this.topic, this.table)

	return this
}

// poll mysql for due jobs and send to kafka.
func (this *Worker) Run() {
	log.Trace("starting %s", this.Ident())

	var (
		wg   sync.WaitGroup
		item job.JobItem
		tick = time.NewTicker(time.Second)
		sql  = fmt.Sprintf("SELECT job_id,app_id,payload,due_time FROM %s WHERE due_time<=?", this.table)
	)

	// handler pool FIXME
	for i := 0; i < 5; i++ {
		wg.Add(1)
		go this.handleDueJobs(&wg)
	}

	for {
		select {
		case <-this.stopper:
			log.Debug("%s stopping", this.ident)
			wg.Wait()
			return

		case now := <-tick.C:
			rows, err := this.mc.Query(jm.AppPool, this.topic, this.aid, sql, now.Unix())
			if err != nil {
				log.Error("%s: %v", this.ident, err)
				continue
			}

			for rows.Next() {
				// FIXME ctime not handled
				err = rows.Scan(&item.JobId, &item.AppId, &item.Payload, &item.DueTime)
				if err == nil {
					this.dueJobs <- item
					log.Debug("%s due %s", this.ident, item)
				} else {
					log.Error("%s: %s", this.ident, err)
				}
			}

			if err = rows.Err(); err != nil {
				log.Error("%s: %s", this.ident, err)
			}

			rows.Close()
		}
	}

}

// TODO batch DELETE/INSERT for better performance.
func (this *Worker) handleDueJobs(wg *sync.WaitGroup) {
	defer wg.Done()

	var (
		sqlDeleteJob     = fmt.Sprintf("DELETE FROM %s WHERE job_id=?", this.table)
		sqlInsertArchive = fmt.Sprintf("INSERT INTO %s(app_id,job_id,payload,ctime,due_time,invoke_time,actor_id) VALUES(?,?,?,?,?,?,?)",
			jm.HistoryTable(this.topic))
	)
	for {
		select {
		case <-this.stopper:
			return

		case item := <-this.dueJobs:
			log.Debug("%s handling %s", this.ident, item)
			affectedRows, _, err := this.mc.Exec(jm.AppPool, this.table, this.aid, sqlDeleteJob, item.JobId)
			if err != nil {
				log.Error("%s: %s", this.ident, err)
				continue
			}
			if affectedRows == 0 {
				// race fails, client Delete wins
				log.Warn("%s: %s race fails", this.ident, item)
				continue
			}

			log.Debug("%s deleted from real time table: %s", this.ident, item)
			_, _, err = store.DefaultPubStore.SyncPub(this.cluster, this.topic, nil, item.Payload)
			if err != nil {
				log.Error("%s: %s", this.ident, err)
				// TODO insert back to job table
			} else {
				this.auditor.Trace(item.String())

				// mv job to archive table
				_, _, err = this.mc.Exec(jm.AppPool, this.table, this.aid, sqlInsertArchive,
					item.AppId, item.JobId, item.Payload, item.Ctime, item.DueTime, time.Now().UnixNano(), this.parentId)
				if err != nil {
					log.Error("%s: %s", this.ident, err)
				} else {
					log.Debug("%s archived %s", this.ident, item)
				}
			}

		}
	}
}

func (this *Worker) Ident() string {
	return this.ident
}
<commit_msg>pool size=1, to guarantee the delivery order<commit_after>package worker

import (
	"fmt"
	"strings"
	"sync"
	"time"

	"github.com/funkygao/fae/servant/mysql"
	"github.com/funkygao/gafka/cmd/kateway/job"
	jm "github.com/funkygao/gafka/cmd/kateway/job/mysql"
	"github.com/funkygao/gafka/cmd/kateway/store"
	log "github.com/funkygao/log4go"
)

// Worker polls a single JobQueue and handle each Job.
type Worker struct {
	parentId       string // controller short id
	cluster, topic string
	mc             *mysql.MysqlCluster
	stopper        <-chan struct{}
	dueJobs        chan job.JobItem
	auditor        log.Logger

	// cached values
	appid string
	aid   int
	table string
	ident string
}

func New(parentId, cluster, topic string, mc *mysql.MysqlCluster,
	stopper <-chan struct{}, auditor log.Logger) *Worker {
	this := &Worker{
		parentId: parentId,
		cluster:  cluster,
		topic:    topic,
		mc:       mc,
		stopper:  stopper,
		dueJobs:  make(chan job.JobItem, 200),
		auditor:  auditor,
	}

	this.appid = topic[:strings.IndexByte(topic, '.')]
	this.aid = jm.App_id(this.appid)
	this.table = jm.JobTable(topic)
	this.ident = fmt.Sprintf("worker{cluster:%s app:%s aid:%d topic:%s table:%s}",
		this.cluster, this.appid, this.aid, this.topic, this.table)

	return this
}

// poll mysql for due jobs and send to kafka.
func (this *Worker) Run() {
	log.Trace("starting %s", this.Ident())

	var (
		wg   sync.WaitGroup
		item job.JobItem
		tick = time.NewTicker(time.Second)
		sql  = fmt.Sprintf("SELECT job_id,app_id,payload,due_time FROM %s WHERE due_time<=?", this.table)
	)

	// handler pool, currently to guarantee the order, we use pool=1
	for i := 0; i < 1; i++ {
		wg.Add(1)
		go this.handleDueJobs(&wg)
	}

	for {
		select {
		case <-this.stopper:
			log.Debug("%s stopping", this.ident)
			wg.Wait()
			return

		case now := <-tick.C:
			rows, err := this.mc.Query(jm.AppPool, this.topic, this.aid, sql, now.Unix())
			if err != nil {
				log.Error("%s: %v", this.ident, err)
				continue
			}

			for rows.Next() {
				// FIXME ctime not handled
				err = rows.Scan(&item.JobId, &item.AppId, &item.Payload, &item.DueTime)
				if err == nil {
					this.dueJobs <- item
					log.Debug("%s due %s", this.ident, item)
				} else {
					log.Error("%s: %s", this.ident, err)
				}
			}

			if err = rows.Err(); err != nil {
				log.Error("%s: %s", this.ident, err)
			}

			rows.Close()
		}
	}

}

// TODO batch DELETE/INSERT for better performance.
func (this *Worker) handleDueJobs(wg *sync.WaitGroup) {
	defer wg.Done()

	var (
		sqlDeleteJob     = fmt.Sprintf("DELETE FROM %s WHERE job_id=?", this.table)
		sqlInsertArchive = fmt.Sprintf("INSERT INTO %s(app_id,job_id,payload,ctime,due_time,invoke_time,actor_id) VALUES(?,?,?,?,?,?,?)",
			jm.HistoryTable(this.topic))
	)
	for {
		select {
		case <-this.stopper:
			return

		case item := <-this.dueJobs:
			log.Debug("%s handling %s", this.ident, item)
			affectedRows, _, err := this.mc.Exec(jm.AppPool, this.table, this.aid, sqlDeleteJob, item.JobId)
			if err != nil {
				log.Error("%s: %s", this.ident, err)
				continue
			}
			if affectedRows == 0 {
				// race fails, client Delete wins
				log.Warn("%s: %s race fails", this.ident, item)
				continue
			}

			log.Debug("%s deleted from real time table: %s", this.ident, item)
			_, _, err = store.DefaultPubStore.SyncPub(this.cluster, this.topic, nil, item.Payload)
			if err != nil {
				log.Error("%s: %s", this.ident, err)
				// TODO insert back to job table
			} else {
				this.auditor.Trace(item.String())

				// mv job to archive table
				_, _, err = this.mc.Exec(jm.AppPool, this.table, this.aid, sqlInsertArchive,
					item.AppId, item.JobId, item.Payload, item.Ctime, item.DueTime, time.Now().UnixNano(), this.parentId)
				if err != nil {
					log.Error("%s: %s", this.ident, err)
				} else {
					log.Debug("%s archived %s", this.ident, item)
				}
			}

		}
	}
}

func (this *Worker) Ident() string {
	return this.ident
}
<|endoftext|>


<commit_before>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package main

import (
	"fmt"
	"strconv"

	gc "launchpad.net/gocheck"

	"launchpad.net/juju-core/constraints"
	"launchpad.net/juju-core/instance"
	jujutesting "launchpad.net/juju-core/juju/testing"
	"launchpad.net/juju-core/state"
	"launchpad.net/juju-core/testing"
	jc "launchpad.net/juju-core/testing/checkers"
)

type AddMachineSuite struct {
	jujutesting.RepoSuite
}

var _ = gc.Suite(&AddMachineSuite{})

func runAddMachine(c *gc.C, args ...string) error {
	_, err := testing.RunCommand(c, &AddMachineCommand{}, args)
	return err
}

func (s *AddMachineSuite) TestAddMachine(c *gc.C) {
	err := runAddMachine(c)
	c.Assert(err, gc.IsNil)
	m, err := s.State.Machine("0")
	c.Assert(err, gc.IsNil)
	c.Assert(m.Life(), gc.Equals, state.Alive)
	c.Assert(m.Series(), gc.DeepEquals, "precise")
	mcons, err := m.Constraints()
	c.Assert(err, gc.IsNil)
	c.Assert(&mcons, jc.Satisfies, constraints.IsEmpty)
}

func (s *AddMachineSuite) TestAddMachineWithSeries(c *gc.C) {
	err := runAddMachine(c, "--series", "series")
	c.Assert(err, gc.IsNil)
	m, err := s.State.Machine("0")
	c.Assert(err, gc.IsNil)
	c.Assert(m.Series(), gc.DeepEquals, "series")
}

func (s *AddMachineSuite) TestAddMachineWithConstraints(c *gc.C) {
	err := runAddMachine(c, "--constraints", "mem=4G")
	c.Assert(err, gc.IsNil)
	m, err := s.State.Machine("0")
	c.Assert(err, gc.IsNil)
	mcons, err := m.Constraints()
	c.Assert(err, gc.IsNil)
	expectedCons := constraints.MustParse("mem=4G")
	c.Assert(mcons, gc.DeepEquals, expectedCons)
}

func (s *AddMachineSuite) _assertAddContainer(c *gc.C, parentId, containerId string, ctype instance.ContainerType) {
	m, err := s.State.Machine(parentId)
	c.Assert(err, gc.IsNil)
	containers, err := m.Containers()
	c.Assert(err, gc.IsNil)
	c.Assert(containers, gc.DeepEquals, []string{containerId})
	container, err := s.State.Machine(containerId)
	c.Assert(err, gc.IsNil)
	containers, err = container.Containers()
	c.Assert(err, gc.IsNil)
	c.Assert(containers, gc.DeepEquals, []string(nil))
	c.Assert(container.ContainerType(), gc.Equals, ctype)
}

func (s *AddMachineSuite) TestAddContainerToNewMachine(c *gc.C) {
	for i, ctype := range instance.SupportedContainerTypes {
		err := runAddMachine(c, fmt.Sprintf("%s", ctype))
		c.Assert(err, gc.IsNil)
		s._assertAddContainer(c, strconv.Itoa(i), fmt.Sprintf("%d/%s/0", i, ctype), ctype)
	}
}

func (s *AddMachineSuite) TestAddContainerToExistingMachine(c *gc.C) {
	err := runAddMachine(c)
	c.Assert(err, gc.IsNil)
	err = runAddMachine(c)
	c.Assert(err, gc.IsNil)
	for i, container := range instance.SupportedContainerTypes {
		err := runAddMachine(c, fmt.Sprintf("%s:1", container))
		c.Assert(err, gc.IsNil)
		s._assertAddContainer(c, "1", fmt.Sprintf("1/%s/%d", container, i), container)
	}
}

func (s *AddMachineSuite) TestAddMachineErrors(c *gc.C) {
	err := runAddMachine(c, ":lxc")
	c.Assert(err, gc.ErrorMatches, `malformed container argument ":lxc"`)
	err = runAddMachine(c, "lxc:")
	c.Assert(err, gc.ErrorMatches, `malformed container argument "lxc:"`)
	err = runAddMachine(c, "2")
	c.Assert(err, gc.ErrorMatches, `malformed container argument "2"`)
	err = runAddMachine(c, "foo")
	c.Assert(err, gc.ErrorMatches, `malformed container argument "foo"`)
	err = runAddMachine(c, "lxc", "--constraints", "container=lxc")
	c.Assert(err, gc.ErrorMatches, `container constraint "lxc" not allowed when adding a machine`)
}
<commit_msg>Again, loop happens more than once.<commit_after>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package main

import (
	"fmt"
	"strconv"

	gc "launchpad.net/gocheck"

	"launchpad.net/juju-core/constraints"
	"launchpad.net/juju-core/instance"
	jujutesting "launchpad.net/juju-core/juju/testing"
	"launchpad.net/juju-core/state"
	"launchpad.net/juju-core/testing"
	jc "launchpad.net/juju-core/testing/checkers"
)

type AddMachineSuite struct {
	jujutesting.RepoSuite
}

var _ = gc.Suite(&AddMachineSuite{})

func runAddMachine(c *gc.C, args ...string) error {
	_, err := testing.RunCommand(c, &AddMachineCommand{}, args)
	return err
}

func (s *AddMachineSuite) TestAddMachine(c *gc.C) {
	err := runAddMachine(c)
	c.Assert(err, gc.IsNil)
	m, err := s.State.Machine("0")
	c.Assert(err, gc.IsNil)
	c.Assert(m.Life(), gc.Equals, state.Alive)
	c.Assert(m.Series(), gc.DeepEquals, "precise")
	mcons, err := m.Constraints()
	c.Assert(err, gc.IsNil)
	c.Assert(&mcons, jc.Satisfies, constraints.IsEmpty)
}

func (s *AddMachineSuite) TestAddMachineWithSeries(c *gc.C) {
	err := runAddMachine(c, "--series", "series")
	c.Assert(err, gc.IsNil)
	m, err := s.State.Machine("0")
	c.Assert(err, gc.IsNil)
	c.Assert(m.Series(), gc.DeepEquals, "series")
}

func (s *AddMachineSuite) TestAddMachineWithConstraints(c *gc.C) {
	err := runAddMachine(c, "--constraints", "mem=4G")
	c.Assert(err, gc.IsNil)
	m, err := s.State.Machine("0")
	c.Assert(err, gc.IsNil)
	mcons, err := m.Constraints()
	c.Assert(err, gc.IsNil)
	expectedCons := constraints.MustParse("mem=4G")
	c.Assert(mcons, gc.DeepEquals, expectedCons)
}

func (s *AddMachineSuite) _assertAddContainer(c *gc.C, parentId, containerId string, ctype instance.ContainerType) {
	m, err := s.State.Machine(parentId)
	c.Assert(err, gc.IsNil)
	containers, err := m.Containers()
	c.Assert(err, gc.IsNil)
	c.Assert(containers, gc.DeepEquals, []string{containerId})
	container, err := s.State.Machine(containerId)
	c.Assert(err, gc.IsNil)
	containers, err = container.Containers()
	c.Assert(err, gc.IsNil)
	c.Assert(containers, gc.DeepEquals, []string(nil))
	c.Assert(container.ContainerType(), gc.Equals, ctype)
}

func (s *AddMachineSuite) TestAddContainerToNewMachine(c *gc.C) {
	for i, ctype := range instance.SupportedContainerTypes {
		err := runAddMachine(c, fmt.Sprintf("%s", ctype))
		c.Assert(err, gc.IsNil)
		s._assertAddContainer(c, strconv.Itoa(i), fmt.Sprintf("%d/%s/0", i, ctype), ctype)
	}
}

func (s *AddMachineSuite) TestAddContainerToExistingMachine(c *gc.C) {
	err := runAddMachine(c)
	c.Assert(err, gc.IsNil)
	for i, container := range instance.SupportedContainerTypes {
		machineNum := strconv.Itoa(i + 1)
		err = runAddMachine(c)
		c.Assert(err, gc.IsNil)
		err := runAddMachine(c, fmt.Sprintf("%s:%s", container, machineNum))
		c.Assert(err, gc.IsNil)
		s._assertAddContainer(c, machineNum, fmt.Sprintf("%s/%s/0", machineNum, container), container)
	}
}

func (s *AddMachineSuite) TestAddMachineErrors(c *gc.C) {
	err := runAddMachine(c, ":lxc")
	c.Assert(err, gc.ErrorMatches, `malformed container argument ":lxc"`)
	err = runAddMachine(c, "lxc:")
	c.Assert(err, gc.ErrorMatches, `malformed container argument "lxc:"`)
	err = runAddMachine(c, "2")
	c.Assert(err, gc.ErrorMatches, `malformed container argument "2"`)
	err = runAddMachine(c, "foo")
	c.Assert(err, gc.ErrorMatches, `malformed container argument "foo"`)
	err = runAddMachine(c, "lxc", "--constraints", "container=lxc")
	c.Assert(err, gc.ErrorMatches, `container constraint "lxc" not allowed when adding a machine`)
}
<|endoftext|>


<commit_before>// Copyright 2012-2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package service

import (
	"errors"
	"fmt"
	"regexp"

	"github.com/juju/cmd"
	"github.com/juju/names"
	"launchpad.net/gnuflag"

	"github.com/juju/juju/cmd/envcmd"
	"github.com/juju/juju/cmd/juju/block"
	"github.com/juju/juju/environs/config"
	"github.com/juju/juju/provider"
)

// UnitCommandBase provides support for commands which deploy units. It handles the parsing
// and validation of --to and --num-units arguments.
type UnitCommandBase struct {
	ToMachineSpec string
	NumUnits      int
}

func (c *UnitCommandBase) SetFlags(f *gnuflag.FlagSet) {
	f.IntVar(&c.NumUnits, "num-units", 1, "")
	f.StringVar(&c.ToMachineSpec, "to", "", "the machine or container to deploy the unit in, bypasses constraints")
}

func (c *UnitCommandBase) Init(args []string) error {
	if c.NumUnits < 1 {
		return errors.New("--num-units must be a positive integer")
	}
	if c.ToMachineSpec != "" {
		if c.NumUnits > 1 {
			return errors.New("cannot use --num-units > 1 with --to")
		}
		if !IsMachineOrNewContainer(c.ToMachineSpec) {
			return fmt.Errorf("invalid --to parameter %q", c.ToMachineSpec)
		}

	}
	return nil
}

// TODO(anastasiamac) 2014-10-20 Bug#1383116
// This exists to provide more context to the user about
// why they cannot allocate units to machine 0. Remove
// this when the local provider's machine 0 is a container.
// TODO(cherylj) Unexport CheckProvider once deploy is moved under service
func (c *UnitCommandBase) CheckProvider(conf *config.Config) error {
	if conf.Type() == provider.Local && c.ToMachineSpec == "0" {
		return errors.New("machine 0 is the state server for a local environment and cannot host units")
	}
	return nil
}

// TODO(cherylj) Unexport GetClientConfig once deploy is moved under service
var GetClientConfig = func(client ServiceAddUnitAPI) (*config.Config, error) {
	// Separated into a variable for easy overrides
	attrs, err := client.EnvironmentGet()
	if err != nil {
		return nil, err
	}

	return config.New(config.NoDefaults, attrs)
}

// AddUnitCommand is responsible adding additional units to a service.
type AddUnitCommand struct {
	envcmd.EnvCommandBase
	UnitCommandBase
	ServiceName string
	api         ServiceAddUnitAPI
}

const addUnitDoc = `
Adding units to an existing service is a way to scale out an environment by
deploying more instances of a service.  Add-unit must be called on services that
have already been deployed via juju deploy.

By default, services are deployed to newly provisioned machines.  Alternatively,
service units can be added to a specific existing machine using the --to
argument.

Examples:
 juju add-unit mysql -n 5          (Add 5 mysql units on 5 new machines)
 juju add-unit mysql --to 23       (Add a mysql unit to machine 23)
 juju add-unit mysql --to 24/lxc/3 (Add unit to lxc container 3 on host machine 24)
 juju add-unit mysql --to lxc:25   (Add unit to a new lxc container on host machine 25)
`

func (c *AddUnitCommand) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "add-unit",
		Args:    "<service name>",
		Purpose: "add one or more units of an already-deployed service",
		Doc:     addUnitDoc,
	}
}

func (c *AddUnitCommand) SetFlags(f *gnuflag.FlagSet) {
	c.UnitCommandBase.SetFlags(f)
	f.IntVar(&c.NumUnits, "n", 1, "number of service units to add")
}

func (c *AddUnitCommand) Init(args []string) error {
	switch len(args) {
	case 1:
		c.ServiceName = args[0]
	case 0:
		return errors.New("no service specified")
	}
	if err := cmd.CheckEmpty(args[1:]); err != nil {
		return err
	}
	return c.UnitCommandBase.Init(args)
}

// ServiceAddUnitAPI defines the methods on the client API
// that the service add-unit command calls.
type ServiceAddUnitAPI interface {
	Close() error
	AddServiceUnits(service string, numUnits int, machineSpec string) ([]string, error)
	EnvironmentGet() (map[string]interface{}, error)
}

func (c *AddUnitCommand) getAPI() (ServiceAddUnitAPI, error) {
	if c.api != nil {
		return c.api, nil
	}
	return c.NewAPIClient()
}

// Run connects to the environment specified on the command line
// and calls AddServiceUnits for the given service.
func (c *AddUnitCommand) Run(_ *cmd.Context) error {
	apiclient, err := c.getAPI()
	if err != nil {
		return err
	}
	defer apiclient.Close()

	conf, err := GetClientConfig(apiclient)
	if err != nil {
		return err
	}

	if err := c.CheckProvider(conf); err != nil {
		return err
	}

	_, err = apiclient.AddServiceUnits(c.ServiceName, c.NumUnits, c.ToMachineSpec)
	return block.ProcessBlockedError(err, block.BlockChange)
}

const (
	deployTarget = "^(" + names.ContainerTypeSnippet + ":)?" + names.MachineSnippet + "$"
)

var (
	validMachineOrNewContainer = regexp.MustCompile(deployTarget)
)

// IsMachineOrNewContainer returns whether spec is a valid machine id
// or new container definition.
func IsMachineOrNewContainer(spec string) bool {
	return validMachineOrNewContainer.MatchString(spec)
}
<commit_msg>Address review comments for service add-unit<commit_after>// Copyright 2012-2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package service

import (
	"errors"
	"fmt"
	"regexp"

	"github.com/juju/cmd"
	"github.com/juju/names"
	"launchpad.net/gnuflag"

	"github.com/juju/juju/cmd/envcmd"
	"github.com/juju/juju/cmd/juju/block"
	"github.com/juju/juju/environs/config"
	"github.com/juju/juju/provider"
)

// UnitCommandBase provides support for commands which deploy units. It handles the parsing
// and validation of --to and --num-units arguments.
type UnitCommandBase struct {
	ToMachineSpec string
	NumUnits      int
}

func (c *UnitCommandBase) SetFlags(f *gnuflag.FlagSet) {
	f.IntVar(&c.NumUnits, "num-units", 1, "")
	f.StringVar(&c.ToMachineSpec, "to", "", "the machine or container to deploy the unit in, bypasses constraints")
}

func (c *UnitCommandBase) Init(args []string) error {
	if c.NumUnits < 1 {
		return errors.New("--num-units must be a positive integer")
	}
	if c.ToMachineSpec != "" {
		if c.NumUnits > 1 {
			return errors.New("cannot use --num-units > 1 with --to")
		}
		if !IsMachineOrNewContainer(c.ToMachineSpec) {
			return fmt.Errorf("invalid --to parameter %q", c.ToMachineSpec)
		}

	}
	return nil
}

// TODO(anastasiamac) 2014-10-20 Bug#1383116
// This exists to provide more context to the user about
// why they cannot allocate units to machine 0. Remove
// this when the local provider's machine 0 is a container.
// TODO(cherylj) Unexport CheckProvider once deploy is moved under service
func (c *UnitCommandBase) CheckProvider(conf *config.Config) error {
	if conf.Type() == provider.Local && c.ToMachineSpec == "0" {
		return errors.New("machine 0 is the state server for a local environment and cannot host units")
	}
	return nil
}

// TODO(cherylj) Unexport GetClientConfig and make it a standard function
// once deploy is moved under service
var GetClientConfig = func(client ServiceAddUnitAPI) (*config.Config, error) {
	// Separated into a variable for easy overrides
	attrs, err := client.EnvironmentGet()
	if err != nil {
		return nil, err
	}

	return config.New(config.NoDefaults, attrs)
}

// AddUnitCommand is responsible adding additional units to a service.
type AddUnitCommand struct {
	envcmd.EnvCommandBase
	UnitCommandBase
	ServiceName string
	api         ServiceAddUnitAPI
}

const addUnitDoc = `
Adding units to an existing service is a way to scale out an environment by
deploying more instances of a service.  Add-unit must be called on services that
have already been deployed via juju deploy.

By default, services are deployed to newly provisioned machines.  Alternatively,
service units can be added to a specific existing machine using the --to
argument.

Examples:
 juju add-unit mysql -n 5          (Add 5 mysql units on 5 new machines)
 juju add-unit mysql --to 23       (Add a mysql unit to machine 23)
 juju add-unit mysql --to 24/lxc/3 (Add unit to lxc container 3 on host machine 24)
 juju add-unit mysql --to lxc:25   (Add unit to a new lxc container on host machine 25)
`

func (c *AddUnitCommand) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "add-unit",
		Args:    "<service name>",
		Purpose: "add one or more units of an already-deployed service",
		Doc:     addUnitDoc,
	}
}

func (c *AddUnitCommand) SetFlags(f *gnuflag.FlagSet) {
	c.UnitCommandBase.SetFlags(f)
	f.IntVar(&c.NumUnits, "n", 1, "number of service units to add")
}

func (c *AddUnitCommand) Init(args []string) error {
	switch len(args) {
	case 1:
		c.ServiceName = args[0]
	case 0:
		return errors.New("no service specified")
	}
	if err := cmd.CheckEmpty(args[1:]); err != nil {
		return err
	}
	return c.UnitCommandBase.Init(args)
}

// ServiceAddUnitAPI defines the methods on the client API
// that the service add-unit command calls.
type ServiceAddUnitAPI interface {
	Close() error
	AddServiceUnits(service string, numUnits int, machineSpec string) ([]string, error)
	EnvironmentGet() (map[string]interface{}, error)
}

func (c *AddUnitCommand) getAPI() (ServiceAddUnitAPI, error) {
	if c.api != nil {
		return c.api, nil
	}
	return c.NewAPIClient()
}

// Run connects to the environment specified on the command line
// and calls AddServiceUnits for the given service.
func (c *AddUnitCommand) Run(_ *cmd.Context) error {
	apiclient, err := c.getAPI()
	if err != nil {
		return err
	}
	defer apiclient.Close()

	conf, err := GetClientConfig(apiclient)
	if err != nil {
		return err
	}

	if err := c.CheckProvider(conf); err != nil {
		return err
	}

	_, err = apiclient.AddServiceUnits(c.ServiceName, c.NumUnits, c.ToMachineSpec)
	return block.ProcessBlockedError(err, block.BlockChange)
}

// deployTarget describes the format a machine or container target must match to be valid.
const deployTarget = "^(" + names.ContainerTypeSnippet + ":)?" + names.MachineSnippet + "$"

var validMachineOrNewContainer = regexp.MustCompile(deployTarget)

// IsMachineOrNewContainer returns whether spec is a valid machine id
// or new container definition.
func IsMachineOrNewContainer(spec string) bool {
	return validMachineOrNewContainer.MatchString(spec)
}
<|endoftext|>


<commit_before>// Copyright 2017 Istio Authors
//
// 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"
	"os"
	"time"

	"github.com/davecgh/go-spew/spew"
	"github.com/golang/glog"
	multierror "github.com/hashicorp/go-multierror"
	"github.com/spf13/cobra"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	proxyconfig "istio.io/api/proxy/v1/config"
	"istio.io/pilot/adapter/config/aggregate"
	"istio.io/pilot/adapter/config/crd"
	"istio.io/pilot/adapter/config/ingress"
	"istio.io/pilot/cmd"
	"istio.io/pilot/model"
	"istio.io/pilot/platform"
	"istio.io/pilot/platform/consul"
	"istio.io/pilot/platform/kube"
	"istio.io/pilot/proxy"
	"istio.io/pilot/proxy/envoy"
	"istio.io/pilot/tools/version"
)

// ConsulArgs store the args related to Consul configuration
type ConsulArgs struct {
	config    string
	serverURL string
}

type args struct {
	kubeconfig string
	meshconfig string

	// ingress sync mode is set to off by default
	controllerOptions kube.ControllerOptions
	discoveryOptions  envoy.DiscoveryServiceOptions

	serviceregistry platform.ServiceRegistry
	consulargs      ConsulArgs
}

var (
	flags args

	rootCmd = &cobra.Command{
		Use:   "pilot",
		Short: "Istio Pilot",
		Long:  "Istio Pilot provides management plane functionality to the Istio service mesh and Istio Mixer.",
	}

	discoveryCmd = &cobra.Command{
		Use:   "discovery",
		Short: "Start Istio proxy discovery service",
		RunE: func(c *cobra.Command, args []string) error {

			// receive mesh configuration
			mesh, fail := cmd.ReadMeshConfig(flags.meshconfig)
			if fail != nil {
				defaultMesh := proxy.DefaultMeshConfig()
				mesh = &defaultMesh
				glog.Warningf("failed to read mesh configuration, using default: %v", fail)
			}
			glog.V(2).Infof("mesh configuration %s", spew.Sdump(mesh))
			glog.V(2).Infof("version %s", version.Line())
			glog.V(2).Infof("flags %s", spew.Sdump(flags))

			var serviceController model.Controller
			var configController model.ConfigStoreCache
			environment := proxy.Environment{
				Mesh: mesh,
			}

			stop := make(chan struct{})

			configClient, err := crd.NewClient(flags.kubeconfig, model.ConfigDescriptor{
				model.RouteRule,
				model.EgressRule,
				model.DestinationPolicy,
			}, flags.controllerOptions.DomainSuffix)
			if err != nil {
				return multierror.Prefix(err, "failed to open a config client.")
			}

			if err = configClient.RegisterResources(); err != nil {
				return multierror.Prefix(err, "failed to register custom resources.")
			}

			// Set up values for input to discovery service in different platforms
			if flags.serviceregistry == platform.KubernetesRegistry || flags.serviceregistry == "" {
				_, client, kuberr := kube.CreateInterface(flags.kubeconfig)
				if kuberr != nil {
					return multierror.Prefix(kuberr, "failed to connect to Kubernetes API.")
				}

				if flags.controllerOptions.Namespace == "" {
					flags.controllerOptions.Namespace = os.Getenv("POD_NAMESPACE")
				}

				kubeController := kube.NewController(client, mesh, flags.controllerOptions)
				if mesh.IngressControllerMode == proxyconfig.ProxyMeshConfig_OFF {
					configController = crd.NewController(configClient, flags.controllerOptions)
				} else {
					configController, err = aggregate.MakeCache([]model.ConfigStoreCache{
						crd.NewController(configClient, flags.controllerOptions),
						ingress.NewController(client, mesh, flags.controllerOptions),
					})
					if err != nil {
						return err
					}
				}

				environment.ServiceDiscovery = kubeController
				environment.ServiceAccounts = kubeController
				environment.IstioConfigStore = model.MakeIstioStore(configController)
				serviceController = kubeController
				ingressSyncer := ingress.NewStatusSyncer(mesh, client, flags.controllerOptions)

				go ingressSyncer.Run(stop)
			} else if flags.serviceregistry == platform.ConsulRegistry {
				glog.V(2).Infof("Consul url: %v", flags.consulargs.serverURL)

				consulController, conerr := consul.NewController(
					flags.consulargs.serverURL, "dc1", 2*time.Second)
				if conerr != nil {
					return fmt.Errorf("failed to create Consul controller: %v", conerr)
				}

				configController = crd.NewController(configClient, flags.controllerOptions)

				environment.ServiceDiscovery = consulController
				environment.ServiceAccounts = consulController
				environment.IstioConfigStore = model.MakeIstioStore(configController)
				serviceController = consulController
			}

			// Set up discovery service
			discovery, err := envoy.NewDiscoveryService(
				serviceController,
				configController,
				environment,
				flags.discoveryOptions)
			if err != nil {
				return fmt.Errorf("failed to create discovery service: %v", err)
			}

			go serviceController.Run(stop)
			go configController.Run(stop)
			go discovery.Run()
			cmd.WaitSignal(stop)
			return nil
		},
	}
)

func init() {
	discoveryCmd.PersistentFlags().StringVar((*string)(&flags.serviceregistry), "serviceregistry",
		string(platform.KubernetesRegistry),
		fmt.Sprintf("Select the platform for service registry, options are {%s, %s}",
			string(platform.KubernetesRegistry), string(platform.ConsulRegistry)))
	discoveryCmd.PersistentFlags().StringVar(&flags.kubeconfig, "kubeconfig", "",
		"Use a Kubernetes configuration file instead of in-cluster configuration")
	discoveryCmd.PersistentFlags().StringVar(&flags.meshconfig, "meshConfig", "/etc/istio/config/mesh",
		fmt.Sprintf("File name for Istio mesh configuration"))
	discoveryCmd.PersistentFlags().StringVarP(&flags.controllerOptions.Namespace, "namespace", "n", "",
		"Select a namespace for the controller loop. If not set, uses ${POD_NAMESPACE} environment variable")
	discoveryCmd.PersistentFlags().StringVarP(&flags.controllerOptions.WatchedNamespace, "app namespace",
		"a", metav1.NamespaceAll,
		"Restrict the applications namespace the controller manages; if not set, controller watches all namespaces")
	discoveryCmd.PersistentFlags().DurationVar(&flags.controllerOptions.ResyncPeriod, "resync", time.Second,
		"Controller resync interval")
	discoveryCmd.PersistentFlags().StringVar(&flags.controllerOptions.DomainSuffix, "domain", "cluster.local",
		"DNS domain suffix")

	discoveryCmd.PersistentFlags().IntVar(&flags.discoveryOptions.Port, "port", 8080,
		"Discovery service port")
	discoveryCmd.PersistentFlags().BoolVar(&flags.discoveryOptions.EnableProfiling, "profile", true,
		"Enable profiling via web interface host:port/debug/pprof")
	discoveryCmd.PersistentFlags().BoolVar(&flags.discoveryOptions.EnableCaching, "discovery_cache", true,
		"Enable caching discovery service responses")
	discoveryCmd.PersistentFlags().StringVar(&flags.consulargs.config, "consulconfig", "",
		"Consul Config file for discovery")
	discoveryCmd.PersistentFlags().StringVar(&flags.consulargs.serverURL, "consulserverURL", "",
		"URL for the consul server")

	cmd.AddFlags(rootCmd)

	rootCmd.AddCommand(discoveryCmd)
	rootCmd.AddCommand(cmd.VersionCmd)
}

func main() {
	if err := rootCmd.Execute(); err != nil {
		glog.Error(err)
		os.Exit(-1)
	}
}
<commit_msg>Increase default ResyncPeriod from 1 to 30 seconds (#1195)<commit_after>// Copyright 2017 Istio Authors
//
// 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"
	"os"
	"time"

	"github.com/davecgh/go-spew/spew"
	"github.com/golang/glog"
	multierror "github.com/hashicorp/go-multierror"
	"github.com/spf13/cobra"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	proxyconfig "istio.io/api/proxy/v1/config"
	"istio.io/pilot/adapter/config/aggregate"
	"istio.io/pilot/adapter/config/crd"
	"istio.io/pilot/adapter/config/ingress"
	"istio.io/pilot/cmd"
	"istio.io/pilot/model"
	"istio.io/pilot/platform"
	"istio.io/pilot/platform/consul"
	"istio.io/pilot/platform/kube"
	"istio.io/pilot/proxy"
	"istio.io/pilot/proxy/envoy"
	"istio.io/pilot/tools/version"
)

// ConsulArgs store the args related to Consul configuration
type ConsulArgs struct {
	config    string
	serverURL string
}

type args struct {
	kubeconfig string
	meshconfig string

	// ingress sync mode is set to off by default
	controllerOptions kube.ControllerOptions
	discoveryOptions  envoy.DiscoveryServiceOptions

	serviceregistry platform.ServiceRegistry
	consulargs      ConsulArgs
}

var (
	flags args

	rootCmd = &cobra.Command{
		Use:   "pilot",
		Short: "Istio Pilot",
		Long:  "Istio Pilot provides management plane functionality to the Istio service mesh and Istio Mixer.",
	}

	discoveryCmd = &cobra.Command{
		Use:   "discovery",
		Short: "Start Istio proxy discovery service",
		RunE: func(c *cobra.Command, args []string) error {

			// receive mesh configuration
			mesh, fail := cmd.ReadMeshConfig(flags.meshconfig)
			if fail != nil {
				defaultMesh := proxy.DefaultMeshConfig()
				mesh = &defaultMesh
				glog.Warningf("failed to read mesh configuration, using default: %v", fail)
			}
			glog.V(2).Infof("mesh configuration %s", spew.Sdump(mesh))
			glog.V(2).Infof("version %s", version.Line())
			glog.V(2).Infof("flags %s", spew.Sdump(flags))

			var serviceController model.Controller
			var configController model.ConfigStoreCache
			environment := proxy.Environment{
				Mesh: mesh,
			}

			stop := make(chan struct{})

			configClient, err := crd.NewClient(flags.kubeconfig, model.ConfigDescriptor{
				model.RouteRule,
				model.EgressRule,
				model.DestinationPolicy,
			}, flags.controllerOptions.DomainSuffix)
			if err != nil {
				return multierror.Prefix(err, "failed to open a config client.")
			}

			if err = configClient.RegisterResources(); err != nil {
				return multierror.Prefix(err, "failed to register custom resources.")
			}

			// Set up values for input to discovery service in different platforms
			if flags.serviceregistry == platform.KubernetesRegistry || flags.serviceregistry == "" {
				_, client, kuberr := kube.CreateInterface(flags.kubeconfig)
				if kuberr != nil {
					return multierror.Prefix(kuberr, "failed to connect to Kubernetes API.")
				}

				if flags.controllerOptions.Namespace == "" {
					flags.controllerOptions.Namespace = os.Getenv("POD_NAMESPACE")
				}

				kubeController := kube.NewController(client, mesh, flags.controllerOptions)
				if mesh.IngressControllerMode == proxyconfig.ProxyMeshConfig_OFF {
					configController = crd.NewController(configClient, flags.controllerOptions)
				} else {
					configController, err = aggregate.MakeCache([]model.ConfigStoreCache{
						crd.NewController(configClient, flags.controllerOptions),
						ingress.NewController(client, mesh, flags.controllerOptions),
					})
					if err != nil {
						return err
					}
				}

				environment.ServiceDiscovery = kubeController
				environment.ServiceAccounts = kubeController
				environment.IstioConfigStore = model.MakeIstioStore(configController)
				serviceController = kubeController
				ingressSyncer := ingress.NewStatusSyncer(mesh, client, flags.controllerOptions)

				go ingressSyncer.Run(stop)
			} else if flags.serviceregistry == platform.ConsulRegistry {
				glog.V(2).Infof("Consul url: %v", flags.consulargs.serverURL)

				consulController, conerr := consul.NewController(
					flags.consulargs.serverURL, "dc1", 2*time.Second)
				if conerr != nil {
					return fmt.Errorf("failed to create Consul controller: %v", conerr)
				}

				configController = crd.NewController(configClient, flags.controllerOptions)

				environment.ServiceDiscovery = consulController
				environment.ServiceAccounts = consulController
				environment.IstioConfigStore = model.MakeIstioStore(configController)
				serviceController = consulController
			}

			// Set up discovery service
			discovery, err := envoy.NewDiscoveryService(
				serviceController,
				configController,
				environment,
				flags.discoveryOptions)
			if err != nil {
				return fmt.Errorf("failed to create discovery service: %v", err)
			}

			go serviceController.Run(stop)
			go configController.Run(stop)
			go discovery.Run()
			cmd.WaitSignal(stop)
			return nil
		},
	}
)

func init() {
	discoveryCmd.PersistentFlags().StringVar((*string)(&flags.serviceregistry), "serviceregistry",
		string(platform.KubernetesRegistry),
		fmt.Sprintf("Select the platform for service registry, options are {%s, %s}",
			string(platform.KubernetesRegistry), string(platform.ConsulRegistry)))
	discoveryCmd.PersistentFlags().StringVar(&flags.kubeconfig, "kubeconfig", "",
		"Use a Kubernetes configuration file instead of in-cluster configuration")
	discoveryCmd.PersistentFlags().StringVar(&flags.meshconfig, "meshConfig", "/etc/istio/config/mesh",
		fmt.Sprintf("File name for Istio mesh configuration"))
	discoveryCmd.PersistentFlags().StringVarP(&flags.controllerOptions.Namespace, "namespace", "n", "",
		"Select a namespace for the controller loop. If not set, uses ${POD_NAMESPACE} environment variable")
	discoveryCmd.PersistentFlags().StringVarP(&flags.controllerOptions.WatchedNamespace, "app namespace",
		"a", metav1.NamespaceAll,
		"Restrict the applications namespace the controller manages; if not set, controller watches all namespaces")
	discoveryCmd.PersistentFlags().DurationVar(&flags.controllerOptions.ResyncPeriod, "resync", 60*time.Second,
		"Controller resync interval")
	discoveryCmd.PersistentFlags().StringVar(&flags.controllerOptions.DomainSuffix, "domain", "cluster.local",
		"DNS domain suffix")

	discoveryCmd.PersistentFlags().IntVar(&flags.discoveryOptions.Port, "port", 8080,
		"Discovery service port")
	discoveryCmd.PersistentFlags().BoolVar(&flags.discoveryOptions.EnableProfiling, "profile", true,
		"Enable profiling via web interface host:port/debug/pprof")
	discoveryCmd.PersistentFlags().BoolVar(&flags.discoveryOptions.EnableCaching, "discovery_cache", true,
		"Enable caching discovery service responses")
	discoveryCmd.PersistentFlags().StringVar(&flags.consulargs.config, "consulconfig", "",
		"Consul Config file for discovery")
	discoveryCmd.PersistentFlags().StringVar(&flags.consulargs.serverURL, "consulserverURL", "",
		"URL for the consul server")

	cmd.AddFlags(rootCmd)

	rootCmd.AddCommand(discoveryCmd)
	rootCmd.AddCommand(cmd.VersionCmd)
}

func main() {
	if err := rootCmd.Execute(); err != nil {
		glog.Error(err)
		os.Exit(-1)
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2018 The Skaffold Authors

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 cmd

import (
	"context"
	"fmt"
	"io"
	"os"
	"strings"

	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/config"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/constants"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/update"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/version"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
)

var (
	opts      = &config.SkaffoldOptions{}
	v         string
	overwrite bool

	updateMsg = make(chan string)
)

var rootCmd = &cobra.Command{
	Use:   "skaffold",
	Short: "A tool that facilitates continuous development for Kubernetes applications.",
}

func NewSkaffoldCommand(out, err io.Writer) *cobra.Command {
	rootCmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
		if err := SetUpLogs(err, v); err != nil {
			return err
		}
		rootCmd.SilenceUsage = true
		logrus.Infof("Skaffold %+v", version.Get())
		go func() {
			if err := updateCheck(updateMsg); err != nil {
				logrus.Infof("update check failed: %s", err)
			}
		}()
		return nil
	}

	rootCmd.PersistentPostRun = func(cmd *cobra.Command, args []string) {
		select {
		case msg := <-updateMsg:
			fmt.Fprintf(out, "%s\n", msg)
		default:
		}
	}

	rootCmd.SilenceErrors = true
	rootCmd.AddCommand(NewCmdCompletion(out))
	rootCmd.AddCommand(NewCmdVersion(out))
	rootCmd.AddCommand(NewCmdRun(out))
	rootCmd.AddCommand(NewCmdDev(out))
	rootCmd.AddCommand(NewCmdBuild(out))
	rootCmd.AddCommand(NewCmdDeploy(out))
	rootCmd.AddCommand(NewCmdDelete(out))
	rootCmd.AddCommand(NewCmdFix(out))
	rootCmd.AddCommand(NewCmdConfig(out))
	rootCmd.AddCommand(NewCmdInit(out))

	rootCmd.PersistentFlags().StringVarP(&v, "verbosity", "v", constants.DefaultLogLevel.String(), "Log level (debug, info, warn, error, fatal, panic")

	setFlagsFromEnvVariables(rootCmd.Commands())

	return rootCmd
}

func updateCheck(ch chan string) error {
	if quietFlag {
		logrus.Debugf("Update check is disabled because of quiet mode")
		return nil
	}
	if !update.IsUpdateCheckEnabled() {
		logrus.Debugf("Update check not enabled, skipping.")
		return nil
	}
	current, err := version.ParseVersion(version.Get().Version)
	if err != nil {
		return errors.Wrap(err, "parsing current semver, skipping update check")
	}
	latest, err := update.GetLatestVersion(context.Background())
	if err != nil {
		return errors.Wrap(err, "getting latest version")
	}
	if latest.GT(current) {
		ch <- fmt.Sprintf("There is a new version (%s) of skaffold available. Download it at %s\n", latest, constants.LatestDownloadURL)
	}
	return nil
}

// Each flag can also be set with an env variable whose name starts with `SKAFFOLD_`.
func setFlagsFromEnvVariables(commands []*cobra.Command) {
	for _, cmd := range commands {
		cmd.Flags().VisitAll(func(f *pflag.Flag) {
			// special case for backward compatibility.
			if f.Name == "namespace" {
				if val, present := os.LookupEnv("SKAFFOLD_DEPLOY_NAMESPACE"); present {
					logrus.Warnln("Using SKAFFOLD_DEPLOY_NAMESPACE env variable is deprecated. Please use SKAFFOLD_NAMESPACE instead.")
					cmd.Flags().Set(f.Name, val)
				}
			}

			envVar := fmt.Sprintf("SKAFFOLD_%s", strings.Replace(strings.ToUpper(f.Name), "-", "_", -1))
			if val, present := os.LookupEnv(envVar); present {
				cmd.Flags().Set(f.Name, val)
			}
		})
	}
}

func AddDevFlags(cmd *cobra.Command) {
	cmd.Flags().BoolVar(&opts.Cleanup, "cleanup", true, "Delete deployments after dev mode is interrupted")
	cmd.Flags().StringArrayVarP(&opts.Watch, "watch-image", "w", nil, "Choose which artifacts to watch. Artifacts with image names that contain the expression will be watched only. Default is to watch sources for all artifacts.")
	cmd.Flags().IntVarP(&opts.WatchPollInterval, "watch-poll-interval", "i", 1000, "Interval (in ms) between two checks for file changes.")
	cmd.Flags().BoolVar(&opts.PortForward, "port-forward", true, "Port-forward exposed container ports within pods")
}

func AddRunDeployFlags(cmd *cobra.Command) {
	cmd.Flags().BoolVar(&opts.Tail, "tail", false, "Stream logs from deployed objects")
}

func AddRunDevFlags(cmd *cobra.Command) {
	cmd.Flags().StringVarP(&opts.ConfigurationFile, "filename", "f", "skaffold.yaml", "Filename or URL to the pipeline file")
	cmd.Flags().BoolVar(&opts.Notification, "toot", false, "Emit a terminal beep after the deploy is complete")
	cmd.Flags().StringArrayVarP(&opts.Profiles, "profile", "p", nil, "Activate profiles by name")
	cmd.Flags().StringVarP(&opts.Namespace, "namespace", "n", "", "Run Helm deployments in the specified namespace")
}

func AddFixFlags(cmd *cobra.Command) {
	cmd.Flags().StringVarP(&opts.ConfigurationFile, "filename", "f", "skaffold.yaml", "Filename or URL to the pipeline file")
	cmd.Flags().BoolVar(&overwrite, "overwrite", false, "Overwrite original config with fixed config")
}

func SetUpLogs(out io.Writer, level string) error {
	logrus.SetOutput(out)
	lvl, err := logrus.ParseLevel(v)
	if err != nil {
		return errors.Wrap(err, "parsing log level")
	}
	logrus.SetLevel(lvl)
	return nil
}
<commit_msg>Fix missing parenthesis<commit_after>/*
Copyright 2018 The Skaffold Authors

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 cmd

import (
	"context"
	"fmt"
	"io"
	"os"
	"strings"

	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/config"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/constants"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/update"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/version"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
)

var (
	opts      = &config.SkaffoldOptions{}
	v         string
	overwrite bool

	updateMsg = make(chan string)
)

var rootCmd = &cobra.Command{
	Use:   "skaffold",
	Short: "A tool that facilitates continuous development for Kubernetes applications.",
}

func NewSkaffoldCommand(out, err io.Writer) *cobra.Command {
	rootCmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
		if err := SetUpLogs(err, v); err != nil {
			return err
		}
		rootCmd.SilenceUsage = true
		logrus.Infof("Skaffold %+v", version.Get())
		go func() {
			if err := updateCheck(updateMsg); err != nil {
				logrus.Infof("update check failed: %s", err)
			}
		}()
		return nil
	}

	rootCmd.PersistentPostRun = func(cmd *cobra.Command, args []string) {
		select {
		case msg := <-updateMsg:
			fmt.Fprintf(out, "%s\n", msg)
		default:
		}
	}

	rootCmd.SilenceErrors = true
	rootCmd.AddCommand(NewCmdCompletion(out))
	rootCmd.AddCommand(NewCmdVersion(out))
	rootCmd.AddCommand(NewCmdRun(out))
	rootCmd.AddCommand(NewCmdDev(out))
	rootCmd.AddCommand(NewCmdBuild(out))
	rootCmd.AddCommand(NewCmdDeploy(out))
	rootCmd.AddCommand(NewCmdDelete(out))
	rootCmd.AddCommand(NewCmdFix(out))
	rootCmd.AddCommand(NewCmdConfig(out))
	rootCmd.AddCommand(NewCmdInit(out))

	rootCmd.PersistentFlags().StringVarP(&v, "verbosity", "v", constants.DefaultLogLevel.String(), "Log level (debug, info, warn, error, fatal, panic)")

	setFlagsFromEnvVariables(rootCmd.Commands())

	return rootCmd
}

func updateCheck(ch chan string) error {
	if quietFlag {
		logrus.Debugf("Update check is disabled because of quiet mode")
		return nil
	}
	if !update.IsUpdateCheckEnabled() {
		logrus.Debugf("Update check not enabled, skipping.")
		return nil
	}
	current, err := version.ParseVersion(version.Get().Version)
	if err != nil {
		return errors.Wrap(err, "parsing current semver, skipping update check")
	}
	latest, err := update.GetLatestVersion(context.Background())
	if err != nil {
		return errors.Wrap(err, "getting latest version")
	}
	if latest.GT(current) {
		ch <- fmt.Sprintf("There is a new version (%s) of skaffold available. Download it at %s\n", latest, constants.LatestDownloadURL)
	}
	return nil
}

// Each flag can also be set with an env variable whose name starts with `SKAFFOLD_`.
func setFlagsFromEnvVariables(commands []*cobra.Command) {
	for _, cmd := range commands {
		cmd.Flags().VisitAll(func(f *pflag.Flag) {
			// special case for backward compatibility.
			if f.Name == "namespace" {
				if val, present := os.LookupEnv("SKAFFOLD_DEPLOY_NAMESPACE"); present {
					logrus.Warnln("Using SKAFFOLD_DEPLOY_NAMESPACE env variable is deprecated. Please use SKAFFOLD_NAMESPACE instead.")
					cmd.Flags().Set(f.Name, val)
				}
			}

			envVar := fmt.Sprintf("SKAFFOLD_%s", strings.Replace(strings.ToUpper(f.Name), "-", "_", -1))
			if val, present := os.LookupEnv(envVar); present {
				cmd.Flags().Set(f.Name, val)
			}
		})
	}
}

func AddDevFlags(cmd *cobra.Command) {
	cmd.Flags().BoolVar(&opts.Cleanup, "cleanup", true, "Delete deployments after dev mode is interrupted")
	cmd.Flags().StringArrayVarP(&opts.Watch, "watch-image", "w", nil, "Choose which artifacts to watch. Artifacts with image names that contain the expression will be watched only. Default is to watch sources for all artifacts.")
	cmd.Flags().IntVarP(&opts.WatchPollInterval, "watch-poll-interval", "i", 1000, "Interval (in ms) between two checks for file changes.")
	cmd.Flags().BoolVar(&opts.PortForward, "port-forward", true, "Port-forward exposed container ports within pods")
}

func AddRunDeployFlags(cmd *cobra.Command) {
	cmd.Flags().BoolVar(&opts.Tail, "tail", false, "Stream logs from deployed objects")
}

func AddRunDevFlags(cmd *cobra.Command) {
	cmd.Flags().StringVarP(&opts.ConfigurationFile, "filename", "f", "skaffold.yaml", "Filename or URL to the pipeline file")
	cmd.Flags().BoolVar(&opts.Notification, "toot", false, "Emit a terminal beep after the deploy is complete")
	cmd.Flags().StringArrayVarP(&opts.Profiles, "profile", "p", nil, "Activate profiles by name")
	cmd.Flags().StringVarP(&opts.Namespace, "namespace", "n", "", "Run Helm deployments in the specified namespace")
}

func AddFixFlags(cmd *cobra.Command) {
	cmd.Flags().StringVarP(&opts.ConfigurationFile, "filename", "f", "skaffold.yaml", "Filename or URL to the pipeline file")
	cmd.Flags().BoolVar(&overwrite, "overwrite", false, "Overwrite original config with fixed config")
}

func SetUpLogs(out io.Writer, level string) error {
	logrus.SetOutput(out)
	lvl, err := logrus.ParseLevel(v)
	if err != nil {
		return errors.Wrap(err, "parsing log level")
	}
	logrus.SetLevel(lvl)
	return nil
}
<|endoftext|>


<commit_before>// +build windows
// This file is compiled only on windows. It contains paths used by the windows
// browser bundle.
// http://golang.org/pkg/go/build/#hdr-Build_Constraints

package main

const (
	firefoxPath        string = "Browser/firefox.exe"
	firefoxProfilePath        = "Data/Browser/profile.meek-http-helper"
)
<commit_msg>Remove a useless type.<commit_after>// +build windows
// This file is compiled only on windows. It contains paths used by the windows
// browser bundle.
// http://golang.org/pkg/go/build/#hdr-Build_Constraints

package main

const (
	firefoxPath        = "Browser/firefox.exe"
	firefoxProfilePath = "Data/Browser/profile.meek-http-helper"
)
<|endoftext|>


<commit_before>package lrserver_test

import (
	"github.com/jaschaephraim/lrserver"
	"golang.org/x/exp/fsnotify"
	"log"
	"net/http"
)

// html includes the client JavaScript
const html = `<!doctype html>
<html>
<head>
  <title>Example</title>
<body>
  <script src="http://localhost:35729/livereload.js"></script>
</body>
</html>`

func Example() {
	// Create file watcher
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		log.Fatalln(err)
	}
	defer watcher.Close()

	// Add dir to watcher
	err = watcher.Add("/path/to/watched/dir")
	if err != nil {
		log.Fatalln(err)
	}

	// Start LiveReload server
	go lrserver.ListenAndServe()

	// Start goroutine that requests reload upon watcher event
	go func() {
		for {
			event := <-watcher.Events
			lrserver.Reload(event.Name)
		}
	}()

	// Start serving html
	http.HandleFunc("/", func(rw http.ResponseWriter, req *http.Request) {
		rw.Write([]byte(html))
	})
	http.ListenAndServe(":3000", nil)
}
<commit_msg>Update use of fsnotify in example<commit_after>package lrserver_test

import (
	"github.com/jaschaephraim/lrserver"
	"golang.org/x/exp/fsnotify"
	"log"
	"net/http"
)

// html includes the client JavaScript
const html = `<!doctype html>
<html>
<head>
  <title>Example</title>
</head>
<body>
  <script src="http://localhost:35729/livereload.js"></script>
</body>
</html>`

func Example() {
	// Create file watcher
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		log.Fatalln(err)
	}
	defer watcher.Close()

	// Watch dir
	err = watcher.Watch("/path/to/watched/dir")
	if err != nil {
		log.Fatalln(err)
	}

	// Start LiveReload server
	go lrserver.ListenAndServe()

	// Start goroutine that requests reload upon watcher event
	go func() {
		for {
			event := <-watcher.Event
			lrserver.Reload(event.Name)
		}
	}()

	// Start serving html
	http.HandleFunc("/", func(rw http.ResponseWriter, req *http.Request) {
		rw.Write([]byte(html))
	})
	http.ListenAndServe(":3000", nil)
}
<|endoftext|>


<commit_before>package rx_test

import (
	"fmt"
	"time"

	"github.com/reactivego/rx"
)

func ExampleObservable_ConcatWith() {
	oa := rx.From(0, 1, 2, 3)
	ob := rx.From(4, 5)
	oc := rx.From(6)
	od := rx.From(7, 8, 9)
	oa.ConcatWith(ob, oc).ConcatWith(od).Subscribe(func(next interface{}, err error, done bool) {
		switch {
		case !done:
			fmt.Printf("%d,", next.(int))
		case err != nil:
			fmt.Print("err", err)
		default:
			fmt.Printf("complete")
		}
	}).Wait()

	// Output:
	// 0,1,2,3,4,5,6,7,8,9,complete
}

func ExampleObservable_Defer() {
	count := 0
	source := rx.Defer(func() rx.Observable {
		return rx.From(count)
	})
	mapped := source.Map(func(next interface{}) interface{} {
		return fmt.Sprintf("observable %d", next)
	})

	mapped.Println()
	count = 123
	mapped.Println()
	count = 456
	mapped.Println()

	// Output:
	// observable 0
	// observable 123
	// observable 456
}

func ExampleObservable_Do() {
	rx.From(1, 2, 3).Do(func(v interface{}) {
		fmt.Println(v.(int))
	}).Wait()

	// Output:
	// 1
	// 2
	// 3
}

func ExampleObservable_Filter() {
	even := func(i interface{}) bool {
		return i.(int)%2 == 0
	}

	rx.From(1, 2, 3, 4, 5, 6, 7, 8).Filter(even).Println()

	// Output:
	// 2
	// 4
	// 6
	// 8
}

func ExampleFromChan() {
	ch := make(chan interface{}, 6)
	for i := 0; i < 5; i++ {
		ch <- i + 1
	}
	close(ch)

	rx.FromChan(ch).Println()

	// Output:
	// 1
	// 2
	// 3
	// 4
	// 5
}

func ExampleFrom() {
	rx.From(1, 2, 3, 4, 5).Println()

	// Output:
	// 1
	// 2
	// 3
	// 4
	// 5
}

func ExampleFromSlice() {
	rx.From([]interface{}{1, 2, 3, 4, 5}...).Println()

	// Output:
	// 1
	// 2
	// 3
	// 4
	// 5
}

func ExampleObservable_Map() {
	rx.From(1, 2, 3, 4).Map(func(i interface{}) interface{} {
		return fmt.Sprintf("%d!", i.(int))
	}).Println()

	// Output:
	// 1!
	// 2!
	// 3!
	// 4!
}

func ExampleObservable_MergeMap() {
	source := rx.From(1, 2).
		MergeMap(func(n interface{}) rx.Observable {
			return rx.Range(n.(int), 2).AsObservable()
		})
	if err := source.Println(); err != nil {
		panic(err)
	}

	// Output:
	// 1
	// 2
	// 2
	// 3
}

func ExampleObservable_Scan() {
	add := func(acc interface{}, value interface{}) interface{} {
		return acc.(int) + value.(int)
	}

	rx.From(1, 2, 3, 4, 5).Scan(add, 0).Println()

	// Output:
	// 1
	// 3
	// 6
	// 10
	// 15
}

func ExampleObservableObservable_SwitchAll() {
	// intToObs creates a new observable that emits an integer starting after and then repeated every 20 milliseconds
	// in the range starting at 0 and incrementing by 1. It takes only the first 10 emitted values and then uses
	// AsObservable to convert the IntObservable back to an untyped Observable.
	intToObs := func(i int) rx.Observable {
		return rx.Interval(20 * time.Millisecond).
			Take(10).
			AsObservable()
	}

	rx.Interval(100 * time.Millisecond).
		Take(3).
		MapObservable(intToObs).
		SwitchAll().
		Println()

	// Output:
	// 0
	// 1
	// 2
	// 3
	// 0
	// 1
	// 2
	// 3
	// 0
	// 1
	// 2
	// 3
	// 4
	// 5
	// 6
	// 7
	// 8
	// 9
}
<commit_msg>Fix names of examples for godoc.<commit_after>package rx_test

import (
	"fmt"
	"time"

	"github.com/reactivego/rx"
)

func ExampleObservable_ConcatWith() {
	oa := rx.From(0, 1, 2, 3)
	ob := rx.From(4, 5)
	oc := rx.From(6)
	od := rx.From(7, 8, 9)
	oa.ConcatWith(ob, oc).ConcatWith(od).Subscribe(func(next interface{}, err error, done bool) {
		switch {
		case !done:
			fmt.Printf("%d,", next.(int))
		case err != nil:
			fmt.Print("err", err)
		default:
			fmt.Printf("complete")
		}
	}).Wait()

	// Output:
	// 0,1,2,3,4,5,6,7,8,9,complete
}

func ExampleDefer() {
	count := 0
	source := rx.Defer(func() rx.Observable {
		return rx.From(count)
	})
	mapped := source.Map(func(next interface{}) interface{} {
		return fmt.Sprintf("observable %d", next)
	})

	mapped.Println()
	count = 123
	mapped.Println()
	count = 456
	mapped.Println()

	// Output:
	// observable 0
	// observable 123
	// observable 456
}

func ExampleObservable_Do() {
	rx.From(1, 2, 3).Do(func(v interface{}) {
		fmt.Println(v.(int))
	}).Wait()

	// Output:
	// 1
	// 2
	// 3
}

func ExampleObservable_Filter() {
	even := func(i interface{}) bool {
		return i.(int)%2 == 0
	}

	rx.From(1, 2, 3, 4, 5, 6, 7, 8).Filter(even).Println()

	// Output:
	// 2
	// 4
	// 6
	// 8
}

func ExampleFromChan() {
	ch := make(chan interface{}, 6)
	for i := 0; i < 5; i++ {
		ch <- i + 1
	}
	close(ch)

	rx.FromChan(ch).Println()

	// Output:
	// 1
	// 2
	// 3
	// 4
	// 5
}

func ExampleFrom() {
	rx.From(1, 2, 3, 4, 5).Println()

	// Output:
	// 1
	// 2
	// 3
	// 4
	// 5
}

func ExampleFrom_slice() {
	rx.From([]interface{}{1, 2, 3, 4, 5}...).Println()

	// Output:
	// 1
	// 2
	// 3
	// 4
	// 5
}

func ExampleObservable_Map() {
	rx.From(1, 2, 3, 4).Map(func(i interface{}) interface{} {
		return fmt.Sprintf("%d!", i.(int))
	}).Println()

	// Output:
	// 1!
	// 2!
	// 3!
	// 4!
}

func ExampleObservable_MergeMap() {
	source := rx.From(1, 2).
		MergeMap(func(n interface{}) rx.Observable {
			return rx.Range(n.(int), 2).AsObservable()
		})
	if err := source.Println(); err != nil {
		panic(err)
	}

	// Output:
	// 1
	// 2
	// 2
	// 3
}

func ExampleObservable_Scan() {
	add := func(acc interface{}, value interface{}) interface{} {
		return acc.(int) + value.(int)
	}

	rx.From(1, 2, 3, 4, 5).Scan(add, 0).Println()

	// Output:
	// 1
	// 3
	// 6
	// 10
	// 15
}

func ExampleObservableObservable_SwitchAll() {
	// intToObs creates a new observable that emits an integer starting after and then repeated every 20 milliseconds
	// in the range starting at 0 and incrementing by 1. It takes only the first 10 emitted values and then uses
	// AsObservable to convert the IntObservable back to an untyped Observable.
	intToObs := func(i int) rx.Observable {
		return rx.Interval(20 * time.Millisecond).
			Take(10).
			AsObservable()
	}

	rx.Interval(100 * time.Millisecond).
		Take(3).
		MapObservable(intToObs).
		SwitchAll().
		Println()

	// Output:
	// 0
	// 1
	// 2
	// 3
	// 0
	// 1
	// 2
	// 3
	// 0
	// 1
	// 2
	// 3
	// 4
	// 5
	// 6
	// 7
	// 8
	// 9
}
<|endoftext|>