@@ -72,7 +72,8 @@ func Example_withTLS() {
 		log.Fatalf("failed to create gRPC client TLS credentials: %v", err)
 	}

-	exp, err := otlp.NewExporter(otlp.WithTLSCredentials(creds))
+	exp, err := otlp.NewExporter(otlp.EmptyConfiguration,
+		otlp.NewConnectionConfig(otlp.WithTLSCredentials(creds)))
 	if err != nil {
 		log.Fatalf("failed to create the collector exporter: %v", err)
 	}

// Copyright The OpenTelemetry 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 otlp_test

import (
	"context"
	"fmt"
	"log"
	"time"

	"google.golang.org/grpc/credentials"

	"go.opentelemetry.io/otel/api/global"
	"go.opentelemetry.io/otel/exporters/otlp"
	sdktrace "go.opentelemetry.io/otel/sdk/trace"
)

func Example_insecure() {
	exp, err := otlp.NewExporter(otlp.WithInsecure())
	if err != nil {
		log.Fatalf("Failed to create the collector exporter: %v", err)
	}
	defer func() {
		ctx, cancel := context.WithTimeout(context.Background(), time.Second)
		defer cancel()
		if err := exp.Shutdown(ctx); err != nil {
			global.Handle(err)
		}
	}()

	tp := sdktrace.NewProvider(
		sdktrace.WithConfig(sdktrace.Config{DefaultSampler: sdktrace.AlwaysSample()}),
		sdktrace.WithBatcher(
			exp,
			// add following two options to ensure flush
			sdktrace.WithBatchTimeout(5),
			sdktrace.WithMaxExportBatchSize(10),
		),
	)
	global.SetTracerProvider(tp)

	tracer := global.Tracer("test-tracer")

	// Then use the OpenTelemetry tracing library, like we normally would.
	ctx, span := tracer.Start(context.Background(), "CollectorExporter-Example")
	defer span.End()

	for i := 0; i < 10; i++ {
		_, iSpan := tracer.Start(ctx, fmt.Sprintf("Sample-%d", i))
		<-time.After(6 * time.Millisecond)
		iSpan.End()
	}
}

func Example_withTLS() {
	// Please take at look at https://pkg.go.dev/google.golang.org/grpc/credentials#TransportCredentials
	// for ways on how to initialize gRPC TransportCredentials.
	creds, err := credentials.NewClientTLSFromFile("my-cert.pem", "")
	if err != nil {
		log.Fatalf("failed to create gRPC client TLS credentials: %v", err)
	}

	exp, err := otlp.NewExporter(otlp.WithTLSCredentials(creds))
	if err != nil {
		log.Fatalf("failed to create the collector exporter: %v", err)
	}
	defer func() {
		ctx, cancel := context.WithTimeout(context.Background(), time.Second)
		defer cancel()
		if err := exp.Shutdown(ctx); err != nil {
			global.Handle(err)
		}
	}()

	tp := sdktrace.NewProvider(
		sdktrace.WithConfig(sdktrace.Config{DefaultSampler: sdktrace.AlwaysSample()}),
		sdktrace.WithBatcher(
			exp,
			// add following two options to ensure flush
			sdktrace.WithBatchTimeout(5),
			sdktrace.WithMaxExportBatchSize(10),
		),
	)
	global.SetTracerProvider(tp)

	tracer := global.Tracer("test-tracer")

	// Then use the OpenTelemetry tracing library, like we normally would.
	ctx, span := tracer.Start(context.Background(), "Securely-Talking-To-Collector-Span")
	defer span.End()

	for i := 0; i < 10; i++ {
		_, iSpan := tracer.Start(ctx, fmt.Sprintf("Sample-%d", i))
		<-time.After(6 * time.Millisecond)
		iSpan.End()
	}
}


@@ -84,20 +84,20 @@ func TestChunkUploadDownload(t *testing.T) {
 		)

 		// try to fetch the same chunk
-		resp := request(t, client, http.MethodGet, resource(validHash), nil, http.StatusOK)
+		resp := request(t, client, http.MethodGet, resource(chunk.Address()), nil, http.StatusOK)
 		data, err := ioutil.ReadAll(resp.Body)
 		if err != nil {
 			t.Fatal(err)
 		}

-		if !bytes.Equal(validContent, data) {
+		if !bytes.Equal(chunk.Data(), data) {
 			t.Fatal("data retrieved doesnt match uploaded content")
 		}
 	})

 	t.Run("pin-invalid-value", func(t *testing.T) {
-		jsonhttptest.Request(t, client, http.MethodPost, resource(validHash), http.StatusOK,
-			jsonhttptest.WithRequestBody(bytes.NewReader(validContent)),
+		jsonhttptest.Request(t, client, http.MethodPost, resource(chunk.Address()), http.StatusOK,
+			jsonhttptest.WithRequestBody(bytes.NewReader(chunk.Data())),
 			jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
 				Message: http.StatusText(http.StatusOK),
 				Code:    http.StatusOK,

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

package api_test

import (
	"bytes"
	"io"
	"io/ioutil"
	"net/http"
	"testing"

	"github.com/ethersphere/bee/pkg/logging"
	statestore "github.com/ethersphere/bee/pkg/statestore/mock"

	"github.com/ethersphere/bee/pkg/tags"

	"github.com/ethersphere/bee/pkg/api"
	"github.com/ethersphere/bee/pkg/jsonhttp"
	"github.com/ethersphere/bee/pkg/jsonhttp/jsonhttptest"
	"github.com/ethersphere/bee/pkg/storage"
	"github.com/ethersphere/bee/pkg/storage/mock"
	"github.com/ethersphere/bee/pkg/storage/mock/validator"
	"github.com/ethersphere/bee/pkg/swarm"
)

// TestChunkUploadDownload uploads a chunk to an API that verifies the chunk according
// to a given validator, then tries to download the uploaded data.
func TestChunkUploadDownload(t *testing.T) {

	var (
		targets              = "0x222"
		resource             = func(addr swarm.Address) string { return "/chunks/" + addr.String() }
		resourceTargets      = func(addr swarm.Address) string { return "/chunks/" + addr.String() + "?targets=" + targets }
		validHash            = swarm.MustParseHexAddress("aabbcc")
		invalidHash          = swarm.MustParseHexAddress("bbccdd")
		validContent         = []byte("bbaatt")
		invalidContent       = []byte("bbaattss")
		mockValidator        = validator.NewMockValidator(validHash, validContent)
		mockStatestore       = statestore.NewStateStore()
		logger               = logging.New(ioutil.Discard, 0)
		tag                  = tags.NewTags(mockStatestore, logger)
		mockValidatingStorer = mock.NewStorer(mock.WithValidator(mockValidator))
		client, _, _         = newTestServer(t, testServerOptions{
			Storer: mockValidatingStorer,
			Tags:   tag,
		})
	)

	t.Run("invalid hash", func(t *testing.T) {
		jsonhttptest.Request(t, client, http.MethodPost, resource(invalidHash), http.StatusBadRequest,
			jsonhttptest.WithRequestBody(bytes.NewReader(validContent)),
			jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
				Message: "chunk write error",
				Code:    http.StatusBadRequest,
			}),
		)

		// make sure chunk is not retrievable
		_ = request(t, client, http.MethodGet, resource(invalidHash), nil, http.StatusNotFound)
	})

	t.Run("invalid content", func(t *testing.T) {
		jsonhttptest.Request(t, client, http.MethodPost, resource(invalidHash), http.StatusBadRequest,
			jsonhttptest.WithRequestBody(bytes.NewReader(invalidContent)),
			jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
				Message: "chunk write error",
				Code:    http.StatusBadRequest,
			}),
		)

		// make sure not retrievable
		_ = request(t, client, http.MethodGet, resource(validHash), nil, http.StatusNotFound)
	})

	t.Run("ok", func(t *testing.T) {
		jsonhttptest.Request(t, client, http.MethodPost, resource(validHash), http.StatusOK,
			jsonhttptest.WithRequestBody(bytes.NewReader(validContent)),
			jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
				Message: http.StatusText(http.StatusOK),
				Code:    http.StatusOK,
			}),
		)

		// try to fetch the same chunk
		resp := request(t, client, http.MethodGet, resource(validHash), nil, http.StatusOK)
		data, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			t.Fatal(err)
		}

		if !bytes.Equal(validContent, data) {
			t.Fatal("data retrieved doesnt match uploaded content")
		}
	})

	t.Run("pin-invalid-value", func(t *testing.T) {
		jsonhttptest.Request(t, client, http.MethodPost, resource(validHash), http.StatusOK,
			jsonhttptest.WithRequestBody(bytes.NewReader(validContent)),
			jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
				Message: http.StatusText(http.StatusOK),
				Code:    http.StatusOK,
			}),
			jsonhttptest.WithRequestHeader(api.SwarmPinHeader, "invalid-pin"),
		)

		// Also check if the chunk is NOT pinned
		if mockValidatingStorer.GetModeSet(validHash) == storage.ModeSetPin {
			t.Fatal("chunk should not be pinned")
		}
	})
	t.Run("pin-header-missing", func(t *testing.T) {
		jsonhttptest.Request(t, client, http.MethodPost, resource(validHash), http.StatusOK,
			jsonhttptest.WithRequestBody(bytes.NewReader(validContent)),
			jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
				Message: http.StatusText(http.StatusOK),
				Code:    http.StatusOK,
			}),
		)

		// Also check if the chunk is NOT pinned
		if mockValidatingStorer.GetModeSet(validHash) == storage.ModeSetPin {
			t.Fatal("chunk should not be pinned")
		}
	})
	t.Run("pin-ok", func(t *testing.T) {
		jsonhttptest.Request(t, client, http.MethodPost, resource(validHash), http.StatusOK,
			jsonhttptest.WithRequestBody(bytes.NewReader(validContent)),
			jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
				Message: http.StatusText(http.StatusOK),
				Code:    http.StatusOK,
			}),
			jsonhttptest.WithRequestHeader(api.SwarmPinHeader, "True"),
		)

		// Also check if the chunk is pinned
		if mockValidatingStorer.GetModePut(validHash) != storage.ModePutUploadPin {
			t.Fatal("chunk is not pinned")
		}

	})
	t.Run("retrieve-targets", func(t *testing.T) {
		resp := request(t, client, http.MethodGet, resourceTargets(validHash), nil, http.StatusOK)

		// Check if the target is obtained correctly
		if resp.Header.Get(api.TargetsRecoveryHeader) != targets {
			t.Fatalf("targets mismatch. got %s, want %s", resp.Header.Get(api.TargetsRecoveryHeader), targets)
		}
	})
}

func request(t *testing.T, client *http.Client, method, resource string, body io.Reader, responseCode int) *http.Response {
	t.Helper()

	req, err := http.NewRequest(method, resource, body)
	if err != nil {
		t.Fatal(err)
	}
	resp, err := client.Do(req)
	if err != nil {
		t.Fatal(err)
	}
	if resp.StatusCode != responseCode {
		t.Fatalf("got response status %s, want %v %s", resp.Status, responseCode, http.StatusText(responseCode))
	}
	return resp
}


@@ -58,6 +58,13 @@ func Register(r *gin.RouterGroup, s *Service) {
 	endpoint.GET("", s.listExperiments)
 	endpoint.GET("/detail/search", s.experimentDetailSearch)
 	endpoint.GET("/detail", s.experimentDetail)
+	endpoint.GET("/report", s.experimentReport)
+}
+
+// ArchiveExperimentDetail represents an experiment instance.
+type ArchiveExperimentDetail struct {
+	core.ArchiveExperimentMeta
+	ExperimentInfo core.ExperimentInfo `json:"experiment_info"`
 }

 // @Summary Get archived chaos experiments.

// Copyright 2020 Chaos Mesh 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,
// See the License for the specific language governing permissions and
// limitations under the License.

package archive

import (
	"context"
	"net/http"

	"github.com/gin-gonic/gin"
	"github.com/jinzhu/gorm"

	"github.com/chaos-mesh/chaos-mesh/pkg/apiserver/utils"
	"github.com/chaos-mesh/chaos-mesh/pkg/config"
	"github.com/chaos-mesh/chaos-mesh/pkg/core"

	"sigs.k8s.io/controller-runtime/pkg/client"
)

// Service defines a handler service for archive experiments.
type Service struct {
	conf    *config.ChaosDashboardConfig
	kubeCli client.Client
	archive core.ExperimentStore
	event   core.EventStore
}

// NewService returns an archive experiment service instance.
func NewService(
	conf *config.ChaosDashboardConfig,
	cli client.Client,
	archive core.ExperimentStore,
	event core.EventStore,
) *Service {
	return &Service{
		conf:    conf,
		kubeCli: cli,
		archive: archive,
		event:   event,
	}
}

// Register mounts our HTTP handler on the mux.
func Register(r *gin.RouterGroup, s *Service) {
	endpoint := r.Group("/archives")

	// TODO: add more api handlers
	endpoint.GET("", s.listExperiments)
	endpoint.GET("/detail/search", s.experimentDetailSearch)
	endpoint.GET("/detail", s.experimentDetail)
}

// @Summary Get archived chaos experiments.
// @Description Get archived chaos experiments.
// @Tags archives
// @Produce json
// @Param namespace query string false "namespace"
// @Param name query string false "name"
// @Param kind query string false "kind" Enums(PodChaos, IoChaos, NetworkChaos, TimeChaos, KernelChaos, StressChaos)
// @Success 200 {array} core.ArchiveExperimentMeta
// @Router /api/archives [get]
// @Failure 500 {object} utils.APIError
func (s *Service) listExperiments(c *gin.Context) {
	kind := c.Query("kind")
	name := c.Query("name")
	ns := c.Query("namespace")

	data, err := s.archive.ListMeta(context.TODO(), kind, ns, name)
	if err != nil {
		c.Status(http.StatusInternalServerError)
		_ = c.Error(utils.ErrInternalServer.NewWithNoMessage())
		return
	}

	c.JSON(http.StatusOK, data)
}

// @Summary Get the details of chaos experiment.
// @Description Get the details of chaos experiment.
// @Tags archives
// @Produce json
// @Param namespace query string false "namespace"
// @Param name query string false "name"
// @Param kind query string false "kind" Enums(PodChaos, IoChaos, NetworkChaos, TimeChaos, KernelChaos, StressChaos)
// @Param uid query string false "uid"
// @Success 200 {array} core.ArchiveExperiment
// @Router /api/archives/detail/search [get]
// @Failure 500 {object} utils.APIError
func (s *Service) experimentDetailSearch(c *gin.Context) {
	kind := c.Query("kind")
	name := c.Query("name")
	ns := c.Query("namespace")
	uid := c.Query("uid")

	data, err := s.archive.DetailList(context.TODO(), kind, ns, name, uid)
	if err != nil {
		if !gorm.IsRecordNotFoundError(err) {
			c.Status(http.StatusInternalServerError)
			_ = c.Error(utils.ErrInternalServer.NewWithNoMessage())
		} else {
			c.Status(http.StatusInternalServerError)
			_ = c.Error(utils.ErrInvalidRequest.New("the archive is not found"))
		}
		return
	}

	c.JSON(http.StatusOK, data)
}

// @Summary Get the details of chaos experiment.
// @Description Get the details of chaos experiment.
// @Tags archives
// @Produce json
// @Param uid query string true "uid"
// @Success 200 {array} core.ArchiveExperiment
// @Router /api/archives/detail [get]
// @Failure 500 {object} utils.APIError
func (s *Service) experimentDetail(c *gin.Context) {

	uid := c.Query("uid")

	if uid == "" {
		c.Status(http.StatusBadRequest)
		_ = c.Error(utils.ErrInvalidRequest.New("uid cannot be empty"))
		return
	}

	data, err := s.archive.FindByUID(context.TODO(), uid)
	if err != nil {
		if !gorm.IsRecordNotFoundError(err) {
			c.Status(http.StatusInternalServerError)
			_ = c.Error(utils.ErrInternalServer.NewWithNoMessage())
		} else {
			c.Status(http.StatusInternalServerError)
			_ = c.Error(utils.ErrInvalidRequest.New("the archive is not found"))
		}
		return
	}

	c.JSON(http.StatusOK, data)
}


@@ -60,7 +60,7 @@ func DefaultIpcPath() (string, error) {

 // NewSigner creates a new connection to the signer at endpoint
 // As clef does not expose public keys it signs a test message to recover the public key
-func NewSigner(clef ExternalSignerInterface, recoverFunc crypto.RecoverFunc) (signer crypto.Signer, err error) {
+func NewSigner(clef ExternalSignerInterface, client RpcClient, recoverFunc crypto.RecoverFunc) (signer crypto.Signer, err error) {
 	// get the list of available ethereum accounts
 	clefAccounts := clef.Accounts()
 	if len(clefAccounts) == 0 {

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

package clef

import (
	"crypto/ecdsa"
	"errors"
	"math/big"
	"os"
	"path/filepath"
	"runtime"

	"github.com/ethereum/go-ethereum/accounts"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethersphere/bee/pkg/crypto"
)

var (
	ErrNoAccounts       = errors.New("no accounts found in clef")
	clefRecoveryMessage = []byte("public key recovery message")
)

// ExternalSignerInterface is the interface for the clef client from go-ethereum
type ExternalSignerInterface interface {
	SignData(account accounts.Account, mimeType string, data []byte) ([]byte, error)
	SignTx(account accounts.Account, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error)
	Accounts() []accounts.Account
}

type clefSigner struct {
	clef    ExternalSignerInterface
	account accounts.Account // the account this signer will use
	pubKey  *ecdsa.PublicKey // the public key for the account
}

// DefaultIpcPath returns the os-dependent default ipc path for clef
func DefaultIpcPath() (string, error) {
	socket := "clef.ipc"
	// on windows clef uses top level pipes
	if runtime.GOOS == "windows" {
		return `\\.\pipe\` + socket, nil
	}

	home, err := os.UserHomeDir()
	if err != nil {
		return "", err
	}

	// on mac os clef defaults to ~/Library/Signer/clef.ipc
	if runtime.GOOS == "darwin" {
		return filepath.Join(home, "Library", "Signer", socket), nil
	}

	// on unix clef defaults to ~/.clef/clef.ipc
	return filepath.Join(home, ".clef", socket), nil
}

// NewSigner creates a new connection to the signer at endpoint
// As clef does not expose public keys it signs a test message to recover the public key
func NewSigner(clef ExternalSignerInterface, recoverFunc crypto.RecoverFunc) (signer crypto.Signer, err error) {
	// get the list of available ethereum accounts
	clefAccounts := clef.Accounts()
	if len(clefAccounts) == 0 {
		return nil, ErrNoAccounts
	}

	// pick the first account as the one we use
	account := clefAccounts[0]

	// clef currently does not expose the public key
	// sign some data so we can recover it
	sig, err := clef.SignData(account, accounts.MimetypeTextPlain, clefRecoveryMessage)
	if err != nil {
		return nil, err
	}

	pubKey, err := recoverFunc(sig, clefRecoveryMessage)
	if err != nil {
		return nil, err
	}

	return &clefSigner{
		clef:    clef,
		account: account,
		pubKey:  pubKey,
	}, nil
}

// PublicKey returns the public key recovered during creation
func (c *clefSigner) PublicKey() (*ecdsa.PublicKey, error) {
	return c.pubKey, nil
}

// SignData signs with the text/plain type which is the standard Ethereum prefix method
func (c *clefSigner) Sign(data []byte) ([]byte, error) {
	return c.clef.SignData(c.account, accounts.MimetypeTextPlain, data)
}

// SignTx signs an ethereum transaction
func (c *clefSigner) SignTx(transaction *types.Transaction) (*types.Transaction, error) {
	// chainId is nil here because it is set on the clef side
	return c.clef.SignTx(c.account, transaction, nil)
}

// EthereumAddress returns the ethereum address this signer uses
func (c *clefSigner) EthereumAddress() (common.Address, error) {
	return c.account.Address, nil
}


@@ -19,6 +19,7 @@ package validation
 import (
 	"fmt"
 	"net"
+	"net/mail"

 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/util/validation/field"

/*
Copyright 2019 The Jetstack cert-manager 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 validation

import (
	"fmt"
	"net"

	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/util/validation/field"

	"github.com/jetstack/cert-manager/pkg/api/util"
	cmapiv1alpha2 "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha2"
	cmapi "github.com/jetstack/cert-manager/pkg/internal/apis/certmanager"
	cmmeta "github.com/jetstack/cert-manager/pkg/internal/apis/meta"
)

// Validation functions for cert-manager Certificate types

func ValidateCertificateSpec(crt *cmapi.CertificateSpec, fldPath *field.Path) field.ErrorList {
	el := field.ErrorList{}
	if crt.SecretName == "" {
		el = append(el, field.Required(fldPath.Child("secretName"), "must be specified"))
	}

	el = append(el, validateIssuerRef(crt.IssuerRef, fldPath)...)

	if len(crt.CommonName) == 0 && len(crt.DNSNames) == 0 && len(crt.URISANs) == 0 {
		el = append(el, field.Required(fldPath.Child("commonName", "dnsNames", "uriSANs"),
			"at least one of commonName, dnsNames, or uriSANs must be set"))
	}

	// if a common name has been specified, ensure it is no longer than 64 chars
	if len(crt.CommonName) > 64 {
		el = append(el, field.TooLong(fldPath.Child("commonName"), crt.CommonName, 64))
	}

	if len(crt.IPAddresses) > 0 {
		el = append(el, validateIPAddresses(crt, fldPath)...)
	}
	switch crt.KeyAlgorithm {
	case cmapi.KeyAlgorithm(""):
	case cmapi.RSAKeyAlgorithm:
		if crt.KeySize > 0 && (crt.KeySize < 2048 || crt.KeySize > 8192) {
			el = append(el, field.Invalid(fldPath.Child("keySize"), crt.KeySize, "must be between 2048 & 8192 for rsa keyAlgorithm"))
		}
	case cmapi.ECDSAKeyAlgorithm:
		if crt.KeySize > 0 && crt.KeySize != 256 && crt.KeySize != 384 && crt.KeySize != 521 {
			el = append(el, field.NotSupported(fldPath.Child("keySize"), crt.KeySize, []string{"256", "384", "521"}))
		}
	default:
		el = append(el, field.Invalid(fldPath.Child("keyAlgorithm"), crt.KeyAlgorithm, "must be either empty or one of rsa or ecdsa"))
	}

	if crt.Duration != nil || crt.RenewBefore != nil {
		el = append(el, ValidateDuration(crt, fldPath)...)
	}
	if len(crt.Usages) > 0 {
		el = append(el, validateUsages(crt, fldPath)...)
	}
	return el
}

func ValidateCertificate(obj runtime.Object) field.ErrorList {
	crt := obj.(*cmapi.Certificate)
	allErrs := ValidateCertificateSpec(&crt.Spec, field.NewPath("spec"))
	return allErrs
}

func validateIssuerRef(issuerRef cmmeta.ObjectReference, fldPath *field.Path) field.ErrorList {
	el := field.ErrorList{}

	issuerRefPath := fldPath.Child("issuerRef")
	if issuerRef.Name == "" {
		el = append(el, field.Required(issuerRefPath.Child("name"), "must be specified"))
	}
	if issuerRef.Group == "" || issuerRef.Group == cmapi.SchemeGroupVersion.Group {
		switch issuerRef.Kind {
		case "":
		case "Issuer", "ClusterIssuer":
		default:
			el = append(el, field.Invalid(issuerRefPath.Child("kind"), issuerRef.Kind, "must be one of Issuer or ClusterIssuer"))
		}
	}
	return el
}

func validateIPAddresses(a *cmapi.CertificateSpec, fldPath *field.Path) field.ErrorList {
	if len(a.IPAddresses) <= 0 {
		return nil
	}
	el := field.ErrorList{}
	for i, d := range a.IPAddresses {
		ip := net.ParseIP(d)
		if ip == nil {
			el = append(el, field.Invalid(fldPath.Child("ipAddresses").Index(i), d, "invalid IP address"))
		}
	}
	return el
}

func validateUsages(a *cmapi.CertificateSpec, fldPath *field.Path) field.ErrorList {
	el := field.ErrorList{}
	for i, u := range a.Usages {
		_, kok := util.KeyUsageType(cmapiv1alpha2.KeyUsage(u))
		_, ekok := util.ExtKeyUsageType(cmapiv1alpha2.KeyUsage(u))
		if !kok && !ekok {
			el = append(el, field.Invalid(fldPath.Child("usages").Index(i), u, "unknown keyusage"))
		}
	}
	return el
}

func ValidateDuration(crt *cmapi.CertificateSpec, fldPath *field.Path) field.ErrorList {
	el := field.ErrorList{}

	duration := util.DefaultCertDuration(crt.Duration)
	renewBefore := cmapiv1alpha2.DefaultRenewBefore
	if crt.RenewBefore != nil {
		renewBefore = crt.RenewBefore.Duration
	}
	if duration < cmapiv1alpha2.MinimumCertificateDuration {
		el = append(el, field.Invalid(fldPath.Child("duration"), duration, fmt.Sprintf("certificate duration must be greater than %s", cmapiv1alpha2.MinimumCertificateDuration)))
	}
	if renewBefore < cmapiv1alpha2.MinimumRenewBefore {
		el = append(el, field.Invalid(fldPath.Child("renewBefore"), renewBefore, fmt.Sprintf("certificate renewBefore must be greater than %s", cmapiv1alpha2.MinimumRenewBefore)))
	}
	if duration <= renewBefore {
		el = append(el, field.Invalid(fldPath.Child("renewBefore"), renewBefore, fmt.Sprintf("certificate duration %s must be greater than renewBefore %s", duration, renewBefore)))
	}
	return el
}


@@ -95,37 +95,9 @@ func buildAndCreateCVR() {
 		TargetIP:   cvrObj.Spec.TargetIP,
 		Phase:      "Recreate",
 		Capacity:   cvrObj.Spec.Capacity,
+		ReplicaID:  replicaID,
 	}
 	ops.Config = cvrConfig
 	newCVRObj = ops.BuildAndCreateCVR()
-
-	cvrName := pvcObj.Spec.VolumeName + "-" + cspObj.Name
-	hashUID, err := hash.Hash(newCVRObj.UID)
-	Expect(err).To(BeNil())
-	ReplicaID = strings.ToUpper(hashUID)
-	for i := 0; i < retryUpdate; i++ {
-		newCVRObj.Spec.ReplicaID = ReplicaID
-		newCVRObj, err = ops.CVRClient.
-			WithNamespace(openebsNamespace).
-			Update(newCVRObj)
-		if err == nil {
-			break
-		}
-		time.Sleep(time.Second * 5)
-		newCVRObj, getErr = ops.CVRClient.Get(cvrName, metav1.GetOptions{})
-		Expect(getErr).To(BeNil())
-	}
-	Expect(err).To(BeNil())
-	//TODO: Need to fix bug in cvr during creation time
-	podLabel := cspLabel + cspObj.Name
-	podObjList, err := ops.PodClient.
-		WithNamespace(openebsNamespace).
-		List(metav1.ListOptions{LabelSelector: podLabel})
-	Expect(err).To(BeNil())
-	err = ops.PodClient.Delete(podObjList.Items[0].Name, &metav1.DeleteOptions{})
-	Expect(err).To(BeNil())
-	isPodDeleted := ops.IsPodDeletedEventually(
-		podObjList.Items[0].Namespace,
-		podObjList.Items[0].Name)
-	Expect(isPodDeleted).To(Equal(true))
+	ReplicaID = replicaID
 }

/*
Copyright 2019 The OpenEBS 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 replicascaleup

import (
	"strconv"
	"strings"
	"time"

	. "github.com/onsi/gomega"
	apis "github.com/openebs/maya/pkg/apis/openebs.io/v1alpha1"
	hash "github.com/openebs/maya/pkg/hash"
	"github.com/openebs/maya/tests"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	// auth plugins
	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
)

func verifyVolumeConfigurationEventually() {
	var err error
	consistencyFactor := (ReplicaCount / 2) + 1
	for i := 0; i < MaxRetry; i++ {
		cvObj, err = ops.CVClient.WithNamespace(openebsNamespace).
			Get(pvcObj.Spec.VolumeName, metav1.GetOptions{})
		Expect(err).To(BeNil())
		if cvObj.Spec.ReplicationFactor == ReplicaCount {
			break
		}
		time.Sleep(5 * time.Second)
	}
	Expect(cvObj.Spec.ConsistencyFactor).To(Equal(consistencyFactor), "mismatch of consistencyFactor")
	_, isReplicaIDExist := cvObj.Status.ReplicaDetails.KnownReplicas[apis.ReplicaID(ReplicaID)]
	Expect(isReplicaIDExist).To(Equal(true), "replicaId should exist in known replicas of cstorvolume")
	Expect(cvObj.Status.Phase).To(Equal(apis.CStorVolumePhase("Healthy")))
}

func buildAndCreateSC() {
	casConfig := strings.Replace(
		openebsCASConfigValue, "$spcName", spcObj.Name, 1)
	casConfig = strings.Replace(
		casConfig, "$count", strconv.Itoa(ReplicaCount), 1)
	annotations[string(apis.CASTypeKey)] = string(apis.CstorVolume)
	annotations[string(apis.CASConfigKey)] = casConfig
	scConfig := &tests.SCConfig{
		Name:        scName,
		Annotations: annotations,
		Provisioner: openebsProvisioner,
	}
	ops.Config = scConfig
	scObj = ops.CreateStorageClass()
}

func updateDesiredReplicationFactor() {
	var err error
	cvObj, err = ops.CVClient.WithNamespace(openebsNamespace).
		Get(pvcObj.Spec.VolumeName, metav1.GetOptions{})
	Expect(err).To(BeNil())
	cvObj.Spec.DesiredReplicationFactor = cvObj.Spec.DesiredReplicationFactor + 1
	// Namespace is already set to CVClient in above step
	cvObj, err = ops.CVClient.Update(cvObj)
	Expect(err).To(BeNil())
}

func buildAndCreateCVR() {
	var err, getErr error
	retryUpdate := 3
	volumeLabel := pvLabel + pvcObj.Spec.VolumeName
	cvrObjList, err := ops.CVRClient.
		WithNamespace(openebsNamespace).
		List(metav1.ListOptions{LabelSelector: volumeLabel})
	Expect(err).To(BeNil())

	cvrObj = &cvrObjList.Items[0]
	poolLabel := string(apis.StoragePoolClaimCPK) + "=" + spcObj.Name
	cspObj = ops.GetUnUsedCStorPool(cvrObjList, poolLabel)
	cvrConfig := &tests.CVRConfig{
		VolumeName: pvcObj.Spec.VolumeName,
		PoolObj:    cspObj,
		Namespace:  openebsNamespace,
		TargetIP:   cvrObj.Spec.TargetIP,
		Phase:      "Recreate",
		Capacity:   cvrObj.Spec.Capacity,
	}
	ops.Config = cvrConfig
	newCVRObj = ops.BuildAndCreateCVR()

	cvrName := pvcObj.Spec.VolumeName + "-" + cspObj.Name
	hashUID, err := hash.Hash(newCVRObj.UID)
	Expect(err).To(BeNil())
	ReplicaID = strings.ToUpper(hashUID)
	for i := 0; i < retryUpdate; i++ {
		newCVRObj.Spec.ReplicaID = ReplicaID
		newCVRObj, err = ops.CVRClient.
			WithNamespace(openebsNamespace).
			Update(newCVRObj)
		if err == nil {
			break
		}
		time.Sleep(time.Second * 5)
		newCVRObj, getErr = ops.CVRClient.Get(cvrName, metav1.GetOptions{})
		Expect(getErr).To(BeNil())
	}
	Expect(err).To(BeNil())
	//TODO: Need to fix bug in cvr during creation time
	podLabel := cspLabel + cspObj.Name
	podObjList, err := ops.PodClient.
		WithNamespace(openebsNamespace).
		List(metav1.ListOptions{LabelSelector: podLabel})
	Expect(err).To(BeNil())
	err = ops.PodClient.Delete(podObjList.Items[0].Name, &metav1.DeleteOptions{})
	Expect(err).To(BeNil())
	isPodDeleted := ops.IsPodDeletedEventually(
		podObjList.Items[0].Namespace,
		podObjList.Items[0].Name)
	Expect(isPodDeleted).To(Equal(true))
}


@@ -57,7 +57,7 @@ type balanceState string
 type PromiseProcessor struct {
 	dialog  communication.Dialog
 	balance identity.Balance
-	storage storage.Storage
+	storage Storer

 	balanceInterval   time.Duration
 	balanceState      balanceState

/*
 * Copyright (C) 2018 The "MysteriumNetwork/node" Authors.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package noop

import (
	"fmt"
	"sync"
	"time"

	log "github.com/cihub/seelog"
	"github.com/mysteriumnetwork/node/communication"
	"github.com/mysteriumnetwork/node/core/promise"
	"github.com/mysteriumnetwork/node/core/storage"
	"github.com/mysteriumnetwork/node/identity"
	"github.com/mysteriumnetwork/node/money"
	"github.com/mysteriumnetwork/node/service_discovery/dto"
)

const (
	processorLogPrefix = "[promise-processor] "

	balanceNotifying = balanceState("Notifying")
	balanceStopped   = balanceState("Stopped")
)

// NewPromiseProcessor creates instance of PromiseProcessor
func NewPromiseProcessor(dialog communication.Dialog, balance identity.Balance, storage storage.Storage) *PromiseProcessor {
	return &PromiseProcessor{
		dialog:  dialog,
		balance: balance,
		storage: storage,

		balanceInterval: 5 * time.Second,
		balanceState:    balanceStopped,
		balanceShutdown: make(chan bool, 1),
	}
}

type balanceState string

// PromiseProcessor process promises in such way, what no actual money is deducted from promise
type PromiseProcessor struct {
	dialog  communication.Dialog
	balance identity.Balance
	storage storage.Storage

	balanceInterval   time.Duration
	balanceState      balanceState
	balanceStateMutex sync.RWMutex
	balanceShutdown   chan bool

	// these are populated later at runtime
	lastPromise promise.Promise
}

// Start processing promises for given service proposal
func (processor *PromiseProcessor) Start(proposal dto.ServiceProposal) error {
	// TODO: replace static value with some real data
	processor.lastPromise = promise.Promise{
		Amount: money.NewMoney(10, money.CURRENCY_MYST),
	}

	consumer := promise.NewConsumer(proposal, processor.balance, processor.storage)
	if err := processor.dialog.Respond(consumer); err != nil {
		return err
	}

	processor.balanceShutdown = make(chan bool, 1)
	go processor.balanceLoop()

	return nil
}

// Stop stops processing promises
func (processor *PromiseProcessor) Stop() error {
	processor.balanceShutdown <- true
	return nil
}

func (processor *PromiseProcessor) balanceLoop() {
	processor.setBalanceState(balanceNotifying)

balanceLoop:
	for {
		select {
		case <-processor.balanceShutdown:
			break balanceLoop

		case <-time.After(processor.balanceInterval):
			// TODO: replace static value with some real data
			processor.balanceSend(
				promise.BalanceMessage{1, true, processor.lastPromise.Amount},
			)
		}
	}

	processor.setBalanceState(balanceStopped)
}

func (processor *PromiseProcessor) setBalanceState(state balanceState) {
	processor.balanceStateMutex.Lock()
	defer processor.balanceStateMutex.Unlock()

	processor.balanceState = state
}

func (processor *PromiseProcessor) getBalanceState() balanceState {
	processor.balanceStateMutex.RLock()
	defer processor.balanceStateMutex.RUnlock()

	return processor.balanceState
}

func (processor *PromiseProcessor) balanceSend(message promise.BalanceMessage) error {
	log.Info(processorLogPrefix, fmt.Sprintf("Notifying balance %s", message.Balance.String()))
	return processor.dialog.Send(&promise.BalanceMessageProducer{
		Message: message,
	})
}


@@ -114,11 +114,22 @@ func (it *InvoiceTracker) getNotReceivedExchangeMessageCount() uint64 {
 }

 func (it *InvoiceTracker) sendInvoiceExpectExchangeMessage() error {
-	err := it.sendInvoice()
+	// TODO: this should be calculated according to the passed in payment period
+	shouldBe := uint64(math.Trunc(it.timeTracker.Elapsed().Minutes() * float64(it.paymentInfo.GetPrice().Amount) * 100000000))
+
+	// TODO: fill in the fee
+	invoice := crypto.CreateInvoice(it.lastInvoice.invoice.AgreementID, shouldBe, 0, it.lastInvoice.r)
+	invoice.Provider = it.providerID.Address
+	err := it.peerInvoiceSender.Send(invoice)
 	if err != nil {
 		return err
 	}

+	err = it.invoiceStorage.Store(it.peer, invoice)
+	if err != nil {
+		return errors.Wrap(err, "could not store invoice")
+	}
+
 	err = it.receiveExchangeMessageOrTimeout()
 	if err != nil {
 		handlerErr := it.handleExchangeMessageReceiveError(err)

/*
 * Copyright (C) 2019 The "MysteriumNetwork/node" Authors.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package pingpong

import (
	"math"
	"sync"
	"sync/atomic"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/mysteriumnetwork/node/identity"
	"github.com/mysteriumnetwork/payments/crypto"
	"github.com/pkg/errors"
	"github.com/rs/zerolog/log"
)

// PeerInvoiceSender allows to send invoices
type PeerInvoiceSender interface {
	Send(crypto.Invoice) error
}

// ErrExchangeWaitTimeout indicates that we did not get an exchange message in time
var ErrExchangeWaitTimeout = errors.New("did not get a new exchange message")

// ErrExchangeValidationFailed indicates that there was an error with the exchange signature
var ErrExchangeValidationFailed = errors.New("exchange validation failed")

const chargePeriodLeeway = time.Hour * 2

// InvoiceTracker keeps tab of invoices and sends them to the consumer
type InvoiceTracker struct {
	peer                            identity.Identity
	stop                            chan struct{}
	peerInvoiceSender               PeerInvoiceSender
	exchangeMessageChan             chan crypto.ExchangeMessage
	chargePeriod                    time.Duration
	exchangeMessageWaitTimeout      time.Duration
	notReceivedExchangeMessageCount uint64
	maxNotReceivedExchangeMessages  uint64
	once                            sync.Once
}

// NewInvoiceTracker creates a new instance of invoice tracker
func NewInvoiceTracker(
	peer identity.Identity,
	peerInvoiceSender PeerInvoiceSender,
	chargePeriod time.Duration,
	exchangeMessageChan chan crypto.ExchangeMessage,
	exchangeMessageWaitTimeout time.Duration) *InvoiceTracker {
	return &InvoiceTracker{
		peer:                           peer,
		stop:                           make(chan struct{}),
		peerInvoiceSender:              peerInvoiceSender,
		exchangeMessageChan:            exchangeMessageChan,
		exchangeMessageWaitTimeout:     exchangeMessageWaitTimeout,
		chargePeriod:                   chargePeriod,
		maxNotReceivedExchangeMessages: calculateMaxNotReceivedExchangeMessageCount(chargePeriodLeeway, chargePeriod),
	}
}

func calculateMaxNotReceivedExchangeMessageCount(chargeLeeway, chargePeriod time.Duration) uint64 {
	return uint64(math.Round(float64(chargeLeeway) / float64(chargePeriod)))
}

// Start stars the invoice tracker
func (it *InvoiceTracker) Start() error {
	log.Debug().Msg("Starting...")
	// give the consumer a second to start up his payments before sending the first request
	firstSend := time.After(time.Second)
	for {
		select {
		case <-firstSend:
			err := it.sendInvoiceExpectExchangeMessage()
			if err != nil {
				return err
			}
		case <-it.stop:
			return nil
		case <-time.After(it.chargePeriod):
			err := it.sendInvoiceExpectExchangeMessage()
			if err != nil {
				return err
			}
		}
	}
}

func (it *InvoiceTracker) markExchangeMessageNotReceived() {
	atomic.AddUint64(&it.notReceivedExchangeMessageCount, 1)
}

func (it *InvoiceTracker) resetNotReceivedExchangeMessageCount() {
	atomic.SwapUint64(&it.notReceivedExchangeMessageCount, 0)
}

func (it *InvoiceTracker) getNotReceivedExchangeMessageCount() uint64 {
	return atomic.LoadUint64(&it.notReceivedExchangeMessageCount)
}

func (it *InvoiceTracker) sendInvoiceExpectExchangeMessage() error {
	err := it.sendInvoice()
	if err != nil {
		return err
	}

	err = it.receiveExchangeMessageOrTimeout()
	if err != nil {
		handlerErr := it.handleExchangeMessageReceiveError(err)
		if handlerErr != nil {
			return err
		}
	} else {
		it.resetNotReceivedExchangeMessageCount()
	}
	return nil
}

func (it *InvoiceTracker) handleExchangeMessageReceiveError(err error) error {
	// if it's a timeout, we'll want to ignore it if we're not exceeding maxNotReceivedexchangeMessages
	if err == ErrExchangeWaitTimeout {
		it.markExchangeMessageNotReceived()
		if it.getNotReceivedExchangeMessageCount() >= it.maxNotReceivedExchangeMessages {
			return err
		}
		log.Warn().Err(err).Msg("Failed to receive exchangeMessage")
		return nil
	}
	return err
}

func (it *InvoiceTracker) sendInvoice() error {
	// TODO: a ton of actions should go here

	// TODO: fill the fields
	return it.peerInvoiceSender.Send(crypto.Invoice{AgreementID: 1234})
}

func (it *InvoiceTracker) receiveExchangeMessageOrTimeout() error {
	select {
	case pm := <-it.exchangeMessageChan:
		if res := pm.ValidateExchangeMessage(common.HexToAddress(it.peer.Address)); !res {
			return ErrExchangeValidationFailed
		}
	case <-time.After(it.exchangeMessageWaitTimeout):
		return ErrExchangeWaitTimeout
	case <-it.stop:
		return nil
	}
	return nil
}

// Stop stops the invoice tracker
func (it *InvoiceTracker) Stop() {
	it.once.Do(func() {
		log.Debug().Msg("Stopping...")
		close(it.stop)
	})
}


@@ -6,6 +6,7 @@ package full

 import (
 	"context"
+	"errors"
 	"math/rand"
 	"sync"
 	"time"

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

package full

import (
	"context"
	"math/rand"
	"sync"
	"time"

	"github.com/ethersphere/bee/pkg/addressbook"
	"github.com/ethersphere/bee/pkg/discovery"
	"github.com/ethersphere/bee/pkg/logging"
	"github.com/ethersphere/bee/pkg/p2p"
	"github.com/ethersphere/bee/pkg/swarm"
	"github.com/ethersphere/bee/pkg/topology"
)

func init() {
	rand.Seed(time.Now().UnixNano())
}

var _ topology.Driver = (*Driver)(nil)

// Driver drives the connectivity between nodes. It is a basic implementation of a connectivity Driver.
// that enabled full connectivity in the sense that:
// - Every peer which is added to the Driver gets broadcasted to every other peer regardless of its address.
// - A random peer is picked when asking for a peer to retrieve an arbitrary chunk (Peerer interface).
type Driver struct {
	discovery     discovery.Driver
	addressBook   addressbook.GetPutter
	p2pService    p2p.Service
	receivedPeers map[string]struct{} // track already received peers. Note: implement cleanup or expiration if needed to stop infinite grow
	mtx           sync.Mutex          // guards received peers
	logger        logging.Logger
}

func New(disc discovery.Driver, addressBook addressbook.GetPutter, p2pService p2p.Service, logger logging.Logger) *Driver {
	return &Driver{
		discovery:     disc,
		addressBook:   addressBook,
		p2pService:    p2pService,
		receivedPeers: make(map[string]struct{}),
		logger:        logger,
	}
}

// AddPeer adds a new peer to the topology driver.
// The peer would be subsequently broadcasted to all connected peers.
// All conneceted peers are also broadcasted to the new peer.
func (d *Driver) AddPeer(ctx context.Context, addr swarm.Address) error {
	d.mtx.Lock()
	if _, ok := d.receivedPeers[addr.ByteString()]; ok {
		d.mtx.Unlock()
		return nil
	}

	d.receivedPeers[addr.ByteString()] = struct{}{}
	d.mtx.Unlock()

	connectedPeers := d.p2pService.Peers()
	ma, exists := d.addressBook.Get(addr)
	if !exists {
		return topology.ErrNotFound
	}

	if !isConnected(addr, connectedPeers) {
		peerAddr, err := d.p2pService.Connect(ctx, ma)
		if err != nil {
			return err
		}

		// update addr if it is wrong or it has been changed
		if !addr.Equal(peerAddr) {
			addr = peerAddr
			d.addressBook.Put(peerAddr, ma)
		}
	}

	connectedAddrs := []swarm.Address{}
	for _, addressee := range connectedPeers {
		// skip newly added peer
		if addressee.Address.Equal(addr) {
			continue
		}

		connectedAddrs = append(connectedAddrs, addressee.Address)
		if err := d.discovery.BroadcastPeers(context.Background(), addressee.Address, addr); err != nil {
			return err
		}
	}

	if len(connectedAddrs) == 0 {
		return nil
	}

	if err := d.discovery.BroadcastPeers(context.Background(), addr, connectedAddrs...); err != nil {
		return err
	}

	return nil
}

// ChunkPeer is used to suggest a peer to ask a certain chunk from.
func (d *Driver) ChunkPeer(addr swarm.Address) (peerAddr swarm.Address, err error) {
	connectedPeers := d.p2pService.Peers()
	if len(connectedPeers) == 0 {
		return swarm.Address{}, topology.ErrNotFound
	}

	itemIdx := rand.Intn(len(connectedPeers))
	i := 0
	for _, v := range connectedPeers {
		if i == itemIdx {
			return v.Address, nil
		}
		i++
	}

	return swarm.Address{}, topology.ErrNotFound
}

func isConnected(addr swarm.Address, connectedPeers []p2p.Peer) bool {
	for _, p := range connectedPeers {
		if p.Address.Equal(addr) {
			return true
		}
	}

	return false
}


@@ -96,17 +96,17 @@ func (api *API) ConfigGet(dottedPath string) (interface{}, error) {

 // ChainHead returns the head tipset
 func (api *API) ChainHead(ctx context.Context) types.TipSet {
-	return api.chain.Head(ctx)
+	return api.chain.Head()
 }

 // ChainLs returns a channel of tipsets from head to genesis
 func (api *API) ChainLs(ctx context.Context) <-chan interface{} {
-	return api.chain.Ls(ctx)
+	return api.chain.BlockHistory(ctx, api.chain.Head())
 }

 // BlockGet gets a block by CID
 func (api *API) BlockGet(ctx context.Context, id cid.Cid) (*types.Block, error) {
-	return api.chain.BlockGet(ctx, id)
+	return api.chain.GetBlock(ctx, id)
 }

 // MessagePoolRemove removes a message from the message pool

package plumbing

import (
	"context"

	"gx/ipfs/QmR8BauakNcBa3RbE4nbQu76PDiJgoQgz8AJdhJuiU4TAw/go-cid"
	"gx/ipfs/QmTu65MVbemtUxJEWgsTtzv9Zv9P8rvmqNA4eG9TrTRGYc/go-libp2p-peer"
	logging "gx/ipfs/QmbkT7eMTyXfpeyB3ZMxxcxg7XH8t6uXp49jqzz4HB7BGF/go-log"

	"github.com/filecoin-project/go-filecoin/address"
	"github.com/filecoin-project/go-filecoin/core"
	"github.com/filecoin-project/go-filecoin/exec"
	"github.com/filecoin-project/go-filecoin/plumbing/cfg"
	"github.com/filecoin-project/go-filecoin/plumbing/chn"
	"github.com/filecoin-project/go-filecoin/plumbing/msg"
	"github.com/filecoin-project/go-filecoin/plumbing/mthdsig"
	"github.com/filecoin-project/go-filecoin/plumbing/ntwk"
	"github.com/filecoin-project/go-filecoin/types"
	"github.com/filecoin-project/go-filecoin/wallet"
)

// API is the plumbing implementation, the irreducible set of calls required
// to implement protocols and user/network-facing features. You probably should
// depend on the higher level porcelain.API instead of this api, as it includes
// these calls in addition to higher level convenience calls to make them more
// ergonomic.
type API struct {
	logger logging.EventLogger

	chain        *chn.Reader
	config       *cfg.Config
	messagePool  *core.MessagePool
	msgPreviewer *msg.Previewer
	msgQueryer   *msg.Queryer
	msgSender    *msg.Sender
	msgWaiter    *msg.Waiter
	network      *ntwk.Network
	sigGetter    *mthdsig.Getter
	wallet       *wallet.Wallet
}

// APIDeps contains all the API's dependencies
type APIDeps struct {
	Chain        *chn.Reader
	Config       *cfg.Config
	MessagePool  *core.MessagePool
	MsgPreviewer *msg.Previewer
	MsgQueryer   *msg.Queryer
	MsgSender    *msg.Sender
	MsgWaiter    *msg.Waiter
	Network      *ntwk.Network
	SigGetter    *mthdsig.Getter
	Wallet       *wallet.Wallet
}

// New constructs a new instance of the API.
func New(deps *APIDeps) *API {
	return &API{
		logger: logging.Logger("porcelain"),

		chain:        deps.Chain,
		config:       deps.Config,
		messagePool:  deps.MessagePool,
		msgPreviewer: deps.MsgPreviewer,
		msgQueryer:   deps.MsgQueryer,
		msgSender:    deps.MsgSender,
		msgWaiter:    deps.MsgWaiter,
		network:      deps.Network,
		sigGetter:    deps.SigGetter,
		wallet:       deps.Wallet,
	}
}

// ActorGetSignature returns the signature of the given actor's given method.
// The function signature is typically used to enable a caller to decode the
// output of an actor method call (message).
func (api *API) ActorGetSignature(ctx context.Context, actorAddr address.Address, method string) (_ *exec.FunctionSignature, err error) {
	return api.sigGetter.Get(ctx, actorAddr, method)
}

// ConfigSet sets the given parameters at the given path in the local config.
// The given path may be either a single field name, or a dotted path to a field.
// The JSON value may be either a single value or a whole data structure to be replace.
// For example:
// ConfigSet("datastore.path", "dev/null") and ConfigSet("datastore", "{\"path\":\"dev/null\"}")
// are the same operation.
func (api *API) ConfigSet(dottedPath string, paramJSON string) error {
	return api.config.Set(dottedPath, paramJSON)
}

// ConfigGet gets config parameters from the given path.
// The path may be either a single field name, or a dotted path to a field.
func (api *API) ConfigGet(dottedPath string) (interface{}, error) {
	return api.config.Get(dottedPath)
}

// ChainHead returns the head tipset
func (api *API) ChainHead(ctx context.Context) types.TipSet {
	return api.chain.Head(ctx)
}

// ChainLs returns a channel of tipsets from head to genesis
func (api *API) ChainLs(ctx context.Context) <-chan interface{} {
	return api.chain.Ls(ctx)
}

// BlockGet gets a block by CID
func (api *API) BlockGet(ctx context.Context, id cid.Cid) (*types.Block, error) {
	return api.chain.BlockGet(ctx, id)
}

// MessagePoolRemove removes a message from the message pool
func (api *API) MessagePoolRemove(cid cid.Cid) {
	api.messagePool.Remove(cid)
}

// MessagePreview previews the Gas cost of a message by running it locally on the client and
// recording the amount of Gas used.
func (api *API) MessagePreview(ctx context.Context, from, to address.Address, method string, params ...interface{}) (types.GasUnits, error) {
	return api.msgPreviewer.Preview(ctx, from, to, method, params...)
}

// MessageQuery calls an actor's method using the most recent chain state. It is read-only,
// it does not change any state. It is use to interrogate actor state. The from address
// is optional; if not provided, an address will be chosen from the node's wallet.
func (api *API) MessageQuery(ctx context.Context, optFrom, to address.Address, method string, params ...interface{}) ([][]byte, *exec.FunctionSignature, error) {
	return api.msgQueryer.Query(ctx, optFrom, to, method, params...)
}

// MessageSend sends a message. It uses the default from address if none is given and signs the
// message using the wallet. This call "sends" in the sense that it enqueues the
// message in the msg pool and broadcasts it to the network; it does not wait for the
// message to go on chain. Note that no default from address is provided. If you need
// a default address, use MessageSendWithDefaultAddress instead.
func (api *API) MessageSend(ctx context.Context, from, to address.Address, value *types.AttoFIL, gasPrice types.AttoFIL, gasLimit types.GasUnits, method string, params ...interface{}) (cid.Cid, error) {
	return api.msgSender.Send(ctx, from, to, value, gasPrice, gasLimit, method, params...)
}

// MessageWait invokes the callback when a message with the given cid appears on chain.
// It will find the message in both the case that it is already on chain and
// the case that it appears in a newly mined block. An error is returned if one is
// encountered or if the context is canceled. Otherwise, it waits forever for the message
// to appear on chain.
func (api *API) MessageWait(ctx context.Context, msgCid cid.Cid, cb func(*types.Block, *types.SignedMessage, *types.MessageReceipt) error) error {
	return api.msgWaiter.Wait(ctx, msgCid, cb)
}

// NetworkGetPeerID gets the current peer id from Util
func (api *API) NetworkGetPeerID() peer.ID {
	return api.network.GetPeerID()
}

// SignBytes uses private key information associated with the given address to sign the given bytes.
func (api *API) SignBytes(data []byte, addr address.Address) (types.Signature, error) {
	return api.wallet.SignBytes(data, addr)
}

// WalletAddresses gets addresses from the wallet
func (api *API) WalletAddresses() []address.Address {
	return api.wallet.Addresses()
}

// WalletFind finds addresses on the wallet
func (api *API) WalletFind(address address.Address) (wallet.Backend, error) {
	return api.wallet.Find(address)
}

// WalletNewAddress generates a new wallet address
func (api *API) WalletNewAddress() (address.Address, error) {
	return wallet.NewAddress(api.wallet)
}


@@ -26,6 +26,10 @@ import (
 )

 const cloneStepID = "CLONE"
+const checkoutStepID = "CHECKOUT"
+const javaArtifactsID = "JAVA-ARTIFACTS"
+const preStepID = "PREPROCESS"
+const extractStepID = "EXTRACT"

 // commonSteps returns cloudbuild BuildSteps for copying a repo and creating
 // an output directory.

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

package config

import (
	"fmt"
	"path"

	"kythe.io/kythe/go/extractors/constants"

	"google.golang.org/api/cloudbuild/v1"
)

const cloneStepID = "CLONE"

// commonSteps returns cloudbuild BuildSteps for copying a repo and creating
// an output directory.
//
// The BuildStep for the repo copy uses id cloneStepID, as described in
// https://cloud.google.com/cloud-build/docs/build-config#id, for any future
// steps that need to depend on the repo clone step.  The repo copy step puts
// the code into /workspace/code.
//
// The output directory is /workspace/out.
func commonSteps() []*cloudbuild.BuildStep {
	return []*cloudbuild.BuildStep{
		&cloudbuild.BuildStep{
			Name:    constants.GCRGitImage, // This triggers with command 'git'.
			Args:    []string{"clone", repoName, "/workspace/code"},
			Id:      cloneStepID,
			WaitFor: []string{"-"},
		},
		&cloudbuild.BuildStep{
			Name:    "ubuntu", // This, however, has no entrypoint command.
			Args:    []string{"mkdir", "/workspace/out"},
			WaitFor: []string{"-"},
		},
	}
}

func preprocessorStep(build string) *cloudbuild.BuildStep {
	return &cloudbuild.BuildStep{
		Name:    constants.KytheBuildPreprocessorImage,
		Args:    []string{build},
		WaitFor: []string{cloneStepID},
	}
}

// TODO(#3095): This step needs to be configurable by the java version used for
// a given BuildTarget.
func javaExtractorsStep() *cloudbuild.BuildStep {
	return &cloudbuild.BuildStep{
		Name: constants.KytheJavacExtractorArtifactsImage,
		Volumes: []*cloudbuild.Volume{
			&cloudbuild.Volume{
				Name: javaVolumeName,
				Path: constants.DefaultExtractorsDir,
			},
		},
		WaitFor: []string{"-"},
	}
}

func zipMergeStep() *cloudbuild.BuildStep {
	return &cloudbuild.BuildStep{
		Name:       constants.KytheKzipToolsImage,
		Entrypoint: "bash",
		Args: []string{
			"-c",
			fmt.Sprintf(
				"%s merge --output %s %s/*.kzip",
				constants.DefaultKzipToolLocation,
				path.Join(outputDirectory, outputFilePattern),
				outputDirectory),
		},
	}
}


@@ -74,6 +74,20 @@ var configSetCmd = &cobra.Command{
 	},
 }

+// configResetCmd represents the config reset command
+var configResetCmd = &cobra.Command{
+	Use:   "reset",
+	Short: "Reset config to default",
+	RunE: func(cmd *cobra.Command, args []string) error {
+		cmd.SilenceUsage = true
+		output, err := reset()
+		if err == nil {
+			fmt.Println(output)
+		}
+		return err
+	},
+}
+
 func init() {
 	configSetCmd.Flags().BoolVar(&Insecure, "insecure", false,
 		"set insecure connection as default")

// Copyright (c) 2019 IoTeX
// This is an alpha (internal) release and is not suitable for production. This source code is provided 'as is' and no
// warranties are given as to title or non-infringement, merchantability or fitness for purpose and, to the extent
// permitted by law, all liability for your use of the code is disclaimed. This source code is governed by Apache
// License 2.0 that can be found in the LICENSE file.

package config

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

	"github.com/spf13/cobra"
	"gopkg.in/yaml.v2"

	"github.com/iotexproject/iotex-core/ioctl/validator"
)

const (
	ipPattern       = `((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)`
	domainPattern   = `[a-zA-Z0-9][a-zA-Z0-9_-]{0,62}(\.[a-zA-Z0-9][a-zA-Z0-9_-]{0,62})*(\.[a-zA-Z][a-zA-Z0-9]{0,10}){1}`
	localPattern    = "localhost"
	endpointPattern = "(" + ipPattern + "|(" + domainPattern + ")" + "|(" + localPattern + "))" + `(:\d{1,5})?`
)

var (
	validArgs       = []string{"endpoint", "wallet", "currentcontext"}
	endpointCompile = regexp.MustCompile("^" + endpointPattern + "$")
)

// configGetCmd represents the config get command
var configGetCmd = &cobra.Command{
	Use:       "get VARIABLE",
	Short:     "Get config from ioctl",
	ValidArgs: validArgs,
	Args: func(cmd *cobra.Command, args []string) error {
		if len(args) != 1 {
			return fmt.Errorf("accepts 1 arg(s), received %d,"+
				" valid arg(s): %s", len(args), validArgs)
		}
		return cobra.OnlyValidArgs(cmd, args)
	},
	RunE: func(cmd *cobra.Command, args []string) error {
		cmd.SilenceUsage = true
		output, err := Get(args[0])
		if err == nil {
			fmt.Println(output)
		}
		return err
	},
}

// configSetCmd represents the config set command
var configSetCmd = &cobra.Command{
	Use:       "set VARIABLE VALUE",
	Short:     "Set config for ioctl",
	ValidArgs: validArgs,
	Args: func(cmd *cobra.Command, args []string) error {
		if len(args) != 2 {
			return fmt.Errorf("accepts 2 arg(s), received %d,"+
				" valid arg(s): %s", len(args), validArgs)
		}
		return cobra.OnlyValidArgs(cmd, args[:1])
	},
	RunE: func(cmd *cobra.Command, args []string) error {
		cmd.SilenceUsage = true
		output, err := set(args)
		if err == nil {
			fmt.Println(output)
		}
		return err
	},
}

func init() {
	configSetCmd.Flags().BoolVar(&Insecure, "insecure", false,
		"set insecure connection as default")
}

// Get gets config variable
func Get(arg string) (string, error) {
	switch arg {
	default:
		return "", ErrConfigNotMatch
	case "endpoint":
		if ReadConfig.Endpoint == "" {
			return "", ErrEmptyEndpoint
		}
		return fmt.Sprint(ReadConfig.Endpoint, "    secure connect(TLS):",
			ReadConfig.SecureConnect), nil
	case "wallet":
		return ReadConfig.Wallet, nil
	case "currentcontext":
		return fmt.Sprint(ReadConfig.CurrentContext), nil
	}
}

// GetContextAddressOrAlias gets current context
func GetContextAddressOrAlias() (string, error) {
	currentcontext := ReadConfig.CurrentContext
	if strings.EqualFold(currentcontext.AddressOrAlias, "") {
		return "", fmt.Errorf(`use "ioctl config set currentcontext address or alias" to config current account first`)
	}
	return currentcontext.AddressOrAlias, nil
}

// GetAddressOrAlias gets address from args or context
func GetAddressOrAlias(args []string) (address string, err error) {
	if len(args) == 1 && !strings.EqualFold(args[0], "") {
		address = args[0]
	} else {
		address, err = GetContextAddressOrAlias()
	}
	return
}

// make sure endpoint match pattern
func isMatch(endpoint string) bool {
	return endpointCompile.MatchString(endpoint)
}

// set sets config variable
func set(args []string) (string, error) {
	switch args[0] {
	default:
		return "", ErrConfigNotMatch
	case "endpoint":
		if !isMatch(args[1]) {
			return "", fmt.Errorf("Endpoint %s is not valid", args[1])
		}
		ReadConfig.Endpoint = args[1]
		ReadConfig.SecureConnect = !Insecure
	case "wallet":
		ReadConfig.Wallet = args[1]
	case "currentcontext":
		err1 := validator.ValidateAlias(args[1])
		err2 := validator.ValidateAddress(args[1])
		if err1 != nil && err2 != nil {
			return "", fmt.Errorf("failed to validate alias or address:%s %s", err1, err2)
		}
		ReadConfig.CurrentContext.AddressOrAlias = args[1]
	}
	out, err := yaml.Marshal(&ReadConfig)
	if err != nil {
		return "", err
	}
	if err := ioutil.WriteFile(DefaultConfigFile, out, 0600); err != nil {
		return "", fmt.Errorf("failed to write to config file %s", DefaultConfigFile)
	}
	return args[0] + " is set to " + args[1], nil
}


@@ -112,11 +112,10 @@ func (s *Store) GetObject(ctx context.Context, path string) (object filestore.Ob

 	object.Path = path
 	object.Content = content
-	object.Size = int64(len(content))
 	return
 }

-func (s *Store) PutObject(ctx context.Context, path string, content []byte) error {
+func (s *Store) Put(ctx context.Context, path string, content []byte) error {
 	wc := s.client.Bucket(s.bucket).Object(path).NewWriter(ctx)
 	if _, err := wc.Write(content); err != nil {
 		wc.Close()

// Copyright 2020 The PipeCD 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 gcs

import (
	"context"
	"io"
	"io/ioutil"
	"net/http"

	"cloud.google.com/go/storage"
	"go.uber.org/zap"
	"google.golang.org/api/iterator"
	"google.golang.org/api/option"

	"github.com/pipe-cd/pipe/pkg/filestore"
)

type Store struct {
	client          *storage.Client
	bucket          string
	credentialsFile string
	httpClient      *http.Client
	logger          *zap.Logger
}

type Option func(*Store)

func WithCredentialsFile(path string) Option {
	return func(s *Store) {
		s.credentialsFile = path
	}
}

func WithHTTPClient(client *http.Client) Option {
	return func(s *Store) {
		s.httpClient = client
	}
}

func WithLogger(logger *zap.Logger) Option {
	return func(s *Store) {
		s.logger = logger.Named("gcs")
	}
}

func NewStore(ctx context.Context, bucket string, opts ...Option) (*Store, error) {
	s := &Store{
		bucket: bucket,
		logger: zap.NewNop(),
	}
	for _, opt := range opts {
		opt(s)
	}

	var options []option.ClientOption
	if s.credentialsFile != "" {
		options = append(options, option.WithCredentialsFile(s.credentialsFile))
	}
	if s.httpClient != nil {
		options = append(options, option.WithHTTPClient(s.httpClient))
	}
	client, err := storage.NewClient(ctx, options...)
	if err != nil {
		return nil, err
	}
	s.client = client
	return s, nil
}

func (s *Store) NewReader(ctx context.Context, path string) (rc io.ReadCloser, err error) {
	rc, err = s.client.Bucket(s.bucket).Object(path).NewReader(ctx)
	switch err {
	case nil:
	case storage.ErrObjectNotExist:
		err = filestore.ErrNotFound
		return
	default:
		s.logger.Error("failed to create GCS object reader", zap.String("path", path), zap.Error(err))
		return
	}
	return
}

func (s *Store) GetObject(ctx context.Context, path string) (object filestore.Object, err error) {
	rc, err := s.NewReader(ctx, path)
	if err != nil {
		return
	}
	defer func() {
		if err := rc.Close(); err != nil {
			s.logger.Error("failed to close object reader")
		}
	}()

	content, err := ioutil.ReadAll(rc)
	if err != nil {
		return
	}

	object.Path = path
	object.Content = content
	object.Size = int64(len(content))
	return
}

func (s *Store) PutObject(ctx context.Context, path string, content []byte) error {
	wc := s.client.Bucket(s.bucket).Object(path).NewWriter(ctx)
	if _, err := wc.Write(content); err != nil {
		wc.Close()
		return err
	}
	if err := wc.Close(); err != nil {
		return err
	}
	return nil
}

func (s *Store) ListObjects(ctx context.Context, prefix string) ([]filestore.Object, error) {
	var objects []filestore.Object
	query := &storage.Query{
		Prefix: prefix,
	}
	it := s.client.Bucket(s.bucket).Objects(ctx, query)
	for {
		attrs, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			s.logger.Error("failed to iterate to the next object",
				zap.String("prefix", prefix),
				zap.Error(err),
			)
			return nil, err
		}
		object := filestore.Object{
			Path:    attrs.Name,
			Size:    attrs.Size,
			Content: []byte{},
		}
		objects = append(objects, object)
	}
	return objects, nil
}

func (s *Store) Close() error {
	return s.client.Close()
}


@@ -1,3 +1,4 @@
+//go:build cgo
 // +build cgo

 package sqlstore

// +build cgo

package sqlstore

import (
	"errors"
	"net/url"

	"github.com/jinzhu/gorm"
	"github.com/mattn/go-sqlite3"
	"github.com/sirupsen/logrus"

	// gorm sqlite dialect init registration
	_ "github.com/jinzhu/gorm/dialects/sqlite"
)

type sqliteDB struct {
	log logrus.FieldLogger
}

func (s sqliteDB) connect(cfg *configuration, isReadOnly bool) (db *gorm.DB, version string, supportsCTE bool, err error) {
	if isReadOnly {
		s.log.Warn("Read-only connection is not applicable for sqlite3. Falling back to primary connection")
	}

	db, err = openSQLite3(cfg.ConnectionString)
	if err != nil {
		return nil, "", false, err
	}

	version, err = queryVersion(db, "SELECT sqlite_version()")
	if err != nil {
		return nil, "", false, err
	}

	// The embedded version of SQLite3 unconditionally supports CTE.
	return db, version, true, nil
}

func (s sqliteDB) isConstraintViolation(err error) bool {
	if err == nil {
		return false
	}
	var e sqlite3.Error
	ok := errors.As(err, &e)
	return ok && e.Code == sqlite3.ErrConstraint
}

func openSQLite3(connString string) (*gorm.DB, error) {
	embellished, err := embellishSQLite3ConnString(connString)
	if err != nil {
		return nil, err
	}
	db, err := gorm.Open("sqlite3", embellished)
	if err != nil {
		return nil, sqlError.Wrap(err)
	}
	return db, nil
}

// embellishSQLite3ConnString adds query values supported by
// github.com/mattn/go-sqlite3 to enable journal mode and foreign key support.
// These query values MUST be part of the connection string in order to be
// enabled for *each* connection opened by db/sql. If the connection string is
// not already a file: URI, it is converted first.
func embellishSQLite3ConnString(connectionString string) (string, error) {
	u, err := url.Parse(connectionString)
	if err != nil {
		return "", sqlError.Wrap(err)
	}

	switch {
	case u.Scheme == "":
		// connection string is a path. move the path section into the
		// opaque section so it renders property for sqlite3, for example:
		// data.db = file:data.db
		// ./data.db = file:./data.db
		// /data.db = file:/data.db
		u.Scheme = "file"
		u.Opaque, u.Path = u.Path, ""
	case u.Scheme != "file":
		// only no scheme (i.e. file path) or file scheme is supported
		return "", sqlError.New("unsupported scheme %q", u.Scheme)
	}

	q := u.Query()
	q.Set("_foreign_keys", "ON")
	q.Set("_journal_mode", "WAL")
	u.RawQuery = q.Encode()
	return u.String(), nil
}


@@ -5,6 +5,14 @@
 // This file defines service deployment resources.
 package deploy

+import (
+	"fmt"
+	"strings"
+)
+
+// FmtTaskECRRepoName is the pattern used to generate the ECR repository's name
+const FmtTaskECRRepoName = "copilot-%s"
+
 // CreateTaskResourcesInput holds the fields required to create a task stack.
 type CreateTaskResourcesInput struct {
 	Name   string

// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

// Package deploy holds the structures to deploy infrastructure resources.
// This file defines service deployment resources.
package deploy

// CreateTaskResourcesInput holds the fields required to create a task stack.
type CreateTaskResourcesInput struct {
	Name   string
	CPU    int
	Memory int

	Image         string
	TaskRole      string
	ExecutionRole string
	Command       []string
	EnvVars       map[string]string

	App string
	Env string

	AdditionalTags map[string]string
}


@@ -1,12 +1,14 @@
 package action

 import (
+	"math/big"
 	"testing"

 	"github.com/iotexproject/iotex-proto/golang/iotextypes"
 	"github.com/stretchr/testify/require"

 	"github.com/iotexproject/iotex-core/pkg/unit"
+	"github.com/iotexproject/iotex-core/state"
 	"github.com/iotexproject/iotex-core/test/identityset"
 )

package action

import (
	"testing"

	"github.com/iotexproject/iotex-proto/golang/iotextypes"
	"github.com/stretchr/testify/require"

	"github.com/iotexproject/iotex-core/pkg/unit"
	"github.com/iotexproject/iotex-core/test/identityset"
)

func TestEnvelope_Basic(t *testing.T) {
	req := require.New(t)
	evlp, tsf := createEnvelope()
	req.Equal(uint32(1), evlp.Version())
	req.Equal(uint64(10), evlp.Nonce())
	req.Equal(uint64(20010), evlp.GasLimit())
	req.Equal("11000000000000000000", evlp.GasPrice().String())
	c, err := evlp.Cost()
	req.NoError(err)
	req.Equal("111010000000000000000000", c.String())
	g, err := evlp.IntrinsicGas()
	req.NoError(err)
	req.Equal(uint64(10000), g)
	d, ok := evlp.Destination()
	req.True(ok)
	req.Equal("io1jh0ekmccywfkmj7e8qsuzsupnlk3w5337hjjg2", d)
	tsf2, ok := evlp.Action().(*Transfer)
	req.True(ok)
	req.Equal(tsf, tsf2)
}
func TestEnvelope_Proto(t *testing.T) {
	req := require.New(t)
	eb, tsf := createEnvelope()
	evlp, ok := eb.(*envelope)
	req.True(ok)

	proto := evlp.Proto()
	actCore := &iotextypes.ActionCore{
		Version:  evlp.version,
		Nonce:    evlp.nonce,
		GasLimit: evlp.gasLimit,
	}
	actCore.GasPrice = evlp.gasPrice.String()
	actCore.Action = &iotextypes.ActionCore_Transfer{Transfer: tsf.Proto()}
	req.Equal(actCore, proto)

	req.NoError(evlp.LoadProto(proto))
	tsf2, ok := evlp.Action().(*Transfer)
	req.True(ok)
	req.Equal(tsf.amount, tsf2.amount)
	req.Equal(tsf.recipient, tsf2.recipient)
	req.Equal(tsf.payload, tsf2.payload)
}

func createEnvelope() (Envelope, *Transfer) {
	tsf, _ := NewTransfer(
		uint64(10),
		unit.ConvertIotxToRau(1000+int64(10)),
		identityset.Address(10%identityset.Size()).String(),
		nil,
		20000+uint64(10),
		unit.ConvertIotxToRau(1+int64(10)),
	)
	eb := EnvelopeBuilder{}
	evlp := eb.
		SetAction(tsf).
		SetGasLimit(tsf.GasLimit()).
		SetGasPrice(tsf.GasPrice()).
		SetNonce(tsf.Nonce()).
		SetVersion(1).
		Build()
	return evlp, tsf
}


@@ -35,7 +35,7 @@ func (b *builder) createGoInstruction(funcPtr llvm.Value, params []llvm.Value, p
 			// The stack size is fixed at compile time. By emitting it here as a
 			// constant, it can be optimized.
 			if b.Scheduler == "tasks" && b.DefaultStackSize == 0 {
-				b.addError(pos, "default stack size for goroutines is not set")
+				b.addError(instr.Pos(), "default stack size for goroutines is not set")
 			}
 			stackSize = llvm.ConstInt(b.uintptrType, b.DefaultStackSize, false)
 		}

package compiler

// This file implements the 'go' keyword to start a new goroutine. See
// goroutine-lowering.go for more details.

import (
	"go/token"

	"github.com/tinygo-org/tinygo/compiler/llvmutil"
	"golang.org/x/tools/go/ssa"
	"tinygo.org/x/go-llvm"
)

// createGoInstruction starts a new goroutine with the provided function pointer
// and parameters.
// In general, you should pass all regular parameters plus the context parameter.
// There is one exception: the task-based scheduler needs to have the function
// pointer passed in as a parameter too in addition to the context.
//
// Because a go statement doesn't return anything, return undef.
func (b *builder) createGoInstruction(funcPtr llvm.Value, params []llvm.Value, prefix string, pos token.Pos) llvm.Value {
	paramBundle := b.emitPointerPack(params)
	var callee, stackSize llvm.Value
	switch b.Scheduler {
	case "none", "tasks":
		callee = b.createGoroutineStartWrapper(funcPtr, prefix, pos)
		if b.AutomaticStackSize {
			// The stack size is not known until after linking. Call a dummy
			// function that will be replaced with a load from a special ELF
			// section that contains the stack size (and is modified after
			// linking).
			stackSizeFn := b.getFunction(b.program.ImportedPackage("internal/task").Members["getGoroutineStackSize"].(*ssa.Function))
			stackSize = b.createCall(stackSizeFn, []llvm.Value{callee, llvm.Undef(b.i8ptrType), llvm.Undef(b.i8ptrType)}, "stacksize")
		} else {
			// The stack size is fixed at compile time. By emitting it here as a
			// constant, it can be optimized.
			if b.Scheduler == "tasks" && b.DefaultStackSize == 0 {
				b.addError(pos, "default stack size for goroutines is not set")
			}
			stackSize = llvm.ConstInt(b.uintptrType, b.DefaultStackSize, false)
		}
	case "coroutines":
		callee = b.CreatePtrToInt(funcPtr, b.uintptrType, "")
		// There is no goroutine stack size: coroutines are used instead of
		// stacks.
		stackSize = llvm.Undef(b.uintptrType)
	default:
		panic("unreachable")
	}
	start := b.getFunction(b.program.ImportedPackage("internal/task").Members["start"].(*ssa.Function))
	b.createCall(start, []llvm.Value{callee, paramBundle, stackSize, llvm.Undef(b.i8ptrType), llvm.ConstPointerNull(b.i8ptrType)}, "")
	return llvm.Undef(funcPtr.Type().ElementType().ReturnType())
}

// createGoroutineStartWrapper creates a wrapper for the task-based
// implementation of goroutines. For example, to call a function like this:
//
//     func add(x, y int) int { ... }
//
// It creates a wrapper like this:
//
//     func add$gowrapper(ptr *unsafe.Pointer) {
//         args := (*struct{
//             x, y int
//         })(ptr)
//         add(args.x, args.y)
//     }
//
// This is useful because the task-based goroutine start implementation only
// allows a single (pointer) argument to the newly started goroutine. Also, it
// ignores the return value because newly started goroutines do not have a
// return value.
func (c *compilerContext) createGoroutineStartWrapper(fn llvm.Value, prefix string, pos token.Pos) llvm.Value {
	var wrapper llvm.Value

	builder := c.ctx.NewBuilder()
	defer builder.Dispose()

	if !fn.IsAFunction().IsNil() {
		// See whether this wrapper has already been created. If so, return it.
		name := fn.Name()
		wrapper = c.mod.NamedFunction(name + "$gowrapper")
		if !wrapper.IsNil() {
			return llvm.ConstPtrToInt(wrapper, c.uintptrType)
		}

		// Create the wrapper.
		wrapperType := llvm.FunctionType(c.ctx.VoidType(), []llvm.Type{c.i8ptrType}, false)
		wrapper = llvm.AddFunction(c.mod, name+"$gowrapper", wrapperType)
		wrapper.SetLinkage(llvm.LinkOnceODRLinkage)
		wrapper.SetUnnamedAddr(true)
		wrapper.AddAttributeAtIndex(-1, c.ctx.CreateStringAttribute("tinygo-gowrapper", name))
		entry := c.ctx.AddBasicBlock(wrapper, "entry")
		builder.SetInsertPointAtEnd(entry)

		if c.Debug {
			pos := c.program.Fset.Position(pos)
			diFuncType := c.dibuilder.CreateSubroutineType(llvm.DISubroutineType{
				File:       c.getDIFile(pos.Filename),
				Parameters: nil, // do not show parameters in debugger
				Flags:      0,   // ?
			})
			difunc := c.dibuilder.CreateFunction(c.getDIFile(pos.Filename), llvm.DIFunction{
				Name:         "<goroutine wrapper>",
				File:         c.getDIFile(pos.Filename),
				Line:         pos.Line,
				Type:         diFuncType,
				LocalToUnit:  true,
				IsDefinition: true,
				ScopeLine:    0,
				Flags:        llvm.FlagPrototyped,
				Optimized:    true,
			})
			wrapper.SetSubprogram(difunc)
			builder.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), difunc, llvm.Metadata{})
		}

		// Create the list of params for the call.
		paramTypes := fn.Type().ElementType().ParamTypes()
		params := llvmutil.EmitPointerUnpack(builder, c.mod, wrapper.Param(0), paramTypes[:len(paramTypes)-1])
		params = append(params, llvm.Undef(c.i8ptrType))

		// Create the call.
		builder.CreateCall(fn, params, "")

	} else {
		// For a function pointer like this:
		//
		//     var funcPtr func(x, y int) int
		//
		// A wrapper like the following is created:
		//
		//     func .gowrapper(ptr *unsafe.Pointer) {
		//         args := (*struct{
		//             x, y int
		//             fn   func(x, y int) int
		//         })(ptr)
		//         args.fn(x, y)
		//     }
		//
		// With a bit of luck, identical wrapper functions like these can be
		// merged into one.

		// Create the wrapper.
		wrapperType := llvm.FunctionType(c.ctx.VoidType(), []llvm.Type{c.i8ptrType}, false)
		wrapper = llvm.AddFunction(c.mod, prefix+".gowrapper", wrapperType)
		wrapper.SetLinkage(llvm.LinkOnceODRLinkage)
		wrapper.SetUnnamedAddr(true)
		wrapper.AddAttributeAtIndex(-1, c.ctx.CreateStringAttribute("tinygo-gowrapper", ""))
		entry := c.ctx.AddBasicBlock(wrapper, "entry")
		builder.SetInsertPointAtEnd(entry)

		if c.Debug {
			pos := c.program.Fset.Position(pos)
			diFuncType := c.dibuilder.CreateSubroutineType(llvm.DISubroutineType{
				File:       c.getDIFile(pos.Filename),
				Parameters: nil, // do not show parameters in debugger
				Flags:      0,   // ?
			})
			difunc := c.dibuilder.CreateFunction(c.getDIFile(pos.Filename), llvm.DIFunction{
				Name:         "<goroutine wrapper>",
				File:         c.getDIFile(pos.Filename),
				Line:         pos.Line,
				Type:         diFuncType,
				LocalToUnit:  true,
				IsDefinition: true,
				ScopeLine:    0,
				Flags:        llvm.FlagPrototyped,
				Optimized:    true,
			})
			wrapper.SetSubprogram(difunc)
			builder.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), difunc, llvm.Metadata{})
		}

		// Get the list of parameters, with the extra parameters at the end.
		paramTypes := fn.Type().ElementType().ParamTypes()
		paramTypes[len(paramTypes)-1] = fn.Type() // the last element is the function pointer
		params := llvmutil.EmitPointerUnpack(builder, c.mod, wrapper.Param(0), paramTypes)

		// Get the function pointer.
		fnPtr := params[len(params)-1]

		// Ignore the last param, which isn't used anymore.
		// TODO: avoid this extra "parent handle" parameter in most functions.
		params[len(params)-1] = llvm.Undef(c.i8ptrType)

		// Create the call.
		builder.CreateCall(fnPtr, params, "")
	}

	// Finish the function. Every basic block must end in a terminator, and
	// because goroutines never return a value we can simply return void.
	builder.CreateRetVoid()

	// Return a ptrtoint of the wrapper, not the function itself.
	return builder.CreatePtrToInt(wrapper, c.uintptrType, "")
}


@@ -50,6 +50,7 @@ var (
 		Name:  "agreed-terms-and-conditions",
 		Usage: "Agree with terms & conditions",
 	}
+
 	// FlagAccessPolicyAddress Trust oracle URL for retrieving access policies.
 	FlagAccessPolicyAddress = cli.StringFlag{
 		Name:  "access-policy.address",

/*
 * Copyright (C) 2019 The "MysteriumNetwork/node" Authors.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package config

import (
	"time"

	"github.com/mysteriumnetwork/node/metadata"
	"github.com/urfave/cli/v2"
)

// ServicesOptions describes options shared among multiple services
type ServicesOptions struct {
	AccessPolicyAddress       string
	AccessPolicyList          []string
	AccessPolicyFetchInterval time.Duration
	ShaperEnabled             bool
}

var (
	// FlagIdentity keystore's identity.
	FlagIdentity = cli.StringFlag{
		Name:  "identity",
		Usage: "Keystore's identity used to provide service. If not given identity will be created automatically",
		Value: "",
	}
	// FlagIdentityPassphrase passphrase to unlock the identity.
	FlagIdentityPassphrase = cli.StringFlag{
		Name:  "identity.passphrase",
		Usage: "Used to unlock keystore's identity",
		Value: "",
	}
	// FlagAgreedTermsConditions agree with terms & conditions.
	FlagAgreedTermsConditions = cli.BoolFlag{
		Name:  "agreed-terms-and-conditions",
		Usage: "Agree with terms & conditions",
	}
	// FlagAccessPolicyAddress Trust oracle URL for retrieving access policies.
	FlagAccessPolicyAddress = cli.StringFlag{
		Name:  "access-policy.address",
		Usage: "URL of trust oracle endpoint for retrieving lists of access policies",
		Value: metadata.DefaultNetwork.AccessPolicyOracleAddress,
	}
	// FlagAccessPolicyList a comma-separated list of access policies that determines allowed identities to use the service.
	FlagAccessPolicyList = cli.StringFlag{
		Name:  "access-policy.list",
		Usage: "Comma separated list that determines the access policies applied to provide service.",
		Value: "",
	}
	// FlagAccessPolicyFetchInterval policy list fetch interval.
	FlagAccessPolicyFetchInterval = cli.DurationFlag{
		Name:  "access-policy.fetch",
		Usage: `Proposal fetch interval { "30s", "3m", "1h20m30s" }`,
		Value: 10 * time.Minute,
	}
	// FlagShaperEnabled enables bandwidth limitation.
	FlagShaperEnabled = cli.BoolFlag{
		Name:  "shaper.enabled",
		Usage: "Limit service bandwidth",
	}
	// FlagNoopPriceMinute sets the price per minute for provided noop service.
	FlagNoopPriceMinute = cli.Float64Flag{
		Name:   "noop.price-minute",
		Usage:  "Sets the price of the noop service per minute.",
		Value:  0.0001,
		Hidden: true,
	}
)

// RegisterFlagsServiceShared registers shared service CLI flags
func RegisterFlagsServiceShared(flags *[]cli.Flag) {
	*flags = append(*flags,
		&FlagIdentity,
		&FlagIdentityPassphrase,
		&FlagAgreedTermsConditions,
		&FlagAccessPolicyAddress,
		&FlagAccessPolicyList,
		&FlagAccessPolicyFetchInterval,
		&FlagShaperEnabled,
		&FlagNoopPriceMinute,
	)
}

// ParseFlagsServiceShared parses shared service CLI flags and registers values to the configuration
func ParseFlagsServiceShared(ctx *cli.Context) {
	Current.ParseStringFlag(ctx, FlagIdentity)
	Current.ParseStringFlag(ctx, FlagIdentityPassphrase)
	Current.ParseBoolFlag(ctx, FlagAgreedTermsConditions)
	Current.ParseStringFlag(ctx, FlagAccessPolicyAddress)
	Current.ParseStringFlag(ctx, FlagAccessPolicyList)
	Current.ParseDurationFlag(ctx, FlagAccessPolicyFetchInterval)
	Current.ParseBoolFlag(ctx, FlagShaperEnabled)
	Current.ParseFloat64Flag(ctx, FlagNoopPriceMinute)
}


@@ -22,6 +22,14 @@ type Bounds struct {
 	index int
 }

+// NewBounds create a new Bounds given start and stop values
+func NewBounds(start, stop values.Time) Bounds {
+	return Bounds{
+		start: start,
+		stop:  stop,
+	}
+}
+
 func (b Bounds) Start() values.Time {
 	return b.start
 }

package interval

import (
	"fmt"
	"math"

	"github.com/influxdata/flux/values"
)

const (
	MaxTime = math.MaxInt64
	MinTime = math.MinInt64
)

type Bounds struct {
	start values.Time
	stop  values.Time
	// index keeps track of how many windows have been added or subtracted as additional
	// windows are added to or subtracted from the initial bounds. In essence, it tracks the
	// offset from the original bounds in order to keep operations more straightforward.
	// See the Window struct and the window tests for additional info.
	index int
}

func (b Bounds) Start() values.Time {
	return b.start
}

func (b Bounds) Stop() values.Time {
	return b.stop
}

func (b Bounds) IsEmpty() bool {
	return b.start >= b.stop
}

func (b Bounds) String() string {
	return fmt.Sprintf("[%v, %v)", b.start, b.stop)
}

func (b Bounds) Contains(t values.Time) bool {
	return t >= b.start && t < b.stop
}

func (b Bounds) Overlaps(o Bounds) bool {
	return b.Contains(o.start) || (b.Contains(o.stop) && o.stop > b.start) || o.Contains(b.start)
}

func (b Bounds) Equal(o Bounds) bool {
	return b == o
}

func (b Bounds) Length() values.Duration {
	if b.IsEmpty() {
		return values.ConvertDurationNsecs(0)
	}
	return b.stop.Sub(b.start)
}


@@ -5,7 +5,6 @@ import (
 	"crypto/tls"
 	"fmt"
 	"net"
-	"sync"
 	"time"

 	"github.com/ethereum/go-ethereum/common"

package locator

import (
	"crypto/ecdsa"
	"crypto/tls"
	"fmt"
	"net"
	"sync"
	"time"

	"github.com/ethereum/go-ethereum/common"
	log "github.com/noxiouz/zapctx/ctxlog"
	"github.com/pkg/errors"
	pb "github.com/sonm-io/core/proto"
	"github.com/sonm-io/core/util"
	"go.uber.org/zap"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/credentials"
	"google.golang.org/grpc/peer"
	"google.golang.org/grpc/status"
)

var errNodeNotFound = errors.New("node with given Eth address cannot be found")

type node struct {
	ethAddr common.Address
	ipAddr  []string
	ts      time.Time
}

type Locator struct {
	mx sync.Mutex

	conf        *LocatorConfig
	db          map[common.Address]*node
	ctx         context.Context
	ethKey      *ecdsa.PrivateKey
	grpc        *grpc.Server
	certRotator util.HitlessCertRotator
	creds       credentials.TransportCredentials
}

func (l *Locator) Announce(ctx context.Context, req *pb.AnnounceRequest) (*pb.Empty, error) {
	ethAddr, err := l.extractEthAddr(ctx)
	if err != nil {
		return nil, err
	}

	log.G(l.ctx).Info("handling Announce request",
		zap.Stringer("eth", ethAddr), zap.Strings("ips", req.IpAddr))

	l.putAnnounce(&node{
		ethAddr: ethAddr,
		ipAddr:  req.IpAddr,
	})

	return &pb.Empty{}, nil
}

func (l *Locator) Resolve(ctx context.Context, req *pb.ResolveRequest) (*pb.ResolveReply, error) {
	log.G(l.ctx).Info("handling Resolve request", zap.String("eth", req.EthAddr))

	if !common.IsHexAddress(req.EthAddr) {
		return nil, fmt.Errorf("invalid ethaddress %s", req.EthAddr)
	}

	n, err := l.getResolve(common.HexToAddress(req.EthAddr))
	if err != nil {
		return nil, err
	}

	return &pb.ResolveReply{IpAddr: n.ipAddr}, nil
}

func (l *Locator) Serve() error {
	lis, err := net.Listen("tcp", l.conf.ListenAddr)
	if err != nil {
		return err
	}

	return l.grpc.Serve(lis)
}

func (l *Locator) extractEthAddr(ctx context.Context) (common.Address, error) {
	pr, ok := peer.FromContext(ctx)
	if !ok {
		return common.Address{}, status.Error(codes.DataLoss, "failed to get peer from ctx")
	}

	switch info := pr.AuthInfo.(type) {
	case util.EthAuthInfo:
		return info.Wallet, nil
	default:
		return common.Address{}, status.Error(codes.Unauthenticated, "wrong AuthInfo type")
	}
}

func (l *Locator) putAnnounce(n *node) {
	l.mx.Lock()
	defer l.mx.Unlock()

	n.ts = time.Now()
	l.db[n.ethAddr] = n
}

func (l *Locator) getResolve(ethAddr common.Address) (*node, error) {
	l.mx.Lock()
	defer l.mx.Unlock()

	n, ok := l.db[ethAddr]
	if !ok {
		return nil, errNodeNotFound
	}

	return n, nil
}

func (l *Locator) cleanExpiredNodes() {
	t := time.NewTicker(l.conf.CleanupPeriod)
	defer t.Stop()

	for {
		select {
		case <-t.C:
			l.traverseAndClean()
		}
	}
}

func (l *Locator) traverseAndClean() {
	deadline := time.Now().Add(-1 * l.conf.NodeTTL)

	l.mx.Lock()
	defer l.mx.Unlock()

	var (
		total = len(l.db)
		del   uint64
		keep  uint64
	)
	for addr, node := range l.db {
		if node.ts.Before(deadline) {
			delete(l.db, addr)
			del++
		} else {
			keep++
		}
	}

	log.G(l.ctx).Debug("expired nodes cleaned",
		zap.Int("total", total), zap.Uint64("keep", keep), zap.Uint64("del", del))
}

func NewLocator(ctx context.Context, conf *LocatorConfig, key *ecdsa.PrivateKey) (l *Locator, err error) {
	if key == nil {
		return nil, errors.Wrap(err, "private key should be provided")
	}

	l = &Locator{
		db:     make(map[common.Address]*node),
		conf:   conf,
		ctx:    ctx,
		ethKey: key,
	}

	var TLSConfig *tls.Config
	l.certRotator, TLSConfig, err = util.NewHitlessCertRotator(ctx, l.ethKey)
	if err != nil {
		return nil, err
	}

	l.creds = util.NewTLS(TLSConfig)
	srv := util.MakeGrpcServer(l.creds)
	l.grpc = srv

	go l.cleanExpiredNodes()

	pb.RegisterLocatorServer(srv, l)

	return l, nil
}


@@ -5,6 +5,7 @@ import (

 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
+	"google.golang.org/protobuf/types/known/structpb"
 	v1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

package k8s

import (
	"context"

	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	k8sapiv1 "github.com/lyft/clutch/backend/api/k8s/v1"
)

func (s *svc) DescribeConfigMap(ctx context.Context, clientset, cluster, namespace, name string) (*k8sapiv1.ConfigMap, error) {
	cs, err := s.manager.GetK8sClientset(ctx, clientset, cluster, namespace)
	if err != nil {
		return nil, err
	}

	configMapList, err := cs.CoreV1().ConfigMaps(cs.Namespace()).List(ctx, metav1.ListOptions{
		FieldSelector: "metadata.name=" + name,
	})

	if err != nil {
		return nil, err
	}

	if len(configMapList.Items) == 1 {
		return protoForConfigMap(cs.Cluster(), &configMapList.Items[0]), nil
	} else if len(configMapList.Items) > 1 {
		return nil, status.Errorf(codes.FailedPrecondition, "located multiple config maps with name '%s'", name)
	}
	return nil, status.Error(codes.NotFound, "unable to locate specified config map")
}

func (s *svc) DeleteConfigMap(ctx context.Context, clientset, cluster, namespace, name string) error {
	cs, err := s.manager.GetK8sClientset(ctx, clientset, cluster, namespace)
	if err != nil {
		return err
	}

	opts := metav1.DeleteOptions{}

	return cs.CoreV1().ConfigMaps(cs.Namespace()).Delete(ctx, name, opts)
}

func (s *svc) ListConfigMaps(ctx context.Context, clientset, cluster, namespace string, listOptions *k8sapiv1.ListOptions) ([]*k8sapiv1.ConfigMap, error) {
	cs, err := s.manager.GetK8sClientset(ctx, clientset, cluster, namespace)
	if err != nil {
		return nil, err
	}

	opts := ApplyListOptions(listOptions)

	configMapList, err := cs.CoreV1().ConfigMaps(cs.Namespace()).List(ctx, opts)
	if err != nil {
		return nil, err
	}

	var configMaps []*k8sapiv1.ConfigMap
	for _, cm := range configMapList.Items {
		configMap := cm
		configMaps = append(configMaps, protoForConfigMap(cs.Cluster(), &configMap))
	}

	return configMaps, nil
}

func protoForConfigMap(cluster string, k8sconfigMap *v1.ConfigMap) *k8sapiv1.ConfigMap {
	clusterName := k8sconfigMap.ClusterName
	if clusterName == "" {
		clusterName = cluster
	}

	return &k8sapiv1.ConfigMap{
		Cluster:     clusterName,
		Namespace:   k8sconfigMap.Namespace,
		Name:        k8sconfigMap.Name,
		Labels:      k8sconfigMap.Labels,
		Annotations: k8sconfigMap.Annotations,
	}
}


@@ -2,6 +2,7 @@ package cfg

 import (
 	"github.com/filecoin-project/go-filecoin/repo"
+	"github.com/pkg/errors"
 	"sync"
 )

package cfg

import (
	"github.com/filecoin-project/go-filecoin/repo"
	"sync"
)

// Config is plumbing implementation for setting and retrieving values from local config.
type Config struct {
	repo repo.Repo
	lock sync.Mutex
}

// NewConfig returns a new Config.
func NewConfig(repo repo.Repo) *Config {
	return &Config{repo: repo}
}

// Set sets a value in config
func (s *Config) Set(dottedKey string, jsonString string) error {
	s.lock.Lock()
	defer s.lock.Unlock()

	cfg := s.repo.Config()
	if err := cfg.Set(dottedKey, jsonString); err != nil {
		return err
	}

	return s.repo.ReplaceConfig(cfg)
}

// Get gets a value from config
func (s *Config) Get(dottedKey string) (interface{}, error) {
	return s.repo.Config().Get(dottedKey)
}


@@ -130,7 +130,7 @@ func ListBuilderForYamls(yamls ...string) *ListBuilder {
 func ListBuilderForObjects(objs ...*unstructured.Unstructured) *ListBuilder {
 	lb := &ListBuilder{list: &UnstructList{}}
 	for _, obj := range objs {
-		lb.list.items = append(lb.list.items, &Unstruct{obj})
+		lb.list.Items = append(lb.list.Items, &Unstruct{obj})
 	}
 	return lb
 }

/*
Copyright 2019 The OpenEBS 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 v1alpha2

import (
	"strings"

	"github.com/ghodss/yaml"
	"github.com/pkg/errors"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)

// Unstruct holds an object of Unstructured
type Unstruct struct {
	object *unstructured.Unstructured
}

// GetUnstructured converts Unstruct object
// to API's Unstructured
func (u *Unstruct) GetUnstructured() *unstructured.Unstructured {
	return u.object
}

// Builder enables building of an
// Unstructured instance
type Builder struct {
	unstruct *Unstruct
	errs     []error
}

// NewBuilder returns a new instance of
// empty Builder
func NewBuilder() *Builder {
	return &Builder{
		unstruct: &Unstruct{
			&unstructured.Unstructured{
				Object: map[string]interface{}{},
			},
		},
	}
}

// BuilderForYaml returns a new instance of
// Unstruct Builder by making use of the provided
// YAML
func BuilderForYaml(doc string) *Builder {
	b := NewBuilder()
	err := yaml.Unmarshal([]byte(doc), &b.unstruct.object)
	if err != nil {
		b.errs = append(b.errs, err)
	}
	return b
}

// BuilderForObject returns a new instance of
// Unstruct Builder by making use of the provided object
func BuilderForObject(obj *unstructured.Unstructured) *Builder {
	b := NewBuilder()
	b.unstruct.object = obj
	return b
}

// Build returns the Unstruct object created by
// the Builder
func (b *Builder) Build() (*Unstruct, error) {
	if len(b.errs) != 0 {
		return nil, errors.Errorf("errors {%+v}", b.errs)
	}
	return b.unstruct, nil
}

// BuildAPIUnstructured returns the Unstruct object created by
// the Builder
func (b *Builder) BuildAPIUnstructured() (*unstructured.Unstructured, error) {
	if len(b.errs) != 0 {
		return nil, errors.Errorf("errors {%+v}", b.errs)
	}
	return b.unstruct.object, nil
}

// UnstructList contains a list of Unstructured
// items
type UnstructList struct {
	items []*Unstruct
}

// ListBuilder enables building a list
// of an Unstruct instance
type ListBuilder struct {
	list *UnstructList
	errs []error
}

// ListBuilderForYamls returns a new instance of
// list Unstruct Builder by making use of the provided YAMLs
func ListBuilderForYamls(yamls ...string) *ListBuilder {
	lb := &ListBuilder{list: &UnstructList{}}
	for _, yaml := range yamls {
		y := strings.Split(strings.Trim(yaml, "---"), "---")
		for _, f := range y {
			f = strings.TrimSpace(f)
			a, err := BuilderForYaml(f).Build()
			if err != nil {
				lb.errs = append(lb.errs, err)
				continue
			}
			lb.list.items = append(lb.list.items, a)
		}
	}
	return lb
}

// ListBuilderForObjects returns a mew instance of
// list Unstruct Builder by making use of the provided
// Unstructured object
func ListBuilderForObjects(objs ...*unstructured.Unstructured) *ListBuilder {
	lb := &ListBuilder{list: &UnstructList{}}
	for _, obj := range objs {
		lb.list.items = append(lb.list.items, &Unstruct{obj})
	}
	return lb
}

// Build returns the list of Unstruct objects created by
// the Builder
func (l *ListBuilder) Build() ([]*Unstruct, error) {
	if len(l.errs) > 0 {
		return nil, errors.Errorf("errors {%+v}", l.errs)
	}
	return l.list.items, nil
}


@@ -39,7 +39,8 @@ type ArtifactStore cp.ArtifactStore
 // New returns a CodePipeline client configured against the input session.
 func New(s *session.Session) *CodePipeline {
 	return &CodePipeline{
-		client: cp.New(s),
+		client:   cp.New(s),
+		rgClient: rg.New(s),
 	}
 }

// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

// Package codepipeline provides a client to make API requests to Amazon Elastic Container Service.
package codepipeline

import (
	"fmt"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	cp "github.com/aws/aws-sdk-go/service/codepipeline"
)

type api interface {
	GetPipeline(*cp.GetPipelineInput) (*cp.GetPipelineOutput, error)
	ListPipelines(*cp.ListPipelinesInput) (*cp.ListPipelinesOutput, error)
}

// CodePipeline wraps the AWS CodePipeline client.
type CodePipeline struct {
	client api
}

// Pipeline contains information about the pipeline
// TODO wrap nested resources or just use what the SDK provides?
type Pipeline struct {
	Name string `json:"name"`
	// Stages        []Stage       `json:"stages"`
	// ArtifactStore ArtifactStore `json:"artifactStore"`
}

// Stage wraps the codepipeline pipeline stage
type Stage cp.StageDeclaration

// ArtifactStore wraps the artifact store for the pipeline
type ArtifactStore cp.ArtifactStore

// New returns a CodePipeline client configured against the input session.
func New(s *session.Session) *CodePipeline {
	return &CodePipeline{
		client: cp.New(s),
	}
}

// GetPipeline retrieves information from a given pipeline
func (c *CodePipeline) GetPipeline(pipelineName string) (*Pipeline, error) {
	input := &cp.GetPipelineInput{
		Name: aws.String(pipelineName),
	}
	resp, err := c.client.GetPipeline(input)

	if err != nil {
		return nil, fmt.Errorf("get pipeline %s: %w", pipelineName, err)
	}
	pipeline := &Pipeline{
		Name: aws.StringValue(resp.Pipeline.Name),
	}

	return pipeline, nil
}

// ListPipelines retrieves summaries of all pipelines for a project
func (c *CodePipeline) ListPipelines() ([]string, error) {
	input := &cp.ListPipelinesInput{}
	resp, err := c.client.ListPipelines(input)
	if err != nil {
		return nil, fmt.Errorf("list pipelines: %w", err)
	}

	var pipelines []string

	for _, ps := range resp.Pipelines {
		p := aws.StringValue(ps.Name)
		pipelines = append(pipelines, p)
	}

	return pipelines, nil
}