@@ -73,7 +73,7 @@ type GcpChaosSpec struct {
 	// The device name of the disk to detach.
 	// Needed in disk-loss.
 	// +optional
-	DeviceName *string `json:"deviceName,omitempty"`
+	DeviceName *[]string `json:"deviceName,omitempty"`
 }

 // GcpChaosStatus represents the status of a GcpChaos

// Copyright 2021 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 v1alpha1

import (
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// +kubebuilder:object:root=true
// +chaos-mesh:base

// GcpChaos is the Schema for the gcpchaos API
type GcpChaos struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	Spec   GcpChaosSpec   `json:"spec"`
	Status GcpChaosStatus `json:"status,omitempty"`
}

// GcpChaosAction represents the chaos action about gcp.
type GcpChaosAction string

const (
	// NodeStop represents the chaos action of stopping the node.
	NodeStop GcpChaosAction = "node-stop"
	// NodeReset represents the chaos action of resetting the node.
	NodeReset GcpChaosAction = "node-reset"
	// DiskLoss represents the chaos action of detaching the disk.
	DiskLoss GcpChaosAction = "disk-loss"
)

// GcpChaosSpec is the content of the specification for a GcpChaos
type GcpChaosSpec struct {
	// Action defines the specific gcp chaos action.
	// Supported action: node-stop / node-reset / disk-loss
	// Default action: node-stop
	// +kubebuilder:validation:Enum=node-stop;node-reset;disk-loss
	Action GcpChaosAction `json:"action"`

	// Duration represents the duration of the chaos action.
	// +optional
	Duration *string `json:"duration,omitempty"`

	// Scheduler defines some schedule rules to control the running time of the chaos experiment about time.
	// +optional
	Scheduler *SchedulerSpec `json:"scheduler,omitempty"`

	// SecretName defines the name of kubernetes secret. It is used for GCP credentials.
	// +optional
	SecretName *string `json:"secretName,omitempty"`

	// Project defines the name of gcp project.
	Project string `json:"project"`

	// Zone defines the zone of gcp project.
	Zone string `json:"zone"`

	// Instance defines the name of the instance
	Instance string `json:"instance"`

	// The device name of the disk to detach.
	// Needed in disk-loss.
	// +optional
	DeviceName *string `json:"deviceName,omitempty"`
}

// GcpChaosStatus represents the status of a GcpChaos
type GcpChaosStatus struct {
	ChaosStatus `json:",inline"`

	// The attached disk info string.
	// Needed in disk-loss.
	AttachedDiskString string `json:"attachedDiskString,omitempty"`
}

since it changes to the array, how about change the name to `DeviceNames`


@@ -155,11 +155,11 @@ func (r *DeliveryReporter) reportEventProcessingTime(ctx context.Context, end ti
 }

 func filterTypeValue(v string) string {
-	if v != "" {
-		return v
+	if v == "" {
+		// the default value if the filter attributes are empty.
+		return "any"
 	}
-	// the default value if the filter attributes are empty.
-	return "any"
+	return EventTypeMetricValue(v)
 }

 func (r *DeliveryReporter) AddTags(ctx context.Context) (context.Context, error) {

/*
Copyright 2020 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package metrics

import (
	"context"
	"fmt"
	"strconv"
	"time"

	"github.com/google/knative-gcp/pkg/broker/config"
	"go.opencensus.io/stats"
	"go.opencensus.io/stats/view"
	"go.opencensus.io/tag"
	"knative.dev/pkg/metrics"
)

type DeliveryMetricsKey int

const (
	startDeliveryProcessingTime DeliveryMetricsKey = iota
)

type DeliveryReporter struct {
	podName               PodName
	containerName         ContainerName
	dispatchTimeInMsecM   *stats.Float64Measure
	processingTimeInMsecM *stats.Float64Measure
}

func (r *DeliveryReporter) register() error {
	return metrics.RegisterResourceView(
		&view.View{
			Name:        "event_count",
			Description: "Number of events delivered to a Trigger subscriber",
			Measure:     r.dispatchTimeInMsecM,
			Aggregation: view.Count(),
			TagKeys: []tag.Key{
				NamespaceNameKey,
				BrokerNameKey,
				TriggerNameKey,
				TriggerFilterTypeKey,
				ResponseCodeKey,
				ResponseCodeClassKey,
				PodNameKey,
				ContainerNameKey,
			},
		},
		&view.View{
			Name:        r.dispatchTimeInMsecM.Name(),
			Description: r.dispatchTimeInMsecM.Description(),
			Measure:     r.dispatchTimeInMsecM,
			Aggregation: view.Distribution(metrics.Buckets125(1, 10000)...), // 1, 2, 5, 10, 20, 50, 100, 1000, 5000, 10000
			TagKeys: []tag.Key{
				NamespaceNameKey,
				BrokerNameKey,
				TriggerNameKey,
				TriggerFilterTypeKey,
				ResponseCodeKey,
				ResponseCodeClassKey,
				PodNameKey,
				ContainerNameKey,
			},
		},
		&view.View{
			Name:        r.processingTimeInMsecM.Name(),
			Description: r.processingTimeInMsecM.Description(),
			Measure:     r.processingTimeInMsecM,
			Aggregation: view.Distribution(metrics.Buckets125(1, 10000)...), // 1, 2, 5, 10, 20, 50, 100, 1000, 5000, 10000
			TagKeys: []tag.Key{
				NamespaceNameKey,
				BrokerNameKey,
				TriggerNameKey,
				TriggerFilterTypeKey,
				PodNameKey,
				ContainerNameKey,
			},
		},
	)
}

// NewDeliveryReporter creates a new DeliveryReporter.
func NewDeliveryReporter(podName PodName, containerName ContainerName) (*DeliveryReporter, error) {
	r := &DeliveryReporter{
		podName:       podName,
		containerName: containerName,
		// dispatchTimeInMsecM records the time spent dispatching an event to
		// a Trigger subscriber, in milliseconds.
		dispatchTimeInMsecM: stats.Float64(
			"event_dispatch_latencies",
			"The time spent dispatching an event to a Trigger subscriber",
			stats.UnitMilliseconds,
		),
		// processingTimeInMsecM records the time spent between arrival at the Broker
		// and the delivery to the Trigger subscriber.
		processingTimeInMsecM: stats.Float64(
			"event_processing_latencies",
			"The time spent processing an event before it is dispatched to a Trigger subscriber",
			stats.UnitMilliseconds,
		),
	}

	if err := r.register(); err != nil {
		return nil, fmt.Errorf("failed to register delivery stats: %w", err)
	}
	return r, nil
}

// ReportEventDispatchTime captures dispatch times.
func (r *DeliveryReporter) ReportEventDispatchTime(ctx context.Context, d time.Duration, responseCode int) {
	// convert time.Duration in nanoseconds to milliseconds.
	metrics.Record(ctx, r.dispatchTimeInMsecM.M(float64(d/time.Millisecond)),
		stats.WithTags(
			tag.Insert(ResponseCodeKey, strconv.Itoa(responseCode)),
			tag.Insert(ResponseCodeClassKey, metrics.ResponseCodeClass(responseCode)),
		),
	)
}

// StartEventProcessing records the start of event processing for delivery within the given context.
func StartEventProcessing(ctx context.Context) context.Context {
	return context.WithValue(ctx, startDeliveryProcessingTime, time.Now())
}

// FinishEventProcessing captures event processing times. Requires StartDelivery to have been
// called previously using ctx.
func (r *DeliveryReporter) FinishEventProcessing(ctx context.Context) error {
	return r.reportEventProcessingTime(ctx, time.Now())
}

// ReportEventProcessingTime captures event processing times. Requires StartDelivery to have been
// called previously using ctx.
func (r *DeliveryReporter) reportEventProcessingTime(ctx context.Context, end time.Time) error {
	start, err := getStartDeliveryProcessingTime(ctx)
	if err != nil {
		return err
	}
	// convert time.Duration in nanoseconds to milliseconds.
	metrics.Record(ctx, r.processingTimeInMsecM.M(float64(end.Sub(start)/time.Millisecond)))
	return nil
}

func filterTypeValue(v string) string {
	if v != "" {
		return v
	}
	// the default value if the filter attributes are empty.
	return "any"
}

func (r *DeliveryReporter) AddTags(ctx context.Context) (context.Context, error) {
	return tag.New(ctx,
		tag.Insert(PodNameKey, string(r.podName)),
		tag.Insert(ContainerNameKey, string(r.containerName)),
	)
}

func AddTargetTags(ctx context.Context, target *config.Target) (context.Context, error) {
	return tag.New(ctx,
		tag.Insert(NamespaceNameKey, target.Namespace),
		tag.Insert(BrokerNameKey, target.Broker),
		tag.Insert(TriggerNameKey, target.Name),
		tag.Insert(TriggerFilterTypeKey, filterTypeValue(target.FilterAttributes["type"])),
	)
}

func getStartDeliveryProcessingTime(ctx context.Context) (time.Time, error) {
	v := ctx.Value(startDeliveryProcessingTime)
	if time, ok := v.(time.Time); ok {
		return time, nil
	}
	return time.Time{}, fmt.Errorf("missing or invalid start time: %v", v)
}

might be worth using a constant. I think we had one somewhere. Same for the "custom" one


@@ -50,6 +50,7 @@ func deps() {
 		"go get -u github.com/alecthomas/gometalinter",
 		"gometalinter --install",
 		"go get -u github.com/stretchr/testify",
+		"go get -u github.com/xeipuuv/gojsonschema",
 	}

 	for _, name := range list {

package main

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"runtime"
	"strings"
)

var lineBreak = "\n"

func init() {
	log.SetFlags(0)
	if runtime.GOOS == "windows" {
		lineBreak = "\r\n"
	}
}

// run executes a given command on the shell, like
// `run("git status")`
func run(name string) string {
	args := strings.Split(name, " ")
	return runParts(args...)
}

func runParts(args ...string) string {
	name := strings.Join(args, " ")
	cmd := exec.Command(args[0], args[1:]...) // #nosec
	log.Println(name)
	out, err := cmd.CombinedOutput()
	if err != nil {
		log.Printf("%s", out)
		log.Fatalf("Command '%s' failed: %s\n", name, err)
	}

	return strings.Trim(string(out), lineBreak)
}

// deps installs all dependencies
func deps() {
	log.Println("Installing dependencies...")

	list := []string{
		"go get -u github.com/whyrusleeping/gx",
		"go get -u github.com/whyrusleeping/gx-go",
		"./fetch_go-ipfs_deps.sh",
		"gx install",
		"go get -u github.com/alecthomas/gometalinter",
		"gometalinter --install",
		"go get -u github.com/stretchr/testify",
	}

	for _, name := range list {
		log.Println(run(name))
	}
}

// lint runs linting using gometalinter
func lint(packages ...string) {
	if len(packages) == 0 {
		packages = []string{"./..."}
	}

	log.Printf("Linting %s ...\n", strings.Join(packages, " "))

	// Run fast linters batched together
	configs := []string{
		"gometalinter",
		"--skip=sharness",
		"--skip=vendor",
		"--disable-all",
	}

	fastLinters := []string{
		"--enable=vet",
		"--enable=gofmt",
		"--enable=misspell",
		"--enable=goconst",
		"--enable=golint",
		"--enable=errcheck",
		"--min-occurrences=6", // for goconst
	}

	log.Println(runParts(append(append(configs, fastLinters...), packages...)...))

	slowLinters := []string{
		"--deadline=10m",
		"--enable=unconvert",
		"--enable=gosimple",
		"--enable=megacheck",
		"--enable=varcheck",
		"--enable=structcheck",
		"--enable=deadcode",
	}

	log.Println(runParts(append(append(configs, slowLinters...), packages...)...))
}

func build() {
	log.Println("Building...")

	commit := run("git log -n 1 --format=%H")

	log.Println(
		runParts(
			"go", "build",
			"-ldflags", fmt.Sprintf("-X github.com/filecoin-project/go-filecoin/flags.Commit=%s", commit),
			"-v", "-o", "go-filecoin", ".",
		),
	)
}

func install() {
	log.Println("Installing...")

	log.Println(runParts("go", "install"))
}

// test executes tests and passes along all additional arguments to `go test`.
func test(args ...string) {
	log.Println("Testing...")

	log.Println(run(fmt.Sprintf("go test ./... %s", strings.Join(args, " "))))
}

func main() {
	args := os.Args[1:]

	if len(args) == 0 {
		log.Fatalf("Missing command")
	}

	cmd := args[0]

	switch cmd {
	case "deps":
		deps()
	case "lint":
		lint(args[1:]...)
	case "build":
		build()
	case "test":
		test(args[1:]...)
	case "install":
		install()
	case "best":
		build()
		test(args[1:]...)
	case "all":
		deps()
		lint()
		build()
		test(args[1:]...)
	default:
		log.Fatalf("Unknown command: %s\n", cmd)
	}
}

is there a reason we don't want to gx this dependency?


@@ -22,39 +22,6 @@ const (
 	DeviceTwinModuleName = "twin"
 )

-// ormerMock is mocked Ormer implementation.
-var ormerMock *beego.MockOrmer
-
-// querySeterMock is mocked QuerySeter implementation.
-var querySeterMock *beego.MockQuerySeter
-
-// fakeModule is mocked implementation of TestModule.
-var fakeModule *beehive.MockModule
-
-// mainContext is beehive context used for communication between modules.
-var mainContext *context.Context
-
-//test is for sending test messages from devicetwin module.
-var test model.Message
-
-// initMocks is function to initialize mocks.
-func initMocks(t *testing.T) {
-	mockCtrl := gomock.NewController(t)
-	defer mockCtrl.Finish()
-	ormerMock = beego.NewMockOrmer(mockCtrl)
-	querySeterMock = beego.NewMockQuerySeter(mockCtrl)
-	fakeModule = beehive.NewMockModule(mockCtrl)
-	dbm.DBAccess = ormerMock
-}
-
-// registerFakeModule is fuction to register all mock modules used.
-func registerFakeModule() {
-	fakeModule.EXPECT().Name().Return(TestModule).Times(3)
-	core.Register(fakeModule)
-	mainContext = context.GetContext(context.MsgCtxTypeChannel)
-	mainContext.AddModule(TestModule)
-}
-
 // TestName is function to test Name().
 func TestName(t *testing.T) {
 	tests := []struct {

package devicetwin

import (
	"testing"
	"time"

	"github.com/golang/mock/gomock"

	"github.com/kubeedge/beehive/pkg/core"
	"github.com/kubeedge/beehive/pkg/core/context"
	"github.com/kubeedge/beehive/pkg/core/model"
	"github.com/kubeedge/kubeedge/edge/mocks/beego"
	"github.com/kubeedge/kubeedge/edge/mocks/beehive"
	"github.com/kubeedge/kubeedge/edge/pkg/common/dbm"
	"github.com/kubeedge/kubeedge/edge/pkg/devicetwin/dtcommon"
)

const (
	//TestModule is name of test.
	TestModule = "test"
	//DeviceTwinModuleName is name of twin
	DeviceTwinModuleName = "twin"
)

// ormerMock is mocked Ormer implementation.
var ormerMock *beego.MockOrmer

// querySeterMock is mocked QuerySeter implementation.
var querySeterMock *beego.MockQuerySeter

// fakeModule is mocked implementation of TestModule.
var fakeModule *beehive.MockModule

// mainContext is beehive context used for communication between modules.
var mainContext *context.Context

//test is for sending test messages from devicetwin module.
var test model.Message

// initMocks is function to initialize mocks.
func initMocks(t *testing.T) {
	mockCtrl := gomock.NewController(t)
	defer mockCtrl.Finish()
	ormerMock = beego.NewMockOrmer(mockCtrl)
	querySeterMock = beego.NewMockQuerySeter(mockCtrl)
	fakeModule = beehive.NewMockModule(mockCtrl)
	dbm.DBAccess = ormerMock
}

// registerFakeModule is fuction to register all mock modules used.
func registerFakeModule() {
	fakeModule.EXPECT().Name().Return(TestModule).Times(3)
	core.Register(fakeModule)
	mainContext = context.GetContext(context.MsgCtxTypeChannel)
	mainContext.AddModule(TestModule)
}

// TestName is function to test Name().
func TestName(t *testing.T) {
	tests := []struct {
		name string
		want string
	}{
		{
			name: "DeviceTwinNametest",
			want: "twin",
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			dt := &DeviceTwin{}
			if got := dt.Name(); got != tt.want {
				t.Errorf("DeviceTwin.Name() = %v, want %v", got, tt.want)
			}
		})
	}
}

// TestGroup is function to test Group().
func TestGroup(t *testing.T) {
	tests := []struct {
		name string
		want string
	}{
		{
			name: "DeviceTwinGroupTest",
			want: "twin",
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			dt := &DeviceTwin{}
			if got := dt.Group(); got != tt.want {
				t.Errorf("DeviceTwin.Group() = %v, want %v", got, tt.want)
			}
		})
	}
}

// TestStart is function to test Start().
func TestStart(t *testing.T) {
	initMocks(t)
	registerFakeModule()
	core.Register(&DeviceTwin{})
	dt := DeviceTwin{}
	mainContext.AddModule(dt.Name())
	mainContext.AddModuleGroup(dt.Name(), dt.Group())
	dt.context = mainContext
	ormerMock.EXPECT().QueryTable(gomock.Any()).Return(querySeterMock).Times(1)
	querySeterMock.EXPECT().All(gomock.Any()).Return(int64(1), nil).Times(1)
	go dt.Start(mainContext)
	time.Sleep(1 * time.Millisecond)
	// Sending a message from devicetwin module to the created fake module(TestModule) to check context is initialized properly.
	dt.context.Send(TestModule, test)
	_, err := mainContext.Receive(TestModule)
	t.Run("MessagePingTest", func(t *testing.T) {
		if err != nil {
			t.Errorf("Error while receiving message: %v", err)
			return
		}
	})
	//Checking whether Mem,Twin,Device and Comm modules are registered and started successfully.
	tests := []struct {
		name       string
		moduleName string
	}{
		{
			name:       "MemModuleHealthCheck",
			moduleName: dtcommon.MemModule,
		},
		{
			name:       "TwinModuleHealthCheck",
			moduleName: dtcommon.TwinModule,
		},
		{
			name:       "DeviceModuleHealthCheck",
			moduleName: dtcommon.DeviceModule,
		},
		{
			name:       "CommModuleHealthCheck",
			moduleName: dtcommon.CommModule,
		},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			moduleCheck := false
			for _, module := range dt.dtcontroller.DTModules {
				if test.moduleName == module.Name {
					moduleCheck = true
					err := dt.dtcontroller.DTContexts.HeartBeat(test.moduleName, "ping")
					if err != nil {
						t.Errorf("Heartbeat of module %v is expired and dtcontroller will start it again", test.moduleName)
					}
					break
				}
			}
			if moduleCheck == false {
				t.Errorf("Registration of module %v failed", test.moduleName)
			}
		})
	}
}

// TestCleanup is function to test Cleanup().
func TestCleanup(t *testing.T) {
	deviceTwin := DeviceTwin{
		context: mainContext,
		dtcontroller: &DTController{
			Stop: make(chan bool, 1),
		},
	}
	deviceTwin.Cleanup()
	//Testing the value of stop channel in dtcontroller
	t.Run("CleanUpTestStopChanTest", func(t *testing.T) {
		if <-deviceTwin.dtcontroller.Stop == false {
			t.Errorf("Want %v on StopChan Got %v", true, false)
		}
	})
	//Send message to avoid deadlock if channel deletion has failed after cleanup
	go mainContext.Send(DeviceTwinModuleName, test)
	_, err := mainContext.Receive(DeviceTwinModuleName)
	t.Run("CheckCleanUp", func(t *testing.T) {
		if err == nil {
			t.Errorf("DeviceTwin Module still has channel after cleanup")
		}
	})
}

Could we reused the `DeviceTwinModuleName` instead of define one?


@@ -18,9 +18,9 @@
 package service

 import (
+	"encoding/json"
 	"errors"

-	log "github.com/cihub/seelog"
 	"github.com/mysteriumnetwork/node/communication"
 	"github.com/mysteriumnetwork/node/identity"
 	identity_selector "github.com/mysteriumnetwork/node/identity/selector"

/*
 * 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 service

import (
	"errors"

	log "github.com/cihub/seelog"
	"github.com/mysteriumnetwork/node/communication"
	"github.com/mysteriumnetwork/node/identity"
	identity_selector "github.com/mysteriumnetwork/node/identity/selector"
	"github.com/mysteriumnetwork/node/market"
	"github.com/mysteriumnetwork/node/market/proposals/registry"
	"github.com/mysteriumnetwork/node/session"
)

const logPrefix = "[service-manager] "

var (
	// ErrorLocation error indicates that action (i.e. disconnect)
	ErrorLocation = errors.New("failed to detect service location")
	// ErrUnsupportedServiceType indicates that manager tried to create an unsupported service type
	ErrUnsupportedServiceType = errors.New("unsupported service type")
)

// ServiceFactory initiates instance which is able to serve connections
type ServiceFactory func(Options) (Service, error)

// Service interface represents pluggable Mysterium service
type Service interface {
	Start(providerID identity.Identity) (market.ServiceProposal, session.ConfigNegotiator, error)
	Wait() error
	Stop() error
}

// DialogWaiterFactory initiates communication channel which waits for incoming dialogs
type DialogWaiterFactory func(providerID identity.Identity, serviceType string) (communication.DialogWaiter, error)

// DialogHandlerFactory initiates instance which is able to handle incoming dialogs
type DialogHandlerFactory func(market.ServiceProposal, session.ConfigNegotiator) communication.DialogHandler

// NewManager creates new instance of pluggable services manager
func NewManager(
	identityLoader identity_selector.Handler,
	serviceFactory ServiceFactory,
	dialogWaiterFactory DialogWaiterFactory,
	dialogHandlerFactory DialogHandlerFactory,
	discoveryService *registry.Discovery,
) *Manager {
	return &Manager{
		identityHandler:      identityLoader,
		serviceFactory:       serviceFactory,
		dialogWaiterFactory:  dialogWaiterFactory,
		dialogHandlerFactory: dialogHandlerFactory,
		discovery:            discoveryService,
	}
}

// Manager entrypoint which knows how to start pluggable Mysterium services
type Manager struct {
	identityHandler identity_selector.Handler

	dialogWaiterFactory  DialogWaiterFactory
	dialogWaiter         communication.DialogWaiter
	dialogHandlerFactory DialogHandlerFactory

	serviceFactory ServiceFactory
	service        Service

	discovery *registry.Discovery
}

// Start starts service - does not block
func (manager *Manager) Start(options Options) (err error) {
	loadIdentity := identity_selector.NewLoader(manager.identityHandler, options.Identity, options.Passphrase)
	providerID, err := loadIdentity()
	if err != nil {
		return err
	}

	manager.service, err = manager.serviceFactory(options)
	if err != nil {
		return err
	}
	proposal, sessionConfigProvider, err := manager.service.Start(providerID)
	if err != nil {
		return err
	}
	manager.dialogWaiter, err = manager.dialogWaiterFactory(providerID, proposal.ServiceType)
	if err != nil {
		return err
	}
	providerContact, err := manager.dialogWaiter.Start()
	if err != nil {
		return err
	}
	proposal.SetProviderContact(providerID, providerContact)

	dialogHandler := manager.dialogHandlerFactory(proposal, sessionConfigProvider)
	if err = manager.dialogWaiter.ServeDialogs(dialogHandler); err != nil {
		return err
	}

	manager.discovery.Start(providerID, proposal)
	return nil
}

// Wait blocks until service is stopped
func (manager *Manager) Wait() error {
	log.Info(logPrefix, "Waiting for discovery service to finish")
	manager.discovery.Wait()

	log.Info(logPrefix, "Waiting for service to finish")
	return manager.service.Wait()
}

// Kill stops service
func (manager *Manager) Kill() error {
	var errDialogWaiter, errService error

	if manager.discovery != nil {
		manager.discovery.Stop()
	}
	if manager.dialogWaiter != nil {
		errDialogWaiter = manager.dialogWaiter.Stop()
	}
	if manager.service != nil {
		errService = manager.service.Stop()
	}

	if errDialogWaiter != nil {
		return errDialogWaiter
	}
	if errService != nil {
		return errService
	}
	return nil
}

`const logPrefix = "[service-manager] "` left and it's unused.


@@ -25,6 +25,10 @@ const (
 	// AttachmentEvent is used to define the attachment state transition events
 	// emitted by ENI watcher
 	AttachmentEvent
+
+	// ManagedAgentEvent is used to define the managed agent state transition events
+	// emitted by the engine
+	ManagedAgentEvent
 )

 // Event defines the type of state change event

// Copyright Amazon.com Inc. or its affiliates. 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. A copy of the
// License is located at
//
//	http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file 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 statechange

const (
	// ContainerEvent is used to define the container state transition events
	// emitted by the engine
	ContainerEvent EventType = iota

	// TaskEvent is used to define the task state transition events emitted by
	// the engine
	TaskEvent

	// AttachmentEvent is used to define the attachment state transition events
	// emitted by ENI watcher
	AttachmentEvent
)

// Event defines the type of state change event
type EventType int32

// Event is used to abstract away the two transition event types
// passed up through a single channel from the the engine
type Event interface {

	// GetEventType implementations should return one the enums defined above to
	// identify the type of event being emitted
	GetEventType() EventType
}

glad to see this differentiation between `ContainerEvent` and `ManagedAgentEvent`


@@ -1,16 +1,21 @@
 package cli

 import (
-	"log"
+	stdlog "log"

 	"github.com/mitchellh/cli"
 	"github.com/spiffe/spire/cmd/spire-agent/cli/api"
 	"github.com/spiffe/spire/cmd/spire-agent/cli/healthcheck"
 	"github.com/spiffe/spire/cmd/spire-agent/cli/run"
+	"github.com/spiffe/spire/pkg/common/log"
 	"github.com/spiffe/spire/pkg/common/version"
 )

-func Run(args []string) int {
+type CLI struct {
+	LogOptions []log.Option
+}
+
+func (cc *CLI) Run(args []string) int {
 	c := cli.NewCLI("spire-agent", version.Version())
 	c.Args = args
 	c.Commands = map[string]cli.CommandFactory{

package cli

import (
	"log"

	"github.com/mitchellh/cli"
	"github.com/spiffe/spire/cmd/spire-agent/cli/api"
	"github.com/spiffe/spire/cmd/spire-agent/cli/healthcheck"
	"github.com/spiffe/spire/cmd/spire-agent/cli/run"
	"github.com/spiffe/spire/pkg/common/version"
)

func Run(args []string) int {
	c := cli.NewCLI("spire-agent", version.Version())
	c.Args = args
	c.Commands = map[string]cli.CommandFactory{
		"api fetch": func() (cli.Command, error) {
			return api.NewFetchX509Command(), nil
		},
		"api fetch x509": func() (cli.Command, error) {
			return api.NewFetchX509Command(), nil
		},
		"api fetch jwt": func() (cli.Command, error) {
			return api.NewFetchJWTCommand(), nil
		},
		"api validate jwt": func() (cli.Command, error) {
			return api.NewValidateJWTCommand(), nil
		},
		"api watch": func() (cli.Command, error) {
			return &api.WatchCLI{}, nil
		},
		"run": func() (cli.Command, error) {
			return &run.Command{}, nil
		},
		"healthcheck": func() (cli.Command, error) {
			return healthcheck.NewHealthCheckCommand(), nil
		},
	}

	exitStatus, err := c.Run()
	if err != nil {
		log.Println(err)
	}
	return exitStatus
}

It feels a bit strange to pass cli args and also log options to Run. Perhaps it is worth considering a `CLI` struct on which the options can be set, similar to how you've done with the Command struct? Our main.go could then become something like `os.Exit(new(cli.CLI).Run(os.Args[1:]))`


package trie

import (
	"bytes"
	"testing"

	"github.com/ledgerwatch/turbo-geth/common"
)

func TestSupplyKeyValue(t *testing.T) {
	bwb := NewBlockWitnessBuilder(false)
	if err := bwb.supplyKey([]byte("key")); err != nil {
		t.Errorf("Could not supply key: %v", err)
	}
	if !bytes.Equal(common.FromHex("0x436b6579"), bwb.Keys.buffer.Bytes()) {
		t.Errorf("Expected 0x436b6579 in keys tape, got: %x", bwb.Keys.buffer.Bytes())
	}
	if err := bwb.supplyValue([]byte("value")); err != nil {
		t.Errorf("Could not supply value: %v", err)
	}
	if !bytes.Equal(common.FromHex("0x4576616c7565"), bwb.Values.buffer.Bytes()) {
		t.Errorf("Expected 0x4576616c7565 in values tape, got: %x", bwb.Values.buffer.Bytes())
	}
}

func TestSupplyHash(t *testing.T) {
	bwb := NewBlockWitnessBuilder(false)
	if err := bwb.supplyHash(common.HexToHash("0x9583498348fc48393abc")); err != nil {
		t.Errorf("Could not supply hash: %v", err)
	}
	if !bytes.Equal(common.FromHex("0x5820000000000000000000000000000000000000000000009583498348fc48393abc"), bwb.Hashes.buffer.Bytes()) {
		t.Errorf("Expected 0x5820000000000000000000000000000000000000000000009583498348fc48393abc in hash tape, got: %x", bwb.Hashes.buffer.Bytes())
	}
}

func TestSupplyCode(t *testing.T) {
	bwb := NewBlockWitnessBuilder(false)
	if err := bwb.supplyCode(common.FromHex("0x9583498348fc48393abc58bc")); err != nil {
		t.Errorf("Could not supply code: %v", err)
	}
	if !bytes.Equal(common.FromHex("0x4c9583498348fc48393abc58bc"), bwb.Codes.buffer.Bytes()) {
		t.Errorf("Expected 0x4c9583498348fc48393abc58bc in codes tape, got: %x", bwb.Codes.buffer.Bytes())
	}
}

func TestOpLeaf(t *testing.T) {
	bwb := NewBlockWitnessBuilder(false)
	if err := bwb.leaf(56); err != nil {
		t.Errorf("Could not call leaf: %v", err)
	}
	if !bytes.Equal(common.FromHex("0x001838"), bwb.Structure.buffer.Bytes()) {
		t.Errorf("Expected 0x001838 in structure tape, got: %x", bwb.Structure.buffer.Bytes())
	}
}
func TestOpLeafHash(t *testing.T) {
	bwb := NewBlockWitnessBuilder(false)
	if err := bwb.leafHash(56); err != nil {
		t.Errorf("Could not call leafHash: %v", err)
	}
	if !bytes.Equal(common.FromHex("0x011838"), bwb.Structure.buffer.Bytes()) {
		t.Errorf("Expected 0x011838 in structure tape, got: %x", bwb.Structure.buffer.Bytes())
	}
}

func TestOpExtension(t *testing.T) {
	bwb := NewBlockWitnessBuilder(false)
	if err := bwb.extension(common.FromHex("0x0f05")); err != nil {
		t.Errorf("Could not call extension: %v", err)
	}
	if !bytes.Equal(common.FromHex("0x02420f05"), bwb.Structure.buffer.Bytes()) {
		t.Errorf("Expected 0x02420f05 in structure tape, got: %x", bwb.Structure.buffer.Bytes())
	}
}

func TestOpExtensionHash(t *testing.T) {
	bwb := NewBlockWitnessBuilder(false)
	if err := bwb.extensionHash(common.FromHex("0x0f05")); err != nil {
		t.Errorf("Could not call extensionHash: %v", err)
	}
	if !bytes.Equal(common.FromHex("0x03420f05"), bwb.Structure.buffer.Bytes()) {
		t.Errorf("Expected 0x03420f05 in structure tape, got: %x", bwb.Structure.buffer.Bytes())
	}
}

func TestOpBranch(t *testing.T) {
	bwb := NewBlockWitnessBuilder(false)
	if err := bwb.branch(1 + 4); err != nil {
		t.Errorf("Could not call branch: %v", err)
	}
	if !bytes.Equal(common.FromHex("0x0405"), bwb.Structure.buffer.Bytes()) {
		t.Errorf("Expected 0x0405 in structure tape, got: %x", bwb.Structure.buffer.Bytes())
	}
}

func TestOpBranchHash(t *testing.T) {
	bwb := NewBlockWitnessBuilder(false)
	if err := bwb.branchHash(1 + 4); err != nil {
		t.Errorf("Could not call branchHash: %v", err)
	}
	if !bytes.Equal(common.FromHex("0x0505"), bwb.Structure.buffer.Bytes()) {
		t.Errorf("Expected 0x0505 in structure tape, got: %x", bwb.Structure.buffer.Bytes())
	}
}

func TestOpHash(t *testing.T) {
	bwb := NewBlockWitnessBuilder(false)
	if err := bwb.hash(3); err != nil {
		t.Errorf("Could not call hash: %v", err)
	}
	if !bytes.Equal(common.FromHex("0x0603"), bwb.Structure.buffer.Bytes()) {
		t.Errorf("Expected 0x0603 in structure tape, got: %x", bwb.Structure.buffer.Bytes())
	}
}

func TestOpCode(t *testing.T) {
	bwb := NewBlockWitnessBuilder(false)
	if err := bwb.code(); err != nil {
		t.Errorf("Could not call code: %v", err)
	}
	if !bytes.Equal(common.FromHex("0x07"), bwb.Structure.buffer.Bytes()) {
		t.Errorf("Expected 0x07 in structure tape, got: %x", bwb.Structure.buffer.Bytes())
	}
}

func TestOpAccountLeaf(t *testing.T) {
	bwb := NewBlockWitnessBuilder(false)
	if err := bwb.accountLeaf(56, 3); err != nil {
		t.Errorf("Could not call acccountLeaf: %v", err)
	}
	expected := common.FromHex("0x08183803")
	if !bytes.Equal(expected, bwb.Structure.buffer.Bytes()) {
		t.Errorf("Expected %x in structure tape, got: %x", expected, bwb.Structure.buffer.Bytes())
	}
}
func TestOpAccountLeafHash(t *testing.T) {
	bwb := NewBlockWitnessBuilder(false)
	if err := bwb.accountLeafHash(56, 3); err != nil {
		t.Errorf("Could not call accountLeafHash: %v", err)
	}
	expected := common.FromHex("0x09183803")
	if !bytes.Equal(expected, bwb.Structure.buffer.Bytes()) {
		t.Errorf("Expected %x in structure tape, got: %x", expected, bwb.Structure.buffer.Bytes())
	}
}

func TestOpEmptyRoot(t *testing.T) {
	bwb := NewBlockWitnessBuilder(false)
	if err := bwb.emptyRoot(); err != nil {
		t.Errorf("Could not call emptyRoot: %v", err)
	}
	expected := common.FromHex("0x0a")
	if !bytes.Equal(expected, bwb.Structure.buffer.Bytes()) {
		t.Errorf("Expected %x in structure tape, got: %x", expected, bwb.Structure.buffer.Bytes())
	}
}

func TestMakeBlockWitness(t *testing.T) {
	tr := New(common.Hash{})
	tr.Update([]byte("ABCD0001"), []byte("val1"), 0)
	tr.Update([]byte("ABCE0002"), []byte("val2"), 0)
	bwb := NewBlockWitnessBuilder(false)
	rs := NewResolveSet(2)
	if err := bwb.MakeBlockWitness(tr, rs, nil, nil); err != nil {
		t.Errorf("Could not make block witness: %v", err)
	}
	expected := common.FromHex("0x0601024704010402040304")
	if !bytes.Equal(expected, bwb.Structure.buffer.Bytes()) {
		t.Errorf("Expected %x in structure tape, got: %x", expected, bwb.Structure.buffer.Bytes())
	}
}

func TestSerialiseBlockWitness(t *testing.T) {
	tr := New(common.Hash{})
	tr.Update([]byte("ABCD0001"), []byte("val1"), 0)
	tr.Update([]byte("ABCE0002"), []byte("val2"), 0)
	bwb := NewBlockWitnessBuilder(false)
	rs := NewResolveSet(2)
	if err := bwb.MakeBlockWitness(tr, rs, nil, nil); err != nil {
		t.Errorf("Could not make block witness: %v", err)
	}
	var b bytes.Buffer
	if err := bwb.WriteTo(&b); err != nil {
		t.Errorf("Could not make block witness: %v", err)
	}
	expected := common.FromHex("0xa76862616c616e6365730065636f64657300666861736865731822646b65797300666e6f6e63657300697374727563747572650b6676616c75657300582023181a62d35fe01562158be610f84e047f99f5e74d896da21682d925964ece3a0601024704010402040304")
	if !bytes.Equal(expected, b.Bytes()) {
		t.Errorf("Expected %x, got: %x", expected, b.Bytes())
	}
	tr1, _, err := BlockWitnessToTrie(b.Bytes(), false)
	if err != nil {
		t.Errorf("Could not restore trie from the block witness: %v", err)
	}
	if tr.Hash() != tr1.Hash() {
		t.Errorf("Reconstructed block witness has different root hash than source trie")
	}
}


@@ -4,22 +4,17 @@ package gpu

 import (
 	"context"
-	"net"
 	"os"

 	"github.com/docker/docker/api/types/container"
-	"github.com/docker/go-plugins-helpers/volume"
-	log "github.com/noxiouz/zapctx/ctxlog"
 	"github.com/sonm-io/core/proto"
-	"github.com/sshaman1101/nvidia-docker/nvidia"
-	"go.uber.org/zap"
 )

 type radeonTuner struct {
 	volumePluginHandler
 }

-func newRadeonTuner(ctx context.Context, opts ...Option) (Tuner, error) {
+func newRadeonTuner(_ context.Context, opts ...Option) (Tuner, error) {
 	options := radeonDefaultOptions()
 	for _, f := range opts {
 		f(options)

// +build !darwin,cl

package gpu

import (
	"context"
	"net"
	"os"

	"github.com/docker/docker/api/types/container"
	"github.com/docker/go-plugins-helpers/volume"
	log "github.com/noxiouz/zapctx/ctxlog"
	"github.com/sonm-io/core/proto"
	"github.com/sshaman1101/nvidia-docker/nvidia"
	"go.uber.org/zap"
)

type radeonTuner struct {
	volumePluginHandler
}

func newRadeonTuner(ctx context.Context, opts ...Option) (Tuner, error) {
	options := radeonDefaultOptions()
	for _, f := range opts {
		f(options)
	}

	tun := radeonTuner{}
	tun.options = options

	if err := hasGPUWithVendor(sonm.GPUVendorType_RADEON); err != nil {
		return nil, err
	}

	tun.devices = tun.getDevices()

	if _, err := os.Stat(openCLVendorDir); err == nil {
		tun.OpenCLVendorDir = openCLVendorDir
	}

	volInfo := []nvidia.VolumeInfo{
		{
			Name:         tun.options.VolumeDriverName,
			Mountpoint:   "/opt/amdgpu-pro",
			MountOptions: "ro",
			Components: map[string][]string{
				"libraries": {
					"amdvlk64.so",
					"libEGL.so",
					"libGL.so",
					"libGLESv2.so",
					"libOpenCL.so",
					"libamdocl12cl64.so",
					"libamdocl64.so",
					// vdpau
					"libvdpau_amdgpu.so.1.0.0",
					// dri
					"radeonsi_drv_video.so",
					// gbm
					"gbm_amdgpu.so",

					// by noxiouz from prev impl
					"libMesaOpenCL.so",
					"pipe_vmwgfx.so",
					"pipe_r600.so",
					"pipe_r300.so",
					"pipe_radeonsi.so",
					"pipe_swrast.so",
					"pipe_nouveau.so",
				},
			},
		},
	}

	log.G(ctx).Info("provisioning volumes", zap.String("at", tun.options.VolumePath))
	volumes, err := nvidia.LookupVolumes(tun.options.VolumePath, tun.options.DriverVersion, volInfo)
	if err != nil {
		return nil, err
	}

	tun.handler = volume.NewHandler(NewPlugin(volumes))
	tun.listener, err = net.Listen("unix", tun.options.SocketPath)
	if err != nil {
		log.G(ctx).Error("failed to create listening socket for to communicate with Docker as plugin",
			zap.String("path", tun.options.SocketPath), zap.Error(err))
		return nil, err
	}

	go func() {
		tun.handler.Serve(tun.listener)
	}()

	return tun, nil
}

func (radeonTuner) getDevices() []string {
	var dev []string
	if _, err := os.Stat("/dev/dri"); err == nil {
		dev = append(dev, "/dev/dri")
	}

	if _, err := os.Stat("/dev/kfd"); err == nil {
		dev = append(dev, "/dev/kfd")
	}

	return dev
}

func (tun radeonTuner) Tune(hostconfig *container.HostConfig) error {
	return tun.tune(hostconfig)
}

func (tun radeonTuner) Close() error {
	if err := tun.listener.Close(); err != nil {
		return err
	}

	return os.Remove(tun.options.SocketPath)
}

If the context doesn't used, maybe drop it?


@@ -76,10 +76,10 @@ func buildBinary(source, target string) error {
 	if !ok {
 		targetArch = runtime.GOARCH
 	}
-	return buildBinaryFor(source, target, targetOS, targetArch)
+	return buildBinaryFor(source, target, targetOS, targetArch, false)
 }

-func buildBinaryFor(source, target, targetOS, targetArch string) error {
+func buildBinaryFor(source, target, targetOS, targetArch string, buildStatic bool) error {
 	log.Info().Msgf("Building %s -> %s %s/%s", source, target, targetOS, targetArch)

 	buildDir, err := filepath.Abs(path.Join("build", target))

/*
 * Copyright (C) 2020 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 packages

import (
	"fmt"
	"os"
	"path"
	"path/filepath"
	"runtime"
	"strings"

	"github.com/magefile/mage/sh"
	"github.com/mysteriumnetwork/go-ci/env"
	"github.com/mysteriumnetwork/node/logconfig"
	"github.com/mysteriumnetwork/node/utils/fileutil"
	"github.com/rs/zerolog/log"
)

// Build builds the project. Like go tool, it supports cross-platform build with env vars: GOOS, GOARCH.
func Build() error {
	logconfig.Bootstrap()
	if err := buildBinary(path.Join("cmd", "mysterium_node", "mysterium_node.go"), "myst"); err != nil {
		return err
	}
	if err := copyConfig("myst"); err != nil {
		return err
	}
	if err := buildBinary(path.Join("cmd", "supervisor", "supervisor.go"), "myst_supervisor"); err != nil {
		return err
	}
	return nil
}

func linkerFlags() (flags []string) {
	if env.Str(env.BuildBranch) != "" {
		flags = append(flags, "-X", fmt.Sprintf("'github.com/mysteriumnetwork/node/metadata.BuildBranch=%s'", env.Str(env.BuildBranch)))
	}
	if env.Str("BUILD_COMMIT") != "" {
		flags = append(flags, "-X", fmt.Sprintf("'github.com/mysteriumnetwork/node/metadata.BuildCommit=%s'", env.Str("BUILD_COMMIT")))
	}
	if env.Str(env.BuildNumber) != "" {
		flags = append(flags, "-X", fmt.Sprintf("'github.com/mysteriumnetwork/node/metadata.BuildNumber=%s'", env.Str(env.BuildNumber)))
	}
	if env.Str(env.BuildVersion) != "" {
		flags = append(flags, "-X", fmt.Sprintf("'github.com/mysteriumnetwork/node/metadata.Version=%s'", env.Str(env.BuildVersion)))
	}
	return flags
}

func buildCrossBinary(os, arch string) error {
	return sh.Run("bin/build_xgo", os+"/"+arch)
}

func buildBinary(source, target string) error {
	targetOS, ok := os.LookupEnv("GOOS")
	if !ok {
		targetOS = runtime.GOOS
	}
	targetArch, ok := os.LookupEnv("GOARCH")
	if !ok {
		targetArch = runtime.GOARCH
	}
	return buildBinaryFor(source, target, targetOS, targetArch)
}

func buildBinaryFor(source, target, targetOS, targetArch string) error {
	log.Info().Msgf("Building %s -> %s %s/%s", source, target, targetOS, targetArch)

	buildDir, err := filepath.Abs(path.Join("build", target))
	if err != nil {
		return err
	}

	var flags = []string{"build"}
	if env.Bool("FLAG_RACE") {
		flags = append(flags, "-race")
	}

	ldFlags := linkerFlags()
	flags = append(flags, fmt.Sprintf(`-ldflags=-w -s %s`, strings.Join(ldFlags, " ")))

	if targetOS == "windows" {
		target += ".exe"
	}
	flags = append(flags, "-o", path.Join(buildDir, target), source)

	envi := map[string]string{
		"GOOS":   targetOS,
		"GOARCH": targetArch,
	}
	return sh.RunWith(envi, "go", flags...)
}

func copyConfig(target string) error {
	dest, err := filepath.Abs(path.Join("build", target, "config"))
	if err != nil {
		return err
	}

	common, err := filepath.Abs(path.Join("bin", "package", "config", "common"))
	if err != nil {
		return err
	}
	if err := fileutil.CopyDirs(common, dest); err != nil {
		return err
	}

	targetOS, ok := os.LookupEnv("GOOS")
	if !ok {
		targetOS = runtime.GOOS
	}
	osSpecific, err := filepath.Abs(path.Join("bin", "package", "config", targetOS))
	if err := fileutil.CopyDirs(osSpecific, dest); err != nil {
		return err
	}

	return nil
}

Just a thought that any further extensions of `buildBinaryFor` signature could be done as `buildBinaryFor(..., opts... BuildOptions)` for better readability.


@@ -30,7 +30,7 @@ var DBATag = "v0.2.0"
 var RouterImage = "drud/nginx-proxy" // Note that this is overridden by make

 // RouterTag defines the tag used for the router.
-var RouterTag = "v0.3.0" // Note that this is overridden by make
+var RouterTag = "router-expose" // Note that this is overridden by make

 // COMMIT is the actual committish, supplied by make
 var COMMIT = "COMMIT should be overridden"

package version

// VERSION is supplied with the git committish this is built from
var VERSION = ""

// IMPORTANT: These versions are overridden by version ldflags specifications VERSION_VARIABLES in the Makefile

// DdevVersion is the current version of ddev, by default the git committish (should be current git tag)
var DdevVersion = "v0.3.0-dev" // Note that this is overridden by make

// WebImg defines the default web image used for applications.
var WebImg = "drud/nginx-php-fpm7-local" // Note that this is overridden by make

// WebTag defines the default web image tag for drud dev
var WebTag = "v0.4.0" // Note that this is overridden by make

// DBImg defines the default db image used for applications.
var DBImg = "drud/mysql-docker-local-57" // Note that this is overridden by make

// DBTag defines the default db image tag for drud dev
var DBTag = "v0.3.0" // Note that this is overridden by make

// DBAImg defines the default phpmyadmin image tag used for applications.
var DBAImg = "drud/phpmyadmin"

// DBATag defines the default phpmyadmin image tag used for applications.
var DBATag = "v0.2.0"

// RouterImage defines the image used for the router.
var RouterImage = "drud/nginx-proxy" // Note that this is overridden by make

// RouterTag defines the tag used for the router.
var RouterTag = "v0.3.0" // Note that this is overridden by make

// COMMIT is the actual committish, supplied by make
var COMMIT = "COMMIT should be overridden"

// BUILDINFO is information with date and context, supplied by make
var BUILDINFO = "BUILDINFO should have new info"


@@ -49,7 +49,7 @@ func (s *Server) handleSignals() {
 				s.Debugf("Trapped %q signal", sig)
 				switch sig {
 				case syscall.SIGINT:
-					s.Noticef("Server Exiting..")
+					s.Shutdown()
 					os.Exit(0)
 				case syscall.SIGUSR1:
 					// File log re-open for rotating file logs.

// Copyright 2012-2019 The NATS 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.

// +build !windows

package server

import (
	"errors"
	"fmt"
	"os"
	"os/exec"
	"os/signal"
	"strconv"
	"strings"
	"syscall"
)

var processName = "nats-server"

// SetProcessName allows to change the expected name of the process.
func SetProcessName(name string) {
	processName = name
}

// Signal Handling
func (s *Server) handleSignals() {
	if s.getOpts().NoSigs {
		return
	}
	c := make(chan os.Signal, 1)

	signal.Notify(c, syscall.SIGINT, syscall.SIGUSR1, syscall.SIGUSR2, syscall.SIGHUP)

	go func() {
		for {
			select {
			case sig := <-c:
				s.Debugf("Trapped %q signal", sig)
				switch sig {
				case syscall.SIGINT:
					s.Noticef("Server Exiting..")
					os.Exit(0)
				case syscall.SIGUSR1:
					// File log re-open for rotating file logs.
					s.ReOpenLogFile()
				case syscall.SIGUSR2:
					go s.lameDuckMode()
				case syscall.SIGHUP:
					// Config reload.
					if err := s.Reload(); err != nil {
						s.Errorf("Failed to reload server configuration: %s", err)
					}
				}
			case <-s.quitCh:
				return
			}
		}
	}()
}

// ProcessSignal sends the given signal command to the given process. If pidStr
// is empty, this will send the signal to the single running instance of
// nats-server. If multiple instances are running, it returns an error. This returns
// an error if the given process is not running or the command is invalid.
func ProcessSignal(command Command, pidStr string) error {
	var pid int
	if pidStr == "" {
		pids, err := resolvePids()
		if err != nil {
			return err
		}
		if len(pids) == 0 {
			return fmt.Errorf("no %s processes running", processName)
		}
		if len(pids) > 1 {
			errStr := fmt.Sprintf("multiple %s processes running:\n", processName)
			prefix := ""
			for _, p := range pids {
				errStr += fmt.Sprintf("%s%d", prefix, p)
				prefix = "\n"
			}
			return errors.New(errStr)
		}
		pid = pids[0]
	} else {
		p, err := strconv.Atoi(pidStr)
		if err != nil {
			return fmt.Errorf("invalid pid: %s", pidStr)
		}
		pid = p
	}

	var err error
	switch command {
	case CommandStop:
		err = kill(pid, syscall.SIGKILL)
	case CommandQuit:
		err = kill(pid, syscall.SIGINT)
	case CommandReopen:
		err = kill(pid, syscall.SIGUSR1)
	case CommandReload:
		err = kill(pid, syscall.SIGHUP)
	case commandLDMode:
		err = kill(pid, syscall.SIGUSR2)
	default:
		err = fmt.Errorf("unknown signal %q", command)
	}
	return err
}

// resolvePids returns the pids for all running nats-server processes.
func resolvePids() ([]int, error) {
	// If pgrep isn't available, this will just bail out and the user will be
	// required to specify a pid.
	output, err := pgrep()
	if err != nil {
		switch err.(type) {
		case *exec.ExitError:
			// ExitError indicates non-zero exit code, meaning no processes
			// found.
			break
		default:
			return nil, errors.New("unable to resolve pid, try providing one")
		}
	}
	var (
		myPid   = os.Getpid()
		pidStrs = strings.Split(string(output), "\n")
		pids    = make([]int, 0, len(pidStrs))
	)
	for _, pidStr := range pidStrs {
		if pidStr == "" {
			continue
		}
		pid, err := strconv.Atoi(pidStr)
		if err != nil {
			return nil, errors.New("unable to resolve pid, try providing one")
		}
		// Ignore the current process.
		if pid == myPid {
			continue
		}
		pids = append(pids, pid)
	}
	return pids, nil
}

var kill = func(pid int, signal syscall.Signal) error {
	return syscall.Kill(pid, signal)
}

var pgrep = func() ([]byte, error) {
	return exec.Command("pgrep", processName).Output()
}

I would do an s.Notice("Initiating Shutdown...") then after Shutdown() do the original Server Exiting.


@@ -53,6 +53,16 @@ func mustSpanIDFromHex(s string) (t trace.SpanID) {
 	return
 }

+func TestBytesMapCarrier(t *testing.T) {
+	carrier := make(propagation.BytesMapCarrier)
+	carrier.Set("foo", "bar")
+	carrier.Set("baz", "qux")
+
+	assert.Equal(t, carrier.Get("foo"), "bar")
+	assert.Equal(t, carrier.Get("baz"), "qux")
+	assert.Equal(t, carrier.Keys(), []string{"foo", "baz"})
+}
+
 type outOfThinAirPropagator struct {
 	t *testing.T
 }

// 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 propagation_test

import (
	"context"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"go.opentelemetry.io/otel/propagation"
	"go.opentelemetry.io/otel/trace"
)

const (
	traceIDStr = "4bf92f3577b34da6a3ce929d0e0e4736"
	spanIDStr  = "00f067aa0ba902b7"
)

var (
	traceID = mustTraceIDFromHex(traceIDStr)
	spanID  = mustSpanIDFromHex(spanIDStr)
)

func mustTraceIDFromHex(s string) (t trace.TraceID) {
	var err error
	t, err = trace.TraceIDFromHex(s)
	if err != nil {
		panic(err)
	}
	return
}

func mustSpanIDFromHex(s string) (t trace.SpanID) {
	var err error
	t, err = trace.SpanIDFromHex(s)
	if err != nil {
		panic(err)
	}
	return
}

type outOfThinAirPropagator struct {
	t *testing.T
}

var _ propagation.TextMapPropagator = outOfThinAirPropagator{}

func (p outOfThinAirPropagator) Extract(ctx context.Context, carrier propagation.TextMapCarrier) context.Context {
	sc := trace.NewSpanContext(trace.SpanContextConfig{
		TraceID:    traceID,
		SpanID:     spanID,
		TraceFlags: 0,
	})
	require.True(p.t, sc.IsValid())
	return trace.ContextWithRemoteSpanContext(ctx, sc)
}

func (outOfThinAirPropagator) Inject(context.Context, propagation.TextMapCarrier) {}

func (outOfThinAirPropagator) Fields() []string {
	return nil
}

type nilCarrier struct{}

var _ propagation.TextMapCarrier = nilCarrier{}

func (nilCarrier) Keys() []string {
	return nil
}

func (nilCarrier) Get(key string) string {
	return ""
}

func (nilCarrier) Set(key string, value string) {}

func TestMultiplePropagators(t *testing.T) {
	ootaProp := outOfThinAirPropagator{t: t}
	ns := nilCarrier{}
	testProps := []propagation.TextMapPropagator{
		propagation.TraceContext{},
	}
	bg := context.Background()
	// sanity check of oota propagator, ensuring that it really
	// generates the valid span context out of thin air
	{
		ctx := ootaProp.Extract(bg, ns)
		sc := trace.SpanContextFromContext(ctx)
		require.True(t, sc.IsValid(), "oota prop failed sanity check")
		require.True(t, sc.IsRemote(), "oota prop is remote")
	}
	// sanity check for real propagators, ensuring that they
	// really are not putting any valid span context into an empty
	// go context in absence of the HTTP headers.
	for _, prop := range testProps {
		ctx := prop.Extract(bg, ns)
		sc := trace.SpanContextFromContext(ctx)
		require.Falsef(t, sc.IsValid(), "%#v failed sanity check", prop)
		require.Falsef(t, sc.IsRemote(), "%#v prop set a remote", prop)
	}
	for _, prop := range testProps {
		props := propagation.NewCompositeTextMapPropagator(ootaProp, prop)
		ctx := props.Extract(bg, ns)
		sc := trace.SpanContextFromContext(ctx)
		assert.Truef(t, sc.IsRemote(), "%#v prop is remote", prop)
		assert.Truef(t, sc.IsValid(), "%#v clobbers span context", prop)
	}
}

Map iteration order isn't guaranteed, so the result will need to be sorted or another set of checks devised. You could assert it's length 2 and contains both "foo" and "bar".


@@ -1,3 +1,5 @@
+// The MIT License
+//
 // Copyright (c) 2017 Uber Technologies, Inc.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy

// Copyright (c) 2017 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//go:generate mockgen -copyright_file ../../LICENSE -package $GOPACKAGE -source $GOFILE -destination interface_mock.go

package frontend

import (
	"go.temporal.io/temporal-proto/workflowservice"

	"github.com/temporalio/temporal/common"
	"github.com/temporalio/temporal/common/resource"

	healthpb "google.golang.org/grpc/health/grpc_health_v1"
)

type (
	// Handler is interface wrapping frontend handler
	Handler interface {
		workflowservice.WorkflowServiceServer
		common.Daemon

		// Health is the health check method for this rpc handler
		healthpb.HealthServer
		// UpdateHealthStatus sets the health status for this rpc handler.
		// This health status will be used within the rpc health check handler
		UpdateHealthStatus(status HealthStatus)

		GetResource() resource.Resource
		GetConfig() *Config
	}
)

Can you also include Temporal copyright too?


@@ -26,12 +26,18 @@ import (

 var ipamDrivers map[string]IPAMDriver

-type IPAMConfig struct {
-	Type    string `json:"type,omitempty"`
-	Subnet  string `json:"subnet,omitempty"`
+type Range struct {
+	Subnet  string `json:"subnet"`
 	Gateway string `json:"gateway,omitempty"`
 }

+type RangeSet []Range
+
+type IPAMConfig struct {
+	Type   string     `json:"type,omitempty"`
+	Ranges []RangeSet `json:"ranges,omitempty"`
+}
+
 type IPAMDriver interface {
 	Add(args *invoke.Args, networkConfig []byte) (*current.Result, error)
 	Del(args *invoke.Args, networkConfig []byte) error

// Copyright 2019 Antrea 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 ipam

import (
	"fmt"
	"sync"

	"github.com/containernetworking/cni/pkg/invoke"
	"github.com/containernetworking/cni/pkg/types/current"

	cnipb "github.com/vmware-tanzu/antrea/pkg/apis/cni/v1beta1"
)

var ipamDrivers map[string]IPAMDriver

type IPAMConfig struct {
	Type    string `json:"type,omitempty"`
	Subnet  string `json:"subnet,omitempty"`
	Gateway string `json:"gateway,omitempty"`
}

type IPAMDriver interface {
	Add(args *invoke.Args, networkConfig []byte) (*current.Result, error)
	Del(args *invoke.Args, networkConfig []byte) error
	Check(args *invoke.Args, networkConfig []byte) error
}

var ipamResults = sync.Map{}

func RegisterIPAMDriver(ipamType string, ipamDriver IPAMDriver) error {
	if ipamDrivers == nil {
		ipamDrivers = make(map[string]IPAMDriver)
	}
	if _, existed := ipamDrivers[ipamType]; existed {
		return fmt.Errorf("Already registered IPAM with type %s", ipamType)
	}
	ipamDrivers[ipamType] = ipamDriver
	return nil
}

func argsFromEnv(cniArgs *cnipb.CniCmdArgs) *invoke.Args {
	return &invoke.Args{
		ContainerID: cniArgs.ContainerId,
		NetNS:       cniArgs.Netns,
		IfName:      cniArgs.Ifname,
		Path:        cniArgs.Path,
	}
}

func ExecIPAMAdd(cniArgs *cnipb.CniCmdArgs, ipamType string, resultKey string) (*current.Result, error) {
	// Return the cached IPAM result for the same Pod. This cache helps to ensure CNIAdd is idempotent. There are two
	// usages of CNIAdd message on Windows: 1) add container network configuration, and 2) query Pod network status.
	// kubelet on Windows sends CNIAdd messages to query Pod status periodically before the sandbox container is ready.
	// The cache here is to ensure only one IP address is allocated to one Pod.
	// TODO: A risk of IP re-allocation exists if agent restarts before kubelet queries Pod status and after the
	//       container networking configurations is added.
	obj, ok := GetIPFromCache(resultKey)
	if ok {
		return obj, nil
	}

	args := argsFromEnv(cniArgs)
	driver := ipamDrivers[ipamType]
	result, err := driver.Add(args, cniArgs.NetworkConfiguration)
	if err != nil {
		return nil, err
	}
	ipamResults.Store(resultKey, result)
	return result, nil
}

func ExecIPAMDelete(cniArgs *cnipb.CniCmdArgs, ipamType string, resultKey string) error {
	args := argsFromEnv(cniArgs)
	driver := ipamDrivers[ipamType]
	err := driver.Del(args, cniArgs.NetworkConfiguration)
	if err != nil {
		return err
	}
	ipamResults.Delete(resultKey)
	return nil
}

func ExecIPAMCheck(cniArgs *cnipb.CniCmdArgs, ipamType string) error {
	args := argsFromEnv(cniArgs)
	driver := ipamDrivers[ipamType]
	return driver.Check(args, cniArgs.NetworkConfiguration)
}

func GetIPFromCache(resultKey string) (*current.Result, bool) {
	obj, ok := ipamResults.Load(resultKey)
	if ok {
		result := obj.(*current.Result)
		return result, ok
	}
	return nil, ok
}

func IsIPAMTypeValid(ipamType string) bool {
	_, valid := ipamDrivers[ipamType]
	return valid
}

Sorry, why Subnet + Gateway is called "Range"?


@@ -65,13 +65,10 @@ const (

 // SPI on the Trinket M0.
 var (
-	SPI0 = SPI{Bus: sam.SERCOM0_SPI,
-		SCK:     SPI0_SCK_PIN,
-		MOSI:    SPI0_MOSI_PIN,
-		MISO:    SPI0_MISO_PIN,
-		DOpad:   spiTXPad2SCK3,
-		DIpad:   sercomRXPad0,
-		PinMode: PinSERCOMAlt}
+	SPI0 = SPI{
+		Bus:    sam.SERCOM0_SPI,
+		SERCOM: 0,
+	}
 )

 // I2C pins

// +build sam,atsamd21,trinket_m0

package machine

import "device/sam"

// used to reset into bootloader
const RESET_MAGIC_VALUE = 0xf01669ef

// GPIO Pins
const (
	D0  = PA08 // PWM available
	D1  = PA02
	D2  = PA09 // PWM available
	D3  = PA07 // PWM available / UART0 RX
	D4  = PA06 // PWM available / UART0 TX
	D13 = PA10 // LED
)

// Analog pins
const (
	A0 = D1
	A1 = D2
	A2 = D0
	A3 = D3
	A4 = D4
)

const (
	LED = D13
)

// UART0 aka USBCDC pins
const (
	USBCDC_DM_PIN = PA24
	USBCDC_DP_PIN = PA25
)

// UART1 pins
const (
	UART_TX_PIN = D4
	UART_RX_PIN = D3
)

// UART1 on the Trinket M0.
var (
	UART1 = UART{Bus: sam.SERCOM1_USART,
		Buffer: NewRingBuffer(),
		Mode:   PinSERCOM,
		IRQVal: sam.IRQ_SERCOM1,
	}
)

//go:export SERCOM1_IRQHandler
func handleUART1() {
	defaultUART1Handler()
}

// SPI pins
const (
	SPI0_SCK_PIN  = D3
	SPI0_MOSI_PIN = D4
	SPI0_MISO_PIN = D2
)

// SPI on the Trinket M0.
var (
	SPI0 = SPI{Bus: sam.SERCOM0_SPI,
		SCK:     SPI0_SCK_PIN,
		MOSI:    SPI0_MOSI_PIN,
		MISO:    SPI0_MISO_PIN,
		DOpad:   spiTXPad2SCK3,
		DIpad:   sercomRXPad0,
		PinMode: PinSERCOMAlt}
)

// I2C pins
const (
	SDA_PIN = D0 // SDA
	SCL_PIN = D2 // SCL
)

// I2C on the Trinket M0.
var (
	I2C0 = I2C{Bus: sam.SERCOM2_I2CM,
		SDA:     SDA_PIN,
		SCL:     SCL_PIN,
		PinMode: PinSERCOMAlt}
)

// I2S pins
const (
	I2S_SCK_PIN = PA10
	I2S_SD_PIN  = PA08
	I2S_WS_PIN  = NoPin // TODO: figure out what this is on Trinket M0.
)

I think this should have been `sercomRXPad1` as well.


@@ -6,20 +6,20 @@ package agent_test

 import (
 	"log"
-	"os"
 	"net"
+	"os"

-        "golang.org/x/crypto/ssh"
-        "golang.org/x/crypto/ssh/agent"
+	"golang.org/x/crypto/ssh"
+	"golang.org/x/crypto/ssh/agent"
 )

 func ExampleClientAgent() {
 	// ssh-agent has a UNIX socket under $SSH_AUTH_SOCK
 	socket := os.Getenv("SSH_AUTH_SOCK")
-        conn, err := net.Dial("unix", socket)
-        if err != nil {
-                log.Fatalf("net.Dial: %v", err)
-        }
+	conn, err := net.Dial("unix", socket)
+	if err != nil {
+		log.Fatalf("net.Dial: %v", err)
+	}
 	agentClient := agent.NewClient(conn)
 	config := &ssh.ClientConfig{
 		User: "username",

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

package agent_test

import (
	"log"
	"os"
	"net"

        "golang.org/x/crypto/ssh"
        "golang.org/x/crypto/ssh/agent"
)

func ExampleClientAgent() {
	// ssh-agent has a UNIX socket under $SSH_AUTH_SOCK
	socket := os.Getenv("SSH_AUTH_SOCK")
        conn, err := net.Dial("unix", socket)
        if err != nil {
                log.Fatalf("net.Dial: %v", err)
        }
	agentClient := agent.NewClient(conn)
	config := &ssh.ClientConfig{
		User: "username",
		Auth: []ssh.AuthMethod{
			// Use a callback rather than PublicKeys
			// so we only consult the agent once the remote server
			// wants it.
			ssh.PublicKeysCallback(agentClient.Signers),
		},
	}

	sshc, err := ssh.Dial("tcp", "localhost:22", config)
	if err != nil {
		log.Fatalf("Dial: %v", err)
	}
	// .. use sshc
	sshc.Close()
}

This does not belong into the PR, did you accidentally run `gofmt` on the `vendor` directory?


@@ -39,4 +39,9 @@ func Start() {
 func Stop() {
 	tch.Stop()
 	yarpc.Stop()
+	http.Stop()
+	apachethrift.Stop()
 }
+
+// TODO(abg): We should probably use defers to ensure things that started up
+// successfully are stopped before we exit.

// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package server

import (
	"github.com/yarpc/yarpc-go/crossdock/server/apachethrift"
	"github.com/yarpc/yarpc-go/crossdock/server/http"
	"github.com/yarpc/yarpc-go/crossdock/server/tch"
	"github.com/yarpc/yarpc-go/crossdock/server/yarpc"
)

// Start starts all required Crossdock test servers
func Start() {
	tch.Start()
	yarpc.Start()
	http.Start()
	apachethrift.Start()
}

// Stop stops all required Crossdock test servers
func Stop() {
	tch.Stop()
	yarpc.Stop()
}

I believe this `Stop` function _is_ called with deferred.


@@ -35,6 +35,10 @@ type ConfigRunner struct {

 	// Must not be nil if using default subnets.
 	VPCGetter VPCGetter
+
+	// Platform configuration
+	OS   string
+	Arch string
 }

 // Run runs tasks given subnets, security groups and the cluster, and returns the tasks.

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

package task

import (
	"fmt"

	"github.com/aws/copilot-cli/internal/pkg/aws/ec2"
	"github.com/aws/copilot-cli/internal/pkg/aws/ecs"
)

const (
	fmtErrDefaultSubnets = "get default subnet IDs: %w"
)

// ConfigRunner runs an Amazon ECS task in the subnets, security groups, and cluster.
// It uses the default subnets and the default cluster if the corresponding field is empty.
type ConfigRunner struct {
	// Count of the tasks to be launched.
	Count int
	// Group Name of the tasks that use the same task definition.
	GroupName string

	// The ARN of the cluster to run the task.
	Cluster string

	// Network configuration
	Subnets        []string
	SecurityGroups []string

	// Interfaces to interact with dependencies. Must not be nil.
	ClusterGetter DefaultClusterGetter
	Starter       Runner

	// Must not be nil if using default subnets.
	VPCGetter VPCGetter
}

// Run runs tasks given subnets, security groups and the cluster, and returns the tasks.
// If subnets are not provided, it uses the default subnets.
// If cluster is not provided, it uses the default cluster.
func (r *ConfigRunner) Run() ([]*Task, error) {
	if err := r.validateDependencies(); err != nil {
		return nil, err
	}

	if r.Cluster == "" {
		cluster, err := r.ClusterGetter.DefaultCluster()
		if err != nil {
			return nil, &errGetDefaultCluster{
				parentErr: err,
			}
		}
		r.Cluster = cluster
	}

	if r.Subnets == nil {
		subnets, err := r.VPCGetter.SubnetIDs(ec2.FilterForDefaultVPCSubnets)
		if err != nil {
			return nil, fmt.Errorf(fmtErrDefaultSubnets, err)
		}
		if len(subnets) == 0 {
			return nil, errNoSubnetFound
		}
		r.Subnets = subnets
	}

	ecsTasks, err := r.Starter.RunTask(ecs.RunTaskInput{
		Cluster:        r.Cluster,
		Count:          r.Count,
		Subnets:        r.Subnets,
		SecurityGroups: r.SecurityGroups,
		TaskFamilyName: taskFamilyName(r.GroupName),
		StartedBy:      startedBy,
	})
	if err != nil {
		return nil, &errRunTask{
			groupName: r.GroupName,
			parentErr: err,
		}
	}

	return convertECSTasks(ecsTasks), nil
}

func (r *ConfigRunner) validateDependencies() error {
	if r.ClusterGetter == nil {
		return errClusterGetterNil
	}

	if r.Starter == nil {
		return errStarterNil
	}

	return nil
}

Is `Arch` used anywhere? (Same for env_runner.go)


@@ -7,6 +7,15 @@ type NodeEntry struct {
 	GossipVersion string
 }

+// Equals method compares two NodeEntries, and returns TRUE if the NodeEntry's data is equal.
+func (ne NodeEntry) Equals(other *NodeEntry) bool {
+	if other == nil {
+		return false
+	} else {
+		return ne.Id == other.Id && ne.Ip == other.Ip && ne.GossipVersion == other.GossipVersion
+	}
+}
+
 // ClusterInfo is the cluster info used while discoveryping nodes
 // and discovering peer nodes using gossip
 type ClusterInfo struct {

package discovery

// NodeEntry is used to discovery nodes in the cluster
type NodeEntry struct {
	Id            string
	Ip            string
	GossipVersion string
}

// ClusterInfo is the cluster info used while discoveryping nodes
// and discovering peer nodes using gossip
type ClusterInfo struct {
	Size    int
	Nodes   map[string]NodeEntry
	Version uint64
}

type WatchClusterCB func(*ClusterInfo, error) error

type Cluster interface {
	// AddNode adds a new node into a cluster so that other can discover
	AddNode(dne NodeEntry) (*ClusterInfo, error)

	// RemoveNode removes a node from a cluster
	RemoveNode(dne NodeEntry) (*ClusterInfo, error)

	// Enumerate enumerates the nodes that have been discovered in the cluster
	Enumerate() (*ClusterInfo, error)

	// WatchCluster starts a watch on the cluster and calls the provided
	// callback function when a node is added or removed.
	WatchCluster(wcb WatchClusterCB, index uint64) error
}

Struct values are comparable if all their fields are comparable. Two struct values are equal if their corresponding non-blank fields are equal.


@@ -31,5 +31,5 @@ func (t Template) eksControlPlanePolicies() []string {
 }

 func eksAssumeRolePolicy() *iamv1.PolicyDocument {
-	return assumeRolePolicy("eks.amazonaws.com")
+	return assumeRolePolicy([]string{"eks.amazonaws.com"})
 }

/*
Copyright 2020 The Kubernetes 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 bootstrap

import iamv1 "sigs.k8s.io/cluster-api-provider-aws/cmd/clusterawsadm/api/iam/v1alpha1"

func (t Template) eksControlPlanePolicies() []string {
	policies := []string{EKSClusterPolicy}
	if t.Spec.EKS.DefaultControlPlaneRole.ExtraPolicyAttachments != nil {
		for _, policy := range t.Spec.EKS.DefaultControlPlaneRole.ExtraPolicyAttachments {
			additionalPolicy := policy
			policies = append(policies, additionalPolicy)
		}
	}

	return policies
}

func eksAssumeRolePolicy() *iamv1.PolicyDocument {
	return assumeRolePolicy("eks.amazonaws.com")
}

Maybe give this a more specific function name, or inline it completely.


@@ -39,10 +39,23 @@ func Test_translateAnnotations(t *testing.T) {

 	validAnnotations := func() map[string]string {
 		return map[string]string{
-			cmapi.CommonNameAnnotationKey:  "www.example.com",
-			cmapi.DurationAnnotationKey:    "168h", // 1 week
-			cmapi.RenewBeforeAnnotationKey: "24h",
-			cmapi.UsagesAnnotationKey:      "server auth,signing",
+			cmapi.CommonNameAnnotationKey:                 "www.example.com",
+			cmapi.EmailsAnnotationKey:                     "test@example.com",
+			cmapi.SubjectOrganizationsAnnotationKey:       "Test Organization",
+			cmapi.SubjectOrganizationalUnitsAnnotationKey: "Test Organizational Unit",
+			cmapi.SubjectCountriesAnnotationKey:           "Country",
+			cmapi.SubjectProvincesAnnotationKey:           "Province",
+			cmapi.SubjectLocalitiesAnnotationKey:          "City",
+<<<<<<< HEAD
+			cmapi.SubjectStreetAddressesAnnotationKey:     "\"1725 Slough Avenue, Suite 200, Scranton Business Park\"",
+=======
+			cmapi.SubjectStreetAddressesAnnotationKey:     "Address",
+>>>>>>> 10a9535a99ece4b45f2ea7d8c4aa57bd35d52768
+			cmapi.SubjectPostalCodesAnnotationKey:         "ABC123",
+			cmapi.SubjectSerialNumberAnnotationKey:        "123456",
+			cmapi.DurationAnnotationKey:                   "168h", // 1 week
+			cmapi.RenewBeforeAnnotationKey:                "24h",
+			cmapi.UsagesAnnotationKey:                     "server auth,signing",
 		}
 	}

/*
Copyright 2020 The cert-manager 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 shimhelper

import (
	"errors"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1"
	"github.com/jetstack/cert-manager/test/unit/gen"
)

func Test_translateAnnotations(t *testing.T) {
	type testCase struct {
		crt           *cmapi.Certificate
		annotations   map[string]string
		mutate        func(*testCase)
		check         func(*assert.Assertions, *cmapi.Certificate)
		expectedError error
	}

	validAnnotations := func() map[string]string {
		return map[string]string{
			cmapi.CommonNameAnnotationKey:  "www.example.com",
			cmapi.DurationAnnotationKey:    "168h", // 1 week
			cmapi.RenewBeforeAnnotationKey: "24h",
			cmapi.UsagesAnnotationKey:      "server auth,signing",
		}
	}

	tests := map[string]testCase{
		"success": {
			crt:         gen.Certificate("example-cert"),
			annotations: validAnnotations(),
			check: func(a *assert.Assertions, crt *cmapi.Certificate) {
				a.Equal("www.example.com", crt.Spec.CommonName)
				a.Equal(&metav1.Duration{Duration: time.Hour * 24 * 7}, crt.Spec.Duration)
				a.Equal(&metav1.Duration{Duration: time.Hour * 24}, crt.Spec.RenewBefore)
				a.Equal([]cmapi.KeyUsage{cmapi.UsageServerAuth, cmapi.UsageSigning}, crt.Spec.Usages)
			},
		},
		"nil annotations": {
			crt:         gen.Certificate("example-cert"),
			annotations: nil,
		},
		"empty annotations": {
			crt:         gen.Certificate("example-cert"),
			annotations: map[string]string{},
		},
		"nil certificate": {
			crt:           nil,
			annotations:   validAnnotations(),
			expectedError: errNilCertificate,
		},
		"bad duration": {
			crt:         gen.Certificate("example-cert"),
			annotations: validAnnotations(),
			mutate: func(tc *testCase) {
				tc.annotations[cmapi.DurationAnnotationKey] = "an un-parsable duration string"
			},
			expectedError: errInvalidIngressAnnotation,
		},
		"bad renewBefore": {
			crt:         gen.Certificate("example-cert"),
			annotations: validAnnotations(),
			mutate: func(tc *testCase) {
				tc.annotations[cmapi.RenewBeforeAnnotationKey] = "an un-parsable duration string"
			},
			expectedError: errInvalidIngressAnnotation,
		},
		"bad usages": {
			crt:         gen.Certificate("example-cert"),
			annotations: validAnnotations(),
			mutate: func(tc *testCase) {
				tc.annotations[cmapi.UsagesAnnotationKey] = "playing ping pong"
			},
			expectedError: errInvalidIngressAnnotation,
		},
		"bad usage list": {
			crt:         gen.Certificate("example-cert"),
			annotations: validAnnotations(),
			mutate: func(tc *testCase) {
				tc.annotations[cmapi.UsagesAnnotationKey] = "server auth,,signing"
			},
			expectedError: errInvalidIngressAnnotation,
		},
	}
	for name, tc := range tests {
		t.Run(name, func(t *testing.T) {
			if tc.mutate != nil {
				tc.mutate(&tc)
			}
			crt := tc.crt.DeepCopy()

			err := translateAnnotations(crt, tc.annotations)

			if tc.expectedError != nil {
				assertErrorIs(t, err, tc.expectedError)
			} else {
				assert.NoError(t, err)
			}
			if tc.check != nil {
				tc.check(assert.New(t), crt)
			}
		})
	}
}

// assertErrorIs checks that the supplied error has the target error in its chain.
// TODO Upgrade to next release of testify package which has this built in.
func assertErrorIs(t *testing.T, err, target error) {
	if assert.Error(t, err) {
		assert.Truef(t, errors.Is(err, target), "unexpected error type. err: %v, target: %v", err, target)
	}
}

I'm guessing these conflicts are just temporary? Obviously will need to be fixed before merging!


@@ -75,7 +75,7 @@ func TestCtlInstall(t *testing.T) {
 			testApiServer, cleanup := install_framework.NewTestInstallApiServer(t)
 			defer cleanup()

-			ctx, cancel := context.WithTimeout(context.TODO(), time.Second*20)
+			ctx, cancel := context.WithTimeout(context.Background(), time.Second*40)
 			defer cancel()

 			if test.prerun {

/*
Copyright 2021 The cert-manager 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 ctl

import (
	"bytes"
	"context"
	"fmt"
	"regexp"
	"strings"
	"testing"
	"time"

	"github.com/sergi/go-diff/diffmatchpatch"

	"github.com/jetstack/cert-manager/cmd/ctl/cmd"
	"github.com/jetstack/cert-manager/test/integration/ctl/install_framework"
	"github.com/jetstack/cert-manager/test/internal/util"
)

func TestCtlInstall(t *testing.T) {
	tests := map[string]struct {
		prerun       bool
		preInputArgs []string
		preExpErr    bool
		preExpOutput string

		inputArgs []string
		expErr    bool
		expOutput string
	}{
		"install cert-manager": {
			inputArgs: []string{},
			expErr:    false,
			expOutput: `STATUS: deployed`,
		},
		"install cert-manager (already installed)": {
			prerun:       true,
			preInputArgs: []string{},
			preExpErr:    false,
			preExpOutput: `STATUS: deployed`,

			inputArgs: []string{},
			expErr:    true,
			expOutput: `^Found existing installed cert-manager CRDs! Cannot continue with installation.$`,
		},
		"install cert-manager (already installed, in other namespace)": {
			prerun:       true,
			preInputArgs: []string{"--namespace=test"},
			preExpErr:    false,
			preExpOutput: `STATUS: deployed`,

			inputArgs: []string{},
			expErr:    true,
			expOutput: `^Found existing installed cert-manager CRDs! Cannot continue with installation.$`,
		},
	}

	for name, test := range tests {
		t.Run(name, func(t *testing.T) {
			testApiServer, cleanup := install_framework.NewTestInstallApiServer(t)
			defer cleanup()

			ctx, cancel := context.WithTimeout(context.TODO(), time.Second*20)
			defer cancel()

			if test.prerun {
				executeCommandAndCheckOutput(t, ctx, testApiServer.KubeConfig(), test.preInputArgs, test.preExpErr, test.preExpOutput)
			}

			executeCommandAndCheckOutput(t, ctx, testApiServer.KubeConfig(), test.inputArgs, test.expErr, test.expOutput)
		})
	}
}

func executeCommandAndCheckOutput(
	t *testing.T,
	ctx context.Context,
	kubeConfig string,
	inputArgs []string,
	expErr bool,
	expOutput string,
) {
	// Options to run status command
	stdin := bytes.NewBufferString("")
	stdout := bytes.NewBufferString("")

	chartPath := util.GetTestPath("deploy", "charts", "cert-manager", "cert-manager.tgz")
	cmd := cmd.NewCertManagerCtlCommand(ctx, stdin, stdout, stdout)
	cmd.SetArgs(append([]string{
		fmt.Sprintf("--kubeconfig=%s", kubeConfig),
		"--wait=false",
		fmt.Sprintf("--chart-name=%s", chartPath),
		"x",
		"install",
	}, inputArgs...))

	err := cmd.Execute()
	if err != nil {
		fmt.Fprintf(stdout, "%s\n", err)

		if !expErr {
			t.Errorf("got unexpected error: %v", err)
		} else {
			t.Logf("got an error, which was expected, details: %v", err)
		}
	} else if expErr {
		// expected error but error is nil
		t.Errorf("expected but got no error")
	}

	match, err := regexp.MatchString(strings.TrimSpace(expOutput), strings.TrimSpace(stdout.String()))
	if err != nil {
		t.Error(err)
	}
	dmp := diffmatchpatch.New()
	if !match {
		diffs := dmp.DiffMain(strings.TrimSpace(expOutput), strings.TrimSpace(stdout.String()), false)
		t.Errorf(
			"got unexpected output, diff (ignoring line anchors ^ and $ and regex for creation time):\n"+
				"diff: %s\n\n"+
				" exp: %s\n\n"+
				" got: %s",
			dmp.DiffPrettyText(diffs),
			expOutput,
			stdout.String(),
		)
	}
}

This `context` is used correctly, there is nothing left TO DO.


@@ -123,36 +123,37 @@ func (p *PoolAttach) Execute() ([]byte, error) {
 		return nil, err
 	}
 	// execute command here
-	return exec.Command(bin.ZPOOL, p.Command).CombinedOutput()
+	return exec.Command(bin.BASH, "-c", p.Command).CombinedOutput()
 }

 // Build returns the PoolAttach object generated by builder
 func (p *PoolAttach) Build() (*PoolAttach, error) {
 	var c strings.Builder
 	p = p.Validate()
-	p.appendCommand(c, fmt.Sprintf(" %s ", Operation))
+	p.appendCommand(&c, bin.ZPOOL)
+	p.appendCommand(&c, fmt.Sprintf(" %s ", Operation))

 	if IsForcefullySet()(p) {
-		p.appendCommand(c, fmt.Sprintf(" -f "))
+		p.appendCommand(&c, fmt.Sprintf(" -f "))
 	}

 	if IsPropertySet()(p) {
 		for _, v := range p.Property {
-			p.appendCommand(c, fmt.Sprintf(" -o %s ", v))
+			p.appendCommand(&c, fmt.Sprintf(" -o %s ", v))
 		}
 	}

-	p.appendCommand(c, p.Pool)
+	p.appendCommand(&c, p.Pool)

-	p.appendCommand(c, fmt.Sprintf(" %s ", p.Device))
-	p.appendCommand(c, fmt.Sprintf(" %s ", p.NewDevice))
+	p.appendCommand(&c, fmt.Sprintf(" %s ", p.Device))
+	p.appendCommand(&c, fmt.Sprintf(" %s ", p.NewDevice))

 	p.Command = c.String()
 	return p, p.err
 }

 // appendCommand append string to given string builder
-func (p *PoolAttach) appendCommand(c strings.Builder, cmd string) {
+func (p *PoolAttach) appendCommand(c *strings.Builder, cmd string) {
 	_, err := c.WriteString(cmd)
 	if err != nil {
 		p.err = errors.Wrapf(p.err, "Failed to append cmd{%s} : %s", cmd, err.Error())

/*
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 pattach

import (
	"fmt"
	"os/exec"
	"reflect"
	"runtime"
	"strings"

	"github.com/openebs/maya/pkg/zfs/cmd/v1alpha1/bin"
	"github.com/pkg/errors"
)

const (
	// Operation defines type of zfs operation
	Operation = "attach"
)

//PoolAttach defines structure for pool 'Attach' operation
type PoolAttach struct {
	//list of property
	Property []string

	//forcefully attach
	Forcefully bool

	//device name
	Device string

	//new device name
	NewDevice string

	//pool name
	Pool string

	// command string
	Command string

	// checks is list of predicate function used for validating object
	checks []PredicateFunc

	// error
	err error
}

// NewPoolAttach returns new instance of object PoolAttach
func NewPoolAttach() *PoolAttach {
	return &PoolAttach{}
}

// WithCheck add given check to checks list
func (p *PoolAttach) WithCheck(check ...PredicateFunc) *PoolAttach {
	p.checks = append(p.checks, check...)
	return p
}

// WithProperty method fills the Property field of PoolAttach object.
func (p *PoolAttach) WithProperty(key, value string) *PoolAttach {
	p.Property = append(p.Property, fmt.Sprintf("%s=%s", key, value))
	return p
}

// WithForcefully method fills the Forcefully field of PoolAttach object.
func (p *PoolAttach) WithForcefully(Forcefully bool) *PoolAttach {
	p.Forcefully = Forcefully
	return p
}

// WithDevice method fills the Device field of PoolAttach object.
func (p *PoolAttach) WithDevice(Device string) *PoolAttach {
	p.Device = Device
	return p
}

// WithNewDevice method fills the NewDevice field of PoolAttach object.
func (p *PoolAttach) WithNewDevice(NewDevice string) *PoolAttach {
	p.NewDevice = NewDevice
	return p
}

// WithPool method fills the Pool field of PoolAttach object.
func (p *PoolAttach) WithPool(Pool string) *PoolAttach {
	p.Pool = Pool
	return p
}

// WithCommand method fills the Command field of PoolAttach object.
func (p *PoolAttach) WithCommand(Command string) *PoolAttach {
	p.Command = Command
	return p
}

// Validate is to validate generated PoolAttach object by builder
func (p *PoolAttach) Validate() *PoolAttach {
	for _, check := range p.checks {
		if !check(p) {
			p.err = errors.Wrapf(p.err, "validation failed {%v}", runtime.FuncForPC(reflect.ValueOf(check).Pointer()).Name())
		}
	}
	return p
}

// Execute is to execute generated PoolAttach object
func (p *PoolAttach) Execute() ([]byte, error) {
	p, err := p.Build()
	if err != nil {
		return nil, err
	}
	// execute command here
	return exec.Command(bin.ZPOOL, p.Command).CombinedOutput()
}

// Build returns the PoolAttach object generated by builder
func (p *PoolAttach) Build() (*PoolAttach, error) {
	var c strings.Builder
	p = p.Validate()
	p.appendCommand(c, fmt.Sprintf(" %s ", Operation))

	if IsForcefullySet()(p) {
		p.appendCommand(c, fmt.Sprintf(" -f "))
	}

	if IsPropertySet()(p) {
		for _, v := range p.Property {
			p.appendCommand(c, fmt.Sprintf(" -o %s ", v))
		}
	}

	p.appendCommand(c, p.Pool)

	p.appendCommand(c, fmt.Sprintf(" %s ", p.Device))
	p.appendCommand(c, fmt.Sprintf(" %s ", p.NewDevice))

	p.Command = c.String()
	return p, p.err
}

// appendCommand append string to given string builder
func (p *PoolAttach) appendCommand(c strings.Builder, cmd string) {
	_, err := c.WriteString(cmd)
	if err != nil {
		p.err = errors.Wrapf(p.err, "Failed to append cmd{%s} : %s", cmd, err.Error())
	}
}

G204: Subprocess launching should be audited (from `gosec`)


@@ -10,11 +10,10 @@ import (

 	"github.com/filecoin-project/go-filecoin/address"
 	"github.com/filecoin-project/go-filecoin/porcelain"
-	"github.com/filecoin-project/go-filecoin/types"
 )

 // MinerCreate runs the `miner create` command against the filecoin process
-func (f *Filecoin) MinerCreate(ctx context.Context, pledge uint64, collateral *types.AttoFIL, options ...ActionOption) (address.Address, error) {
+func (f *Filecoin) MinerCreate(ctx context.Context, pledge uint64, collateral *big.Int, options ...ActionOption) (address.Address, error) {
 	var out address.Address

 	sPledge := fmt.Sprintf("%d", pledge)

package fat

import (
	"context"
	"fmt"
	"math/big"

	cid "gx/ipfs/QmR8BauakNcBa3RbE4nbQu76PDiJgoQgz8AJdhJuiU4TAw/go-cid"
	"gx/ipfs/QmY5Grm8pJdiSSVsYxx4uNRgweY72EmYwuSDbRnbFok3iY/go-libp2p-peer"

	"github.com/filecoin-project/go-filecoin/address"
	"github.com/filecoin-project/go-filecoin/porcelain"
	"github.com/filecoin-project/go-filecoin/types"
)

// MinerCreate runs the `miner create` command against the filecoin process
func (f *Filecoin) MinerCreate(ctx context.Context, pledge uint64, collateral *types.AttoFIL, options ...ActionOption) (address.Address, error) {
	var out address.Address

	sPledge := fmt.Sprintf("%d", pledge)
	sCollateral := collateral.String()

	args := []string{"go-filecoin", "miner", "create"}

	for _, option := range options {
		args = append(args, option()...)
	}

	args = append(args, sPledge, sCollateral)

	if err := f.RunCmdJSONWithStdin(ctx, nil, &out, args...); err != nil {
		return address.Address{}, err
	}

	return out, nil
}

// MinerUpdatePeerid runs the `miner update-peerid` command against the filecoin process
func (f *Filecoin) MinerUpdatePeerid(ctx context.Context, minerAddr address.Address, pid peer.ID, options ...ActionOption) (cid.Cid, error) {
	var out cid.Cid

	args := []string{"go-filecoin", "miner", "update-peerid"}

	for _, option := range options {
		args = append(args, option()...)
	}

	args = append(args, minerAddr.String(), pid.Pretty())

	if err := f.RunCmdJSONWithStdin(ctx, nil, &out, args...); err != nil {
		return cid.Undef, err
	}

	return out, nil
}

// MinerAddAsk runs the `miner add-ask` command against the filecoin process
func (f *Filecoin) MinerAddAsk(ctx context.Context, minerAddr address.Address, fil *big.Float, expiry big.Int, options ...ActionOption) (cid.Cid, error) {
	var out cid.Cid

	sMinerAddr := minerAddr.String()
	sExpiry := expiry.String()
	sFil := fil.String()

	args := []string{"go-filecoin", "miner", "add-ask"}

	for _, option := range options {
		args = append(args, option()...)
	}

	args = append(args, sMinerAddr, sFil, sExpiry)

	if err := f.RunCmdJSONWithStdin(ctx, nil, &out, args...); err != nil {
		return cid.Undef, err
	}
	return out, nil
}

// MinerOwner runs the `miner owner` command against the filecoin process
func (f *Filecoin) MinerOwner(ctx context.Context, minerAddr address.Address) (address.Address, error) {
	var out address.Address

	sMinerAddr := minerAddr.String()

	if err := f.RunCmdJSONWithStdin(ctx, nil, &out, "go-filecoin", "miner", "owner", sMinerAddr); err != nil {
		return address.Address{}, err
	}

	return out, nil
}

// MinerPledge runs the `miner pledge` command against the filecoin process
func (f *Filecoin) MinerPledge(ctx context.Context, minerAddr address.Address) (*big.Int, error) {
	var out big.Int

	sMinerAddr := minerAddr.String()

	if err := f.RunCmdJSONWithStdin(ctx, nil, &out, "go-filecoin", "miner", "pledge", sMinerAddr); err != nil {
		return big.NewInt(0), err
	}

	return &out, nil
}

// MinerPower runs the `miner power` command against the filecoin process
func (f *Filecoin) MinerPower(ctx context.Context, minerAddr address.Address) (*big.Int, error) {
	var out big.Int

	sMinerAddr := minerAddr.String()

	if err := f.RunCmdJSONWithStdin(ctx, nil, &out, "go-filecoin", "miner", "power", sMinerAddr); err != nil {
		return big.NewInt(0), err
	}

	return &out, nil
}

// MinerSetPrice runs the `miner set-price` command against the filecoin process
func (f *Filecoin) MinerSetPrice(ctx context.Context, fil *big.Float, expiry *big.Int, options ...ActionOption) (*porcelain.MinerSetPriceResponse, error) {
	var out porcelain.MinerSetPriceResponse

	sExpiry := expiry.String()
	sFil := fil.String()

	args := []string{"go-filecoin", "miner", "set-price"}

	for _, option := range options {
		args = append(args, option()...)
	}

	args = append(args, sFil, sExpiry)

	if err := f.RunCmdJSONWithStdin(ctx, nil, &out, args...); err != nil {
		return nil, err
	}

	return &out, nil
}


@@ -37,6 +37,11 @@ const (
 	StoragePoolClaimCPK CasPoolKey = "openebs.io/storage-pool-claim"
 	// CStorPoolClusterCPK is the CStorPoolcluster label
 	CStorPoolClusterCPK CasPoolKey = "openebs.io/cstor-pool-cluster"
+	// CStorPoolInstanceCPK is the CStorPoolInstance label
+	CStorPoolInstanceCPK CasPoolKey = "openebs.io/cstor-pool-instance"
+	// PredecessorBlockDeviceCPK is the annotation on the block device claim
+	// holding previous block device name
+	PredecessorBlockDeviceCPK CasPoolKey = "openebs.io/bd-predecessor"
 	// NdmDiskTypeCPK is the node-disk-manager disk type e.g. 'sparse' or 'disk'
 	NdmDiskTypeCPK CasPoolKey = "ndm.io/disk-type"
 	// NdmBlockDeviceTypeCPK is the node-disk-manager blockdevice type e.g. // 'blockdevice'

/*
Copyright 2017 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 v1alpha1

import (
	ndm "github.com/openebs/maya/pkg/apis/openebs.io/ndm/v1alpha1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// CasPoolKey is the key for the CasPool.
type CasPoolKey string

// CasPoolValString represents the string value for a CasPoolKey.
type CasPoolValString string

// CasPoolValInt represents the integer value for a CasPoolKey
type CasPoolValInt int

const (
	// HostNameCPK is the kubernetes host name label
	HostNameCPK CasPoolKey = "kubernetes.io/hostname"
	// StoragePoolClaimCPK is the storage pool claim label
	StoragePoolClaimCPK CasPoolKey = "openebs.io/storage-pool-claim"
	// CStorPoolClusterCPK is the CStorPoolcluster label
	CStorPoolClusterCPK CasPoolKey = "openebs.io/cstor-pool-cluster"
	// NdmDiskTypeCPK is the node-disk-manager disk type e.g. 'sparse' or 'disk'
	NdmDiskTypeCPK CasPoolKey = "ndm.io/disk-type"
	// NdmBlockDeviceTypeCPK is the node-disk-manager blockdevice type e.g. // 'blockdevice'
	NdmBlockDeviceTypeCPK CasPoolKey = "ndm.io/blockdevice-type"
	// PoolTypeMirroredCPV is a key for mirrored for pool
	PoolTypeMirroredCPV CasPoolValString = "mirrored"
	// PoolTypeStripedCPV is a key for striped for pool
	PoolTypeStripedCPV CasPoolValString = "striped"
	// PoolTypeRaidzCPV is a key for raidz for pool
	PoolTypeRaidzCPV CasPoolValString = "raidz"
	// PoolTypeRaidz2CPV is a key for raidz for pool
	PoolTypeRaidz2CPV CasPoolValString = "raidz2"
	// TypeSparseCPV is a key for sparse disk pool
	TypeSparseCPV CasPoolValString = "sparse"
	// TypeDiskCPV is a key for physical,iscsi,virtual etc disk pool
	TypeDiskCPV CasPoolValString = "disk"
	// TypeBlockDeviceCPV is a key for physical,iscsi,virtual etc disk pool
	TypeBlockDeviceCPV CasPoolValString = "blockdevice"
	// StripedBlockDeviceCountCPV is the count for striped type pool
	StripedBlockDeviceCountCPV CasPoolValInt = 1
	// MirroredBlockDeviceCountCPV is the count for mirrored type pool
	MirroredBlockDeviceCountCPV CasPoolValInt = 2
	// RaidzBlockDeviceCountCPV is the count for raidz type pool
	RaidzBlockDeviceCountCPV CasPoolValInt = 3
	// Raidz2BlockDeviceCountCPV is the count for raidz2 type pool
	Raidz2BlockDeviceCountCPV CasPoolValInt = 6
)

// CasPool is a type which will be utilised by CAS engine to perform
// storagepool related operation.
// TODO: Restrucutre CasPool struct.
type CasPool struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`
	// StoragePoolClaim is the name of the storagepoolclaim object
	StoragePoolClaim string

	// CasCreateTemplate is the cas template that will be used for storagepool create
	// operation
	CasCreateTemplate string

	// CasDeleteTemplate is the cas template that will be used for storagepool delete
	// operation
	CasDeleteTemplate string

	// Namespace can be passed via storagepoolclaim as labels to decide on the
	// execution of namespaced resources with respect to storagepool
	Namespace string

	// BlockDeviceList is the list of block devices over which a storagepool will be provisioned
	BlockDeviceList []BlockDeviceGroup

	// PoolType is the type of pool to be provisioned e.g. striped or mirrored
	PoolType string

	// PoolCacheFile is cache file which used at the time of importing a pool
	PoolCacheFile string

	// MaxPool is the maximum number of pool that should be provisioned
	MaxPools int

	// MinPool is the minimum number of pool that should be provisioned
	MinPools int

	// Type is the CasPool type e.g. sparse or openebs-cstor
	Type string

	// NodeName is the node where cstor pool will be created
	NodeName string

	// reSync will decide whether the event is a reconciliation event
	ReSync bool

	// PendingPoolCount is the number of pools that will be tried for creation as a part of reconciliation.
	PendingPoolCount int

	DeviceID           []string
	APIBlockDeviceList ndm.BlockDeviceList
}

don't we need to set this label on pool pods? I don't see them being set


@@ -6,11 +6,16 @@ import (
 	"encoding/json"

 	"github.com/influxdata/flux/ast"
+	"github.com/influxdata/flux/internal/parser"
 	"github.com/influxdata/flux/internal/token"
 	"github.com/influxdata/flux/libflux/go/libflux"
 )

 func parseFile(f *token.File, src []byte) (*ast.File, error) {
+	if !useRustParser() {
+		return parser.ParseFile(f, src), nil
+	}
+
 	astFile := libflux.Parse(string(src))
 	defer astFile.Free()

// +build libflux

package parser

import (
	"encoding/json"

	"github.com/influxdata/flux/ast"
	"github.com/influxdata/flux/internal/token"
	"github.com/influxdata/flux/libflux/go/libflux"
)

func parseFile(f *token.File, src []byte) (*ast.File, error) {
	astFile := libflux.Parse(string(src))
	defer astFile.Free()

	data, err := astFile.MarshalJSON()
	if err != nil {
		return nil, err
	}

	var file ast.File
	if err := json.Unmarshal(data, &file); err != nil {
		return nil, err
	}
	file.Name = f.Name()

	// The go parser will not fill in the imports if there are
	// none so we remove them here to retain compatibility.
	if len(file.Imports) == 0 {
		file.Imports = nil
	}
	return &file, nil
}

Another question is, do we want to call `os.Getenv()` every time we parse a file? That seems a lot.