<commit_before>/*
Copyright 2020 The Knative 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 v1

import (
	"context"
	"encoding/json"
	"fmt"

	"go.uber.org/zap"

	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/runtime/schema"

	"knative.dev/pkg/apis"
	"knative.dev/pkg/apis/duck"
	duckv1 "knative.dev/pkg/apis/duck/v1"
	"knative.dev/pkg/logging"
	"knative.dev/pkg/tracker"
)

var sbCondSet = apis.NewLivingConditionSet(
	SinkBindingConditionSinkProvided,
)

// GetConditionSet retrieves the condition set for this resource. Implements the KRShaped interface.
func (*SinkBinding) GetConditionSet() apis.ConditionSet {
	return sbCondSet
}

// GetGroupVersionKind returns the GroupVersionKind.
func (*SinkBinding) GetGroupVersionKind() schema.GroupVersionKind {
	return SchemeGroupVersion.WithKind("SinkBinding")
}

// GetUntypedSpec implements apis.HasSpec
func (s *SinkBinding) GetUntypedSpec() interface{} {
	return s.Spec
}

// GetSubject implements psbinding.Bindable
func (sb *SinkBinding) GetSubject() tracker.Reference {
	return sb.Spec.Subject
}

// GetBindingStatus implements psbinding.Bindable
func (sb *SinkBinding) GetBindingStatus() duck.BindableStatus {
	return &sb.Status
}

// SetObservedGeneration implements psbinding.BindableStatus
func (sbs *SinkBindingStatus) SetObservedGeneration(gen int64) {
	sbs.ObservedGeneration = gen
}

// InitializeConditions populates the SinkBindingStatus's conditions field
// with all of its conditions configured to Unknown.
func (sbs *SinkBindingStatus) InitializeConditions() {
	sbCondSet.Manage(sbs).InitializeConditions()
}

// MarkBindingUnavailable marks the SinkBinding's Ready condition to False with
// the provided reason and message.
func (sbs *SinkBindingStatus) MarkBindingUnavailable(reason, message string) {
	sbCondSet.Manage(sbs).MarkFalse(SinkBindingConditionReady, reason, message)
}

// MarkBindingAvailable marks the SinkBinding's Ready condition to True.
func (sbs *SinkBindingStatus) MarkBindingAvailable() {
	sbCondSet.Manage(sbs).MarkTrue(SinkBindingConditionReady)
}

// MarkSink sets the condition that the source has a sink configured.
func (sbs *SinkBindingStatus) MarkSink(uri *apis.URL) {
	sbs.SinkURI = uri
	if uri != nil {
		sbCondSet.Manage(sbs).MarkTrue(SinkBindingConditionSinkProvided)
	} else {
		sbCondSet.Manage(sbs).MarkFalse(SinkBindingConditionSinkProvided, "SinkEmpty", "Sink has resolved to empty.%s", "")
	}
}

// Do implements psbinding.Bindable
func (sb *SinkBinding) Do(ctx context.Context, ps *duckv1.WithPod) {
	// First undo so that we can just unconditionally append below.
	sb.Undo(ctx, ps)

	resolver := GetURIResolver(ctx)
	if resolver == nil {
		logging.FromContext(ctx).Errorf("No Resolver associated with context for sink: %+v", sb)
	}
	uri, err := resolver.URIFromDestinationV1(ctx, sb.Spec.Sink, sb)
	if err != nil {
		logging.FromContext(ctx).Errorw("URI could not be extracted from destination: ", zap.Error(err))
		return
	}
	sb.Status.MarkSink(uri)

	var ceOverrides string
	if sb.Spec.CloudEventOverrides != nil {
		if co, err := json.Marshal(sb.Spec.SourceSpec.CloudEventOverrides); err != nil {
			logging.FromContext(ctx).Errorw(fmt.Sprintf("Failed to marshal CloudEventOverrides into JSON for %+v", sb), zap.Error(err))
		} else if len(co) > 0 {
			ceOverrides = string(co)
		}
	}

	spec := ps.Spec.Template.Spec
	for i := range spec.InitContainers {
		spec.InitContainers[i].Env = append(spec.InitContainers[i].Env, corev1.EnvVar{
			Name:  "K_SINK",
			Value: uri.String(),
		})
		spec.InitContainers[i].Env = append(spec.InitContainers[i].Env, corev1.EnvVar{
			Name:  "K_CE_OVERRIDES",
			Value: ceOverrides,
		})
	}
	for i := range spec.Containers {
		spec.Containers[i].Env = append(spec.Containers[i].Env, corev1.EnvVar{
			Name:  "K_SINK",
			Value: uri.String(),
		})
		spec.Containers[i].Env = append(spec.Containers[i].Env, corev1.EnvVar{
			Name:  "K_CE_OVERRIDES",
			Value: ceOverrides,
		})
	}
}

func (sb *SinkBinding) Undo(ctx context.Context, ps *duckv1.WithPod) {
	spec := ps.Spec.Template.Spec
	for i, c := range spec.InitContainers {
		if len(c.Env) == 0 {
			continue
		}
		env := make([]corev1.EnvVar, 0, len(spec.InitContainers[i].Env))
		for j, ev := range c.Env {
			switch ev.Name {
			case "K_SINK", "K_CE_OVERRIDES":
				continue
			default:
				env = append(env, spec.InitContainers[i].Env[j])
			}
		}
		spec.InitContainers[i].Env = env
	}
	for i, c := range spec.Containers {
		if len(c.Env) == 0 {
			continue
		}
		env := make([]corev1.EnvVar, 0, len(spec.Containers[i].Env))
		for j, ev := range c.Env {
			switch ev.Name {
			case "K_SINK", "K_CE_OVERRIDES":
				continue
			default:
				env = append(env, spec.Containers[i].Env[j])
			}
		}
		spec.Containers[i].Env = env
	}
}
<commit_msg>return when URIResolver is not set to avoid nil pointer reference. (#4374)<commit_after>/*
Copyright 2020 The Knative 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 v1

import (
	"context"
	"encoding/json"
	"fmt"

	"go.uber.org/zap"

	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/runtime/schema"

	"knative.dev/pkg/apis"
	"knative.dev/pkg/apis/duck"
	duckv1 "knative.dev/pkg/apis/duck/v1"
	"knative.dev/pkg/logging"
	"knative.dev/pkg/tracker"
)

var sbCondSet = apis.NewLivingConditionSet(
	SinkBindingConditionSinkProvided,
)

// GetConditionSet retrieves the condition set for this resource. Implements the KRShaped interface.
func (*SinkBinding) GetConditionSet() apis.ConditionSet {
	return sbCondSet
}

// GetGroupVersionKind returns the GroupVersionKind.
func (*SinkBinding) GetGroupVersionKind() schema.GroupVersionKind {
	return SchemeGroupVersion.WithKind("SinkBinding")
}

// GetUntypedSpec implements apis.HasSpec
func (s *SinkBinding) GetUntypedSpec() interface{} {
	return s.Spec
}

// GetSubject implements psbinding.Bindable
func (sb *SinkBinding) GetSubject() tracker.Reference {
	return sb.Spec.Subject
}

// GetBindingStatus implements psbinding.Bindable
func (sb *SinkBinding) GetBindingStatus() duck.BindableStatus {
	return &sb.Status
}

// SetObservedGeneration implements psbinding.BindableStatus
func (sbs *SinkBindingStatus) SetObservedGeneration(gen int64) {
	sbs.ObservedGeneration = gen
}

// InitializeConditions populates the SinkBindingStatus's conditions field
// with all of its conditions configured to Unknown.
func (sbs *SinkBindingStatus) InitializeConditions() {
	sbCondSet.Manage(sbs).InitializeConditions()
}

// MarkBindingUnavailable marks the SinkBinding's Ready condition to False with
// the provided reason and message.
func (sbs *SinkBindingStatus) MarkBindingUnavailable(reason, message string) {
	sbCondSet.Manage(sbs).MarkFalse(SinkBindingConditionReady, reason, message)
}

// MarkBindingAvailable marks the SinkBinding's Ready condition to True.
func (sbs *SinkBindingStatus) MarkBindingAvailable() {
	sbCondSet.Manage(sbs).MarkTrue(SinkBindingConditionReady)
}

// MarkSink sets the condition that the source has a sink configured.
func (sbs *SinkBindingStatus) MarkSink(uri *apis.URL) {
	sbs.SinkURI = uri
	if uri != nil {
		sbCondSet.Manage(sbs).MarkTrue(SinkBindingConditionSinkProvided)
	} else {
		sbCondSet.Manage(sbs).MarkFalse(SinkBindingConditionSinkProvided, "SinkEmpty", "Sink has resolved to empty.%s", "")
	}
}

// Do implements psbinding.Bindable
func (sb *SinkBinding) Do(ctx context.Context, ps *duckv1.WithPod) {
	// First undo so that we can just unconditionally append below.
	sb.Undo(ctx, ps)

	resolver := GetURIResolver(ctx)
	if resolver == nil {
		logging.FromContext(ctx).Errorf("No Resolver associated with context for sink: %+v", sb)
		return
	}
	uri, err := resolver.URIFromDestinationV1(ctx, sb.Spec.Sink, sb)
	if err != nil {
		logging.FromContext(ctx).Errorw("URI could not be extracted from destination: ", zap.Error(err))
		return
	}
	sb.Status.MarkSink(uri)

	var ceOverrides string
	if sb.Spec.CloudEventOverrides != nil {
		if co, err := json.Marshal(sb.Spec.SourceSpec.CloudEventOverrides); err != nil {
			logging.FromContext(ctx).Errorw(fmt.Sprintf("Failed to marshal CloudEventOverrides into JSON for %+v", sb), zap.Error(err))
		} else if len(co) > 0 {
			ceOverrides = string(co)
		}
	}

	spec := ps.Spec.Template.Spec
	for i := range spec.InitContainers {
		spec.InitContainers[i].Env = append(spec.InitContainers[i].Env, corev1.EnvVar{
			Name:  "K_SINK",
			Value: uri.String(),
		})
		spec.InitContainers[i].Env = append(spec.InitContainers[i].Env, corev1.EnvVar{
			Name:  "K_CE_OVERRIDES",
			Value: ceOverrides,
		})
	}
	for i := range spec.Containers {
		spec.Containers[i].Env = append(spec.Containers[i].Env, corev1.EnvVar{
			Name:  "K_SINK",
			Value: uri.String(),
		})
		spec.Containers[i].Env = append(spec.Containers[i].Env, corev1.EnvVar{
			Name:  "K_CE_OVERRIDES",
			Value: ceOverrides,
		})
	}
}

func (sb *SinkBinding) Undo(ctx context.Context, ps *duckv1.WithPod) {
	spec := ps.Spec.Template.Spec
	for i, c := range spec.InitContainers {
		if len(c.Env) == 0 {
			continue
		}
		env := make([]corev1.EnvVar, 0, len(spec.InitContainers[i].Env))
		for j, ev := range c.Env {
			switch ev.Name {
			case "K_SINK", "K_CE_OVERRIDES":
				continue
			default:
				env = append(env, spec.InitContainers[i].Env[j])
			}
		}
		spec.InitContainers[i].Env = env
	}
	for i, c := range spec.Containers {
		if len(c.Env) == 0 {
			continue
		}
		env := make([]corev1.EnvVar, 0, len(spec.Containers[i].Env))
		for j, ev := range c.Env {
			switch ev.Name {
			case "K_SINK", "K_CE_OVERRIDES":
				continue
			default:
				env = append(env, spec.Containers[i].Env[j])
			}
		}
		spec.Containers[i].Env = env
	}
}
<|endoftext|>


<commit_before>package oauth

import (
	"github.com/skygeario/skygear-server/pkg/auth/dependency/principal"
	"github.com/skygeario/skygear-server/pkg/core/config"
)

type GetByProviderOptions struct {
	ProviderType   string
	ProviderKeys   map[string]interface{}
	ProviderUserID string
}

type GetByUserOptions struct {
	ProviderType string
	ProviderKeys map[string]interface{}
	UserID       string
}

type Provider interface {
	principal.Provider
	GetPrincipalByProvider(options GetByProviderOptions) (*Principal, error)

	GetPrincipalByUser(options GetByUserOptions) (*Principal, error)
	CreatePrincipal(principal *Principal) error
	UpdatePrincipal(principal *Principal) error
	DeletePrincipal(principal *Principal) error
}

func ProviderKeysFromProviderConfig(c config.OAuthProviderConfiguration) map[string]interface{} {
	m := map[string]interface{}{}
	if c.Tenant != "" {
		m["tenant"] = c.Tenant
	}
	return m
}
<commit_msg>Add TeamID to OAuth provider keys<commit_after>package oauth

import (
	"github.com/skygeario/skygear-server/pkg/auth/dependency/principal"
	"github.com/skygeario/skygear-server/pkg/core/config"
)

type GetByProviderOptions struct {
	ProviderType   string
	ProviderKeys   map[string]interface{}
	ProviderUserID string
}

type GetByUserOptions struct {
	ProviderType string
	ProviderKeys map[string]interface{}
	UserID       string
}

type Provider interface {
	principal.Provider
	GetPrincipalByProvider(options GetByProviderOptions) (*Principal, error)

	GetPrincipalByUser(options GetByUserOptions) (*Principal, error)
	CreatePrincipal(principal *Principal) error
	UpdatePrincipal(principal *Principal) error
	DeletePrincipal(principal *Principal) error
}

func ProviderKeysFromProviderConfig(c config.OAuthProviderConfiguration) map[string]interface{} {
	m := map[string]interface{}{}
	if c.Tenant != "" {
		m["tenant"] = c.Tenant
	}
	if c.TeamID != "" {
		m["team_id"] = c.TeamID
	}
	return m
}
<|endoftext|>


<commit_before>package migrator

type MigrationCondition interface {
	Sql(dialect Dialect) (string, []interface{})
	IsFulfilled(results []map[string][]byte) bool
}

type ExistsMigrationCondition struct{}

func (c *ExistsMigrationCondition) IsFulfilled(results []map[string][]byte) bool {
	return len(results) == 1
}

type NotExistsMigrationCondition struct{}

func (c *NotExistsMigrationCondition) IsFulfilled(results []map[string][]byte) bool {
	return len(results) == 0
}

type IfIndexExistsCondition struct {
	ExistsMigrationCondition
	TableName string
	IndexName string
}

func (c *IfIndexExistsCondition) Sql(dialect Dialect) (string, []interface{}) {
	return dialect.IndexCheckSql(c.TableName, c.IndexName)
}

type IfIndexNotExistsCondition struct {
	NotExistsMigrationCondition
	TableName string
	IndexName string
}

func (c *IfIndexNotExistsCondition) Sql(dialect Dialect) (string, []interface{}) {
	return dialect.IndexCheckSql(c.TableName, c.IndexName)
}
<commit_msg>fix handling of indices with multiple columns (mysql)<commit_after>package migrator

type MigrationCondition interface {
	Sql(dialect Dialect) (string, []interface{})
	IsFulfilled(results []map[string][]byte) bool
}

type ExistsMigrationCondition struct{}

func (c *ExistsMigrationCondition) IsFulfilled(results []map[string][]byte) bool {
	return len(results) >= 1
}

type NotExistsMigrationCondition struct{}

func (c *NotExistsMigrationCondition) IsFulfilled(results []map[string][]byte) bool {
	return len(results) == 0
}

type IfIndexExistsCondition struct {
	ExistsMigrationCondition
	TableName string
	IndexName string
}

func (c *IfIndexExistsCondition) Sql(dialect Dialect) (string, []interface{}) {
	return dialect.IndexCheckSql(c.TableName, c.IndexName)
}

type IfIndexNotExistsCondition struct {
	NotExistsMigrationCondition
	TableName string
	IndexName string
}

func (c *IfIndexNotExistsCondition) Sql(dialect Dialect) (string, []interface{}) {
	return dialect.IndexCheckSql(c.TableName, c.IndexName)
}
<|endoftext|>


<commit_before>package apply

import (
	"github.com/Aptomi/aptomi/pkg/slinga/engine/diff"
	"github.com/Aptomi/aptomi/pkg/slinga/engine/plugin"
	"github.com/Aptomi/aptomi/pkg/slinga/language"
	"github.com/Aptomi/aptomi/pkg/slinga/object"
	"github.com/stretchr/testify/assert"
	"testing"
	"time"
)

const (
	ResSuccess = iota
	ResError   = iota
)

func TestApplyCreateSuccess(t *testing.T) {
	externalData := getExternalData()

	// resolve empty policy
	actualPolicy := language.NewPolicyNamespace()
	actualState := resolvePolicy(t, actualPolicy, externalData)

	// resolve full policy
	desiredPolicy := getPolicy()
	desiredState := resolvePolicy(t, desiredPolicy, externalData)

	// make plugin to successfully process all components
	pluginApply := NewEnginePluginImpl([]string{})

	// process all actions
	actions := diff.NewPolicyResolutionDiff(desiredState, actualState).Actions
	plugins := []plugin.EnginePlugin{pluginApply}
	apply := NewEngineApply(
		desiredPolicy,
		desiredState,
		actualPolicy,
		actualState,
		externalData,
		actions,
		plugins,
	)

	// check actual state
	assert.Equal(t, 0, len(actualState.ComponentInstanceMap), "Actual state should be empty")

	// check that policy apply finished with expected results
	actualState = applyAndCheck(t, apply, ResSuccess, 0, "")

	// check that actual state got updated
	assert.Equal(t, 16, len(actualState.ComponentInstanceMap), "Actual state should be empty")
}

func TestApplyCreateFailure(t *testing.T) {
	externalData := getExternalData()

	// resolve empty policy
	actualPolicy := language.NewPolicyNamespace()
	actualState := resolvePolicy(t, actualPolicy, externalData)

	// resolve full policy
	desiredPolicy := getPolicy()
	desiredState := resolvePolicy(t, desiredPolicy, externalData)

	// make plugin to successfully process all components, while failing all instances of component2
	pluginApplyFailComponent2 := NewEnginePluginImpl([]string{"component2"})

	// process all actions
	actions := diff.NewPolicyResolutionDiff(desiredState, actualState).Actions
	plugins := []plugin.EnginePlugin{pluginApplyFailComponent2}
	apply := NewEngineApply(
		desiredPolicy,
		desiredState,
		actualPolicy,
		actualState,
		externalData,
		actions,
		plugins,
	)

	// check actual state
	assert.Equal(t, 0, len(actualState.ComponentInstanceMap), "Actual state should be empty")

	// check that policy apply finished with expected results
	actualState = applyAndCheck(t, apply, ResError, 4, "Apply failed for component")

	// check that actual state got updated
	assert.Equal(t, 12, len(actualState.ComponentInstanceMap), "Actual state should be empty")
}

func TestDiffHasUpdatedComponentsAndCheckTimes(t *testing.T) {
	var key string
	externalData := getExternalData()

	/*
		Step 1: actual = empty, desired = unit test policy, check = kafka update/create times
	*/

	// Create initial empty resolution data (do not resolve any dependencies)
	actualPolicy := language.NewPolicyNamespace()
	actualState := resolvePolicy(t, actualPolicy, externalData)

	// Resolve all dependencies in policy
	desiredPolicy := getPolicy()
	desiredState := resolvePolicy(t, desiredPolicy, externalData)

	// Apply to update component times in actual state
	apply := NewEngineApply(
		desiredPolicy,
		desiredState,
		actualPolicy,
		actualState,
		externalData,
		diff.NewPolicyResolutionDiff(desiredState, actualState).Actions,
		[]plugin.EnginePlugin{},
	)

	// Check that policy apply finished with expected results
	updatedActualState := applyAndCheck(t, apply, ResSuccess, 0, "")

	// Check creation/update times
	key = getInstanceKey("kafka", "test", []string{"platform_services"}, "component2", desiredPolicy)
	kafkaTimes1 := getTimes(t, key, updatedActualState)
	assert.WithinDuration(t, time.Now(), kafkaTimes1.created, time.Second, "Creation time should be initialized correctly for kafka")
	assert.Equal(t, kafkaTimes1.updated, kafkaTimes1.updated, "Update time should be equal to creation time")

	actualState = updatedActualState
	actualPolicy = desiredPolicy

	/*
		Step 2: desired = add a dependency, check = component update/create times remained the same in actual state
	*/

	// Sleep a little bit to introduce time delay
	time.Sleep(25 * time.Millisecond)

	// Add another dependency, resolve, calculate difference against prev resolution data, emulate save/load
	desiredPolicyNext := getPolicy()
	dependencyNew := &language.Dependency{
		Metadata: object.Metadata{
			Namespace: "main",
			Name:      "dep_id_5",
		},
		UserID:  "5",
		Service: "kafka",
	}
	desiredPolicyNext.Dependencies.AddDependency(dependencyNew)
	desiredStateNext := resolvePolicy(t, desiredPolicyNext, externalData)
	assert.NotEmpty(t, desiredStateNext.DependencyInstanceMap["dep_id_5"], "New dependency should be resolved")

	// Apply to update component times in actual state
	apply = NewEngineApply(
		desiredPolicyNext,
		desiredStateNext,
		actualPolicy,
		actualState,
		externalData,
		diff.NewPolicyResolutionDiff(desiredStateNext, actualState).Actions,
		[]plugin.EnginePlugin{},
	)

	// Check that policy apply finished with expected results
	updatedActualState = applyAndCheck(t, apply, ResSuccess, 0, "")

	// Check creation/update times
	kafkaTimes2 := getTimes(t, key, updatedActualState)
	assert.Equal(t, kafkaTimes1.created, kafkaTimes2.created, "Creation time should be carried over to remain the same")
	assert.Equal(t, kafkaTimes1.updated, kafkaTimes2.updated, "Update time should be carried over to remain the same")

	actualState = updatedActualState
	actualPolicy = desiredPolicy

	/*
		Step 3: desired = update user label, check = component update time changed
	*/

	keyComponent := getInstanceKey("kafka", "prod-high", []string{"Elena"}, "component2", desiredPolicyNext)
	componentTimes := getTimes(t, keyComponent, actualState)
	keyService := getInstanceKey("kafka", "prod-high", []string{"Elena"}, "root", desiredPolicyNext)
	serviceTimes := getTimes(t, keyService, actualState)

	// Sleep a little bit to introduce time delay
	time.Sleep(25 * time.Millisecond)

	// Update user label, re-evaluate and see that component instance has changed
	externalData.UserLoader.LoadUserByID("5").Labels["changinglabel"] = "newvalue"
	desiredStateAfterUpdate := resolvePolicy(t, desiredPolicyNext, externalData)

	// Apply to update component times in actual state
	apply = NewEngineApply(
		desiredPolicyNext,
		desiredStateAfterUpdate,
		actualPolicy,
		actualState,
		externalData,
		diff.NewPolicyResolutionDiff(desiredStateAfterUpdate, actualState).Actions,
		[]plugin.EnginePlugin{},
	)

	// Check that policy apply finished with expected results
	updatedActualState = applyAndCheck(t, apply, ResSuccess, 0, "")

	// Check creation/update times for component
	componentTimesUpdated := getTimes(t, keyComponent, updatedActualState)
	assert.Equal(t, componentTimes.created, componentTimesUpdated.created, "Creation time for component should be carried over to remain the same")
	assert.True(t, componentTimesUpdated.updated.After(componentTimes.updated), "Update time for component should be changed")

	// Check creation/update times for service
	serviceTimesUpdated := getTimes(t, keyService, updatedActualState)
	assert.Equal(t, serviceTimes.created, serviceTimesUpdated.created, "Creation time for parent service should be carried over to remain the same")
	assert.True(t, serviceTimesUpdated.updated.After(serviceTimes.updated), "Update time for parent service should be changed")
}
<commit_msg>Fix engine apply test<commit_after>package apply

import (
	"github.com/Aptomi/aptomi/pkg/slinga/engine/diff"
	"github.com/Aptomi/aptomi/pkg/slinga/language"
	"github.com/Aptomi/aptomi/pkg/slinga/object"
	"github.com/stretchr/testify/assert"
	"testing"
	"time"
)

const (
	ResSuccess = iota
	ResError   = iota
)

func TestApplyCreateSuccess(t *testing.T) {
	externalData := getExternalData()

	// resolve empty policy
	actualPolicy := language.NewPolicyNamespace()
	actualState := resolvePolicy(t, actualPolicy, externalData)

	// resolve full policy
	desiredPolicy := getPolicy()
	desiredState := resolvePolicy(t, desiredPolicy, externalData)

	// process all actions
	actions := diff.NewPolicyResolutionDiff(desiredState, actualState).Actions

	apply := NewEngineApply(
		desiredPolicy,
		desiredState,
		actualPolicy,
		actualState,
		externalData,
		NewTestPluginRegistry(),
		actions,
	)

	// check actual state
	assert.Equal(t, 0, len(actualState.ComponentInstanceMap), "Actual state should be empty")

	// check that policy apply finished with expected results
	actualState = applyAndCheck(t, apply, ResSuccess, 0, "")

	// check that actual state got updated
	assert.Equal(t, 16, len(actualState.ComponentInstanceMap), "Actual state should be empty")
}

func TestApplyCreateFailure(t *testing.T) {
	externalData := getExternalData()

	// resolve empty policy
	actualPolicy := language.NewPolicyNamespace()
	actualState := resolvePolicy(t, actualPolicy, externalData)

	// resolve full policy
	desiredPolicy := getPolicy()
	desiredState := resolvePolicy(t, desiredPolicy, externalData)

	// process all actions
	actions := diff.NewPolicyResolutionDiff(desiredState, actualState).Actions
	apply := NewEngineApply(
		desiredPolicy,
		desiredState,
		actualPolicy,
		actualState,
		externalData,
		NewTestPluginRegistry("component2"),
		actions,
	)

	// check actual state
	assert.Equal(t, 0, len(actualState.ComponentInstanceMap), "Actual state should be empty")

	// check that policy apply finished with expected results
	actualState = applyAndCheck(t, apply, ResError, 4, "Apply failed for component")

	// check that actual state got updated
	assert.Equal(t, 12, len(actualState.ComponentInstanceMap), "Actual state should be empty")
}

func TestDiffHasUpdatedComponentsAndCheckTimes(t *testing.T) {
	var key string
	externalData := getExternalData()

	/*
		Step 1: actual = empty, desired = unit test policy, check = kafka update/create times
	*/

	// Create initial empty resolution data (do not resolve any dependencies)
	actualPolicy := language.NewPolicyNamespace()
	actualState := resolvePolicy(t, actualPolicy, externalData)

	// Resolve all dependencies in policy
	desiredPolicy := getPolicy()
	desiredState := resolvePolicy(t, desiredPolicy, externalData)

	// Apply to update component times in actual state
	apply := NewEngineApply(
		desiredPolicy,
		desiredState,
		actualPolicy,
		actualState,
		externalData,
		NewTestPluginRegistry(),
		diff.NewPolicyResolutionDiff(desiredState, actualState).Actions,
	)

	// Check that policy apply finished with expected results
	updatedActualState := applyAndCheck(t, apply, ResSuccess, 0, "")

	// Check creation/update times
	key = getInstanceKey("kafka", "test", []string{"platform_services"}, "component2", desiredPolicy)
	kafkaTimes1 := getTimes(t, key, updatedActualState)
	assert.WithinDuration(t, time.Now(), kafkaTimes1.created, time.Second, "Creation time should be initialized correctly for kafka")
	assert.Equal(t, kafkaTimes1.updated, kafkaTimes1.updated, "Update time should be equal to creation time")

	actualState = updatedActualState
	actualPolicy = desiredPolicy

	/*
		Step 2: desired = add a dependency, check = component update/create times remained the same in actual state
	*/

	// Sleep a little bit to introduce time delay
	time.Sleep(25 * time.Millisecond)

	// Add another dependency, resolve, calculate difference against prev resolution data, emulate save/load
	desiredPolicyNext := getPolicy()
	dependencyNew := &language.Dependency{
		Metadata: object.Metadata{
			Namespace: "main",
			Name:      "dep_id_5",
		},
		UserID:  "5",
		Service: "kafka",
	}
	desiredPolicyNext.Dependencies.AddDependency(dependencyNew)
	desiredStateNext := resolvePolicy(t, desiredPolicyNext, externalData)
	assert.NotEmpty(t, desiredStateNext.DependencyInstanceMap["dep_id_5"], "New dependency should be resolved")

	// Apply to update component times in actual state
	apply = NewEngineApply(
		desiredPolicyNext,
		desiredStateNext,
		actualPolicy,
		actualState,
		externalData,
		NewTestPluginRegistry(),
		diff.NewPolicyResolutionDiff(desiredStateNext, actualState).Actions,
	)

	// Check that policy apply finished with expected results
	updatedActualState = applyAndCheck(t, apply, ResSuccess, 0, "")

	// Check creation/update times
	kafkaTimes2 := getTimes(t, key, updatedActualState)
	assert.Equal(t, kafkaTimes1.created, kafkaTimes2.created, "Creation time should be carried over to remain the same")
	assert.Equal(t, kafkaTimes1.updated, kafkaTimes2.updated, "Update time should be carried over to remain the same")

	actualState = updatedActualState
	actualPolicy = desiredPolicy

	/*
		Step 3: desired = update user label, check = component update time changed
	*/

	keyComponent := getInstanceKey("kafka", "prod-high", []string{"Elena"}, "component2", desiredPolicyNext)
	componentTimes := getTimes(t, keyComponent, actualState)
	keyService := getInstanceKey("kafka", "prod-high", []string{"Elena"}, "root", desiredPolicyNext)
	serviceTimes := getTimes(t, keyService, actualState)

	// Sleep a little bit to introduce time delay
	time.Sleep(25 * time.Millisecond)

	// Update user label, re-evaluate and see that component instance has changed
	externalData.UserLoader.LoadUserByID("5").Labels["changinglabel"] = "newvalue"
	desiredStateAfterUpdate := resolvePolicy(t, desiredPolicyNext, externalData)

	// Apply to update component times in actual state
	apply = NewEngineApply(
		desiredPolicyNext,
		desiredStateAfterUpdate,
		actualPolicy,
		actualState,
		externalData,
		NewTestPluginRegistry(),
		diff.NewPolicyResolutionDiff(desiredStateAfterUpdate, actualState).Actions,
	)

	// Check that policy apply finished with expected results
	updatedActualState = applyAndCheck(t, apply, ResSuccess, 0, "")

	// Check creation/update times for component
	componentTimesUpdated := getTimes(t, keyComponent, updatedActualState)
	assert.Equal(t, componentTimes.created, componentTimesUpdated.created, "Creation time for component should be carried over to remain the same")
	assert.True(t, componentTimesUpdated.updated.After(componentTimes.updated), "Update time for component should be changed")

	// Check creation/update times for service
	serviceTimesUpdated := getTimes(t, keyService, updatedActualState)
	assert.Equal(t, serviceTimes.created, serviceTimesUpdated.created, "Creation time for parent service should be carried over to remain the same")
	assert.True(t, serviceTimesUpdated.updated.After(serviceTimes.updated), "Update time for parent service should be changed")
}
<|endoftext|>


<commit_before>package rest

import (
	"github.com/emicklei/go-restful"
	"github.com/materials-commons/mcstore/pkg/db"
	"github.com/materials-commons/mcstore/pkg/db/dai"
	"github.com/materials-commons/mcstore/pkg/ws/rest"
	"github.com/materials-commons/mcstore/server/mcstored/service/data"
	"github.com/materials-commons/mcstore/server/mcstored/service/rest/filters"
	"github.com/materials-commons/mcstore/server/mcstored/service/rest/upload"
	"github.com/materials-commons/mcstore/server/mcstored/service/uploads"
)

// NewServicesContainer creates a new restful.Container made up of all
// the rest resources handled by the server.
func NewServicesContainer() *restful.Container {
	apikeyFilter := filters.NewAPIKeyFilter(dai.NewRUsers(db.RSessionMust()))
	container := restful.NewContainer()
	container.Filter(apikeyFilter.Filter)
	uploadResource := uploadResource()
	container.Add(uploadResource.WebService())
	return container
}

// uploadResource creates a new upload resource.
func uploadResource() rest.Service {
	return upload.NewResource(uploads.NewUploadService(), uploads.NewIDService(), data.NewDirService())
}
<commit_msg>Add projects resource instantiation.<commit_after>package rest

import (
	"github.com/emicklei/go-restful"
	"github.com/materials-commons/mcstore/pkg/db"
	"github.com/materials-commons/mcstore/pkg/db/dai"
	"github.com/materials-commons/mcstore/pkg/ws/rest"
	"github.com/materials-commons/mcstore/server/mcstored/service/data"
	"github.com/materials-commons/mcstore/server/mcstored/service/rest/filters"
	"github.com/materials-commons/mcstore/server/mcstored/service/rest/projects"
	"github.com/materials-commons/mcstore/server/mcstored/service/rest/upload"
	"github.com/materials-commons/mcstore/server/mcstored/service/uploads"
)

// NewServicesContainer creates a new restful.Container made up of all
// the rest resources handled by the server.
func NewServicesContainer() *restful.Container {
	container := restful.NewContainer()

	apikeyFilter := filters.NewAPIKeyFilter(dai.NewRUsers(db.RSessionMust()))
	container.Filter(apikeyFilter.Filter)

	uploadResource := uploadResource()
	container.Add(uploadResource.WebService())

	projectsResource := projectsResource()
	container.Add(projectsResource.WebService())

	return container
}

// uploadResource creates a new upload resource.
func uploadResource() rest.Service {
	return upload.NewResource(uploads.NewUploadService(), uploads.NewIDService(), data.NewDirService())
}

// projectsResource creates a new projects resource.
func projectsResource() rest.Service {
	return projects.NewResource(data.NewDirService())
}
<|endoftext|>


<commit_before>package cli

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

	"github.com/codegangsta/cli"
	"github.com/inconshreveable/log15"
	"github.com/spacemonkeygo/errors"
	"github.com/spacemonkeygo/errors/try"

	"go.polydawn.net/repeatr/core/executor/util"
	"go.polydawn.net/repeatr/lib/guid"
	"go.polydawn.net/repeatr/rio"
	"go.polydawn.net/repeatr/rio/placer"
)

func UnpackCommandPattern(stderr io.Writer) cli.Command {
	return cli.Command{
		Name:  "unpack",
		Usage: "fetch a ware and unpack it to a local filesystem",
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "place",
				Usage: "Optional.  Where to place the filesystem.  Defaults to \"./unpack-[hash]\"",
			},
			cli.StringFlag{
				Name:  "kind",
				Usage: "What kind of data storage format to work with.",
			},
			cli.StringFlag{
				Name:  "hash",
				Usage: "The ID of the object to explore.",
			},
			cli.StringFlag{
				Name:  "where",
				Usage: "A URL giving coordinates to a warehouse where repeatr should find the object to explore.",
			},
		},
		Action: func(ctx *cli.Context) {
			if ctx.String("kind") == "" {
				panic(Error.New("%q is a required parameter", "kind"))
			}
			hash := ctx.String("hash")
			if hash == "" {
				panic(Error.New("%q is a required parameter", "hash"))
			}
			if ctx.String("where") == "" {
				panic(Error.New("%q is a required parameter", "where"))
			}
			placePath := ctx.String("place")
			if placePath == "" {
				placePath = fmt.Sprintf("./unpack-%s", hash)
			}

			log := log15.New()
			log.SetHandler(log15.StreamHandler(stderr, log15.TerminalFormat()))

			try.Do(func() {
				// Materialize the things.
				arena := util.DefaultTransmat().Materialize(
					rio.TransmatKind(ctx.String("kind")),
					rio.CommitID(hash),
					[]rio.SiloURI{rio.SiloURI(ctx.String("where"))},
					log,
				)
				defer arena.Teardown()
				// Pick a temp path we'll move things into first.
				//  The materialize arena can't be jumped into the final resting
				//  place atomically, so we get it close, then do an atomic op last.
				placePathDir := filepath.Dir(placePath)
				placePathName := filepath.Base(placePath)
				tmpPlacePath := filepath.Join(
					placePathDir,
					".tmp." + placePathName + "." + guid.New(),
				)
				// Copy the materialized data into (within-one-step-of) its permanent new home.
				//  This feels kind of redundant at first glance (e.g., "why couldn't
				//  we just materialize it in the right place the first time?"), but
				//  makes sense when you remember transmats might just be returning a
				//  pointer into a shared cache that already existed (or other non-relocatable
				//  excuse for a filesystem, e.g. fuse happened or something).
				placer.CopyingPlacer(arena.Path(), tmpPlacePath, true, false)
				// Atomic move into final place.
				if err := os.Rename(tmpPlacePath, placePath); err != nil {
					panic(err)
				}
			}).Catch(rio.ConfigError, func(err *errors.Error) {
				panic(Error.NewWith(err.Message(), SetExitCode(EXIT_BADARGS)))
			}).Catch(rio.WarehouseUnavailableError, func(err *errors.Error) {
				panic(Error.New("%s", err.Message()))
			}).Catch(rio.DataDNE, func(err *errors.Error) {
				panic(Error.New("%s", err.Message()))
			}).Done()
		},
	}
}
<commit_msg>Add option to `repeatr unpack` to accept existing files and noop.<commit_after>package cli

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

	"github.com/codegangsta/cli"
	"github.com/inconshreveable/log15"
	"github.com/spacemonkeygo/errors"
	"github.com/spacemonkeygo/errors/try"

	"go.polydawn.net/repeatr/core/executor/util"
	"go.polydawn.net/repeatr/lib/guid"
	"go.polydawn.net/repeatr/rio"
	"go.polydawn.net/repeatr/rio/placer"
)

func UnpackCommandPattern(stderr io.Writer) cli.Command {
	return cli.Command{
		Name:  "unpack",
		Usage: "fetch a ware and unpack it to a local filesystem",
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "place",
				Usage: "Optional.  Where to place the filesystem.  Defaults to \"./unpack-[hash]\"",
			},
			cli.StringFlag{
				Name:  "kind",
				Usage: "What kind of data storage format to work with.",
			},
			cli.StringFlag{
				Name:  "hash",
				Usage: "The ID of the object to explore.",
			},
			cli.StringFlag{
				Name:  "where",
				Usage: "A URL giving coordinates to a warehouse where repeatr should find the object to explore.",
			},
			cli.BoolFlag{
				Name: "skip-exists",
				Usage: "If a file already exists at at '--place=%s', assume it's correct and exit immediately.  If this flag is not provided, the default behavior is to do the whole unpack, rolling over the existing files." +
					"  BE WARY of using this: it's effectively caching with no cachebusting rule.  Caveat emptor.",
			},
		},
		Action: func(ctx *cli.Context) {
			if ctx.String("kind") == "" {
				panic(Error.New("%q is a required parameter", "kind"))
			}
			hash := ctx.String("hash")
			if hash == "" {
				panic(Error.New("%q is a required parameter", "hash"))
			}
			if ctx.String("where") == "" {
				panic(Error.New("%q is a required parameter", "where"))
			}
			placePath := ctx.String("place")
			if placePath == "" {
				placePath = fmt.Sprintf("./unpack-%s", hash)
			}

			log := log15.New()
			log.SetHandler(log15.StreamHandler(stderr, log15.TerminalFormat()))

			if ctx.Bool("skip-exists") {
				if _, err := os.Stat(placePath); err == nil {
					return
				}
			}

			try.Do(func() {
				// Materialize the things.
				arena := util.DefaultTransmat().Materialize(
					rio.TransmatKind(ctx.String("kind")),
					rio.CommitID(hash),
					[]rio.SiloURI{rio.SiloURI(ctx.String("where"))},
					log,
				)
				defer arena.Teardown()
				// Pick a temp path we'll move things into first.
				//  The materialize arena can't be jumped into the final resting
				//  place atomically, so we get it close, then do an atomic op last.
				placePathDir := filepath.Dir(placePath)
				placePathName := filepath.Base(placePath)
				tmpPlacePath := filepath.Join(
					placePathDir,
					".tmp."+placePathName+"."+guid.New(),
				)
				// Copy the materialized data into (within-one-step-of) its permanent new home.
				//  This feels kind of redundant at first glance (e.g., "why couldn't
				//  we just materialize it in the right place the first time?"), but
				//  makes sense when you remember transmats might just be returning a
				//  pointer into a shared cache that already existed (or other non-relocatable
				//  excuse for a filesystem, e.g. fuse happened or something).
				placer.CopyingPlacer(arena.Path(), tmpPlacePath, true, false)
				// Atomic move into final place.
				if err := os.Rename(tmpPlacePath, placePath); err != nil {
					panic(err)
				}
			}).Catch(rio.ConfigError, func(err *errors.Error) {
				panic(Error.NewWith(err.Message(), SetExitCode(EXIT_BADARGS)))
			}).Catch(rio.WarehouseUnavailableError, func(err *errors.Error) {
				panic(Error.New("%s", err.Message()))
			}).Catch(rio.DataDNE, func(err *errors.Error) {
				panic(Error.New("%s", err.Message()))
			}).Done()
		},
	}
}
<|endoftext|>


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

package binary

import (
	"fmt"

	"github.com/google/gapid/core/math/f16"
)

// Writer provides methods for encoding values.
type Writer interface {
	// Data writes the data bytes in their entirety.
	Data([]byte)
	// Bool encodes a boolean value to the Writer.
	Bool(bool)
	// Int8 encodes a signed, 8 bit integer value to the Writer.
	Int8(int8)
	// Uint8 encodes an unsigned, 8 bit integer value to the Writer.
	Uint8(uint8)
	// Int16 encodes a signed, 16 bit integer value to the Writer.
	Int16(int16)
	// Uint16 encodes an unsigned, 16 bit integer value to the Writer.
	Uint16(uint16)
	// Int32 encodes a signed, 32 bit integer value to the Writer.
	Int32(int32)
	// Uint32 encodes an usigned, 32 bit integer value to the Writer.
	Uint32(uint32)
	// Float16 encodes a 16 bit floating-point value to the Writer.
	Float16(f16.Number)
	// Float32 encodes a 32 bit floating-point value to the Writer.
	Float32(float32)
	// Int64 encodes a signed, 64 bit integer value to the Writer.
	Int64(int64)
	// Uint64 encodes an unsigned, 64 bit integer value to the Encoders's io.Writer.
	Uint64(uint64)
	// Float64 encodes a 64 bit floating-point value to the Writer.
	Float64(float64)
	// String encodes a string to the Writer.
	String(string)
	// Simple encodes a Writable type to the Writer.
	Simple(Writable)
	// If there is an error writing any output, all further writing becomes
	// a no-op. Error() returns the error which stopped writing to the stream.
	// If writing has not stopped it returns nil.
	Error() error
	// Set the error state and stop writing to the stream.
	SetError(error)
}

// WriteUint writes the unsigned integer v of either 8, 16, 32 or 64 bits to w.
func WriteUint(w Writer, bits int32, v uint64) {
	switch bits {
	case 8:
		w.Uint8(uint8(v))
	case 16:
		w.Uint16(uint16(v))
	case 32:
		w.Uint32(uint32(v))
	case 64:
		w.Uint64(uint64(v))
	default:
		w.SetError(fmt.Errorf("Unsupported integer bit count %v", bits))
	}
}

// WriteInt writes the signed integer v of either 8, 16, 32 or 64 bits to w.
func WriteInt(w Writer, bits int32, v int64) {
	switch bits {
	case 8:
		w.Int8(int8(v))
	case 16:
		w.Int16(int16(v))
	case 32:
		w.Int32(int32(v))
	case 64:
		w.Int64(int64(v))
	default:
		w.SetError(fmt.Errorf("Unsupported integer bit count %v", bits))
	}
}

// WriteBytes writes the given v for count times to writer w.
func WriteBytes(w Writer, v uint8, count int32) {
	for i := int32(0); i < count; i++ {
		w.Uint8(v)
	}
}
<commit_msg>core/data/binary: Add Write() method for writing POD types.<commit_after>// Copyright (C) 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package binary

import (
	"fmt"
	"reflect"

	"github.com/google/gapid/core/math/f16"
)

// Writer provides methods for encoding values.
type Writer interface {
	// Data writes the data bytes in their entirety.
	Data([]byte)
	// Bool encodes a boolean value to the Writer.
	Bool(bool)
	// Int8 encodes a signed, 8 bit integer value to the Writer.
	Int8(int8)
	// Uint8 encodes an unsigned, 8 bit integer value to the Writer.
	Uint8(uint8)
	// Int16 encodes a signed, 16 bit integer value to the Writer.
	Int16(int16)
	// Uint16 encodes an unsigned, 16 bit integer value to the Writer.
	Uint16(uint16)
	// Int32 encodes a signed, 32 bit integer value to the Writer.
	Int32(int32)
	// Uint32 encodes an usigned, 32 bit integer value to the Writer.
	Uint32(uint32)
	// Float16 encodes a 16 bit floating-point value to the Writer.
	Float16(f16.Number)
	// Float32 encodes a 32 bit floating-point value to the Writer.
	Float32(float32)
	// Int64 encodes a signed, 64 bit integer value to the Writer.
	Int64(int64)
	// Uint64 encodes an unsigned, 64 bit integer value to the Encoders's io.Writer.
	Uint64(uint64)
	// Float64 encodes a 64 bit floating-point value to the Writer.
	Float64(float64)
	// String encodes a string to the Writer.
	String(string)
	// Simple encodes a Writable type to the Writer.
	Simple(Writable)
	// If there is an error writing any output, all further writing becomes
	// a no-op. Error() returns the error which stopped writing to the stream.
	// If writing has not stopped it returns nil.
	Error() error
	// Set the error state and stop writing to the stream.
	SetError(error)
}

// WriteUint writes the unsigned integer v of either 8, 16, 32 or 64 bits to w.
func WriteUint(w Writer, bits int32, v uint64) {
	switch bits {
	case 8:
		w.Uint8(uint8(v))
	case 16:
		w.Uint16(uint16(v))
	case 32:
		w.Uint32(uint32(v))
	case 64:
		w.Uint64(uint64(v))
	default:
		w.SetError(fmt.Errorf("Unsupported integer bit count %v", bits))
	}
}

// WriteInt writes the signed integer v of either 8, 16, 32 or 64 bits to w.
func WriteInt(w Writer, bits int32, v int64) {
	switch bits {
	case 8:
		w.Int8(int8(v))
	case 16:
		w.Int16(int16(v))
	case 32:
		w.Int32(int32(v))
	case 64:
		w.Int64(int64(v))
	default:
		w.SetError(fmt.Errorf("Unsupported integer bit count %v", bits))
	}
}

// WriteBytes writes the given v for count times to writer w.
func WriteBytes(w Writer, v uint8, count int32) {
	for i := int32(0); i < count; i++ {
		w.Uint8(v)
	}
}

// Write writes v to the writer w. v must be an byte, integer, float, boolean,
// string, slice or array.
func Write(w Writer, v interface{}) {
	r := reflect.ValueOf(v)
	switch r.Kind() {
	case reflect.Bool:
		w.Bool(r.Bool())
	case reflect.Int8:
		w.Int8(int8(r.Int()))
	case reflect.Int16:
		w.Int16(int16(r.Int()))
	case reflect.Int32:
		w.Int32(int32(r.Int()))
	case reflect.Int, reflect.Int64:
		w.Int64(int64(r.Int()))
	case reflect.Uint8:
		w.Uint8(uint8(r.Uint()))
	case reflect.Uint16:
		w.Uint16(uint16(r.Uint()))
	case reflect.Uint32:
		w.Uint32(uint32(r.Uint()))
	case reflect.Uint, reflect.Uint64, reflect.Uintptr:
		w.Uint64(uint64(r.Uint()))
	case reflect.Float32:
		w.Float32(float32(r.Float()))
	case reflect.Float64:
		w.Float64(r.Float())
	case reflect.Slice, reflect.Array:
		for i, c := 0, r.Len(); i < c; i++ {
			Write(w, r.Index(i).Interface())
		}
	case reflect.String:
		w.String(r.String())
	default:
		panic(fmt.Errorf("Cannot write type %T", v))
	}
}
<|endoftext|>


<commit_before>// Copyright 2021 Prometheus Team
// 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 sns

import (
	"context"
	"fmt"
	"net/http"
	"unicode/utf8"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/sns"
	"github.com/go-kit/kit/log"
	"github.com/prometheus/alertmanager/config"
	"github.com/prometheus/alertmanager/notify"
	"github.com/prometheus/alertmanager/template"
	"github.com/prometheus/alertmanager/types"
	commoncfg "github.com/prometheus/common/config"
)

// Notifier implements a Notifier for SNS notifications.
type Notifier struct {
	conf    *config.SNSConfig
	tmpl    *template.Template
	logger  log.Logger
	client  *http.Client
	retrier *notify.Retrier
}

func (n Notifier) Notify(ctx context.Context, alert ...*types.Alert) (bool, error) {
	credentials := credentials.NewStaticCredentials(n.conf.Sigv4.AccessKey, string(n.conf.Sigv4.SecretKey), "")
	if n.conf.Sigv4.AccessKey == "" {
		credentials = nil
	}

	sess, err := session.NewSessionWithOptions(session.Options{
		Config: aws.Config{
			Region:      aws.String(n.conf.Sigv4.Region),
			Credentials: credentials,
			Endpoint:    aws.String(n.conf.APIUrl),
		},
		Profile: n.conf.Sigv4.Profile,
	})

	if _, err := sess.Config.Credentials.Get(); err != nil {
		return false, fmt.Errorf("could not get SigV4 credentials: %w", err)
	}

	if n.conf.Sigv4.RoleARN != "" {
		sess.Config.Credentials = stscreds.NewCredentials(sess, n.conf.Sigv4.RoleARN)
	}

	data := notify.GetTemplateData(ctx, n.tmpl, alert, n.logger)
	tmpl := notify.TmplText(n.tmpl, data, &err)
	message := tmpl(n.conf.Message)

	client := sns.New(sess, &aws.Config{Credentials: credentials})
	publishInput := &sns.PublishInput{}

	if n.conf.TopicARN != "" {
		publishInput.SetTopicArn(n.conf.TopicARN)
		messageToSend, isTrunc, err := validateAndTruncateMessage(message)
		if err != nil {
			return false, err
		}
		if isTrunc {
			n.conf.Attributes["truncated"] = "true"
		}
		publishInput.SetMessage(messageToSend)
	}
	if n.conf.PhoneNumber != "" {
		publishInput.SetPhoneNumber(n.conf.PhoneNumber)
		// Truncate for SMS
		trunc, isTruncated := notify.Truncate(message, 140)
		if isTruncated {
			publishInput.SetMessage(trunc)
		} else {
			publishInput.SetMessage(message)
		}
	}
	if n.conf.TopicARN != "" {
		publishInput.SetTopicArn(n.conf.TopicARN)
		messageToSend, isTrunc, err := validateAndTruncateMessage(message)
		if err != nil {
			return false, err
		}
		if isTrunc {
			n.conf.Attributes["truncated"] = "true"
		}
		publishInput.SetMessage(messageToSend)
	}

	if len(n.conf.Attributes) > 0 {
		attributes := map[string]*sns.MessageAttributeValue{}
		for k, v := range n.conf.Attributes {
			attributes[k] = &sns.MessageAttributeValue{DataType: aws.String("String"), StringValue: aws.String(v)}
		}
		publishInput.SetMessageAttributes(attributes)
	}

	if n.conf.Subject != "" {
		publishInput.SetSubject(n.conf.Subject)
	}

	// Deduplication key is only added if it's a FIFO SNS Topic.
	if n.conf.IsFIFOTopic {
		key, err := notify.ExtractGroupKey(ctx)
		if err != nil {
			return false, err
		}
		publishInput.SetMessageDeduplicationId(key.Hash())
	}

	publishOutput, err := client.Publish(publishInput)
	if err != nil {
		// AWS Response is bad, probably a config issue.
		return false, err
	}

	err = n.logger.Log(publishOutput.String())
	if err != nil {
		return false, err
	}

	// Response is good and does not need to be retried.
	return false, nil
}

func validateAndTruncateMessage(message string) (string, bool, error) {
	if utf8.ValidString(message) {
		// if the message is larger than 256KB we have to truncate.
		if len(message) > 256*1000 {
			truncated := make([]byte, 256*1000, 256*1000)
			copy(truncated, message)
			return string(truncated), true, nil
		}
		return message, false, nil
	}
	return "", false, fmt.Errorf("non utf8 encoded message string")
}

// New returns a new SNS notification handler.
func New(c *config.SNSConfig, t *template.Template, l log.Logger, httpOpts ...commoncfg.HTTPClientOption) (*Notifier, error) {

	client, err := commoncfg.NewClientFromConfig(*c.HTTPConfig, "sns", append(httpOpts, commoncfg.WithHTTP2Disabled())...)
	if err != nil {
		return nil, err
	}

	return &Notifier{
		conf:    c,
		tmpl:    t,
		logger:  l,
		client:  client,
		retrier: &notify.Retrier{},
	}, nil
}
<commit_msg>Use 1024 rather than 1000 for KB size, fix target arn, handle large SMS messages correctly<commit_after>// Copyright 2021 Prometheus Team
// 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 sns

import (
	"context"
	"fmt"
	"net/http"
	"unicode/utf8"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/sns"
	"github.com/go-kit/kit/log"
	"github.com/prometheus/alertmanager/config"
	"github.com/prometheus/alertmanager/notify"
	"github.com/prometheus/alertmanager/template"
	"github.com/prometheus/alertmanager/types"
	commoncfg "github.com/prometheus/common/config"
)

// Notifier implements a Notifier for SNS notifications.
type Notifier struct {
	conf    *config.SNSConfig
	tmpl    *template.Template
	logger  log.Logger
	client  *http.Client
	retrier *notify.Retrier
}

func (n Notifier) Notify(ctx context.Context, alert ...*types.Alert) (bool, error) {
	credentials := credentials.NewStaticCredentials(n.conf.Sigv4.AccessKey, string(n.conf.Sigv4.SecretKey), "")
	if n.conf.Sigv4.AccessKey == "" {
		credentials = nil
	}

	sess, err := session.NewSessionWithOptions(session.Options{
		Config: aws.Config{
			Region:      aws.String(n.conf.Sigv4.Region),
			Credentials: credentials,
			Endpoint:    aws.String(n.conf.APIUrl),
		},
		Profile: n.conf.Sigv4.Profile,
	})

	if _, err := sess.Config.Credentials.Get(); err != nil {
		return false, fmt.Errorf("could not get SigV4 credentials: %w", err)
	}

	if n.conf.Sigv4.RoleARN != "" {
		sess.Config.Credentials = stscreds.NewCredentials(sess, n.conf.Sigv4.RoleARN)
	}

	data := notify.GetTemplateData(ctx, n.tmpl, alert, n.logger)
	tmpl := notify.TmplText(n.tmpl, data, &err)
	message := tmpl(n.conf.Message)

	client := sns.New(sess, &aws.Config{Credentials: credentials})
	publishInput := &sns.PublishInput{}

	if n.conf.TopicARN != "" {
		publishInput.SetTopicArn(n.conf.TopicARN)
		messageToSend, isTrunc, err := validateAndTruncateMessage(message)
		if err != nil {
			return false, err
		}
		if isTrunc {
			n.conf.Attributes["truncated"] = "true"
		}
		publishInput.SetMessage(messageToSend)
	}
	if n.conf.PhoneNumber != "" {
		publishInput.SetPhoneNumber(n.conf.PhoneNumber)
		// If SMS message is over 1600 chars, SNS will reject the message.
		_, isTruncated := notify.Truncate(message, 1600)
		if isTruncated {
			return false, fmt.Errorf("SMS message exeeds length of 1600 charactors")
		} else {
			publishInput.SetMessage(message)
		}
	}
	if n.conf.TargetARN != "" {
		publishInput.SetTargetArn(n.conf.TargetARN)
		messageToSend, isTrunc, err := validateAndTruncateMessage(message)
		if err != nil {
			return false, err
		}
		if isTrunc {
			n.conf.Attributes["truncated"] = "true"
		}
		publishInput.SetMessage(messageToSend)
	}

	if len(n.conf.Attributes) > 0 {
		attributes := map[string]*sns.MessageAttributeValue{}
		for k, v := range n.conf.Attributes {
			attributes[k] = &sns.MessageAttributeValue{DataType: aws.String("String"), StringValue: aws.String(v)}
		}
		publishInput.SetMessageAttributes(attributes)
	}

	if n.conf.Subject != "" {
		publishInput.SetSubject(n.conf.Subject)
	}

	// Deduplication key is only added if it's a FIFO SNS Topic.
	if n.conf.IsFIFOTopic {
		key, err := notify.ExtractGroupKey(ctx)
		if err != nil {
			return false, err
		}
		publishInput.SetMessageDeduplicationId(key.Hash())
	}

	publishOutput, err := client.Publish(publishInput)
	if err != nil {
		// AWS Response is bad, probably a config issue.
		return false, err
	}

	err = n.logger.Log(publishOutput.String())
	if err != nil {
		return false, err
	}

	// Response is good and does not need to be retried.
	return false, nil
}

func validateAndTruncateMessage(message string) (string, bool, error) {
	if utf8.ValidString(message) {
		// if the message is larger than 256KB we have to truncate.
		if len(message) > 256*1024 {
			truncated := make([]byte, 256*1024, 256*1024)
			copy(truncated, message)
			return string(truncated), true, nil
		}
		return message, false, nil
	}
	return "", false, fmt.Errorf("non utf8 encoded message string")
}

// New returns a new SNS notification handler.
func New(c *config.SNSConfig, t *template.Template, l log.Logger, httpOpts ...commoncfg.HTTPClientOption) (*Notifier, error) {

	client, err := commoncfg.NewClientFromConfig(*c.HTTPConfig, "sns", append(httpOpts, commoncfg.WithHTTP2Disabled())...)
	if err != nil {
		return nil, err
	}

	return &Notifier{
		conf:    c,
		tmpl:    t,
		logger:  l,
		client:  client,
		retrier: &notify.Retrier{},
	}, nil
}
<|endoftext|>


<commit_before>/*
Copyright 2014 Google Inc. All rights reserved.

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

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

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

package factory

import (
	"net/http"
	"net/http/httptest"
	"path"
	"reflect"
	"testing"
	"time"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client/cache"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
	algorithm "github.com/GoogleCloudPlatform/kubernetes/pkg/scheduler"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
	schedulerapi "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/scheduler/api"
	latestschedulerapi "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/scheduler/api/latest"
)

func TestCreate(t *testing.T) {
	handler := util.FakeHandler{
		StatusCode:   500,
		ResponseBody: "",
		T:            t,
	}
	server := httptest.NewServer(&handler)
	defer server.Close()
	client := client.NewOrDie(&client.Config{Host: server.URL, Version: testapi.Version()})
	factory := NewConfigFactory(client)
	factory.Create()
}

func TestCreateFromConfig(t *testing.T) {
	var configData []byte
	var policy schedulerapi.Policy

	handler := util.FakeHandler{
		StatusCode:   500,
		ResponseBody: "",
		T:            t,
	}
	server := httptest.NewServer(&handler)
	defer server.Close()
	client := client.NewOrDie(&client.Config{Host: server.URL, Version: testapi.Version()})
	factory := NewConfigFactory(client)

	// Register the predicate and priority functions
	// These would be registered by the DefaultProvider in regular operation
	RegisterFitPredicate("PodFitsPorts", algorithm.PodFitsPorts)
	RegisterFitPredicate("PodFitsResources", algorithm.NewResourceFitPredicate(MinionLister))
	RegisterFitPredicate("NoDiskConflict", algorithm.NoDiskConflict)
	RegisterFitPredicate("MatchNodeSelector", algorithm.NewSelectorMatchPredicate(MinionLister))
	RegisterFitPredicate("HostName", algorithm.PodFitsHost)
	RegisterPriorityFunction("LeastRequestedPriority", algorithm.LeastRequestedPriority, 1)
	RegisterPriorityFunction("ServiceSpreadingPriority", algorithm.NewServiceSpreadPriority(ServiceLister), 1)
	RegisterPriorityFunction("EqualPriority", algorithm.EqualPriority, 0)

	configData = []byte(`{
		"kind" : "Policy",
		"apiVersion" : "v1",
		"predicates" : [
			{"name" : "TestZoneAffinity", "argument" : {"serviceAffinity" : {"labels" : ["zone"]}}},
			{"name" : "TestRequireZone", "argument" : {"labelsPresence" : {"labels" : ["zone"], "presence" : true}}},
			{"name" : "PodFitsPorts"},
			{"name" : "MatchNodeSelector"}
		],
		"priorities" : [
			{"name" : "RackSpread", "weight" : 2, "argument" : {"serviceAntiAffinity" : {"label" : "rack"}}},
			{"name" : "ServiceSpreadingPriority", "weight" : 1}
		]
	}`)
	err := latestschedulerapi.Codec.DecodeInto(configData, &policy)
	if err != nil {
		t.Errorf("Invalid configuration: %v", err)
	}

	factory.CreateFromConfig(policy)
}

func TestCreateFromEmptyConfig(t *testing.T) {
	var configData []byte
	var policy schedulerapi.Policy

	handler := util.FakeHandler{
		StatusCode:   500,
		ResponseBody: "",
		T:            t,
	}
	server := httptest.NewServer(&handler)
	defer server.Close()
	client := client.NewOrDie(&client.Config{Host: server.URL, Version: testapi.Version()})
	factory := NewConfigFactory(client)

	configData = []byte(`{}`)
	err := latestschedulerapi.Codec.DecodeInto(configData, &policy)
	if err != nil {
		t.Errorf("Invalid configuration: %v", err)
	}

	factory.CreateFromConfig(policy)
}

func TestPollMinions(t *testing.T) {
	table := []struct {
		minions       []api.Node
		expectedCount int
	}{
		{
			minions: []api.Node{
				{
					ObjectMeta: api.ObjectMeta{Name: "foo"},
					Status: api.NodeStatus{
						Conditions: []api.NodeCondition{
							{Type: api.NodeReady, Status: api.ConditionFull},
						},
					},
				},
				{
					ObjectMeta: api.ObjectMeta{Name: "bar"},
					Status: api.NodeStatus{
						Conditions: []api.NodeCondition{
							{Type: api.NodeReachable, Status: api.ConditionFull},
						},
					},
				},
				{
					ObjectMeta: api.ObjectMeta{Name: "baz"},
					Status: api.NodeStatus{
						Conditions: []api.NodeCondition{
							{Type: api.NodeReady, Status: api.ConditionFull},
							{Type: api.NodeReachable, Status: api.ConditionFull},
						},
					},
				},
				{
					ObjectMeta: api.ObjectMeta{Name: "baz"},
					Status: api.NodeStatus{
						Conditions: []api.NodeCondition{
							{Type: api.NodeReady, Status: api.ConditionFull},
							{Type: api.NodeReady, Status: api.ConditionFull},
						},
					},
				},
			},
			expectedCount: 4,
		},
		{
			minions: []api.Node{
				{
					ObjectMeta: api.ObjectMeta{Name: "foo"},
					Status: api.NodeStatus{
						Conditions: []api.NodeCondition{
							{Type: api.NodeReady, Status: api.ConditionFull},
						},
					},
				},
				{
					ObjectMeta: api.ObjectMeta{Name: "bar"},
					Status: api.NodeStatus{
						Conditions: []api.NodeCondition{
							{Type: api.NodeReady, Status: api.ConditionNone},
						},
					},
				},
			},
			expectedCount: 1,
		},
		{
			minions: []api.Node{
				{
					ObjectMeta: api.ObjectMeta{Name: "foo"},
					Status: api.NodeStatus{
						Conditions: []api.NodeCondition{
							{Type: api.NodeReady, Status: api.ConditionFull},
							{Type: api.NodeReachable, Status: api.ConditionNone}},
					},
				},
			},
			expectedCount: 1,
		},
		{
			minions: []api.Node{
				{
					ObjectMeta: api.ObjectMeta{Name: "foo"},
					Status: api.NodeStatus{
						Conditions: []api.NodeCondition{
							{Type: api.NodeReachable, Status: api.ConditionFull},
							{Type: "invalidValue", Status: api.ConditionNone}},
					},
				},
			},
			expectedCount: 1,
		},
		{
			minions: []api.Node{
				{
					ObjectMeta: api.ObjectMeta{Name: "foo"},
					Status: api.NodeStatus{
						Conditions: []api.NodeCondition{},
					},
				},
			},
			expectedCount: 1,
		},
	}

	for _, item := range table {
		ml := &api.NodeList{Items: item.minions}
		handler := util.FakeHandler{
			StatusCode:   200,
			ResponseBody: runtime.EncodeOrDie(latest.Codec, ml),
			T:            t,
		}
		mux := http.NewServeMux()
		// FakeHandler musn't be sent requests other than the one you want to test.
		mux.Handle("/api/"+testapi.Version()+"/minions", &handler)
		server := httptest.NewServer(mux)
		defer server.Close()
		client := client.NewOrDie(&client.Config{Host: server.URL, Version: testapi.Version()})
		cf := NewConfigFactory(client)

		ce, err := cf.pollMinions()
		if err != nil {
			t.Errorf("Unexpected error: %v", err)
			continue
		}
		handler.ValidateRequest(t, "/api/"+testapi.Version()+"/minions", "GET", nil)

		if a := ce.Len(); item.expectedCount != a {
			t.Errorf("Expected %v, got %v", item.expectedCount, a)
		}
	}
}

func makeNamespaceURL(namespace, suffix string, isClient bool) string {
	if !(testapi.Version() == "v1beta1" || testapi.Version() == "v1beta2") {
		return makeURL("/ns/" + namespace + suffix)
	}
	// if this is a url the client should call, encode the url
	if isClient {
		return makeURL(suffix + "?namespace=" + namespace)
	}
	// its not a client url, so its what the server needs to listen on
	return makeURL(suffix)
}

func makeURL(suffix string) string {
	return path.Join("/api", testapi.Version(), suffix)
}

func TestDefaultErrorFunc(t *testing.T) {
	testPod := &api.Pod{
		ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "bar"},
		Spec: api.PodSpec{
			RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
			DNSPolicy:     api.DNSClusterFirst,
		},
	}
	handler := util.FakeHandler{
		StatusCode:   200,
		ResponseBody: runtime.EncodeOrDie(latest.Codec, testPod),
		T:            t,
	}
	mux := http.NewServeMux()

	// FakeHandler musn't be sent requests other than the one you want to test.
	mux.Handle(makeNamespaceURL("bar", "/pods/foo", false), &handler)
	server := httptest.NewServer(mux)
	defer server.Close()
	factory := NewConfigFactory(client.NewOrDie(&client.Config{Host: server.URL, Version: testapi.Version()}))
	queue := cache.NewFIFO(cache.MetaNamespaceKeyFunc)
	podBackoff := podBackoff{
		perPodBackoff:   map[string]*backoffEntry{},
		clock:           &fakeClock{},
		defaultDuration: 1 * time.Millisecond,
		maxDuration:     1 * time.Second,
	}
	errFunc := factory.makeDefaultErrorFunc(&podBackoff, queue)

	errFunc(testPod, nil)
	for {
		// This is a terrible way to do this but I plan on replacing this
		// whole error handling system in the future. The test will time
		// out if something doesn't work.
		time.Sleep(10 * time.Millisecond)
		got, exists, _ := queue.Get(testPod)
		if !exists {
			continue
		}
		handler.ValidateRequest(t, makeNamespaceURL("bar", "/pods/foo", true), "GET", nil)
		if e, a := testPod, got; !reflect.DeepEqual(e, a) {
			t.Errorf("Expected %v, got %v", e, a)
		}
		break
	}
}

func TestMinionEnumerator(t *testing.T) {
	testList := &api.NodeList{
		Items: []api.Node{
			{ObjectMeta: api.ObjectMeta{Name: "foo"}},
			{ObjectMeta: api.ObjectMeta{Name: "bar"}},
			{ObjectMeta: api.ObjectMeta{Name: "baz"}},
		},
	}
	me := nodeEnumerator{testList}

	if e, a := 3, me.Len(); e != a {
		t.Fatalf("expected %v, got %v", e, a)
	}
	for i := range testList.Items {
		gotObj := me.Get(i)
		if e, a := testList.Items[i].Name, gotObj.(*api.Node).Name; e != a {
			t.Errorf("Expected %v, got %v", e, a)
		}
		if e, a := &testList.Items[i], gotObj; !reflect.DeepEqual(e, a) {
			t.Errorf("Expected %#v, got %v#", e, a)
		}
	}
}

type fakeClock struct {
	t time.Time
}

func (f *fakeClock) Now() time.Time {
	return f.t
}

func TestBind(t *testing.T) {
	table := []struct {
		binding *api.Binding
	}{
		{binding: &api.Binding{
			ObjectMeta: api.ObjectMeta{
				Namespace: api.NamespaceDefault,
			},
			PodID: "foo",
			Host:  "foohost.kubernetes.mydomain.com",
		}},
	}

	for _, item := range table {
		handler := util.FakeHandler{
			StatusCode:   200,
			ResponseBody: "",
			T:            t,
		}
		server := httptest.NewServer(&handler)
		defer server.Close()
		client := client.NewOrDie(&client.Config{Host: server.URL, Version: testapi.Version()})
		b := binder{client}

		if err := b.Bind(item.binding); err != nil {
			t.Errorf("Unexpected error: %v", err)
			continue
		}
		expectedBody := runtime.EncodeOrDie(testapi.Codec(), item.binding)
		handler.ValidateRequest(t, "/api/"+testapi.Version()+"/bindings?namespace=default", "POST", &expectedBody)
	}
}

func TestBackoff(t *testing.T) {
	clock := fakeClock{}
	backoff := podBackoff{
		perPodBackoff:   map[string]*backoffEntry{},
		clock:           &clock,
		defaultDuration: 1 * time.Second,
		maxDuration:     60 * time.Second,
	}

	tests := []struct {
		podID            string
		expectedDuration time.Duration
		advanceClock     time.Duration
	}{
		{
			podID:            "foo",
			expectedDuration: 1 * time.Second,
		},
		{
			podID:            "foo",
			expectedDuration: 2 * time.Second,
		},
		{
			podID:            "foo",
			expectedDuration: 4 * time.Second,
		},
		{
			podID:            "bar",
			expectedDuration: 1 * time.Second,
			advanceClock:     120 * time.Second,
		},
		// 'foo' should have been gc'd here.
		{
			podID:            "foo",
			expectedDuration: 1 * time.Second,
		},
	}

	for _, test := range tests {
		duration := backoff.getBackoff(test.podID)
		if duration != test.expectedDuration {
			t.Errorf("expected: %s, got %s for %s", test.expectedDuration.String(), duration.String(), test.podID)
		}
		clock.t = clock.t.Add(test.advanceClock)
		backoff.gc()
	}

	backoff.perPodBackoff["foo"].backoff = 60 * time.Second
	duration := backoff.getBackoff("foo")
	if duration != 60*time.Second {
		t.Errorf("expected: 60, got %s", duration.String())
	}
}
<commit_msg>Fixing test case to remove dependency on algorithm provider<commit_after>/*
Copyright 2014 Google Inc. All rights reserved.

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

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

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

package factory

import (
	"net/http"
	"net/http/httptest"
	"path"
	"reflect"
	"testing"
	"time"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client/cache"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
	algorithm "github.com/GoogleCloudPlatform/kubernetes/pkg/scheduler"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
	schedulerapi "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/scheduler/api"
	latestschedulerapi "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/scheduler/api/latest"
)

func TestCreate(t *testing.T) {
	handler := util.FakeHandler{
		StatusCode:   500,
		ResponseBody: "",
		T:            t,
	}
	server := httptest.NewServer(&handler)
	defer server.Close()
	client := client.NewOrDie(&client.Config{Host: server.URL, Version: testapi.Version()})
	factory := NewConfigFactory(client)
	factory.Create()
}

// Test configures a scheduler from a policies defined in a file
// It combines some configurable predicate/priorities with some pre-defined ones
func TestCreateFromConfig(t *testing.T) {
	var configData []byte
	var policy schedulerapi.Policy

	handler := util.FakeHandler{
		StatusCode:   500,
		ResponseBody: "",
		T:            t,
	}
	server := httptest.NewServer(&handler)
	defer server.Close()
	client := client.NewOrDie(&client.Config{Host: server.URL, Version: testapi.Version()})
	factory := NewConfigFactory(client)

	// Pre-register some predicate and priority functions
	RegisterFitPredicate("PredicateOne", PredicateOne)
	RegisterFitPredicate("PredicateTwo", PredicateTwo)
	RegisterPriorityFunction("PriorityOne", PriorityOne, 1)
	RegisterPriorityFunction("PriorityTwo", PriorityTwo, 1)

	configData = []byte(`{
		"kind" : "Policy",
		"apiVersion" : "v1",
		"predicates" : [
			{"name" : "TestZoneAffinity", "argument" : {"serviceAffinity" : {"labels" : ["zone"]}}},
			{"name" : "TestRequireZone", "argument" : {"labelsPresence" : {"labels" : ["zone"], "presence" : true}}},
			{"name" : "PredicateOne"},
			{"name" : "PredicateTwo"}
		],
		"priorities" : [
			{"name" : "RackSpread", "weight" : 3, "argument" : {"serviceAntiAffinity" : {"label" : "rack"}}},
			{"name" : "PriorityOne", "weight" : 2},
			{"name" : "PriorityTwo", "weight" : 1}		]
	}`)
	err := latestschedulerapi.Codec.DecodeInto(configData, &policy)
	if err != nil {
		t.Errorf("Invalid configuration: %v", err)
	}

	factory.CreateFromConfig(policy)
}

func TestCreateFromEmptyConfig(t *testing.T) {
	var configData []byte
	var policy schedulerapi.Policy

	handler := util.FakeHandler{
		StatusCode:   500,
		ResponseBody: "",
		T:            t,
	}
	server := httptest.NewServer(&handler)
	defer server.Close()
	client := client.NewOrDie(&client.Config{Host: server.URL, Version: testapi.Version()})
	factory := NewConfigFactory(client)

	configData = []byte(`{}`)
	err := latestschedulerapi.Codec.DecodeInto(configData, &policy)
	if err != nil {
		t.Errorf("Invalid configuration: %v", err)
	}

	factory.CreateFromConfig(policy)
}

func PredicateOne(pod api.Pod, existingPods []api.Pod, node string) (bool, error) {
	return true, nil
}

func PredicateTwo(pod api.Pod, existingPods []api.Pod, node string) (bool, error) {
	return true, nil
}

func PriorityOne(pod api.Pod, podLister algorithm.PodLister, minionLister algorithm.MinionLister) (algorithm.HostPriorityList, error) {
	return []algorithm.HostPriority{}, nil
}

func PriorityTwo(pod api.Pod, podLister algorithm.PodLister, minionLister algorithm.MinionLister) (algorithm.HostPriorityList, error) {
	return []algorithm.HostPriority{}, nil
}

func TestPollMinions(t *testing.T) {
	table := []struct {
		minions       []api.Node
		expectedCount int
	}{
		{
			minions: []api.Node{
				{
					ObjectMeta: api.ObjectMeta{Name: "foo"},
					Status: api.NodeStatus{
						Conditions: []api.NodeCondition{
							{Type: api.NodeReady, Status: api.ConditionFull},
						},
					},
				},
				{
					ObjectMeta: api.ObjectMeta{Name: "bar"},
					Status: api.NodeStatus{
						Conditions: []api.NodeCondition{
							{Type: api.NodeReachable, Status: api.ConditionFull},
						},
					},
				},
				{
					ObjectMeta: api.ObjectMeta{Name: "baz"},
					Status: api.NodeStatus{
						Conditions: []api.NodeCondition{
							{Type: api.NodeReady, Status: api.ConditionFull},
							{Type: api.NodeReachable, Status: api.ConditionFull},
						},
					},
				},
				{
					ObjectMeta: api.ObjectMeta{Name: "baz"},
					Status: api.NodeStatus{
						Conditions: []api.NodeCondition{
							{Type: api.NodeReady, Status: api.ConditionFull},
							{Type: api.NodeReady, Status: api.ConditionFull},
						},
					},
				},
			},
			expectedCount: 4,
		},
		{
			minions: []api.Node{
				{
					ObjectMeta: api.ObjectMeta{Name: "foo"},
					Status: api.NodeStatus{
						Conditions: []api.NodeCondition{
							{Type: api.NodeReady, Status: api.ConditionFull},
						},
					},
				},
				{
					ObjectMeta: api.ObjectMeta{Name: "bar"},
					Status: api.NodeStatus{
						Conditions: []api.NodeCondition{
							{Type: api.NodeReady, Status: api.ConditionNone},
						},
					},
				},
			},
			expectedCount: 1,
		},
		{
			minions: []api.Node{
				{
					ObjectMeta: api.ObjectMeta{Name: "foo"},
					Status: api.NodeStatus{
						Conditions: []api.NodeCondition{
							{Type: api.NodeReady, Status: api.ConditionFull},
							{Type: api.NodeReachable, Status: api.ConditionNone}},
					},
				},
			},
			expectedCount: 1,
		},
		{
			minions: []api.Node{
				{
					ObjectMeta: api.ObjectMeta{Name: "foo"},
					Status: api.NodeStatus{
						Conditions: []api.NodeCondition{
							{Type: api.NodeReachable, Status: api.ConditionFull},
							{Type: "invalidValue", Status: api.ConditionNone}},
					},
				},
			},
			expectedCount: 1,
		},
		{
			minions: []api.Node{
				{
					ObjectMeta: api.ObjectMeta{Name: "foo"},
					Status: api.NodeStatus{
						Conditions: []api.NodeCondition{},
					},
				},
			},
			expectedCount: 1,
		},
	}

	for _, item := range table {
		ml := &api.NodeList{Items: item.minions}
		handler := util.FakeHandler{
			StatusCode:   200,
			ResponseBody: runtime.EncodeOrDie(latest.Codec, ml),
			T:            t,
		}
		mux := http.NewServeMux()
		// FakeHandler musn't be sent requests other than the one you want to test.
		mux.Handle("/api/"+testapi.Version()+"/minions", &handler)
		server := httptest.NewServer(mux)
		defer server.Close()
		client := client.NewOrDie(&client.Config{Host: server.URL, Version: testapi.Version()})
		cf := NewConfigFactory(client)

		ce, err := cf.pollMinions()
		if err != nil {
			t.Errorf("Unexpected error: %v", err)
			continue
		}
		handler.ValidateRequest(t, "/api/"+testapi.Version()+"/minions", "GET", nil)

		if a := ce.Len(); item.expectedCount != a {
			t.Errorf("Expected %v, got %v", item.expectedCount, a)
		}
	}
}

func makeNamespaceURL(namespace, suffix string, isClient bool) string {
	if !(testapi.Version() == "v1beta1" || testapi.Version() == "v1beta2") {
		return makeURL("/ns/" + namespace + suffix)
	}
	// if this is a url the client should call, encode the url
	if isClient {
		return makeURL(suffix + "?namespace=" + namespace)
	}
	// its not a client url, so its what the server needs to listen on
	return makeURL(suffix)
}

func makeURL(suffix string) string {
	return path.Join("/api", testapi.Version(), suffix)
}

func TestDefaultErrorFunc(t *testing.T) {
	testPod := &api.Pod{
		ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "bar"},
		Spec: api.PodSpec{
			RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}},
			DNSPolicy:     api.DNSClusterFirst,
		},
	}
	handler := util.FakeHandler{
		StatusCode:   200,
		ResponseBody: runtime.EncodeOrDie(latest.Codec, testPod),
		T:            t,
	}
	mux := http.NewServeMux()

	// FakeHandler musn't be sent requests other than the one you want to test.
	mux.Handle(makeNamespaceURL("bar", "/pods/foo", false), &handler)
	server := httptest.NewServer(mux)
	defer server.Close()
	factory := NewConfigFactory(client.NewOrDie(&client.Config{Host: server.URL, Version: testapi.Version()}))
	queue := cache.NewFIFO(cache.MetaNamespaceKeyFunc)
	podBackoff := podBackoff{
		perPodBackoff:   map[string]*backoffEntry{},
		clock:           &fakeClock{},
		defaultDuration: 1 * time.Millisecond,
		maxDuration:     1 * time.Second,
	}
	errFunc := factory.makeDefaultErrorFunc(&podBackoff, queue)

	errFunc(testPod, nil)
	for {
		// This is a terrible way to do this but I plan on replacing this
		// whole error handling system in the future. The test will time
		// out if something doesn't work.
		time.Sleep(10 * time.Millisecond)
		got, exists, _ := queue.Get(testPod)
		if !exists {
			continue
		}
		handler.ValidateRequest(t, makeNamespaceURL("bar", "/pods/foo", true), "GET", nil)
		if e, a := testPod, got; !reflect.DeepEqual(e, a) {
			t.Errorf("Expected %v, got %v", e, a)
		}
		break
	}
}

func TestMinionEnumerator(t *testing.T) {
	testList := &api.NodeList{
		Items: []api.Node{
			{ObjectMeta: api.ObjectMeta{Name: "foo"}},
			{ObjectMeta: api.ObjectMeta{Name: "bar"}},
			{ObjectMeta: api.ObjectMeta{Name: "baz"}},
		},
	}
	me := nodeEnumerator{testList}

	if e, a := 3, me.Len(); e != a {
		t.Fatalf("expected %v, got %v", e, a)
	}
	for i := range testList.Items {
		gotObj := me.Get(i)
		if e, a := testList.Items[i].Name, gotObj.(*api.Node).Name; e != a {
			t.Errorf("Expected %v, got %v", e, a)
		}
		if e, a := &testList.Items[i], gotObj; !reflect.DeepEqual(e, a) {
			t.Errorf("Expected %#v, got %v#", e, a)
		}
	}
}

type fakeClock struct {
	t time.Time
}

func (f *fakeClock) Now() time.Time {
	return f.t
}

func TestBind(t *testing.T) {
	table := []struct {
		binding *api.Binding
	}{
		{binding: &api.Binding{
			ObjectMeta: api.ObjectMeta{
				Namespace: api.NamespaceDefault,
			},
			PodID: "foo",
			Host:  "foohost.kubernetes.mydomain.com",
		}},
	}

	for _, item := range table {
		handler := util.FakeHandler{
			StatusCode:   200,
			ResponseBody: "",
			T:            t,
		}
		server := httptest.NewServer(&handler)
		defer server.Close()
		client := client.NewOrDie(&client.Config{Host: server.URL, Version: testapi.Version()})
		b := binder{client}

		if err := b.Bind(item.binding); err != nil {
			t.Errorf("Unexpected error: %v", err)
			continue
		}
		expectedBody := runtime.EncodeOrDie(testapi.Codec(), item.binding)
		handler.ValidateRequest(t, "/api/"+testapi.Version()+"/bindings?namespace=default", "POST", &expectedBody)
	}
}

func TestBackoff(t *testing.T) {
	clock := fakeClock{}
	backoff := podBackoff{
		perPodBackoff:   map[string]*backoffEntry{},
		clock:           &clock,
		defaultDuration: 1 * time.Second,
		maxDuration:     60 * time.Second,
	}

	tests := []struct {
		podID            string
		expectedDuration time.Duration
		advanceClock     time.Duration
	}{
		{
			podID:            "foo",
			expectedDuration: 1 * time.Second,
		},
		{
			podID:            "foo",
			expectedDuration: 2 * time.Second,
		},
		{
			podID:            "foo",
			expectedDuration: 4 * time.Second,
		},
		{
			podID:            "bar",
			expectedDuration: 1 * time.Second,
			advanceClock:     120 * time.Second,
		},
		// 'foo' should have been gc'd here.
		{
			podID:            "foo",
			expectedDuration: 1 * time.Second,
		},
	}

	for _, test := range tests {
		duration := backoff.getBackoff(test.podID)
		if duration != test.expectedDuration {
			t.Errorf("expected: %s, got %s for %s", test.expectedDuration.String(), duration.String(), test.podID)
		}
		clock.t = clock.t.Add(test.advanceClock)
		backoff.gc()
	}

	backoff.perPodBackoff["foo"].backoff = 60 * time.Second
	duration := backoff.getBackoff("foo")
	if duration != 60*time.Second {
		t.Errorf("expected: 60, got %s", duration.String())
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.

package runtime

import (
	"math/big"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/state"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/ethereum/go-ethereum/ethdb"
	"github.com/ethereum/go-ethereum/params"
)

// The default, always homestead, rule set for the vm env
type ruleSet struct{}

func (ruleSet) IsHomestead(*big.Int) bool { return true }
func (ruleSet) GasTable(*big.Int) params.GasTable {
	return params.GasTableHomesteadGasRepriceFork
}

// Config is a basic type specifying certain configuration flags for running
// the EVM.
type Config struct {
	ChainConfig *params.ChainConfig
	Difficulty  *big.Int
	Origin      common.Address
	Coinbase    common.Address
	BlockNumber *big.Int
	Time        *big.Int
	GasLimit    *big.Int
	GasPrice    *big.Int
	Value       *big.Int
	DisableJit  bool // "disable" so it's enabled by default
	Debug       bool

	State     *state.StateDB
	GetHashFn func(n uint64) common.Hash
}

// sets defaults on the config
func setDefaults(cfg *Config) {
	if cfg.ChainConfig == nil {
		cfg.ChainConfig = &params.ChainConfig{big.NewInt(1), new(big.Int), new(big.Int), false, new(big.Int), common.Hash{}, new(big.Int), new(big.Int), new(big.Int)}
	}

	if cfg.Difficulty == nil {
		cfg.Difficulty = new(big.Int)
	}
	if cfg.Time == nil {
		cfg.Time = big.NewInt(time.Now().Unix())
	}
	if cfg.GasLimit == nil {
		cfg.GasLimit = new(big.Int).Set(common.MaxBig)
	}
	if cfg.GasPrice == nil {
		cfg.GasPrice = new(big.Int)
	}
	if cfg.Value == nil {
		cfg.Value = new(big.Int)
	}
	if cfg.BlockNumber == nil {
		cfg.BlockNumber = new(big.Int)
	}
	if cfg.GetHashFn == nil {
		cfg.GetHashFn = func(n uint64) common.Hash {
			return common.BytesToHash(crypto.Keccak256([]byte(new(big.Int).SetUint64(n).String())))
		}
	}
}

// Execute executes the code using the input as call data during the execution.
// It returns the EVM's return value, the new state and an error if it failed.
//
// Executes sets up a in memory, temporarily, environment for the execution of
// the given code. It enabled the JIT by default and make sure that it's restored
// to it's original state afterwards.
func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
	if cfg == nil {
		cfg = new(Config)
	}
	setDefaults(cfg)

	if cfg.State == nil {
		db, _ := ethdb.NewMemDatabase()
		cfg.State, _ = state.New(common.Hash{}, db)
	}
	var (
		vmenv    = NewEnv(cfg, cfg.State)
		sender   = cfg.State.CreateAccount(cfg.Origin)
		receiver = cfg.State.CreateAccount(common.StringToAddress("contract"))
	)
	// set the receiver's (the executing contract) code for execution.
	receiver.SetCode(crypto.Keccak256Hash(code), code)

	// Call the code with the given configuration.
	ret, err := vmenv.Call(
		sender,
		receiver.Address(),
		input,
		cfg.GasLimit,
		cfg.GasPrice,
		cfg.Value,
	)

	return ret, cfg.State, err
}

// Call executes the code given by the contract's address. It will return the
// EVM's return value or an error if it failed.
//
// Call, unlike Execute, requires a config and also requires the State field to
// be set.
func Call(address common.Address, input []byte, cfg *Config) ([]byte, error) {
	setDefaults(cfg)

	vmenv := NewEnv(cfg, cfg.State)

	sender := cfg.State.GetOrNewStateObject(cfg.Origin)
	// Call the code with the given configuration.
	ret, err := vmenv.Call(
		sender,
		address,
		input,
		cfg.GasLimit,
		cfg.GasPrice,
		cfg.Value,
	)

	return ret, err
}
<commit_msg>core/vm/runtime: fixed go vet<commit_after>// Copyright 2015 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.

package runtime

import (
	"math/big"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/state"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/ethereum/go-ethereum/ethdb"
	"github.com/ethereum/go-ethereum/params"
)

// The default, always homestead, rule set for the vm env
type ruleSet struct{}

func (ruleSet) IsHomestead(*big.Int) bool { return true }
func (ruleSet) GasTable(*big.Int) params.GasTable {
	return params.GasTableHomesteadGasRepriceFork
}

// Config is a basic type specifying certain configuration flags for running
// the EVM.
type Config struct {
	ChainConfig *params.ChainConfig
	Difficulty  *big.Int
	Origin      common.Address
	Coinbase    common.Address
	BlockNumber *big.Int
	Time        *big.Int
	GasLimit    *big.Int
	GasPrice    *big.Int
	Value       *big.Int
	DisableJit  bool // "disable" so it's enabled by default
	Debug       bool

	State     *state.StateDB
	GetHashFn func(n uint64) common.Hash
}

// sets defaults on the config
func setDefaults(cfg *Config) {
	if cfg.ChainConfig == nil {
		cfg.ChainConfig = &params.ChainConfig{
			ChainId:        big.NewInt(1),
			HomesteadBlock: new(big.Int),
			DAOForkBlock:   new(big.Int),
			DAOForkSupport: false,
			EIP150Block:    new(big.Int),
			EIP155Block:    new(big.Int),
			EIP158Block:    new(big.Int),
		}
	}

	if cfg.Difficulty == nil {
		cfg.Difficulty = new(big.Int)
	}
	if cfg.Time == nil {
		cfg.Time = big.NewInt(time.Now().Unix())
	}
	if cfg.GasLimit == nil {
		cfg.GasLimit = new(big.Int).Set(common.MaxBig)
	}
	if cfg.GasPrice == nil {
		cfg.GasPrice = new(big.Int)
	}
	if cfg.Value == nil {
		cfg.Value = new(big.Int)
	}
	if cfg.BlockNumber == nil {
		cfg.BlockNumber = new(big.Int)
	}
	if cfg.GetHashFn == nil {
		cfg.GetHashFn = func(n uint64) common.Hash {
			return common.BytesToHash(crypto.Keccak256([]byte(new(big.Int).SetUint64(n).String())))
		}
	}
}

// Execute executes the code using the input as call data during the execution.
// It returns the EVM's return value, the new state and an error if it failed.
//
// Executes sets up a in memory, temporarily, environment for the execution of
// the given code. It enabled the JIT by default and make sure that it's restored
// to it's original state afterwards.
func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
	if cfg == nil {
		cfg = new(Config)
	}
	setDefaults(cfg)

	if cfg.State == nil {
		db, _ := ethdb.NewMemDatabase()
		cfg.State, _ = state.New(common.Hash{}, db)
	}
	var (
		vmenv    = NewEnv(cfg, cfg.State)
		sender   = cfg.State.CreateAccount(cfg.Origin)
		receiver = cfg.State.CreateAccount(common.StringToAddress("contract"))
	)
	// set the receiver's (the executing contract) code for execution.
	receiver.SetCode(crypto.Keccak256Hash(code), code)

	// Call the code with the given configuration.
	ret, err := vmenv.Call(
		sender,
		receiver.Address(),
		input,
		cfg.GasLimit,
		cfg.GasPrice,
		cfg.Value,
	)

	return ret, cfg.State, err
}

// Call executes the code given by the contract's address. It will return the
// EVM's return value or an error if it failed.
//
// Call, unlike Execute, requires a config and also requires the State field to
// be set.
func Call(address common.Address, input []byte, cfg *Config) ([]byte, error) {
	setDefaults(cfg)

	vmenv := NewEnv(cfg, cfg.State)

	sender := cfg.State.GetOrNewStateObject(cfg.Origin)
	// Call the code with the given configuration.
	ret, err := vmenv.Call(
		sender,
		address,
		input,
		cfg.GasLimit,
		cfg.GasPrice,
		cfg.Value,
	)

	return ret, err
}
<|endoftext|>


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

package main

import (
	"fmt"
	"os" // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
	"strings"

	"github.com/spf13/cobra"
	_ "k8s.io/client-go/plugin/pkg/client/auth"
	"sigs.k8s.io/controller-runtime/pkg/cache"
	"sigs.k8s.io/controller-runtime/pkg/client/config"
	"sigs.k8s.io/controller-runtime/pkg/manager"
	"sigs.k8s.io/controller-runtime/pkg/manager/signals"

	"istio.io/istio/operator/pkg/apis"
	"istio.io/istio/operator/pkg/controller"
	"istio.io/pkg/ctrlz"
	"istio.io/pkg/log"
)

// Should match deploy/service.yaml
const (
	metricsHost       = "0.0.0.0"
	metricsPort int32 = 8383
)

func serverCmd() *cobra.Command {
	loggingOptions := log.DefaultOptions()
	introspectionOptions := ctrlz.DefaultOptions()

	serverCmd := &cobra.Command{
		Use:   "server",
		Short: "Starts the Istio operator server",
		Args:  cobra.ExactArgs(0),
		RunE: func(cmd *cobra.Command, args []string) error {
			if err := log.Configure(loggingOptions); err != nil {
				log.Errorf("Unable to configure logging: %v", err)
			}

			if cs, err := ctrlz.Run(introspectionOptions, nil); err == nil {
				defer cs.Close()
			} else {
				log.Errorf("Unable to initialize ControlZ: %v", err)
			}

			run()
			return nil
		},
	}

	loggingOptions.AttachCobraFlags(serverCmd)
	introspectionOptions.AttachCobraFlags(serverCmd)

	return serverCmd
}

// getWatchNamespace returns the namespace the operator should be watching for changes
func getWatchNamespace() (string, error) {
	ns, found := os.LookupEnv("WATCH_NAMESPACE")
	if !found {
		return "", fmt.Errorf("WATCH_NAMESPACE must be set")
	}
	return ns, nil
}

// getLeaderElectionNamespace returns the namespace in which the leader election configmap will be created
func getLeaderElectionNamespace() (string, bool) {
	return os.LookupEnv("LEADER_ELECTION_NAMESPACE")
}

func run() {
	watchNS, err := getWatchNamespace()
	if err != nil {
		log.Fatalf("Failed to get watch namespace: %v", err)
	}

	leaderElectionNS, leaderElectionEnabled := getLeaderElectionNamespace()
	if !leaderElectionEnabled {
		log.Warn("Leader election namespace not set. Leader election is disabled. NOT APPROPRIATE FOR PRODUCTION USE!")
	}

	// Get a config to talk to the apiserver
	cfg, err := config.GetConfig()
	if err != nil {
		log.Fatalf("Could not get apiserver config: %v", err)
	}

	var mgrOpt manager.Options
	if watchNS != "" {
		namespaces := strings.Split(watchNS, ",")
		// Create MultiNamespacedCache with watched namespaces if it's not empty.
		mgrOpt = manager.Options{
			NewCache:                cache.MultiNamespacedCacheBuilder(namespaces),
			MetricsBindAddress:      fmt.Sprintf("%s:%d", metricsHost, metricsPort),
			LeaderElection:          leaderElectionEnabled,
			LeaderElectionNamespace: leaderElectionNS,
			LeaderElectionID:        "istio-operator-lock",
		}
	} else {
		// Create manager option for watching all namespaces.
		mgrOpt = manager.Options{
			Namespace:               watchNS,
			MetricsBindAddress:      fmt.Sprintf("%s:%d", metricsHost, metricsPort),
			LeaderElection:          leaderElectionEnabled,
			LeaderElectionNamespace: leaderElectionNS,
			LeaderElectionID:        "istio-operator-lock",
		}
	}

	// Create a new Cmd to provide shared dependencies and start components
	mgr, err := manager.New(cfg, mgrOpt)
	if err != nil {
		log.Fatalf("Could not create a controller manager: %v", err)
	}

	log.Info("Registering Components.")

	// Setup Scheme for all resources
	if err := apis.AddToScheme(mgr.GetScheme()); err != nil {
		log.Fatalf("Could not add manager scheme: %v", err)
	}

	// Setup all Controllers
	if err := controller.AddToManager(mgr); err != nil {
		log.Fatalf("Could not add all controllers to operator manager: %v", err)
	}

	log.Info("Starting the Cmd.")

	// Start the Cmd
	if err := mgr.Start(signals.SetupSignalHandler()); err != nil {
		log.Fatalf("Manager exited non-zero: %v", err)
	}
}
<commit_msg>fix wrong comment (#25563)<commit_after>// Copyright Istio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"fmt"
	"os"
	"strings"

	"github.com/spf13/cobra"
	// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
	_ "k8s.io/client-go/plugin/pkg/client/auth"
	"sigs.k8s.io/controller-runtime/pkg/cache"
	"sigs.k8s.io/controller-runtime/pkg/client/config"
	"sigs.k8s.io/controller-runtime/pkg/manager"
	"sigs.k8s.io/controller-runtime/pkg/manager/signals"

	"istio.io/istio/operator/pkg/apis"
	"istio.io/istio/operator/pkg/controller"
	"istio.io/pkg/ctrlz"
	"istio.io/pkg/log"
)

// Should match deploy/service.yaml
const (
	metricsHost       = "0.0.0.0"
	metricsPort int32 = 8383
)

func serverCmd() *cobra.Command {
	loggingOptions := log.DefaultOptions()
	introspectionOptions := ctrlz.DefaultOptions()

	serverCmd := &cobra.Command{
		Use:   "server",
		Short: "Starts the Istio operator server",
		Args:  cobra.ExactArgs(0),
		RunE: func(cmd *cobra.Command, args []string) error {
			if err := log.Configure(loggingOptions); err != nil {
				log.Errorf("Unable to configure logging: %v", err)
			}

			if cs, err := ctrlz.Run(introspectionOptions, nil); err == nil {
				defer cs.Close()
			} else {
				log.Errorf("Unable to initialize ControlZ: %v", err)
			}

			run()
			return nil
		},
	}

	loggingOptions.AttachCobraFlags(serverCmd)
	introspectionOptions.AttachCobraFlags(serverCmd)

	return serverCmd
}

// getWatchNamespace returns the namespace the operator should be watching for changes
func getWatchNamespace() (string, error) {
	ns, found := os.LookupEnv("WATCH_NAMESPACE")
	if !found {
		return "", fmt.Errorf("WATCH_NAMESPACE must be set")
	}
	return ns, nil
}

// getLeaderElectionNamespace returns the namespace in which the leader election configmap will be created
func getLeaderElectionNamespace() (string, bool) {
	return os.LookupEnv("LEADER_ELECTION_NAMESPACE")
}

func run() {
	watchNS, err := getWatchNamespace()
	if err != nil {
		log.Fatalf("Failed to get watch namespace: %v", err)
	}

	leaderElectionNS, leaderElectionEnabled := getLeaderElectionNamespace()
	if !leaderElectionEnabled {
		log.Warn("Leader election namespace not set. Leader election is disabled. NOT APPROPRIATE FOR PRODUCTION USE!")
	}

	// Get a config to talk to the apiserver
	cfg, err := config.GetConfig()
	if err != nil {
		log.Fatalf("Could not get apiserver config: %v", err)
	}

	var mgrOpt manager.Options
	if watchNS != "" {
		namespaces := strings.Split(watchNS, ",")
		// Create MultiNamespacedCache with watched namespaces if it's not empty.
		mgrOpt = manager.Options{
			NewCache:                cache.MultiNamespacedCacheBuilder(namespaces),
			MetricsBindAddress:      fmt.Sprintf("%s:%d", metricsHost, metricsPort),
			LeaderElection:          leaderElectionEnabled,
			LeaderElectionNamespace: leaderElectionNS,
			LeaderElectionID:        "istio-operator-lock",
		}
	} else {
		// Create manager option for watching all namespaces.
		mgrOpt = manager.Options{
			Namespace:               watchNS,
			MetricsBindAddress:      fmt.Sprintf("%s:%d", metricsHost, metricsPort),
			LeaderElection:          leaderElectionEnabled,
			LeaderElectionNamespace: leaderElectionNS,
			LeaderElectionID:        "istio-operator-lock",
		}
	}

	// Create a new Cmd to provide shared dependencies and start components
	mgr, err := manager.New(cfg, mgrOpt)
	if err != nil {
		log.Fatalf("Could not create a controller manager: %v", err)
	}

	log.Info("Registering Components.")

	// Setup Scheme for all resources
	if err := apis.AddToScheme(mgr.GetScheme()); err != nil {
		log.Fatalf("Could not add manager scheme: %v", err)
	}

	// Setup all Controllers
	if err := controller.AddToManager(mgr); err != nil {
		log.Fatalf("Could not add all controllers to operator manager: %v", err)
	}

	log.Info("Starting the Cmd.")

	// Start the Cmd
	if err := mgr.Start(signals.SetupSignalHandler()); err != nil {
		log.Fatalf("Manager exited non-zero: %v", err)
	}
}
<|endoftext|>