<commit_before>package main

import (
	"encoding/json"
	"errors"
	"github.com/appc/spec/schema"
	"github.com/appc/spec/schema/types"
	"github.com/blablacar/dgr/bin-dgr/common"
	"github.com/n0rad/go-erlog/data"
	"github.com/n0rad/go-erlog/errs"
	"github.com/n0rad/go-erlog/logs"
	"io/ioutil"
	"os"
	"sync"
)

const pathPodManifestJson = "/pod-manifest.json"

func (p *Pod) CleanAndBuild() error {
	defer p.giveBackUserRightsToTarget()
	p.Clean()
	logs.WithF(p.fields).Info("Building")

	os.RemoveAll(p.target)
	os.MkdirAll(p.target, 0777)

	p.preparePodVersion()
	apps, err := p.processAcis()
	if err != nil {
		return err
	}

	if err := p.writePodManifest(apps); err != nil {
		return err
	}
	return nil
}

func (p *Pod) preparePodVersion() {
	if p.manifest.Name.Version() == "" {
		p.manifest.Name = *common.NewACFullName(p.manifest.Name.Name() + ":" + common.GenerateVersion(p.path))
	}
}

func (p *Pod) processAcis() ([]schema.RuntimeApp, error) {
	apps := make([]schema.RuntimeApp, len(p.manifest.Pod.Apps))
	errors := make([]error, len(p.manifest.Pod.Apps))
	var wg sync.WaitGroup
	for i, e := range p.manifest.Pod.Apps {
		wg.Add(1)
		f := func(i int, e common.RuntimeApp) {
			defer wg.Done()

			app, err := p.processAci(e)
			if app != nil {
				apps[i] = *app
			}
			errors[i] = err
		}

		if !p.args.ParallelBuild {
			f(i, e)
		} else {
			go f(i, e)
		}
	}
	wg.Wait()

	failed := 0
	for _, err := range errors {
		if err != nil {
			failed++
		}
	}
	if failed > 0 {
		return apps, errs.With("Acis process failed").WithErrs(errors...)
	}
	return apps, nil
}

func (p *Pod) processAci(e common.RuntimeApp) (*schema.RuntimeApp, error) {
	aci, err := p.buildAci(e)
	if err != nil {
		return nil, err
	}

	name, err := types.NewACName(e.Name)
	if err != nil {
		return nil, errs.WithEF(err, p.fields.WithField("name", e.Name), "Invalid name format")
	}

	sum, err := Sha512sum(aci.target + pathImageAci)
	if err != nil {
		return nil, errs.WithEF(err, p.fields.WithField("file", aci.target+pathImageAci), "Failed to calculate sha512 of aci")
	}

	tmp, _ := types.NewHash("sha512-" + sum)

	labels := types.Labels{}
	labels = append(labels, types.Label{Name: "version", Value: aci.manifest.NameAndVersion.Version()})
	identifier, _ := types.NewACIdentifier(aci.manifest.NameAndVersion.Name())
	ttmp := schema.RuntimeImage{Name: identifier, ID: *tmp, Labels: labels}

	e.App.Group = aci.manifest.Aci.App.Group
	e.App.User = aci.manifest.Aci.App.User
	if e.App.User == "" {
		e.App.User = "0"
	}
	if e.App.Group == "" {
		e.App.Group = "0"
	}

	isolators, err := common.ToAppcIsolators(e.App.Isolators)
	if err != nil {
		return nil, errs.WithEF(err, p.fields, "Failed to prepare isolators")
	}

	return &schema.RuntimeApp{
		Name:  *name,
		Image: ttmp,
		App: &types.App{
			Exec:              e.App.Exec,
			User:              e.App.User,
			Group:             e.App.Group,
			WorkingDirectory:  e.App.WorkingDirectory,
			SupplementaryGIDs: e.App.SupplementaryGIDs,
			Environment:       e.App.Environment,
			MountPoints:       e.App.MountPoints,
			Ports:             e.App.Ports,
			Isolators:         isolators,
		},
		Mounts:      e.Mounts,
		Annotations: e.Annotations}, nil
}

func (p *Pod) fillRuntimeAppFromDependencies(e *common.RuntimeApp) error {
	fields := p.fields.WithField("aci", e.Name)
	if len(e.Dependencies) > 1 && len(e.App.Exec) == 0 {
		return errs.WithF(fields, "There is more than 1 dependency, manifest aci must be set explicitly")
	}

	if len(e.Dependencies) == 1 {
		Home.Rkt.Fetch(e.Dependencies[0].String())
		manifestStr, err := Home.Rkt.CatManifest(e.Dependencies[0].String())
		if err != nil {
			return errs.WithEF(err, fields.WithField("dependency", e.Dependencies[0].String()), "Failed to get dependency manifest")
		}
		manifest := schema.ImageManifest{}
		if err := json.Unmarshal([]byte(manifestStr), &manifest); err != nil {
			return errs.WithEF(err, fields.WithField("content", manifestStr), "Failed to unmarshal stage1 manifest received from rkt")
		}

		if len(e.App.Exec) == 0 {
			e.App.Exec = manifest.App.Exec
		}
		if e.App.User == "" {
			e.App.User = manifest.App.User
		}
		if e.App.Group == "" {
			e.App.Group = manifest.App.Group
		}
		if e.App.WorkingDirectory == "" {
			e.App.WorkingDirectory = manifest.App.WorkingDirectory
		}
		if len(e.App.SupplementaryGIDs) == 0 {
			e.App.SupplementaryGIDs = manifest.App.SupplementaryGIDs
		}
		if len(e.App.Isolators) == 0 {
			res, err := common.FromAppcIsolators(manifest.App.Isolators)
			if err != nil {
				return errs.WithEF(err, fields, "Failed to replicate isolators from aci to pod")
			}
			e.App.Isolators = res
		}
		if len(e.App.Ports) == 0 {
			e.App.Ports = manifest.App.Ports
		}
		if len(e.App.MountPoints) == 0 {
			e.App.MountPoints = manifest.App.MountPoints
		}
		if len(e.App.Environment) == 0 {
			e.App.Environment = manifest.App.Environment
		}

		anns := e.Annotations
		e.Annotations = manifest.Annotations
		for _, ann := range anns {
			e.Annotations.Set(ann.Name, ann.Value)
		}
	}
	return nil
}

func (p *Pod) buildAci(e common.RuntimeApp) (*Aci, error) {
	if err := p.fillRuntimeAppFromDependencies(&e); err != nil {
		return nil, err
	}

	aci, err := p.toPodAci(e)
	if err != nil {
		return nil, err
	}
	if err := aci.CleanAndBuild(); err != nil {
		return nil, errs.WithEF(err, p.fields.WithField("name", e.Name), "build of  pod's aci failed")
	}
	return aci, nil
}

func (p *Pod) writePodManifest(apps []schema.RuntimeApp) error {
	m := p.manifest.Pod
	ver, _ := types.NewSemVer("0.6.1")
	manifest := schema.PodManifest{
		ACKind:      "PodManifest",
		ACVersion:   *ver,
		Apps:        apps,
		Volumes:     m.Volumes,
		Isolators:   m.Isolators,
		Annotations: m.Annotations,
		Ports:       m.Ports}
	return WritePodManifest(&manifest, p.target+pathPodManifestJson)
}

func WritePodManifest(im *schema.PodManifest, targetFile string) error {
	buff, err := json.MarshalIndent(im, "", "  ")
	if err != nil {
		return errs.WithEF(err, data.WithField("object", im), "Failed to marshal manifest")
	}
	err = ioutil.WriteFile(targetFile, []byte(buff), 0644)
	if err != nil {
		return errs.WithEF(err, data.WithField("file", targetFile), "Failed to write pod manifest")
	}
	return nil
}

func (p *Pod) getVolumeMountValue(mountName types.ACName) (*types.Volume, error) {
	for _, volume := range p.manifest.Pod.Volumes {
		if volume.Name.Equals(mountName) {
			return &volume, nil
		}
	}
	return nil, errors.New("Volume mount point not set :" + mountName.String())
}
<commit_msg>[#184] use first aci of pod as default params for app node<commit_after>package main

import (
	"encoding/json"
	"errors"
	"github.com/appc/spec/schema"
	"github.com/appc/spec/schema/types"
	"github.com/blablacar/dgr/bin-dgr/common"
	"github.com/n0rad/go-erlog/data"
	"github.com/n0rad/go-erlog/errs"
	"github.com/n0rad/go-erlog/logs"
	"io/ioutil"
	"os"
	"sync"
)

const pathPodManifestJson = "/pod-manifest.json"

func (p *Pod) CleanAndBuild() error {
	defer p.giveBackUserRightsToTarget()
	p.Clean()
	logs.WithF(p.fields).Info("Building")

	os.RemoveAll(p.target)
	os.MkdirAll(p.target, 0777)

	p.preparePodVersion()
	apps, err := p.processAcis()
	if err != nil {
		return err
	}

	if err := p.writePodManifest(apps); err != nil {
		return err
	}
	return nil
}

func (p *Pod) preparePodVersion() {
	if p.manifest.Name.Version() == "" {
		p.manifest.Name = *common.NewACFullName(p.manifest.Name.Name() + ":" + common.GenerateVersion(p.path))
	}
}

func (p *Pod) processAcis() ([]schema.RuntimeApp, error) {
	apps := make([]schema.RuntimeApp, len(p.manifest.Pod.Apps))
	errors := make([]error, len(p.manifest.Pod.Apps))
	var wg sync.WaitGroup
	for i, e := range p.manifest.Pod.Apps {
		wg.Add(1)
		f := func(i int, e common.RuntimeApp) {
			defer wg.Done()

			app, err := p.processAci(e)
			if app != nil {
				apps[i] = *app
			}
			errors[i] = err
		}

		if !p.args.ParallelBuild {
			f(i, e)
		} else {
			go f(i, e)
		}
	}
	wg.Wait()

	failed := 0
	for _, err := range errors {
		if err != nil {
			failed++
		}
	}
	if failed > 0 {
		return apps, errs.With("Acis process failed").WithErrs(errors...)
	}
	return apps, nil
}

func (p *Pod) processAci(e common.RuntimeApp) (*schema.RuntimeApp, error) {
	aci, err := p.buildAci(e)
	if err != nil {
		return nil, err
	}

	name, err := types.NewACName(e.Name)
	if err != nil {
		return nil, errs.WithEF(err, p.fields.WithField("name", e.Name), "Invalid name format")
	}

	sum, err := Sha512sum(aci.target + pathImageAci)
	if err != nil {
		return nil, errs.WithEF(err, p.fields.WithField("file", aci.target+pathImageAci), "Failed to calculate sha512 of aci")
	}

	tmp, _ := types.NewHash("sha512-" + sum)

	labels := types.Labels{}
	labels = append(labels, types.Label{Name: "version", Value: aci.manifest.NameAndVersion.Version()})
	identifier, _ := types.NewACIdentifier(aci.manifest.NameAndVersion.Name())
	ttmp := schema.RuntimeImage{Name: identifier, ID: *tmp, Labels: labels}

	e.App.Group = aci.manifest.Aci.App.Group
	e.App.User = aci.manifest.Aci.App.User
	if e.App.User == "" {
		e.App.User = "0"
	}
	if e.App.Group == "" {
		e.App.Group = "0"
	}

	isolators, err := common.ToAppcIsolators(e.App.Isolators)
	if err != nil {
		return nil, errs.WithEF(err, p.fields, "Failed to prepare isolators")
	}

	return &schema.RuntimeApp{
		Name:  *name,
		Image: ttmp,
		App: &types.App{
			Exec:              e.App.Exec,
			User:              e.App.User,
			Group:             e.App.Group,
			WorkingDirectory:  e.App.WorkingDirectory,
			SupplementaryGIDs: e.App.SupplementaryGIDs,
			Environment:       e.App.Environment,
			MountPoints:       e.App.MountPoints,
			Ports:             e.App.Ports,
			Isolators:         isolators,
		},
		Mounts:      e.Mounts,
		Annotations: e.Annotations}, nil
}

func (p *Pod) fillRuntimeAppFromDependencies(e *common.RuntimeApp) error {
	fields := p.fields.WithField("aci", e.Name)

	if len(e.Dependencies) >= 1 {
		Home.Rkt.Fetch(e.Dependencies[0].String())
		manifestStr, err := Home.Rkt.CatManifest(e.Dependencies[0].String())
		if err != nil {
			return errs.WithEF(err, fields.WithField("dependency", e.Dependencies[0].String()), "Failed to get dependency manifest")
		}
		manifest := schema.ImageManifest{}
		if err := json.Unmarshal([]byte(manifestStr), &manifest); err != nil {
			return errs.WithEF(err, fields.WithField("content", manifestStr), "Failed to unmarshal stage1 manifest received from rkt")
		}

		if len(e.App.Exec) == 0 {
			e.App.Exec = manifest.App.Exec
		}
		if e.App.User == "" {
			e.App.User = manifest.App.User
		}
		if e.App.Group == "" {
			e.App.Group = manifest.App.Group
		}
		if e.App.WorkingDirectory == "" {
			e.App.WorkingDirectory = manifest.App.WorkingDirectory
		}
		if len(e.App.SupplementaryGIDs) == 0 {
			e.App.SupplementaryGIDs = manifest.App.SupplementaryGIDs
		}
		if len(e.App.Isolators) == 0 {
			res, err := common.FromAppcIsolators(manifest.App.Isolators)
			if err != nil {
				return errs.WithEF(err, fields, "Failed to replicate isolators from aci to pod")
			}
			e.App.Isolators = res
		}
		if len(e.App.Ports) == 0 {
			e.App.Ports = manifest.App.Ports
		}
		if len(e.App.MountPoints) == 0 {
			e.App.MountPoints = manifest.App.MountPoints
		}
		if len(e.App.Environment) == 0 {
			e.App.Environment = manifest.App.Environment
		}

		anns := e.Annotations
		e.Annotations = manifest.Annotations
		for _, ann := range anns {
			e.Annotations.Set(ann.Name, ann.Value)
		}
	}
	return nil
}

func (p *Pod) buildAci(e common.RuntimeApp) (*Aci, error) {
	if err := p.fillRuntimeAppFromDependencies(&e); err != nil {
		return nil, err
	}

	aci, err := p.toPodAci(e)
	if err != nil {
		return nil, err
	}
	if err := aci.CleanAndBuild(); err != nil {
		return nil, errs.WithEF(err, p.fields.WithField("name", e.Name), "build of  pod's aci failed")
	}
	return aci, nil
}

func (p *Pod) writePodManifest(apps []schema.RuntimeApp) error {
	m := p.manifest.Pod
	ver, _ := types.NewSemVer("0.6.1")
	manifest := schema.PodManifest{
		ACKind:      "PodManifest",
		ACVersion:   *ver,
		Apps:        apps,
		Volumes:     m.Volumes,
		Isolators:   m.Isolators,
		Annotations: m.Annotations,
		Ports:       m.Ports}
	return WritePodManifest(&manifest, p.target+pathPodManifestJson)
}

func WritePodManifest(im *schema.PodManifest, targetFile string) error {
	buff, err := json.MarshalIndent(im, "", "  ")
	if err != nil {
		return errs.WithEF(err, data.WithField("object", im), "Failed to marshal manifest")
	}
	err = ioutil.WriteFile(targetFile, []byte(buff), 0644)
	if err != nil {
		return errs.WithEF(err, data.WithField("file", targetFile), "Failed to write pod manifest")
	}
	return nil
}

func (p *Pod) getVolumeMountValue(mountName types.ACName) (*types.Volume, error) {
	for _, volume := range p.manifest.Pod.Volumes {
		if volume.Name.Equals(mountName) {
			return &volume, nil
		}
	}
	return nil, errors.New("Volume mount point not set :" + mountName.String())
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://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 metric

import (
	"context"
	"log"
	"net"
	"os"
	"testing"

	"github.com/golang/protobuf/ptypes/empty"
	"google.golang.org/genproto/googleapis/monitoring/v3"
	"google.golang.org/genproto/googleapis/rpc/status"
	"google.golang.org/genproto/googleapis/api/monitoredres"
	"google.golang.org/genproto/googleapis/api/metric"
	"google.golang.org/grpc"
	"google.golang.org/grpc/test/bufconn"
	"google.golang.org/protobuf/proto"
)

const bufSize = 1024 * 1024

var (
	client monitoring.MetricServiceClient
	conn   *grpc.ClientConn
	ctx    context.Context
	grpcServer *grpc.Server
	lis    *bufconn.Listener
)

func setup() {
	// Setup the in-memory server.
	lis = bufconn.Listen(bufSize)
	grpcServer = grpc.NewServer()
	monitoring.RegisterMetricServiceServer(grpcServer, &MockMetricServer{})
	go func() {
		if err := grpcServer.Serve(lis); err != nil {
			log.Fatalf("server exited with error: %v", err)
		}
	}()

	// Setup the connection and client.
	ctx = context.Background()
	var err error
	conn, err = grpc.DialContext(ctx, "bufnet", grpc.WithContextDialer(bufDialer), grpc.WithInsecure())
	if err != nil {
		log.Fatalf("failed to dial bufnet: %v", err)
	}
	client = monitoring.NewMetricServiceClient(conn)
}

func tearDown() {
	conn.Close()
	grpcServer.GracefulStop()
}

func TestMain(m *testing.M) {
	setup()
	retCode := m.Run()
	tearDown()
	os.Exit(retCode)
}

func bufDialer(context.Context, string) (net.Conn, error) {
	return lis.Dial()
}

func TestMockMetricServer_CreateTimeSeries(t *testing.T) {
	cases := []struct {
		in *monitoring.CreateTimeSeriesRequest
		want *empty.Empty
	}{
		{
			&monitoring.CreateTimeSeriesRequest{
				Name: "test create time series request",
			},
			&empty.Empty{},
		},
	}

	for _, c := range cases {
		response, err := client.CreateTimeSeries(ctx, c.in)
		if err != nil {
			t.Fatalf("failed to call CreateTimeSeries %v", err)
		}

		if !proto.Equal(response, c.want) {
			t.Errorf("CreateTimeSeries(%q) == %q, want %q", c.in, response, c.want)
		}
	}
}

func TestMockMetricServer_ListTimeSeries(t *testing.T) {
	cases := []struct {
		in *monitoring.ListTimeSeriesRequest
		want *monitoring.ListTimeSeriesResponse
	}{
		{
			&monitoring.ListTimeSeriesRequest{
				Name: "test list time series request",
			},
			&monitoring.ListTimeSeriesResponse{
				TimeSeries:      []*monitoring.TimeSeries{},
				NextPageToken:   "",
				ExecutionErrors: []*status.Status{},
			},
		},
	}

	for _, c := range cases {
		response, err := client.ListTimeSeries(ctx, c.in)
		if err != nil {
			t.Fatalf("failed to call ListTimeSeries %v", err)
		}

		if !proto.Equal(response, c.want) {
			t.Errorf("ListTimeSeries(%q) == %q, want %q", c.in, response, c.want)
		}
	}
}

func TestMockMetricServer_GetMonitoredResourceDescriptor(t *testing.T) {
	cases := []struct {
		in *monitoring.GetMonitoredResourceDescriptorRequest
		want *monitoredres.MonitoredResourceDescriptor
	}{
		{
			&monitoring.GetMonitoredResourceDescriptorRequest{
				Name: "test get metric monitored resource descriptor",
			},
			&monitoredres.MonitoredResourceDescriptor{},
		},
	}

	for _, c := range cases {
		response, err := client.GetMonitoredResourceDescriptor(ctx, c.in)
		if err != nil {
			t.Fatalf("failed to call GetMonitoredResourceDescriptor %v", err)
		}

		if !proto.Equal(response, c.want) {
			t.Errorf("GetMonitoredResourceDescriptor(%q) == %q, want %q", c.in, response, c.want)
		}
	}
}

func TestMockMetricServer_ListMonitoredResourceDescriptors(t *testing.T) {
	cases := []struct {
		in *monitoring.ListMonitoredResourceDescriptorsRequest
		want *monitoring.ListMonitoredResourceDescriptorsResponse
	}{
		{
			&monitoring.ListMonitoredResourceDescriptorsRequest{
				Name: "test list monitored resource descriptors",
			},
			&monitoring.ListMonitoredResourceDescriptorsResponse{
				ResourceDescriptors: []*monitoredres.MonitoredResourceDescriptor{},
			},
		},
	}

	for _, c := range cases {
		response, err := client.ListMonitoredResourceDescriptors(ctx, c.in)
		if err != nil {
			t.Fatalf("failed to call ListMonitoredResourceDescriptors %v", err)
		}

		if !proto.Equal(response, c.want) {
			t.Errorf("ListMonitoredResourceDescriptors(%q) == %q, want %q", c.in, response, c.want)
		}
	}
}

func TestMockMetricServer_GetMetricDescriptor(t *testing.T) {
	cases := []struct {
		in *monitoring.GetMetricDescriptorRequest
		want *metric.MetricDescriptor
	}{
		{
			&monitoring.GetMetricDescriptorRequest{
				Name: "test get metric descriptor",
			},
			&metric.MetricDescriptor{},
		},
	}

	for _, c := range cases {
		response, err := client.GetMetricDescriptor(ctx, c.in)
		if err != nil {
			t.Fatalf("failed to call GetMetricDescriptor %v", err)
		}

		if !proto.Equal(response, c.want) {
			t.Errorf("GetMetricDescriptor(%q) == %q, want %q", c.in, response, c.want)
		}
	}
}

func TestMockMetricServer_CreateMetricDescriptor(t *testing.T) {
	cases := []struct {
		in *monitoring.CreateMetricDescriptorRequest
		want *metric.MetricDescriptor
	}{
		{
			&monitoring.CreateMetricDescriptorRequest{
				Name: "test create metric descriptor",
				MetricDescriptor: &metric.MetricDescriptor{},
			},
			&metric.MetricDescriptor{},
		},
	}

	for _, c := range cases {
		response, err := client.CreateMetricDescriptor(ctx, c.in)
		if err != nil {
			t.Fatalf("failed to call CreateMetricDescriptorRequest: %v", err)
		}

		if !proto.Equal(response, c.want) {
			t.Errorf("CreateMetricDescriptorRequest(%q) == %q, want %q", c.in, response, c.want)
		}
	}
}

func TestMockMetricServer_DeleteMetricDescriptor(t *testing.T) {
	cases := []struct {
		in *monitoring.DeleteMetricDescriptorRequest
		want *empty.Empty
	}{
		{
			&monitoring.DeleteMetricDescriptorRequest{
				Name: "test create metric descriptor",
			},
			&empty.Empty{},
		},
	}

	for _, c := range cases {
		response, err := client.DeleteMetricDescriptor(ctx, c.in)
		if err != nil {
			t.Fatalf("failed to call DeleteMetricDescriptorRequest: %v", err)
		}

		if !proto.Equal(response, c.want) {
			t.Errorf("DeleteMetricDescriptorRequest(%q) == %q, want %q", c.in, response, c.want)
		}
	}
}

func TestMockMetricServer_ListMetricDescriptors(t *testing.T) {
	cases := []struct {
		in *monitoring.ListMetricDescriptorsRequest
		want *monitoring.ListMetricDescriptorsResponse
	}{
		{
			&monitoring.ListMetricDescriptorsRequest{
				Name: "test list metric decriptors request",
			},
			&monitoring.ListMetricDescriptorsResponse{
				MetricDescriptors: []*metric.MetricDescriptor{},
				NextPageToken:     "",
			},
		},
	}

	for _, c := range cases {
		response, err := client.ListMetricDescriptors(ctx, c.in)
		if err != nil {
			t.Fatalf("failed to call ListMetricDescriptors %v", err)
		}

		if !proto.Equal(response, c.want) {
			t.Errorf("ListMetricDescriptors(%q) == %q, want %q", c.in, response, c.want)
		}
	}
}<commit_msg>replace "cases" with just single in/want for tests<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://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 metric

import (
	"context"
	"log"
	"net"
	"os"
	"testing"

	"github.com/golang/protobuf/ptypes/empty"
	"google.golang.org/genproto/googleapis/monitoring/v3"
	"google.golang.org/genproto/googleapis/rpc/status"
	"google.golang.org/genproto/googleapis/api/monitoredres"
	"google.golang.org/genproto/googleapis/api/metric"
	"google.golang.org/grpc"
	"google.golang.org/grpc/test/bufconn"
	"google.golang.org/protobuf/proto"
)

const bufSize = 1024 * 1024

var (
	client monitoring.MetricServiceClient
	conn   *grpc.ClientConn
	ctx    context.Context
	grpcServer *grpc.Server
	lis    *bufconn.Listener
)

func setup() {
	// Setup the in-memory server.
	lis = bufconn.Listen(bufSize)
	grpcServer = grpc.NewServer()
	monitoring.RegisterMetricServiceServer(grpcServer, &MockMetricServer{})
	go func() {
		if err := grpcServer.Serve(lis); err != nil {
			log.Fatalf("server exited with error: %v", err)
		}
	}()

	// Setup the connection and client.
	ctx = context.Background()
	var err error
	conn, err = grpc.DialContext(ctx, "bufnet", grpc.WithContextDialer(bufDialer), grpc.WithInsecure())
	if err != nil {
		log.Fatalf("failed to dial bufnet: %v", err)
	}
	client = monitoring.NewMetricServiceClient(conn)
}

func tearDown() {
	conn.Close()
	grpcServer.GracefulStop()
}

func TestMain(m *testing.M) {
	setup()
	retCode := m.Run()
	tearDown()
	os.Exit(retCode)
}

func bufDialer(context.Context, string) (net.Conn, error) {
	return lis.Dial()
}

func TestMockMetricServer_CreateTimeSeries(t *testing.T) {
	in := &monitoring.CreateTimeSeriesRequest{
		Name: "test create time series request",
	}
	want :=	&empty.Empty{}
	response, err := client.CreateTimeSeries(ctx, in)
	if err != nil {
		t.Fatalf("failed to call CreateTimeSeries %v", err)
	}

	if !proto.Equal(response, want) {
		t.Errorf("CreateTimeSeries(%q) == %q, want %q", in, response, want)
	}
}

func TestMockMetricServer_ListTimeSeries(t *testing.T) {
	in := &monitoring.ListTimeSeriesRequest{
		Name: "test list time series request",
	}
	want := &monitoring.ListTimeSeriesResponse{
		TimeSeries:      []*monitoring.TimeSeries{},
		NextPageToken:   "",
		ExecutionErrors: []*status.Status{},
	}

	response, err := client.ListTimeSeries(ctx, in)
	if err != nil {
		t.Fatalf("failed to call ListTimeSeries %v", err)
	}

	if !proto.Equal(response, want) {
		t.Errorf("ListTimeSeries(%q) == %q, want %q", in, response, want)
	}
}

func TestMockMetricServer_GetMonitoredResourceDescriptor(t *testing.T) {
	in := &monitoring.GetMonitoredResourceDescriptorRequest{
		Name: "test get metric monitored resource descriptor",
	}
	want := &monitoredres.MonitoredResourceDescriptor{}
	response, err := client.GetMonitoredResourceDescriptor(ctx, in)
	if err != nil {
		t.Fatalf("failed to call GetMonitoredResourceDescriptor %v", err)
	}

	if !proto.Equal(response, want) {
		t.Errorf("GetMonitoredResourceDescriptor(%q) == %q, want %q", in, response, want)
	}
}

func TestMockMetricServer_ListMonitoredResourceDescriptors(t *testing.T) {
	in := &monitoring.ListMonitoredResourceDescriptorsRequest{
		Name: "test list monitored resource descriptors",
	}
	want := &monitoring.ListMonitoredResourceDescriptorsResponse{
		ResourceDescriptors: []*monitoredres.MonitoredResourceDescriptor{},
	}
	response, err := client.ListMonitoredResourceDescriptors(ctx, in)
	if err != nil {
		t.Fatalf("failed to call ListMonitoredResourceDescriptors %v", err)
	}

	if !proto.Equal(response, want) {
		t.Errorf("ListMonitoredResourceDescriptors(%q) == %q, want %q", in, response, want)
	}
}

func TestMockMetricServer_GetMetricDescriptor(t *testing.T) {
	in := &monitoring.GetMetricDescriptorRequest{
		Name: "test get metric descriptor",
	}
	want := &metric.MetricDescriptor{}
	response, err := client.GetMetricDescriptor(ctx, in)
	if err != nil {
		t.Fatalf("failed to call GetMetricDescriptor %v", err)
	}

	if !proto.Equal(response, want) {
		t.Errorf("GetMetricDescriptor(%q) == %q, want %q", in, response, want)
	}
}

func TestMockMetricServer_CreateMetricDescriptor(t *testing.T) {
	in := &monitoring.CreateMetricDescriptorRequest{
		Name: "test create metric descriptor",
		MetricDescriptor: &metric.MetricDescriptor{},
	}
	want := &metric.MetricDescriptor{}

	response, err := client.CreateMetricDescriptor(ctx, in)
	if err != nil {
		t.Fatalf("failed to call CreateMetricDescriptorRequest: %v", err)
	}

	if !proto.Equal(response, want) {
		t.Errorf("CreateMetricDescriptorRequest(%q) == %q, want %q", in, response, want)
	}
}

func TestMockMetricServer_DeleteMetricDescriptor(t *testing.T) {
	in := &monitoring.DeleteMetricDescriptorRequest{
		Name: "test create metric descriptor",
	}
	want := &empty.Empty{}

	response, err := client.DeleteMetricDescriptor(ctx, in)
	if err != nil {
		t.Fatalf("failed to call DeleteMetricDescriptorRequest: %v", err)
	}

	if !proto.Equal(response, want) {
		t.Errorf("DeleteMetricDescriptorRequest(%q) == %q, want %q", in, response, want)
	}
}

func TestMockMetricServer_ListMetricDescriptors(t *testing.T) {
	in := &monitoring.ListMetricDescriptorsRequest{
		Name: "test list metric decriptors request",
	}
	want := &monitoring.ListMetricDescriptorsResponse{
		MetricDescriptors: []*metric.MetricDescriptor{},
	}
	response, err := client.ListMetricDescriptors(ctx, in)
	if err != nil {
		t.Fatalf("failed to call ListMetricDescriptors %v", err)
	}

	if !proto.Equal(response, want) {
		t.Errorf("ListMetricDescriptors(%q) == %q, want %q", in, response, want)
	}
}<|endoftext|>


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

package dochtml

const tmplSidenav = `
{{if or .Doc .Consts .Vars .Funcs .Types .Examples.List}}
	` + IdentifierSidenavStart + `

			{{if or .Doc (index .Examples.Map "")}}

					Overview

			{{end}}
			{{- if or .Consts .Vars .Funcs .Types .Examples.List -}}

					Index

					Constants

					Variables

					Functions

						{{range .Funcs}}

								{{render_short_synopsis .Decl}}

						{{end}}

					Types

						{{range .Types}}
							{{$tname := .Name}}

								{{if or .Funcs .Methods}}
									{{$navgroupname := (printf "nav.group.%s" $tname)}}
									{{$navgroupid := (safe_id $navgroupname)}}
									type {{$tname}}

										{{range .Funcs}}

												{{render_short_synopsis .Decl}}

										{{end}}
										{{range .Methods}}

												{{render_short_synopsis .Decl}}

										{{end}}

								{{else}}
									type {{$tname}}
								{{end}} {{/* if or .Funcs .Methods */}}

						{{end}} {{/* range .Types */}}

					Notes

						{{range $marker, $item := .Notes}}

								{{$marker}}s

						{{end}}

			{{end}}

	` + IdentifierSidenavMobileStart + `

			<svg class="DocNavMobile-selectIcon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="black" width="18px" height="18px">
				<path d="M0 0h24v24H0z" fill="none"/><path d="M3 9h14V7H3v2zm0 4h14v-2H3v2zm0 4h14v-2H3v2zm16 0h2v-2h-2v2zm0-10v2h2V7h-2zm0 6h2v-2h-2v2z"/>
			</svg>
			Outline

		<select id="DocNavMobile-select" class="DocNavMobile-select">
			<option value="">Outline</option>
			{{if or .Doc (index .Examples.Map "")}}
				<option value="pkg-overview">Overview</option>
			{{end}}
			{{if .Examples.List}}
				<option value="pkg-examples">Examples</option>
			{{end}}
			{{if .Consts}}
				<option value="pkg-constants">Constants</option>
			{{end}}
			{{if .Vars}}
				<option value="pkg-variables">Variables</option>
			{{end}}

			{{if .Funcs}}
				<optgroup label="Functions">
					{{range .Funcs}}
						<option value="{{.Name}}">{{render_short_synopsis .Decl}}</option>
					{{end}}
				</optgroup>
			{{end}}

			{{if .Types}}
				<optgroup label="Types">
					{{range .Types}}
						{{$tname := .Name}}
						<option value="{{$tname}}">type {{$tname}}</option>
						{{range .Funcs}}
							<option value="{{.Name}}">{{render_short_synopsis .Decl}}</option>
						{{end}}
						{{range .Methods}}
							<option value="{{$tname}}.{{.Name}}">{{render_short_synopsis .Decl}}</option>
						{{end}}
					{{end}} {{/* range .Types */}}
				</optgroup>
			{{end}}

			{{if .Notes}}
				<optgroup label="Notes">
					{{range $marker, $item := .Notes}}
						<option value="pkg-note-{{$marker}}">{{$marker}}s</option>
					{{end}}
				</optgroup>
			{{end}}
		</select>
	` + IdentifierSidenavEnd + `
{{end}}`
<commit_msg>internal/godoc: collapse top level headings in doc outline<commit_after>// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package dochtml

const tmplSidenav = `
{{if or .Doc .Consts .Vars .Funcs .Types .Examples.List}}
	` + IdentifierSidenavStart + `

			{{if or .Doc (index .Examples.Map "")}}

					Overview

			{{end}}
			{{- if or .Consts .Vars .Funcs .Types .Examples.List -}}

					Index

					Constants

					Variables

					Functions

						{{range .Funcs}}

								{{render_short_synopsis .Decl}}

						{{end}}

					Types

						{{range .Types}}
							{{$tname := .Name}}

								{{if or .Funcs .Methods}}
									{{$navgroupname := (printf "nav.group.%s" $tname)}}
									{{$navgroupid := (safe_id $navgroupname)}}
									type {{$tname}}

										{{range .Funcs}}

												{{render_short_synopsis .Decl}}

										{{end}}
										{{range .Methods}}

												{{render_short_synopsis .Decl}}

										{{end}}

								{{else}}
									type {{$tname}}
								{{end}} {{/* if or .Funcs .Methods */}}

						{{end}} {{/* range .Types */}}

					Notes

						{{range $marker, $item := .Notes}}

								{{$marker}}s

						{{end}}

			{{end}}

	` + IdentifierSidenavMobileStart + `

			<svg class="DocNavMobile-selectIcon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="black" width="18px" height="18px">
				<path d="M0 0h24v24H0z" fill="none"/><path d="M3 9h14V7H3v2zm0 4h14v-2H3v2zm0 4h14v-2H3v2zm16 0h2v-2h-2v2zm0-10v2h2V7h-2zm0 6h2v-2h-2v2z"/>
			</svg>
			Outline

		<select id="DocNavMobile-select" class="DocNavMobile-select">
			<option value="">Outline</option>
			{{if or .Doc (index .Examples.Map "")}}
				<option value="pkg-overview">Overview</option>
			{{end}}
			{{if .Examples.List}}
				<option value="pkg-examples">Examples</option>
			{{end}}
			{{if .Consts}}
				<option value="pkg-constants">Constants</option>
			{{end}}
			{{if .Vars}}
				<option value="pkg-variables">Variables</option>
			{{end}}

			{{if .Funcs}}
				<optgroup label="Functions">
					{{range .Funcs}}
						<option value="{{.Name}}">{{render_short_synopsis .Decl}}</option>
					{{end}}
				</optgroup>
			{{end}}

			{{if .Types}}
				<optgroup label="Types">
					{{range .Types}}
						{{$tname := .Name}}
						<option value="{{$tname}}">type {{$tname}}</option>
						{{range .Funcs}}
							<option value="{{.Name}}">{{render_short_synopsis .Decl}}</option>
						{{end}}
						{{range .Methods}}
							<option value="{{$tname}}.{{.Name}}">{{render_short_synopsis .Decl}}</option>
						{{end}}
					{{end}} {{/* range .Types */}}
				</optgroup>
			{{end}}

			{{if .Notes}}
				<optgroup label="Notes">
					{{range $marker, $item := .Notes}}
						<option value="pkg-note-{{$marker}}">{{$marker}}s</option>
					{{end}}
				</optgroup>
			{{end}}
		</select>
	` + IdentifierSidenavEnd + `
{{end}}`
<|endoftext|>


<commit_before>// BaruwaAPI Golang bindings for Baruwa REST API
// Copyright (C) 2019 Andrew Colin Kissa <andrew@topdog.za.net>

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.

package api
<commit_msg>TST: Add Relay Servers tests<commit_after>// BaruwaAPI Golang bindings for Baruwa REST API
// Copyright (C) 2019 Andrew Colin Kissa <andrew@topdog.za.net>

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.

package api

import (
	"fmt"
	"net/http"
	"testing"
)

func TestGetRelaySettingError(t *testing.T) {
	data := ``
	server, client, err := getTestServerAndClient(http.StatusOK, data)
	if err != nil {
		t.Fatalf("An error should not be returned")
	}
	defer server.Close()
	rs, err := client.GetRelaySetting(0)
	if err == nil {
		t.Fatalf("An error should be returned")
	}
	if err.Error() != relayIDError {
		t.Errorf("Expected '%s' got '%s'", relayIDError, err)
	}
	if rs != nil {
		t.Errorf("Expected %v got %v", nil, rs)
	}
}

func TestGetRelaySettingOK(t *testing.T) {
	serverID := 3
	data := fmt.Sprintf(`
	{
		"username": "outboundsmtp",
		"description": "Backup-outbound-smtp",
		"enabled": true,
		"require_tls": false,
		"spam_actions": 2,
		"low_score": 10.0,
		"high_score": 15.0,
		"address": "192.168.1.20",
		"id": %d,
		"highspam_actions": 3
	}
	`, serverID)
	server, client, err := getTestServerAndClient(http.StatusOK, data)
	if err != nil {
		t.Fatalf("An error should not be returned")
	}
	defer server.Close()
	rs, err := client.GetRelaySetting(serverID)
	if err != nil {
		t.Fatalf("An error should not be returned")
	}
	if rs.ID != serverID {
		t.Errorf("Expected %d got %d", serverID, rs.ID)
	}
}

func TestCreateRelaySettingError(t *testing.T) {
	data := ``
	server, client, err := getTestServerAndClient(http.StatusOK, data)
	if err != nil {
		t.Fatalf("An error should not be returned")
	}
	defer server.Close()
	err = client.CreateRelaySetting(0, nil)
	if err == nil {
		t.Fatalf("An error should be returned")
	}
	if err.Error() != organizationIDError {
		t.Errorf("Expected '%s' got '%s'", organizationIDError, err)
	}
	err = client.CreateRelaySetting(1, nil)
	if err == nil {
		t.Fatalf("An error should be returned")
	}
	if err.Error() != serverParamError {
		t.Errorf("Expected '%s' got '%s'", serverParamError, err)
	}
}

func TestCreateRelaySettingOK(t *testing.T) {
	serverID := 3
	data := fmt.Sprintf(`
	{
		"username": "outboundsmtp",
		"description": "Backup-outbound-smtp",
		"enabled": true,
		"require_tls": false,
		"spam_actions": 2,
		"low_score": 10.0,
		"high_score": 15.0,
		"address": "192.168.1.20",
		"id": %d,
		"highspam_actions": 3
	}
	`, serverID)
	server, client, err := getTestServerAndClient(http.StatusOK, data)
	if err != nil {
		t.Fatalf("An error should not be returned")
	}
	defer server.Close()
	rs := &RelaySetting{
		Username:        "outboundsmtp",
		Description:     "Backup-outbound-smtp",
		Enabled:         true,
		SpamActions:     2,
		LowScore:        10.0,
		HighScore:       15.0,
		Address:         "192.168.1.20",
		HighSpamActions: 3,
	}
	err = client.CreateRelaySetting(1, rs)
	if err != nil {
		t.Fatalf("An error should not be returned")
	}
	if rs.ID != serverID {
		t.Errorf("Expected %d got %d", serverID, rs.ID)
	}
}

func TestUpdateRelaySettingError(t *testing.T) {
	data := ``
	server, client, err := getTestServerAndClient(http.StatusOK, data)
	if err != nil {
		t.Fatalf("An error should not be returned")
	}
	defer server.Close()
	err = client.UpdateRelaySetting(nil)
	if err == nil {
		t.Fatalf("An error should be returned")
	}
	if err.Error() != serverParamError {
		t.Errorf("Expected '%s' got '%s'", serverParamError, err)
	}
	rs := &RelaySetting{
		Username:        "outboundsmtp",
		Description:     "Backup-outbound-smtp",
		Enabled:         true,
		SpamActions:     2,
		LowScore:        10.0,
		HighScore:       15.0,
		Address:         "192.168.1.20",
		HighSpamActions: 3,
	}
	err = client.UpdateRelaySetting(rs)
	if err == nil {
		t.Fatalf("An error should be returned")
	}
	if err.Error() != serverSIDError {
		t.Errorf("Expected '%s' got '%s'", serverSIDError, err)
	}
}

func TestUpdateRelaySettingOK(t *testing.T) {
	serverID := 3
	data := fmt.Sprintf(`
	{
		"username": "outboundsmtp",
		"description": "Backup-outbound-smtp",
		"enabled": true,
		"require_tls": false,
		"spam_actions": 2,
		"low_score": 10.0,
		"high_score": 15.0,
		"address": "192.168.1.20",
		"id": %d,
		"highspam_actions": 3
	}
	`, serverID)
	server, client, err := getTestServerAndClient(http.StatusOK, data)
	if err != nil {
		t.Fatalf("An error should not be returned")
	}
	defer server.Close()
	rs := &RelaySetting{
		ID:              serverID,
		Username:        "outboundsmtp",
		Description:     "Backup-outbound-smtp",
		Enabled:         true,
		SpamActions:     2,
		LowScore:        10.0,
		HighScore:       15.0,
		Address:         "192.168.1.20",
		HighSpamActions: 3,
	}
	err = client.UpdateRelaySetting(rs)
	if err != nil {
		t.Fatalf("An error should not be returned")
	}
}

func TestDeleteRelaySettingError(t *testing.T) {
	data := ``
	server, client, err := getTestServerAndClient(http.StatusOK, data)
	if err != nil {
		t.Fatalf("An error should not be returned")
	}
	defer server.Close()
	err = client.DeleteRelaySetting(nil)
	if err == nil {
		t.Fatalf("An error should be returned")
	}
	if err.Error() != serverParamError {
		t.Errorf("Expected '%s' got '%s'", serverParamError, err)
	}
	rs := &RelaySetting{
		Username:        "outboundsmtp",
		Description:     "Backup-outbound-smtp",
		Enabled:         true,
		SpamActions:     2,
		LowScore:        10.0,
		HighScore:       15.0,
		Address:         "192.168.1.20",
		HighSpamActions: 3,
	}
	err = client.DeleteRelaySetting(rs)
	if err == nil {
		t.Fatalf("An error should be returned")
	}
	if err.Error() != serverSIDError {
		t.Errorf("Expected '%s' got '%s'", serverSIDError, err)
	}
}

func TestDeleteRelaySettingOK(t *testing.T) {
	serverID := 3
	data := ``
	server, client, err := getTestServerAndClient(http.StatusOK, data)
	if err != nil {
		t.Fatalf("An error should not be returned")
	}
	defer server.Close()
	rs := &RelaySetting{
		ID:              serverID,
		Username:        "outboundsmtp",
		Description:     "Backup-outbound-smtp",
		Enabled:         true,
		SpamActions:     2,
		LowScore:        10.0,
		HighScore:       15.0,
		Address:         "192.168.1.20",
		HighSpamActions: 3,
	}
	err = client.DeleteRelaySetting(rs)
	if err != nil {
		t.Fatalf("An error should not be returned")
	}
}
<|endoftext|>


<commit_before>/*
 * This file is part of the kubevirt project
 *
 * 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.
 *
 * Copyright 2018 Red Hat, Inc.
 *
 */

package tests_test

import (
	"flag"
	"fmt"
	"strings"
	"time"

	expect "github.com/google/goexpect"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	k8sv1 "k8s.io/api/core/v1"

	"kubevirt.io/kubevirt/pkg/api/v1"
	"kubevirt.io/kubevirt/pkg/kubecli"
	"kubevirt.io/kubevirt/pkg/log"
	"kubevirt.io/kubevirt/tests"
)

var _ = Describe("Networking", func() {

	flag.Parse()

	virtClient, err := kubecli.GetKubevirtClient()
	tests.PanicOnError(err)

	var vmi *v1.VirtualMachineInstance
	var container k8sv1.Container

	FContext("VirtualMachineInstance with slirp interface", func() {
		tests.BeforeAll(func() {
			ports := []v1.Port{{Name: "http", Port: 80}}
			vmi = tests.NewRandomVMIWithSlirpInterfaceEphemeralDiskAndUserdata(tests.RegistryDiskFor(tests.RegistryDiskCirros), "#!/bin/bash\necho 'hello'\n", ports)
			vmi, err = virtClient.VirtualMachineInstance(tests.NamespaceTestDefault).Create(vmi)
			Expect(err).ToNot(HaveOccurred())
			tests.WaitForSuccessfulVMIStartIgnoreWarnings(vmi)
			generateHelloWorldServer(vmi, virtClient, 80, "tcp")
		})
		FIt("should contains containerPort in the pod manifest", func() {
			vmiPod := tests.GetRunningPodByLabel(vmi.Name, v1.DomainLabel, tests.NamespaceTestDefault)
			for _, containerSpec := range vmiPod.Spec.Containers {
				if containerSpec.Name == "compute" {
					container = containerSpec
					break
				}
			}
			Expect(container.Name).ToNot(Equal(""))
			Expect(container.Ports).ToNot(Equal(nil))
			Expect(container.Ports[0].Name).To(Equal("http"))
			Expect(container.Ports[0].Protocol).To(Equal(k8sv1.Protocol("TCP")))
			Expect(container.Ports[0].ContainerPort).To(Equal(int32(80)))
		})
		It("should start the virtial machine with slirp interface", func() {
			vmiPod := tests.GetRunningPodByLabel(vmi.Name, v1.DomainLabel, tests.NamespaceTestDefault)
			output, err := tests.ExecuteCommandOnPod(
				virtClient,
				vmiPod,
				vmiPod.Spec.Containers[1].Name,
				[]string{"netstat", "-tnlp"},
			)
			log.Log.Infof("%v", output)
			Expect(err).ToNot(HaveOccurred())
			Expect(strings.Contains(output, "0.0.0.0:80")).To(BeTrue())
		})
		It("should return \"Hello World\" when connecting to localhost on port 80", func() {
			vmiPod := tests.GetRunningPodByLabel(vmi.Name, v1.DomainLabel, tests.NamespaceTestDefault)
			output, err := tests.ExecuteCommandOnPod(
				virtClient,
				vmiPod,
				vmiPod.Spec.Containers[1].Name,
				[]string{"curl", "-s", "--retry", "30", "--retry-delay", "30", "127.0.0.1"},
			)
			fmt.Println(err)
			log.Log.Infof("%v", output)
			Expect(err).ToNot(HaveOccurred())
			Expect(strings.Contains(output, "Hello World!")).To(BeTrue())
		})
		It("should reject the connecting to localhost and port different than 80", func() {
			vmiPod := tests.GetRunningPodByLabel(vmi.Name, v1.DomainLabel, tests.NamespaceTestDefault)
			output, err := tests.ExecuteCommandOnPod(
				virtClient,
				vmiPod,
				vmiPod.Spec.Containers[1].Name,
				[]string{"curl", "127.0.0.1:9080"},
			)
			log.Log.Infof("%v", output)
			Expect(err).To(HaveOccurred())
		})
		It("should be able to communicate with the outside world", func() {
			expecter, _, err := tests.NewConsoleExpecter(virtClient, vmi, 10*time.Second)
			defer expecter.Close()
			Expect(err).ToNot(HaveOccurred())

			out, err := expecter.ExpectBatch([]expect.Batcher{
				&expect.BSnd{S: "\n"},
				&expect.BExp{R: "\\$ "},
				&expect.BSnd{S: "curl -o /dev/null -s -w \"%{http_code}\\n\" -k https://google.com\n"},
				&expect.BExp{R: "301"},
			}, 180*time.Second)
			log.Log.Infof("%v", out)
			Expect(err).ToNot(HaveOccurred())
		})
	})
})
<commit_msg>Remove 'F' in the test<commit_after>/*
 * This file is part of the kubevirt project
 *
 * 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.
 *
 * Copyright 2018 Red Hat, Inc.
 *
 */

package tests_test

import (
	"flag"
	"fmt"
	"strings"
	"time"

	expect "github.com/google/goexpect"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	k8sv1 "k8s.io/api/core/v1"

	"kubevirt.io/kubevirt/pkg/api/v1"
	"kubevirt.io/kubevirt/pkg/kubecli"
	"kubevirt.io/kubevirt/pkg/log"
	"kubevirt.io/kubevirt/tests"
)

var _ = Describe("Networking", func() {

	flag.Parse()

	virtClient, err := kubecli.GetKubevirtClient()
	tests.PanicOnError(err)

	var vmi *v1.VirtualMachineInstance
	var container k8sv1.Container

	Context("VirtualMachineInstance with slirp interface", func() {
		tests.BeforeAll(func() {
			ports := []v1.Port{{Name: "http", Port: 80}}
			vmi = tests.NewRandomVMIWithSlirpInterfaceEphemeralDiskAndUserdata(tests.RegistryDiskFor(tests.RegistryDiskCirros), "#!/bin/bash\necho 'hello'\n", ports)
			vmi, err = virtClient.VirtualMachineInstance(tests.NamespaceTestDefault).Create(vmi)
			Expect(err).ToNot(HaveOccurred())
			tests.WaitForSuccessfulVMIStartIgnoreWarnings(vmi)
			generateHelloWorldServer(vmi, virtClient, 80, "tcp")
		})
		It("should contains containerPort in the pod manifest", func() {
			vmiPod := tests.GetRunningPodByLabel(vmi.Name, v1.DomainLabel, tests.NamespaceTestDefault)
			for _, containerSpec := range vmiPod.Spec.Containers {
				if containerSpec.Name == "compute" {
					container = containerSpec
					break
				}
			}
			Expect(container.Name).ToNot(Equal(""))
			Expect(container.Ports).ToNot(Equal(nil))
			Expect(container.Ports[0].Name).To(Equal("http"))
			Expect(container.Ports[0].Protocol).To(Equal(k8sv1.Protocol("TCP")))
			Expect(container.Ports[0].ContainerPort).To(Equal(int32(80)))
		})
		It("should start the virtial machine with slirp interface", func() {
			vmiPod := tests.GetRunningPodByLabel(vmi.Name, v1.DomainLabel, tests.NamespaceTestDefault)
			output, err := tests.ExecuteCommandOnPod(
				virtClient,
				vmiPod,
				vmiPod.Spec.Containers[1].Name,
				[]string{"netstat", "-tnlp"},
			)
			log.Log.Infof("%v", output)
			Expect(err).ToNot(HaveOccurred())
			Expect(strings.Contains(output, "0.0.0.0:80")).To(BeTrue())
		})
		It("should return \"Hello World\" when connecting to localhost on port 80", func() {
			vmiPod := tests.GetRunningPodByLabel(vmi.Name, v1.DomainLabel, tests.NamespaceTestDefault)
			output, err := tests.ExecuteCommandOnPod(
				virtClient,
				vmiPod,
				vmiPod.Spec.Containers[1].Name,
				[]string{"curl", "-s", "--retry", "30", "--retry-delay", "30", "127.0.0.1"},
			)
			fmt.Println(err)
			log.Log.Infof("%v", output)
			Expect(err).ToNot(HaveOccurred())
			Expect(strings.Contains(output, "Hello World!")).To(BeTrue())
		})
		It("should reject the connecting to localhost and port different than 80", func() {
			vmiPod := tests.GetRunningPodByLabel(vmi.Name, v1.DomainLabel, tests.NamespaceTestDefault)
			output, err := tests.ExecuteCommandOnPod(
				virtClient,
				vmiPod,
				vmiPod.Spec.Containers[1].Name,
				[]string{"curl", "127.0.0.1:9080"},
			)
			log.Log.Infof("%v", output)
			Expect(err).To(HaveOccurred())
		})
		It("should be able to communicate with the outside world", func() {
			expecter, _, err := tests.NewConsoleExpecter(virtClient, vmi, 10*time.Second)
			defer expecter.Close()
			Expect(err).ToNot(HaveOccurred())

			out, err := expecter.ExpectBatch([]expect.Batcher{
				&expect.BSnd{S: "\n"},
				&expect.BExp{R: "\\$ "},
				&expect.BSnd{S: "curl -o /dev/null -s -w \"%{http_code}\\n\" -k https://google.com\n"},
				&expect.BExp{R: "301"},
			}, 180*time.Second)
			log.Log.Infof("%v", out)
			Expect(err).ToNot(HaveOccurred())
		})
	})
})
<|endoftext|>


<commit_before>package manager

type Client struct {

}

type ResourceOwner struct {

}

type AccessToken struct {

}

type RefreshToken struct {

}

type AuthorizationCode struct {

}

type Delegate interface {
	LoadAccessToken() *AccessToken
}

type Manager struct {

}
<commit_msg>removed manager<commit_after><|endoftext|>


<commit_before>package bitbucket

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/url"
)

// Bitbucket POSTs to the service URL you specify. The service
// receives an POST whenever user pushes to the repository.
const BrokerTypePost = "POST"

const BrokerTypePullRequestPost = "Pull Request POST"

type Broker struct {
	// A Bitbucket assigned integer representing a unique
	// identifier for the service.
	Id int `json:"id"`

	// A profile describing the service.
	Profile *BrokerProfile `json:"service"`
}

type BrokerProfile struct {
	// One of the supported services. The type is a
	// case-insensitive value.
	Type string `json:"type"`

	// A parameter array containing a name and value pair
	// for each parameter associated with the service.
	Fields []*BrokerField `json:"fields"`
}

type BrokerField struct {
	Name  string `json:"name"`
	Value string `json:"value"`
}

// Bitbucket offers integration with external services by allowing a set of
// services, or brokers, to run at certain events.
//
// The Bitbucket services resource provides functionality for adding,
// removing, and configuring brokers on your repositories.  All the methods
// on this resource require the caller to authenticate.
//
// https://confluence.atlassian.com/display/BITBUCKET/services+Resource
type BrokerResource struct {
	client *Client
}

func (r *BrokerResource) List(owner, slug string) ([]*Broker, error) {
	brokers := []*Broker{}
	path := fmt.Sprintf("/repositories/%s/%s/services", owner, slug)

	if err := r.client.do("GET", path, nil, nil, &brokers); err != nil {
		return nil, err
	}

	return brokers, nil
}

func (r *BrokerResource) Find(owner, slug string, id int) (*Broker, error) {
	brokers := []*Broker{}
	path := fmt.Sprintf("/repositories/%s/%s/services/%v", owner, slug, id)

	if err := r.client.do("GET", path, nil, nil, &brokers); err != nil {
		return nil, err
	}

	if len(brokers) == 0 {
		return nil, ErrNotFound
	}

	return brokers[0], nil
}

func (r *BrokerResource) FindUrl(owner, slug, link, brokerType string) (*Broker, error) {
	brokers, err := r.List(owner, slug)
	if err != nil {
		return nil, err
	}

	//fmt.Println("Total borkers:", len(brokers))

	// iterate though list of brokers
	for _, broker := range brokers {
		if broker.Profile != nil && broker.Profile.Fields != nil {
			//fmt.Printf("Compare: %v == %v is %v\n", broker.Profile.Type, brokerType, broker.Profile.Type == brokerType)
			if broker.Profile.Type != brokerType {
				continue
			}
			// iterate through list of fields
			for _, field := range broker.Profile.Fields {
				//fmt.Printf("-->%v==%v\n", field.Name, field.Value)
				if field.Name == "URL" && field.Value == link {
					//	fmt.Println("Found match")
					return broker, nil
				}
			}
			//fmt.Println("Skipping...")
		}
	}

	//fmt.Println("Not match found")
	return nil, ErrNotFound
}

func (r *BrokerResource) Create(owner, slug, link, brokerType string) (*Broker, error) {
	values := url.Values{}
	values.Add("type", brokerType)
	values.Add("URL", link)

	if brokerType == BrokerTypePullRequestPost {
		values.Add("comments", "off")
		// TODO: figure out how to only set the hook for pull request create and update
		// This is the sample string from the docs...it does not work becuase of
		// the stupid slashes
		// Check out the docs: https://confluence.atlassian.com/display/BITBUCKET/Pull+Request+POST+hook+management
		// Sample string:
		// -data "type=POST&URL=https://www.test.comcreate%2Fedit%2Fmerge%2Fdecline=on&comments=on&approve%2Funapprove=on"
	}

	b := Broker{}
	path := fmt.Sprintf("/repositories/%s/%s/services", owner, slug)
	if err := r.client.do("POST", path, nil, values, &b); err != nil {
		return nil, err
	}

	return &b, nil
}

func (r *BrokerResource) Update(owner, slug, link, brokerType string, id int) (*Broker, error) {
	values := url.Values{}
	values.Add("type", brokerType)
	values.Add("URL", link)

	if brokerType == BrokerTypePullRequestPost {
		values.Add("comments", "off")
		// TODO: figure out how to also shutoff other events!
	}

	b := Broker{}
	path := fmt.Sprintf("/repositories/%s/%s/services/%v", owner, slug, id)
	if err := r.client.do("PUT", path, nil, values, &b); err != nil {
		return nil, err
	}

	return &b, nil
}

// CreateUpdate will attempt to Create a Broker (Server Hook) if
// it doesn't already exist in the Bitbucket.
func (r *BrokerResource) CreateUpdate(owner, slug, link, brokerType string) (*Broker, error) {
	if found, err := r.FindUrl(owner, slug, link, brokerType); err == nil {
		// if the Broker already exists, just return it
		// ... not need to re-create
		//fmt.Println("Broker already found, skipping!", brokerType)
		return found, nil
	}

	return r.Create(owner, slug, link, brokerType)
}

func (r *BrokerResource) Delete(owner, slug string, id int) error {
	path := fmt.Sprintf("/repositories/%s/%s/services/%v", owner, slug, id)
	return r.client.do("DELETE", path, nil, nil, nil)
}

func (r *BrokerResource) DeleteUrl(owner, slug, url, brokerType string) error {
	broker, err := r.FindUrl(owner, slug, url, brokerType)
	if err != nil {
		return err
	}

	return r.Delete(owner, slug, broker.Id)
}

// patch := bitbucket.GetPatch(repo, p.Id, u.BitbucketToken, u.BitbucketSecret)
func (r *BrokerResource) GetPatch(owner, slug string, id int) (string, error) {
	data := []byte{}
	// uri, err := url.Parse("https://api.bitbucket.org/1.0" + path)
	// https://bitbucket.org/!api/2.0/repositories/tdburke/test_mymysql/pullrequests/1/patch

	path := fmt.Sprintf("/repositories/tdburke/test_mymysql/pullrequests/1/patch")

	fmt.Println(path)

	if err := r.client.do("GET", path, nil, nil, &data); err != nil {
		fmt.Println("Get error:", err)
		return "", err
	}

	fmt.Println(data)

	if len(data) == 0 {
		return "", ErrNotFound
	}

	return "", nil
}

// -----------------------------------------------------------------------------
// Post Receive Hook Functions

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

var ErrInvalidPostReceiveHook = errors.New("Invalid Post Receive Hook")

type PullRequestHook struct {
	Id string `json:"id"`
}

type PostReceiveHook struct {
	Repo    *Repo     `json:"repository"`
	User    string    `json:"user"`
	Url     string    `json:"canon_url"`
	Commits []*Commit `json:"commits"`
}

type Commit struct {
	Message string `json:"message"`
	Author  string `json:"author"`
	Branch  string `json:"branch"`
	Hash    string `json:"raw_node"`
	Files []*File `json:"files"`
}

type File struct {
	Name string `json:"file"`
	Type string `json:"type"`
}

func ParseHook(raw []byte) (*PostReceiveHook, error) {
	hook := PostReceiveHook{}
	if err := json.Unmarshal(raw, &hook); err != nil {
		return nil, err
	}

	// it is possible the JSON was parsed, however,
	// was not from Bitbucket (maybe was from Google Code)
	// So we'll check to be sure certain key fields
	// were populated
	switch {
	case hook.Repo == nil:
		return nil, ErrInvalidPostReceiveHook
	case hook.Commits == nil:
		return nil, ErrInvalidPostReceiveHook
	case len(hook.User) == 0:
		return nil, ErrInvalidPostReceiveHook
	case len(hook.Commits) == 0:
		return nil, ErrInvalidPostReceiveHook
	}

	return &hook, nil
}

func ParsePullRequestHook(raw []byte) (*PullRequestHook, error) {
	data := make(map[string]map[string]interface{})
	if err := json.Unmarshal(raw, &data); err != nil {
		return nil, err
	}

	hook := PullRequestHook{}

	if p, ok := data["pullrequest_created"]; ok {
		fmt.Println(p["id"])
		hook.Id = fmt.Sprintf("%v", p["id"])
		if hook.Id == "" {
			return nil, errors.New("Could not parse bitbucket pullrequest_created message")
		}

		/*
			brokers := []*Broker{}
			path := fmt.Sprintf("/repositories/%s/%s/services/%v", owner, slug, id)

			if err := r.client.do("GET", path, nil, nil, &brokers); err != nil {
				return nil, err
			}

		*/

		return &hook, nil

	}

	//

	// How do we get the diff file?
	return nil, errors.New("Could not parse bitbucket pull request hook")
}

var ips = map[string]bool{
	"63.246.22.222": true,
}

// Check's to see if the Post-Receive Build Hook is coming
// from a valid sender (IP Address)
func IsValidSender(ip string) bool {
	return ips[ip]
}
<commit_msg>add RawAuthor field for Commit struct<commit_after>package bitbucket

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/url"
)

// Bitbucket POSTs to the service URL you specify. The service
// receives an POST whenever user pushes to the repository.
const BrokerTypePost = "POST"

const BrokerTypePullRequestPost = "Pull Request POST"

type Broker struct {
	// A Bitbucket assigned integer representing a unique
	// identifier for the service.
	Id int `json:"id"`

	// A profile describing the service.
	Profile *BrokerProfile `json:"service"`
}

type BrokerProfile struct {
	// One of the supported services. The type is a
	// case-insensitive value.
	Type string `json:"type"`

	// A parameter array containing a name and value pair
	// for each parameter associated with the service.
	Fields []*BrokerField `json:"fields"`
}

type BrokerField struct {
	Name  string `json:"name"`
	Value string `json:"value"`
}

// Bitbucket offers integration with external services by allowing a set of
// services, or brokers, to run at certain events.
//
// The Bitbucket services resource provides functionality for adding,
// removing, and configuring brokers on your repositories.  All the methods
// on this resource require the caller to authenticate.
//
// https://confluence.atlassian.com/display/BITBUCKET/services+Resource
type BrokerResource struct {
	client *Client
}

func (r *BrokerResource) List(owner, slug string) ([]*Broker, error) {
	brokers := []*Broker{}
	path := fmt.Sprintf("/repositories/%s/%s/services", owner, slug)

	if err := r.client.do("GET", path, nil, nil, &brokers); err != nil {
		return nil, err
	}

	return brokers, nil
}

func (r *BrokerResource) Find(owner, slug string, id int) (*Broker, error) {
	brokers := []*Broker{}
	path := fmt.Sprintf("/repositories/%s/%s/services/%v", owner, slug, id)

	if err := r.client.do("GET", path, nil, nil, &brokers); err != nil {
		return nil, err
	}

	if len(brokers) == 0 {
		return nil, ErrNotFound
	}

	return brokers[0], nil
}

func (r *BrokerResource) FindUrl(owner, slug, link, brokerType string) (*Broker, error) {
	brokers, err := r.List(owner, slug)
	if err != nil {
		return nil, err
	}

	//fmt.Println("Total borkers:", len(brokers))

	// iterate though list of brokers
	for _, broker := range brokers {
		if broker.Profile != nil && broker.Profile.Fields != nil {
			//fmt.Printf("Compare: %v == %v is %v\n", broker.Profile.Type, brokerType, broker.Profile.Type == brokerType)
			if broker.Profile.Type != brokerType {
				continue
			}
			// iterate through list of fields
			for _, field := range broker.Profile.Fields {
				//fmt.Printf("-->%v==%v\n", field.Name, field.Value)
				if field.Name == "URL" && field.Value == link {
					//	fmt.Println("Found match")
					return broker, nil
				}
			}
			//fmt.Println("Skipping...")
		}
	}

	//fmt.Println("Not match found")
	return nil, ErrNotFound
}

func (r *BrokerResource) Create(owner, slug, link, brokerType string) (*Broker, error) {
	values := url.Values{}
	values.Add("type", brokerType)
	values.Add("URL", link)

	if brokerType == BrokerTypePullRequestPost {
		values.Add("comments", "off")
		// TODO: figure out how to only set the hook for pull request create and update
		// This is the sample string from the docs...it does not work becuase of
		// the stupid slashes
		// Check out the docs: https://confluence.atlassian.com/display/BITBUCKET/Pull+Request+POST+hook+management
		// Sample string:
		// -data "type=POST&URL=https://www.test.comcreate%2Fedit%2Fmerge%2Fdecline=on&comments=on&approve%2Funapprove=on"
	}

	b := Broker{}
	path := fmt.Sprintf("/repositories/%s/%s/services", owner, slug)
	if err := r.client.do("POST", path, nil, values, &b); err != nil {
		return nil, err
	}

	return &b, nil
}

func (r *BrokerResource) Update(owner, slug, link, brokerType string, id int) (*Broker, error) {
	values := url.Values{}
	values.Add("type", brokerType)
	values.Add("URL", link)

	if brokerType == BrokerTypePullRequestPost {
		values.Add("comments", "off")
		// TODO: figure out how to also shutoff other events!
	}

	b := Broker{}
	path := fmt.Sprintf("/repositories/%s/%s/services/%v", owner, slug, id)
	if err := r.client.do("PUT", path, nil, values, &b); err != nil {
		return nil, err
	}

	return &b, nil
}

// CreateUpdate will attempt to Create a Broker (Server Hook) if
// it doesn't already exist in the Bitbucket.
func (r *BrokerResource) CreateUpdate(owner, slug, link, brokerType string) (*Broker, error) {
	if found, err := r.FindUrl(owner, slug, link, brokerType); err == nil {
		// if the Broker already exists, just return it
		// ... not need to re-create
		//fmt.Println("Broker already found, skipping!", brokerType)
		return found, nil
	}

	return r.Create(owner, slug, link, brokerType)
}

func (r *BrokerResource) Delete(owner, slug string, id int) error {
	path := fmt.Sprintf("/repositories/%s/%s/services/%v", owner, slug, id)
	return r.client.do("DELETE", path, nil, nil, nil)
}

func (r *BrokerResource) DeleteUrl(owner, slug, url, brokerType string) error {
	broker, err := r.FindUrl(owner, slug, url, brokerType)
	if err != nil {
		return err
	}

	return r.Delete(owner, slug, broker.Id)
}

// patch := bitbucket.GetPatch(repo, p.Id, u.BitbucketToken, u.BitbucketSecret)
func (r *BrokerResource) GetPatch(owner, slug string, id int) (string, error) {
	data := []byte{}
	// uri, err := url.Parse("https://api.bitbucket.org/1.0" + path)
	// https://bitbucket.org/!api/2.0/repositories/tdburke/test_mymysql/pullrequests/1/patch

	path := fmt.Sprintf("/repositories/tdburke/test_mymysql/pullrequests/1/patch")

	fmt.Println(path)

	if err := r.client.do("GET", path, nil, nil, &data); err != nil {
		fmt.Println("Get error:", err)
		return "", err
	}

	fmt.Println(data)

	if len(data) == 0 {
		return "", ErrNotFound
	}

	return "", nil
}

// -----------------------------------------------------------------------------
// Post Receive Hook Functions

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

var ErrInvalidPostReceiveHook = errors.New("Invalid Post Receive Hook")

type PullRequestHook struct {
	Id string `json:"id"`
}

type PostReceiveHook struct {
	Repo    *Repo     `json:"repository"`
	User    string    `json:"user"`
	Url     string    `json:"canon_url"`
	Commits []*Commit `json:"commits"`
}

type Commit struct {
	Message   string  `json:"message"`
	Author    string  `json:"author"`
	RawAuthor string  `json:"raw_author"`
	Branch    string  `json:"branch"`
	Hash      string  `json:"raw_node"`
	Files     []*File `json:"files"`
}

type File struct {
	Name string `json:"file"`
	Type string `json:"type"`
}

func ParseHook(raw []byte) (*PostReceiveHook, error) {
	hook := PostReceiveHook{}
	if err := json.Unmarshal(raw, &hook); err != nil {
		return nil, err
	}

	// it is possible the JSON was parsed, however,
	// was not from Bitbucket (maybe was from Google Code)
	// So we'll check to be sure certain key fields
	// were populated
	switch {
	case hook.Repo == nil:
		return nil, ErrInvalidPostReceiveHook
	case hook.Commits == nil:
		return nil, ErrInvalidPostReceiveHook
	case len(hook.User) == 0:
		return nil, ErrInvalidPostReceiveHook
	case len(hook.Commits) == 0:
		return nil, ErrInvalidPostReceiveHook
	}

	return &hook, nil
}

func ParsePullRequestHook(raw []byte) (*PullRequestHook, error) {
	data := make(map[string]map[string]interface{})
	if err := json.Unmarshal(raw, &data); err != nil {
		return nil, err
	}

	hook := PullRequestHook{}

	if p, ok := data["pullrequest_created"]; ok {
		fmt.Println(p["id"])
		hook.Id = fmt.Sprintf("%v", p["id"])
		if hook.Id == "" {
			return nil, errors.New("Could not parse bitbucket pullrequest_created message")
		}

		/*
			brokers := []*Broker{}
			path := fmt.Sprintf("/repositories/%s/%s/services/%v", owner, slug, id)

			if err := r.client.do("GET", path, nil, nil, &brokers); err != nil {
				return nil, err
			}

		*/

		return &hook, nil

	}

	//

	// How do we get the diff file?
	return nil, errors.New("Could not parse bitbucket pull request hook")
}

var ips = map[string]bool{
	"63.246.22.222": true,
}

// Check's to see if the Post-Receive Build Hook is coming
// from a valid sender (IP Address)
func IsValidSender(ip string) bool {
	return ips[ip]
}
<|endoftext|>


<commit_before>// Copyright 2022 PingCAP, 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 node

import (
	"path"
	"testing"
	"time"

	"github.com/pingcap/tidb/util/etcd"
	"github.com/stretchr/testify/require"
	"go.etcd.io/etcd/tests/v3/integration"
	"golang.org/x/net/context"
)

var nodePrefix = path.Join(DefaultRootPath, NodePrefix[PumpNode])

type RegisrerTestClient interface {
	Node(context.Context, string, string) (*Status, int64, error)
}

func TestUpdateNodeInfo(t *testing.T) {
	integration.BeforeTest(t)
	testEtcdCluster := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
	defer testEtcdCluster.Terminate(t)

	etcdclient := etcd.NewClient(testEtcdCluster.RandClient(), DefaultRootPath)
	r := NewEtcdRegistry(etcdclient, time.Duration(5)*time.Second)
	ns := &Status{
		NodeID:  "test",
		Addr:    "test",
		State:   Online,
		IsAlive: true,
	}

	err := r.UpdateNode(context.Background(), nodePrefix, ns)
	require.NoError(t, err)
	mustEqualStatus(t, r, ns.NodeID, ns)

	ns.Addr = "localhost:1234"
	err = r.UpdateNode(context.Background(), nodePrefix, ns)
	require.NoError(t, err)
	mustEqualStatus(t, r, ns.NodeID, ns)
	// use Nodes() to query node status
	ss, _, err := r.Nodes(context.Background(), nodePrefix)
	require.NoError(t, err)
	require.Len(t, ss, 1)
}

func TestRegisterNode(t *testing.T) {
	integration.BeforeTest(t)
	testEtcdCluster := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
	defer testEtcdCluster.Terminate(t)

	etcdclient := etcd.NewClient(testEtcdCluster.RandClient(), DefaultRootPath)
	r := NewEtcdRegistry(etcdclient, time.Duration(5)*time.Second)

	ns := &Status{
		NodeID:  "test",
		Addr:    "test",
		State:   Online,
		IsAlive: true,
	}
	err := r.UpdateNode(context.Background(), nodePrefix, ns)
	require.NoError(t, err)
	mustEqualStatus(t, r, ns.NodeID, ns)

	ns.State = Offline
	err = r.UpdateNode(context.Background(), nodePrefix, ns)
	require.NoError(t, err)
	mustEqualStatus(t, r, ns.NodeID, ns)

	// TODO: now don't have function to delete node, maybe do it later
	//err = r.UnregisterNode(context.Background(), nodePrefix, ns.NodeID)
	//require.NoError(t, err)
	//exist, err := r.checkNodeExists(context.Background(), nodePrefix, ns.NodeID)
	//require.NoError(t, err)
	//require.False(t, exist)
}

func TestRefreshNode(t *testing.T) {
	integration.BeforeTest(t)
	testEtcdCluster := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
	defer testEtcdCluster.Terminate(t)

	etcdclient := etcd.NewClient(testEtcdCluster.RandClient(), DefaultRootPath)
	r := NewEtcdRegistry(etcdclient, time.Duration(5)*time.Second)

	ns := &Status{
		NodeID:  "test",
		Addr:    "test",
		State:   Online,
		IsAlive: true,
	}
	err := r.UpdateNode(context.Background(), nodePrefix, ns)
	require.NoError(t, err)

	ns.IsAlive = true
	mustEqualStatus(t, r, ns.NodeID, ns)

	// TODO: fix it later
	//time.Sleep(2 * time.Second)
	//ns.IsAlive = false
	//mustEqualStatus(t, r, ns.NodeID, ns)
}

func mustEqualStatus(t *testing.T, r RegisrerTestClient, nodeID string, status *Status) {
	ns, _, err := r.Node(context.Background(), nodePrefix, nodeID)
	require.NoError(t, err)
	require.Equal(t, status, ns)
}
<commit_msg>tidb-binlog: fix testcase timeout (#33785)<commit_after>// Copyright 2022 PingCAP, 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 node

import (
	"path"
	"testing"
	"time"

	"github.com/pingcap/tidb/util/etcd"
	"github.com/stretchr/testify/require"
	"go.etcd.io/etcd/tests/v3/integration"
	"golang.org/x/net/context"
)

var nodePrefix = path.Join(DefaultRootPath, NodePrefix[PumpNode])

type RegisrerTestClient interface {
	Node(context.Context, string, string) (*Status, int64, error)
}

func TestUpdateNodeInfo(t *testing.T) {
	integration.BeforeTest(t)
	testEtcdCluster := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
	defer testEtcdCluster.Terminate(t)

	etcdclient := etcd.NewClient(testEtcdCluster.RandClient(), DefaultRootPath)
	r := NewEtcdRegistry(etcdclient, time.Duration(30)*time.Second)
	ns := &Status{
		NodeID:  "test",
		Addr:    "test",
		State:   Online,
		IsAlive: true,
	}

	err := r.UpdateNode(context.Background(), nodePrefix, ns)
	require.NoError(t, err)
	mustEqualStatus(t, r, ns.NodeID, ns)

	ns.Addr = "localhost:1234"
	err = r.UpdateNode(context.Background(), nodePrefix, ns)
	require.NoError(t, err)
	mustEqualStatus(t, r, ns.NodeID, ns)
	// use Nodes() to query node status
	ss, _, err := r.Nodes(context.Background(), nodePrefix)
	require.NoError(t, err)
	require.Len(t, ss, 1)
}

func TestRegisterNode(t *testing.T) {
	integration.BeforeTest(t)
	testEtcdCluster := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
	defer testEtcdCluster.Terminate(t)

	etcdclient := etcd.NewClient(testEtcdCluster.RandClient(), DefaultRootPath)
	r := NewEtcdRegistry(etcdclient, time.Duration(5)*time.Second)

	ns := &Status{
		NodeID:  "test",
		Addr:    "test",
		State:   Online,
		IsAlive: true,
	}
	err := r.UpdateNode(context.Background(), nodePrefix, ns)
	require.NoError(t, err)
	mustEqualStatus(t, r, ns.NodeID, ns)

	ns.State = Offline
	err = r.UpdateNode(context.Background(), nodePrefix, ns)
	require.NoError(t, err)
	mustEqualStatus(t, r, ns.NodeID, ns)

	// TODO: now don't have function to delete node, maybe do it later
	//err = r.UnregisterNode(context.Background(), nodePrefix, ns.NodeID)
	//require.NoError(t, err)
	//exist, err := r.checkNodeExists(context.Background(), nodePrefix, ns.NodeID)
	//require.NoError(t, err)
	//require.False(t, exist)
}

func TestRefreshNode(t *testing.T) {
	integration.BeforeTest(t)
	testEtcdCluster := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
	defer testEtcdCluster.Terminate(t)

	etcdclient := etcd.NewClient(testEtcdCluster.RandClient(), DefaultRootPath)
	r := NewEtcdRegistry(etcdclient, time.Duration(5)*time.Second)

	ns := &Status{
		NodeID:  "test",
		Addr:    "test",
		State:   Online,
		IsAlive: true,
	}
	err := r.UpdateNode(context.Background(), nodePrefix, ns)
	require.NoError(t, err)

	ns.IsAlive = true
	mustEqualStatus(t, r, ns.NodeID, ns)

	// TODO: fix it later
	//time.Sleep(2 * time.Second)
	//ns.IsAlive = false
	//mustEqualStatus(t, r, ns.NodeID, ns)
}

func mustEqualStatus(t *testing.T, r RegisrerTestClient, nodeID string, status *Status) {
	ns, _, err := r.Node(context.Background(), nodePrefix, nodeID)
	require.NoError(t, err)
	require.Equal(t, status, ns)
}
<|endoftext|>


<commit_before>// Copyright (C) 2014 Andreas Klauer <Andreas.Klauer@metamorpher.de>
// License: GPL

// nbdsetup is an alternative to losetup using network block devices.
package main

import (
	"flag"
	"fmt"
	"os"

	"github.com/frostschutz/nbd"
)

func main() {
	file := flag.String("file", "", "regular file or block device")
	flag.Parse()
	fmt.Printf("Using %s\n", *file)
	device, err := os.Open(*file)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	stat, _ := device.Stat()
	nbd.Create(device, stat.Size())
}

// End of file.
<commit_msg>nbdsetup<commit_after>// Copyright (C) 2014 Andreas Klauer <Andreas.Klauer@metamorpher.de>
// License: GPL

// nbdsetup is an alternative to losetup using network block devices.
package main

import (
	"flag"
	"fmt"
	"os"

	"github.com/frostschutz/nbd"
)

func main() {
	file := flag.String("file", "", "regular file or block device")
	flag.Parse()
	fmt.Printf("Using %s\n", *file)
	device, err := os.Open(*file)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	stat, _ := device.Stat()
	dev, err := nbd.Create(device, stat.Size()).Connect()

	fmt.Println(dev)
	fmt.Println(err)
}

// End of file.
<|endoftext|>


<commit_before>package http

import (
	"fmt"
	"math"
	"net"
	"strconv"
	"strings"
	"sync/atomic"
	"time"
	"unsafe"

	"github.com/trafficstars/registry"
)

// BalancingStrategy type
type BalancingStrategy int

// Balancyng strategy variants
const (
	RoundRobinStrategy BalancingStrategy = iota
	WeightStrategy
)

var _balancer balancer

// Init balancer based on descovery
func Init(strategy BalancingStrategy, discovery registry.Discovery, localAddrs ...string) {
	if len(localAddrs) == 0 || localAddrs[0] == "" {
		localAddrs, _ = listOfLocalAddresses()

		// all IPv4 addresses on the local machine
		const allAddress = "0.0.0.0"
		hasAllAddress := false
		for _, addr := range localAddrs {
			if addr == allAddress {
				hasAllAddress = true
				break
			}
		}
		if !hasAllAddress {
			localAddrs = append(localAddrs, allAddress)
		}
	}

	_balancer = balancer{
		strategy:   strategy,
		discovery:  discovery,
		localAddrs: localAddrs,
	}

	upstreams := make(map[string]*upstream)
	atomic.StorePointer(&_balancer.upstreams, unsafe.Pointer(&upstreams))

	_balancer.lookup()
	go _balancer.supervisor()
}

type balancer struct {
	// Strategy of address balancing
	strategy BalancingStrategy

	// upstreams map[string]*upstream
	upstreams unsafe.Pointer
	discovery registry.Discovery

	localAddrs []string
}

func (b *balancer) lookup() error {
	var (
		backendServices = map[string]backends{}
		services, err   = b.discovery.Lookup(nil)
	)
	if err != nil {
		return err
	}

	// Group backends by services
	for _, service := range services {
		if service.Status == registry.SERVICE_STATUS_PASSING {
			backendServices[service.Name] = append(backendServices[service.Name], &backend{
				weight:      int32(serverWeight(&service)),
				hostaddress: service.Address,
				address:     net.JoinHostPort(service.Address, strconv.Itoa(service.Port)),
			})
		}
	}

	upstreams := map[string]*upstream{}

	for key, backends := range backendServices {
		var priorityBackend *backend

	loop:
		for _, bk := range backends {
			for _, addr := range b.localAddrs {
				if addr == bk.hostaddress {
					priorityBackend = bk
					break loop
				}
			}
		}

		upstreams[key] = &upstream{
			priorityBackend: priorityBackend,
			backends:        backends,
			gcd:             backends.gcd(),
			maxWeight:       backends.maxWeight(),
		}
	}

	atomic.StorePointer(&b.upstreams, unsafe.Pointer(&upstreams))

	return nil
}

func (b *balancer) supervisor() {
	tick := time.Tick(5 * time.Second)
	for {
		select {
		case <-tick:
			b.lookup()
		}
	}
}

func (b *balancer) countOfBackends(service string) int {
	upstreams := *(*map[string]*upstream)(atomic.LoadPointer(&b.upstreams))
	if upstream, found := upstreams[service]; found {
		return len(upstream.backends)
	}
	return 0
}

func (b *balancer) nextRoundRobin(service string, maxRequestsByBackend int) (*backend, error) {
	upstream := b.getUpstreamByServiceName(service)
	if upstream != nil {
		return upstream.nextBackend(maxRequestsByBackend), nil
	}
	return nil, fmt.Errorf("Service '%s' not found", service)
}

func (b *balancer) nextWeight(service string, maxRequestsByBackend int) (*backend, error) {
	upstream := b.getUpstreamByServiceName(service)
	if upstream == nil {
		return nil, fmt.Errorf("Service '%s' not found", service)
	}

	if backend := upstream.nextWeightBackend(maxRequestsByBackend); backend != nil {
		return backend, nil
	}

	return nil, fmt.Errorf("Service backend of '%s' not found", service)
}

func (b *balancer) next(service string, maxRequestsByBackend int) (*backend, error) {
	if b.strategy == WeightStrategy {
		return b.nextWeight(service, maxRequestsByBackend)
	}
	return b.nextRoundRobin(service, maxRequestsByBackend)
}

func (b *balancer) getUpstreamByServiceName(service string) *upstream {
	upstreams := *(*map[string]*upstream)(atomic.LoadPointer(&b.upstreams))
	ups, _ := upstreams[service]
	return ups
}

func serverWeight(s *registry.Service) int {
	weight := 1
	for _, tag := range s.Tags {
		if strings.HasPrefix(tag, "SERVICE_WEIGHT=") {
			if v, _ := strconv.ParseInt(strings.TrimPrefix(tag, "SERVICE_WEIGHT="), 10, 64); v != 0 {
				weight = int(v)
			}
		}
	}
	weight *= 100
	for _, tag := range s.Tags {
		if strings.HasPrefix(tag, "CPU_USAGE=") {
			if v, _ := strconv.ParseFloat(strings.TrimPrefix(tag, "CPU_USAGE="), 64); v != 0 {
				if usage := int(math.Ceil(v / 4.0)); usage != 0 {
					weight = weight / int(math.Ceil(v/4.0))
				}
			}
		}
	}
	return weight
}
<commit_msg>Remove all address to the local interfaces<commit_after>package http

import (
	"fmt"
	"math"
	"net"
	"strconv"
	"strings"
	"sync/atomic"
	"time"
	"unsafe"

	"github.com/trafficstars/registry"
)

// BalancingStrategy type
type BalancingStrategy int

// Balancyng strategy variants
const (
	RoundRobinStrategy BalancingStrategy = iota
	WeightStrategy
)

var _balancer balancer

// Init balancer based on descovery
func Init(strategy BalancingStrategy, discovery registry.Discovery, localAddrs ...string) {
	if len(localAddrs) == 0 || localAddrs[0] == "" {
		localAddrs, _ = listOfLocalAddresses()
	}

	_balancer = balancer{
		strategy:   strategy,
		discovery:  discovery,
		localAddrs: localAddrs,
	}

	upstreams := make(map[string]*upstream)
	atomic.StorePointer(&_balancer.upstreams, unsafe.Pointer(&upstreams))

	_balancer.lookup()
	go _balancer.supervisor()
}

type balancer struct {
	// Strategy of address balancing
	strategy BalancingStrategy

	// upstreams map[string]*upstream
	upstreams unsafe.Pointer
	discovery registry.Discovery

	localAddrs []string
}

func (b *balancer) lookup() error {
	var (
		backendServices = map[string]backends{}
		services, err   = b.discovery.Lookup(nil)
	)
	if err != nil {
		return err
	}

	// Group backends by services
	for _, service := range services {
		if service.Status == registry.SERVICE_STATUS_PASSING {
			backendServices[service.Name] = append(backendServices[service.Name], &backend{
				weight:      int32(serverWeight(&service)),
				hostaddress: service.Address,
				address:     net.JoinHostPort(service.Address, strconv.Itoa(service.Port)),
			})
		}
	}

	upstreams := map[string]*upstream{}

	for key, backends := range backendServices {
		var priorityBackend *backend

	loop:
		for _, bk := range backends {
			for _, addr := range b.localAddrs {
				if addr == bk.hostaddress {
					priorityBackend = bk
					break loop
				}
			}
		}

		upstreams[key] = &upstream{
			priorityBackend: priorityBackend,
			backends:        backends,
			gcd:             backends.gcd(),
			maxWeight:       backends.maxWeight(),
		}
	}

	atomic.StorePointer(&b.upstreams, unsafe.Pointer(&upstreams))

	return nil
}

func (b *balancer) supervisor() {
	tick := time.Tick(5 * time.Second)
	for {
		select {
		case <-tick:
			b.lookup()
		}
	}
}

func (b *balancer) countOfBackends(service string) int {
	upstreams := *(*map[string]*upstream)(atomic.LoadPointer(&b.upstreams))
	if upstream, found := upstreams[service]; found {
		return len(upstream.backends)
	}
	return 0
}

func (b *balancer) nextRoundRobin(service string, maxRequestsByBackend int) (*backend, error) {
	upstream := b.getUpstreamByServiceName(service)
	if upstream != nil {
		return upstream.nextBackend(maxRequestsByBackend), nil
	}
	return nil, fmt.Errorf("Service '%s' not found", service)
}

func (b *balancer) nextWeight(service string, maxRequestsByBackend int) (*backend, error) {
	upstream := b.getUpstreamByServiceName(service)
	if upstream == nil {
		return nil, fmt.Errorf("Service '%s' not found", service)
	}

	if backend := upstream.nextWeightBackend(maxRequestsByBackend); backend != nil {
		return backend, nil
	}

	return nil, fmt.Errorf("Service backend of '%s' not found", service)
}

func (b *balancer) next(service string, maxRequestsByBackend int) (*backend, error) {
	if b.strategy == WeightStrategy {
		return b.nextWeight(service, maxRequestsByBackend)
	}
	return b.nextRoundRobin(service, maxRequestsByBackend)
}

func (b *balancer) getUpstreamByServiceName(service string) *upstream {
	upstreams := *(*map[string]*upstream)(atomic.LoadPointer(&b.upstreams))
	ups, _ := upstreams[service]
	return ups
}

func serverWeight(s *registry.Service) int {
	weight := 1
	for _, tag := range s.Tags {
		if strings.HasPrefix(tag, "SERVICE_WEIGHT=") {
			if v, _ := strconv.ParseInt(strings.TrimPrefix(tag, "SERVICE_WEIGHT="), 10, 64); v != 0 {
				weight = int(v)
			}
		}
	}
	weight *= 100
	for _, tag := range s.Tags {
		if strings.HasPrefix(tag, "CPU_USAGE=") {
			if v, _ := strconv.ParseFloat(strings.TrimPrefix(tag, "CPU_USAGE="), 64); v != 0 {
				if usage := int(math.Ceil(v / 4.0)); usage != 0 {
					weight = weight / int(math.Ceil(v/4.0))
				}
			}
		}
	}
	return weight
}
<|endoftext|>


<commit_before>package pod

import (
	"fmt"
	"strings"
	"sync"
)

type PodList struct {
	pods           map[string]*XPod
	containers     map[string]string
	containerNames map[string]string
	mu             *sync.RWMutex
}

func NewPodList() *PodList {
	return &PodList{
		pods:           make(map[string]*XPod),
		containers:     make(map[string]string),
		containerNames: make(map[string]string),
		mu:             &sync.RWMutex{},
	}
}

func (pl *PodList) Get(id string) (*XPod, bool) {
	pl.mu.RLock()
	defer pl.mu.RUnlock()

	p, ok := pl.pods[id]
	return p, ok
}

func (pl *PodList) ReserveContainerID(id, pod string) error {
	if pn, ok := pl.containers[id]; ok && pn != pod {
		return fmt.Errorf("the container id %s has already taken by pod %s", id, pn)
	}
	pl.containers[id] = pod
	return nil
}

func (pl *PodList) ReserveContainerName(name, pod string) error {
	if pn, ok := pl.containerNames[name]; ok && pn != pod {
		return fmt.Errorf("the container name %s has already taken by pod %s", name, pn)
	}
	pl.containerNames[name] = pod
	return nil
}

func (pl *PodList) ReserveContainer(id, name, pod string) error {
	pl.mu.Lock()
	defer pl.mu.Unlock()
	if _, ok := pl.pods[pod]; !ok {
		return fmt.Errorf("pod %s not exist for adding container %s(%s)", pod, name, id)
	}
	if pn, ok := pl.containerNames[name]; ok && pn != pod {
		return fmt.Errorf("container name %s has already taken by pod %s", name, pn)
	}
	if id != "" {
		if pn, ok := pl.containers[id]; ok && pn != pod {
			return fmt.Errorf("the container id %s has already taken by pod %s", id, pn)
		}
		pl.containers[id] = pod
	}
	pl.containerNames[name] = pod
	return nil
}

func (pl *PodList) ReservePod(p *XPod) error {
	pl.mu.Lock()
	defer pl.mu.Unlock()

	name := p.Id()
	// check availability
	if pe, ok := pl.pods[name]; ok && pe != p {
		return fmt.Errorf("pod name %s has already in use", p.Id())
	}

	pl.pods[name] = p
	return nil
}

func (pl *PodList) Release(id string) {
	pl.mu.Lock()
	defer pl.mu.Unlock()
	if p, ok := pl.pods[id]; ok {
		for _, c := range p.ContainerIds() {
			delete(pl.containers, c)
		}
		for _, c := range p.ContainerNames() {
			delete(pl.containerNames, c)
		}
	}
	delete(pl.pods, id)
}

func (pl *PodList) ReleaseContainer(id, name string) {
	pl.mu.Lock()
	defer pl.mu.Unlock()

	delete(pl.containers, id)
	delete(pl.containerNames, name)
}

func (pl *PodList) ReleaseContainerName(name string) {
	pl.mu.Lock()
	defer pl.mu.Unlock()

	delete(pl.containerNames, name)
}

func (pl *PodList) GetByContainerId(cid string) (*XPod, bool) {
	pl.mu.RLock()
	defer pl.mu.RUnlock()

	if podid, ok := pl.containers[cid]; ok {
		p, ok := pl.pods[podid]
		return p, ok
	}
	return nil, false
}

func (pl *PodList) GetByContainerIdOrName(cid string) (*XPod, string, bool) {
	pl.mu.RLock()
	defer pl.mu.RUnlock()

	if podid, ok := pl.containerNames[cid]; ok {
		if p, ok := pl.pods[podid]; ok {
			id, _ := p.ContainerName2Id(cid)
			return p, id, true
		}
		return nil, "", false
	}
	if podid, ok := pl.containers[cid]; ok {
		if p, ok := pl.pods[podid]; ok {
			return p, cid, true
		}
		return nil, "", false
	}

	matchPods := []string{}
	fullid := ""
	for c, p := range pl.containers {
		if strings.HasPrefix(c, cid) {
			fullid = c
			matchPods = append(matchPods, p)
		}
	}
	if len(matchPods) > 1 {
		return nil, "", false
	} else if len(matchPods) == 1 {
		if p, ok := pl.pods[matchPods[0]]; ok {
			return p, fullid, true
		}
		return nil, "", false
	}

	return nil, "", false
}

func (pl *PodList) CountRunning() int64 {
	return pl.CountStatus(S_POD_RUNNING) + pl.CountStatus(S_POD_STARTING) + pl.CountStatus(S_POD_PAUSED)
}

func (pl *PodList) CountAll() int64 {
	return int64(len(pl.pods))
}

func (pl *PodList) CountStatus(status PodState) (num int64) {
	num = 0

	pl.mu.RLock()
	defer pl.mu.RUnlock()

	if pl.pods == nil {
		return
	}

	for _, pod := range pl.pods {
		if pod.status == status {
			num++
		}
	}

	return
}

func (pl *PodList) CountContainers() (num int64) {
	num = 0
	pl.mu.RLock()
	defer pl.mu.RUnlock()

	return int64(len(pl.containers))
}

type PodOp func(*XPod) error
type PodFilterOp func(*XPod) bool

func (pl *PodList) Foreach(fn PodOp) error {
	pl.mu.RLock()
	defer pl.mu.RUnlock()
	return pl.foreachUnsafe(fn)
}

func (pl *PodList) foreachUnsafe(fn PodOp) error {
	for _, p := range pl.pods {
		if err := fn(p); err != nil {
			return err
		}
	}
	return nil
}

func (pl *PodList) Find(fn PodFilterOp) *XPod {
	pl.mu.RLock()
	defer pl.mu.RUnlock()
	return pl.findUnsafe(fn)
}

func (pl *PodList) findUnsafe(fn PodFilterOp) *XPod {
	for _, p := range pl.pods {
		if fn(p) {
			return p
		}
	}
	return nil
}
<commit_msg>protect ReserveContainer with lock<commit_after>package pod

import (
	"fmt"
	"strings"
	"sync"
)

type PodList struct {
	pods           map[string]*XPod
	containers     map[string]string
	containerNames map[string]string
	mu             *sync.RWMutex
}

func NewPodList() *PodList {
	return &PodList{
		pods:           make(map[string]*XPod),
		containers:     make(map[string]string),
		containerNames: make(map[string]string),
		mu:             &sync.RWMutex{},
	}
}

func (pl *PodList) Get(id string) (*XPod, bool) {
	pl.mu.RLock()
	defer pl.mu.RUnlock()

	p, ok := pl.pods[id]
	return p, ok
}

func (pl *PodList) ReserveContainerID(id, pod string) error {
	pl.mu.Lock()
	defer pl.mu.Unlock()

	if pn, ok := pl.containers[id]; ok && pn != pod {
		return fmt.Errorf("the container id %s has already taken by pod %s", id, pn)
	}
	pl.containers[id] = pod
	return nil
}

func (pl *PodList) ReserveContainerName(name, pod string) error {
	pl.mu.Lock()
	defer pl.mu.Unlock()

	if pn, ok := pl.containerNames[name]; ok && pn != pod {
		return fmt.Errorf("the container name %s has already taken by pod %s", name, pn)
	}
	pl.containerNames[name] = pod
	return nil
}

func (pl *PodList) ReserveContainer(id, name, pod string) error {
	pl.mu.Lock()
	defer pl.mu.Unlock()
	if _, ok := pl.pods[pod]; !ok {
		return fmt.Errorf("pod %s not exist for adding container %s(%s)", pod, name, id)
	}
	if pn, ok := pl.containerNames[name]; ok && pn != pod {
		return fmt.Errorf("container name %s has already taken by pod %s", name, pn)
	}
	if id != "" {
		if pn, ok := pl.containers[id]; ok && pn != pod {
			return fmt.Errorf("the container id %s has already taken by pod %s", id, pn)
		}
		pl.containers[id] = pod
	}
	pl.containerNames[name] = pod
	return nil
}

func (pl *PodList) ReservePod(p *XPod) error {
	pl.mu.Lock()
	defer pl.mu.Unlock()

	name := p.Id()
	// check availability
	if pe, ok := pl.pods[name]; ok && pe != p {
		return fmt.Errorf("pod name %s has already in use", p.Id())
	}

	pl.pods[name] = p
	return nil
}

func (pl *PodList) Release(id string) {
	pl.mu.Lock()
	defer pl.mu.Unlock()
	if p, ok := pl.pods[id]; ok {
		for _, c := range p.ContainerIds() {
			delete(pl.containers, c)
		}
		for _, c := range p.ContainerNames() {
			delete(pl.containerNames, c)
		}
	}
	delete(pl.pods, id)
}

func (pl *PodList) ReleaseContainer(id, name string) {
	pl.mu.Lock()
	defer pl.mu.Unlock()

	delete(pl.containers, id)
	delete(pl.containerNames, name)
}

func (pl *PodList) ReleaseContainerName(name string) {
	pl.mu.Lock()
	defer pl.mu.Unlock()

	delete(pl.containerNames, name)
}

func (pl *PodList) GetByContainerId(cid string) (*XPod, bool) {
	pl.mu.RLock()
	defer pl.mu.RUnlock()

	if podid, ok := pl.containers[cid]; ok {
		p, ok := pl.pods[podid]
		return p, ok
	}
	return nil, false
}

func (pl *PodList) GetByContainerIdOrName(cid string) (*XPod, string, bool) {
	pl.mu.RLock()
	defer pl.mu.RUnlock()

	if podid, ok := pl.containerNames[cid]; ok {
		if p, ok := pl.pods[podid]; ok {
			id, _ := p.ContainerName2Id(cid)
			return p, id, true
		}
		return nil, "", false
	}
	if podid, ok := pl.containers[cid]; ok {
		if p, ok := pl.pods[podid]; ok {
			return p, cid, true
		}
		return nil, "", false
	}

	matchPods := []string{}
	fullid := ""
	for c, p := range pl.containers {
		if strings.HasPrefix(c, cid) {
			fullid = c
			matchPods = append(matchPods, p)
		}
	}
	if len(matchPods) > 1 {
		return nil, "", false
	} else if len(matchPods) == 1 {
		if p, ok := pl.pods[matchPods[0]]; ok {
			return p, fullid, true
		}
		return nil, "", false
	}

	return nil, "", false
}

func (pl *PodList) CountRunning() int64 {
	return pl.CountStatus(S_POD_RUNNING) + pl.CountStatus(S_POD_STARTING) + pl.CountStatus(S_POD_PAUSED)
}

func (pl *PodList) CountAll() int64 {
	return int64(len(pl.pods))
}

func (pl *PodList) CountStatus(status PodState) (num int64) {
	num = 0

	pl.mu.RLock()
	defer pl.mu.RUnlock()

	if pl.pods == nil {
		return
	}

	for _, pod := range pl.pods {
		if pod.status == status {
			num++
		}
	}

	return
}

func (pl *PodList) CountContainers() (num int64) {
	num = 0
	pl.mu.RLock()
	defer pl.mu.RUnlock()

	return int64(len(pl.containers))
}

type PodOp func(*XPod) error
type PodFilterOp func(*XPod) bool

func (pl *PodList) Foreach(fn PodOp) error {
	pl.mu.RLock()
	defer pl.mu.RUnlock()
	return pl.foreachUnsafe(fn)
}

func (pl *PodList) foreachUnsafe(fn PodOp) error {
	for _, p := range pl.pods {
		if err := fn(p); err != nil {
			return err
		}
	}
	return nil
}

func (pl *PodList) Find(fn PodFilterOp) *XPod {
	pl.mu.RLock()
	defer pl.mu.RUnlock()
	return pl.findUnsafe(fn)
}

func (pl *PodList) findUnsafe(fn PodFilterOp) *XPod {
	for _, p := range pl.pods {
		if fn(p) {
			return p
		}
	}
	return nil
}
<|endoftext|>