<commit_before>// Copyright 2016 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 query

import (
	"fmt"
	"os"
	"time"

	"github.com/golang/protobuf/proto"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"

	log "github.com/golang/glog"
	ocpb "github.com/openconfig/reference/rpc/openconfig"
)

const (
	// TimeFormat is the default time format for the query.
	TimeFormat = "2000-01-01-01:01:01.00000000"
	// Delimiter is the default delimiter for the query.
	Delimiter = "/"
	// DialTimeout is the default dial timeout for the query.
	DialTimeout = 10 * time.Second
)

var (
	// defaultDisplay is the default implementation for displaying output from the
	// query.
	defaultDisplay = func(b []byte) {
		os.Stdout.Write(b)
	}
)

// Query contains the target and query for a request.
type Query struct {
	Address     string
	Target      string
	DialOptions []grpc.DialOption
	// Queries is a list queries made of query elements.
	Queries [][]string
	// Update is a single SetRequest to be made on the target.
	Update *ocpb.SetRequest
}

// Config contains the configuration for displaying a query.
type Config struct {
	Count       uint64
	Once        bool
	Delimiter   string
	DialTimeout time.Duration
	Display     func([]byte)
	TimeFormat  string
}

// Display creates a gRPC connection to the query target and makes a Get call
// for the queried paths and displays the response via cfg.Display.
func Display(ctx context.Context, query Query, cfg *Config) error {
	c, err := createClient(ctx, query, cfg)
	if err != nil {
		return err
	}
	request, err := createRequest(query)
	if err != nil {
		return err
	}
	log.Infof("Get with:\n%s\n", request)
	resp, err := c.Get(ctx, request)
	if err != nil {
		return err
	}
	for _, n := range resp.GetNotification() {
		cfg.Display([]byte(n.String()))
	}
	return nil
}

// DisplayStream creates a gRPC connection to the query target and makes a
// Subscribe call for the queried paths and streams the response via
// cfg.Display.
func DisplayStream(ctx context.Context, query Query, cfg *Config) error {
	c, err := createClient(ctx, query, cfg)
	if err != nil {
		return err
	}
	request, err := createSubscribeRequest(query)
	if err != nil {
		return err
	}
	stream, err := c.Subscribe(ctx)
	if err != nil {
		return err
	}
	if err := stream.Send(request); err != nil {
		return err
	}
	log.Infof("Subscribed with:\n%s", proto.MarshalTextString(request))
	for {
		resp, err := stream.Recv()
		log.Info(proto.MarshalTextString(resp))
		if err != nil {
			// TODO(hines): This should be io.EOF but for some reason the server
			// currently sends this code.
			if grpc.Code(err) != codes.OutOfRange {
				return err
			}
			return nil
		}
		switch v := resp.Response.(type) {
		default:
			log.Infof("Unknown response:\n%s\n", resp.String())
		case *ocpb.SubscribeResponse_Heartbeat:
			log.Infof("Heartbeat:%s\n", resp.String())
		case *ocpb.SubscribeResponse_Update:
			cfg.Display([]byte(proto.MarshalTextString(v.Update)))
		case *ocpb.SubscribeResponse_SyncResponse:
			log.Infof("Sync Response: %s", resp.String())
			if cfg.Once {
				stream.CloseSend()
			}
		}
	}
}

// Update sends a SetRequest to the target.  If the Set fails an error will be
// returned.  The response will be displayed by the configure cfg.Display.
func Update(ctx context.Context, query Query, cfg *Config) error {
	c, err := createClient(ctx, query, cfg)
	if err != nil {
		return err
	}
	if query.Update == nil {
		return fmt.Errorf("query.Updates must be defined for Update")
	}
	resp, err := c.Set(ctx, query.Update)
	if err != nil {
		return fmt.Errorf("failed to set %s: %s", proto.MarshalTextString(query.Update), err)
	}
	cfg.Display([]byte(resp.String()))
	return nil
}

func createClient(ctx context.Context, query Query, cfg *Config) (ocpb.OpenConfigClient, error) {
	switch {
	case ctx == nil:
		return nil, fmt.Errorf("ctx must not be nil")
	case cfg == nil:
		return nil, fmt.Errorf("cfg must not be nil")
	case query.Target == "":
		return nil, fmt.Errorf("query target must be specified")
	}
	if cfg.Display == nil {
		cfg.Display = defaultDisplay
	}
	log.Infof("Creating connection: %+v", query)
	conn, err := grpc.Dial(query.Target, query.DialOptions...)
	if err != nil {
		return nil, err
	}
	return ocpb.NewOpenConfigClient(conn), nil
}

func createRequest(q Query) (*ocpb.GetRequest, error) {
	r := &ocpb.GetRequest{}
	for _, qItem := range q.Queries {
		p := &ocpb.Path{
			Element: qItem,
		}
		r.Path = append(r.Path, p)
	}
	return r, nil
}

func createSubscribeRequest(q Query) (*ocpb.SubscribeRequest, error) {
	// TODO(hines): Re-add once bug is resolved for lack of mode support.
	//subList := &ocpb.SubscriptionList{
	//	 Mode: &ocpb.SubscriptionList_Once{
	//	 Once: true,
	//	 },
	// }
	subList := &ocpb.SubscriptionList{}
	for _, qItem := range q.Queries {
		subList.Subscription = append(subList.Subscription, &ocpb.Subscription{
			Path: &ocpb.Path{
				Element: qItem,
			},
		})
	}
	return &ocpb.SubscribeRequest{
		Request: &ocpb.SubscribeRequest_Subscribe{
			Subscribe: subList,
		}}, nil
}
<commit_msg>Change the serialization to a file from list of updates to list of notifications to easier support golden testing.<commit_after>// Copyright 2016 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 query

import (
	"fmt"
	"os"
	"time"

	"github.com/golang/protobuf/proto"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"

	log "github.com/golang/glog"
	ocpb "github.com/openconfig/reference/rpc/openconfig"
)

const (
	// TimeFormat is the default time format for the query.
	TimeFormat = "2000-01-01-01:01:01.00000000"
	// Delimiter is the default delimiter for the query.
	Delimiter = "/"
	// DialTimeout is the default dial timeout for the query.
	DialTimeout = 10 * time.Second
)

var (
	// defaultDisplay is the default implementation for displaying output from the
	// query.
	defaultDisplay = func(b []byte) {
		os.Stdout.Write(b)
	}
)

// Query contains the target and query for a request.
type Query struct {
	Address     string
	Target      string
	DialOptions []grpc.DialOption
	// Queries is a list queries made of query elements.
	Queries [][]string
	// Update is a single SetRequest to be made on the target.
	Update *ocpb.SetRequest
}

// Config contains the configuration for displaying a query.
type Config struct {
	Count       uint64
	Once        bool
	Delimiter   string
	DialTimeout time.Duration
	Display     func([]byte)
	TimeFormat  string
}

// Display creates a gRPC connection to the query target and makes a Get call
// for the queried paths and displays the response via cfg.Display.
func Display(ctx context.Context, query Query, cfg *Config) error {
	c, err := createClient(ctx, query, cfg)
	if err != nil {
		return err
	}
	request, err := createRequest(query)
	if err != nil {
		return err
	}
	log.Infof("Get with:\n%s\n", request)
	resp, err := c.Get(ctx, request)
	if err != nil {
		return err
	}
	for _, n := range resp.GetNotification() {
		cfg.Display([]byte(n.String()))
	}
	return nil
}

// DisplayStream creates a gRPC connection to the query target and makes a
// Subscribe call for the queried paths and streams the response via
// cfg.Display.
func DisplayStream(ctx context.Context, query Query, cfg *Config) error {
	c, err := createClient(ctx, query, cfg)
	if err != nil {
		return err
	}
	request, err := createSubscribeRequest(query)
	if err != nil {
		return err
	}
	stream, err := c.Subscribe(ctx)
	if err != nil {
		return err
	}
	if err := stream.Send(request); err != nil {
		return err
	}
	log.Infof("Subscribed with:\n%s", proto.MarshalTextString(request))
	for {
		resp, err := stream.Recv()
		log.V(2).Info(proto.MarshalTextString(resp))
		if err != nil {
			// TODO(hines): This should be io.EOF but for some reason the server
			// currently sends this code.
			if grpc.Code(err) != codes.OutOfRange {
				return err
			}
			return nil
		}
		switch resp.Response.(type) {
		default:
			log.Infof("Unknown response:\n%s\n", resp.String())
		case *ocpb.SubscribeResponse_Heartbeat:
			log.Infof("Heartbeat:%s\n", resp.String())
		case *ocpb.SubscribeResponse_Update:
			cfg.Display([]byte(proto.MarshalTextString(resp)))
		case *ocpb.SubscribeResponse_SyncResponse:
			log.Infof("Sync Response: %s", resp.String())
			if cfg.Once {
				stream.CloseSend()
				return nil
			}
		}
	}
}

// Update sends a SetRequest to the target.  If the Set fails an error will be
// returned.  The response will be displayed by the configure cfg.Display.
func Update(ctx context.Context, query Query, cfg *Config) error {
	c, err := createClient(ctx, query, cfg)
	_ = c
	if err != nil {
		return err
	}
	if query.Update == nil {
		return fmt.Errorf("query.Updates must be defined for Update")
	}
	resp, err := c.Set(ctx, query.Update)
	if err != nil {
		return fmt.Errorf("failed to set %s: %s", proto.MarshalTextString(query.Update), err)
	}
	cfg.Display([]byte(resp.String()))
	return nil
}

func createClient(ctx context.Context, query Query, cfg *Config) (ocpb.OpenConfigClient, error) {
	switch {
	case ctx == nil:
		return nil, fmt.Errorf("ctx must not be nil")
	case cfg == nil:
		return nil, fmt.Errorf("cfg must not be nil")
	case query.Target == "":
		return nil, fmt.Errorf("query target must be specified")
	}
	if cfg.Display == nil {
		cfg.Display = defaultDisplay
	}
	log.Infof("Creating connection: %+v", query)
	conn, err := grpc.Dial(query.Target, query.DialOptions...)
	if err != nil {
		return nil, err
	}
	return ocpb.NewOpenConfigClient(conn), nil
}

func createRequest(q Query) (*ocpb.GetRequest, error) {
	r := &ocpb.GetRequest{}
	for _, qItem := range q.Queries {
		p := &ocpb.Path{
			Element: qItem,
		}
		r.Path = append(r.Path, p)
	}
	return r, nil
}

func createSubscribeRequest(q Query) (*ocpb.SubscribeRequest, error) {
	// TODO(hines): Re-add once bug is resolved for lack of mode support.
	//subList := &ocpb.SubscriptionList{
	//	 Mode: &ocpb.SubscriptionList_Once{
	//	 Once: true,
	//	 },
	// }
	subList := &ocpb.SubscriptionList{}
	for _, qItem := range q.Queries {
		subList.Subscription = append(subList.Subscription, &ocpb.Subscription{
			Path: &ocpb.Path{
				Element: qItem,
			},
		})
	}
	return &ocpb.SubscribeRequest{
		Request: &ocpb.SubscribeRequest_Subscribe{
			Subscribe: subList,
		}}, nil
}
<|endoftext|>


<commit_before>/*
Copyright 2018 The Kubernetes Authors.

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

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

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

package dryrun

import (
	"context"
	"testing"

	v1 "k8s.io/api/core/v1"
	apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/util/sets"
	"k8s.io/apiserver/pkg/features"
	utilfeature "k8s.io/apiserver/pkg/util/feature"
	"k8s.io/client-go/dynamic"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/util/retry"
	featuregatetesting "k8s.io/component-base/featuregate/testing"
	kubeapiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
	"k8s.io/kubernetes/test/integration/etcd"
	"k8s.io/kubernetes/test/integration/framework"
)

// Only add kinds to this list when this a virtual resource with get and create verbs that doesn't actually
// store into it's kind.  We've used this downstream for mappings before.
var kindAllowList = sets.NewString()

// namespace used for all tests, do not change this
const testNamespace = "dryrunnamespace"

func DryRunCreateTest(t *testing.T, rsc dynamic.ResourceInterface, obj *unstructured.Unstructured, gvResource schema.GroupVersionResource) {
	createdObj, err := rsc.Create(context.TODO(), obj, metav1.CreateOptions{DryRun: []string{metav1.DryRunAll}})
	if err != nil {
		t.Fatalf("failed to dry-run create stub for %s: %#v", gvResource, err)
	}
	if obj.GroupVersionKind() != createdObj.GroupVersionKind() {
		t.Fatalf("created object doesn't have the same gvk as original object: got %v, expected %v",
			createdObj.GroupVersionKind(),
			obj.GroupVersionKind())
	}

	if _, err := rsc.Get(context.TODO(), obj.GetName(), metav1.GetOptions{}); !apierrors.IsNotFound(err) {
		t.Fatalf("object shouldn't exist: %v", err)
	}
}

func DryRunPatchTest(t *testing.T, rsc dynamic.ResourceInterface, name string) {
	patch := []byte(`{"metadata":{"annotations":{"patch": "true"}}}`)
	obj, err := rsc.Patch(context.TODO(), name, types.MergePatchType, patch, metav1.PatchOptions{DryRun: []string{metav1.DryRunAll}})
	if err != nil {
		t.Fatalf("failed to dry-run patch object: %v", err)
	}
	if v := obj.GetAnnotations()["patch"]; v != "true" {
		t.Fatalf("dry-run patched annotations should be returned, got: %v", obj.GetAnnotations())
	}
	obj, err = rsc.Get(context.TODO(), obj.GetName(), metav1.GetOptions{})
	if err != nil {
		t.Fatalf("failed to get object: %v", err)
	}
	if v := obj.GetAnnotations()["patch"]; v == "true" {
		t.Fatalf("dry-run patched annotations should not be persisted, got: %v", obj.GetAnnotations())
	}
}

func getReplicasOrFail(t *testing.T, obj *unstructured.Unstructured) int64 {
	t.Helper()
	replicas, found, err := unstructured.NestedInt64(obj.UnstructuredContent(), "spec", "replicas")
	if err != nil {
		t.Fatalf("failed to get int64 for replicas: %v", err)
	}
	if !found {
		t.Fatal("object doesn't have spec.replicas")
	}
	return replicas
}

func DryRunScalePatchTest(t *testing.T, rsc dynamic.ResourceInterface, name string) {
	obj, err := rsc.Get(context.TODO(), name, metav1.GetOptions{}, "scale")
	if apierrors.IsNotFound(err) {
		return
	}
	if err != nil {
		t.Fatalf("failed to get object: %v", err)
	}

	replicas := getReplicasOrFail(t, obj)
	patch := []byte(`{"spec":{"replicas":10}}`)
	patchedObj, err := rsc.Patch(context.TODO(), name, types.MergePatchType, patch, metav1.PatchOptions{DryRun: []string{metav1.DryRunAll}}, "scale")
	if err != nil {
		t.Fatalf("failed to dry-run patch object: %v", err)
	}
	if newReplicas := getReplicasOrFail(t, patchedObj); newReplicas != 10 {
		t.Fatalf("dry-run patch to replicas didn't return new value: %v", newReplicas)
	}
	persistedObj, err := rsc.Get(context.TODO(), name, metav1.GetOptions{}, "scale")
	if err != nil {
		t.Fatalf("failed to get scale sub-resource")
	}
	if newReplicas := getReplicasOrFail(t, persistedObj); newReplicas != replicas {
		t.Fatalf("number of replicas changed, expected %v, got %v", replicas, newReplicas)
	}
}

func DryRunScaleUpdateTest(t *testing.T, rsc dynamic.ResourceInterface, name string) {
	obj, err := rsc.Get(context.TODO(), name, metav1.GetOptions{}, "scale")
	if apierrors.IsNotFound(err) {
		return
	}
	if err != nil {
		t.Fatalf("failed to get object: %v", err)
	}

	replicas := getReplicasOrFail(t, obj)
	if err := unstructured.SetNestedField(obj.Object, int64(10), "spec", "replicas"); err != nil {
		t.Fatalf("failed to set spec.replicas: %v", err)
	}
	updatedObj, err := rsc.Update(context.TODO(), obj, metav1.UpdateOptions{DryRun: []string{metav1.DryRunAll}}, "scale")
	if err != nil {
		t.Fatalf("failed to dry-run update scale sub-resource: %v", err)
	}
	if newReplicas := getReplicasOrFail(t, updatedObj); newReplicas != 10 {
		t.Fatalf("dry-run update to replicas didn't return new value: %v", newReplicas)
	}
	persistedObj, err := rsc.Get(context.TODO(), name, metav1.GetOptions{}, "scale")
	if err != nil {
		t.Fatalf("failed to get scale sub-resource")
	}
	if newReplicas := getReplicasOrFail(t, persistedObj); newReplicas != replicas {
		t.Fatalf("number of replicas changed, expected %v, got %v", replicas, newReplicas)
	}
}

func DryRunUpdateTest(t *testing.T, rsc dynamic.ResourceInterface, name string) {
	var err error
	var obj *unstructured.Unstructured
	err = retry.RetryOnConflict(retry.DefaultBackoff, func() error {
		obj, err = rsc.Get(context.TODO(), name, metav1.GetOptions{})
		if err != nil {
			t.Fatalf("failed to retrieve object: %v", err)
		}
		obj.SetAnnotations(map[string]string{"update": "true"})
		obj, err = rsc.Update(context.TODO(), obj, metav1.UpdateOptions{DryRun: []string{metav1.DryRunAll}})
		if apierrors.IsConflict(err) {
			t.Logf("conflict error: %v", err)
		}
		return err
	})
	if err != nil {
		t.Fatalf("failed to dry-run update resource: %v", err)
	}
	if v := obj.GetAnnotations()["update"]; v != "true" {
		t.Fatalf("dry-run updated annotations should be returned, got: %v", obj.GetAnnotations())
	}

	obj, err = rsc.Get(context.TODO(), obj.GetName(), metav1.GetOptions{})
	if err != nil {
		t.Fatalf("failed to get object: %v", err)
	}
	if v := obj.GetAnnotations()["update"]; v == "true" {
		t.Fatalf("dry-run updated annotations should not be persisted, got: %v", obj.GetAnnotations())
	}
}

func DryRunDeleteCollectionTest(t *testing.T, rsc dynamic.ResourceInterface, name string) {
	err := rsc.DeleteCollection(context.TODO(), metav1.DeleteOptions{DryRun: []string{metav1.DryRunAll}}, metav1.ListOptions{})
	if err != nil {
		t.Fatalf("dry-run delete collection failed: %v", err)
	}
	obj, err := rsc.Get(context.TODO(), name, metav1.GetOptions{})
	if err != nil {
		t.Fatalf("failed to get object: %v", err)
	}
	ts := obj.GetDeletionTimestamp()
	if ts != nil {
		t.Fatalf("object has a deletion timestamp after dry-run delete collection")
	}
}

func DryRunDeleteTest(t *testing.T, rsc dynamic.ResourceInterface, name string) {
	err := rsc.Delete(context.TODO(), name, metav1.DeleteOptions{DryRun: []string{metav1.DryRunAll}})
	if err != nil {
		t.Fatalf("dry-run delete failed: %v", err)
	}
	obj, err := rsc.Get(context.TODO(), name, metav1.GetOptions{})
	if err != nil {
		t.Fatalf("failed to get object: %v", err)
	}
	ts := obj.GetDeletionTimestamp()
	if ts != nil {
		t.Fatalf("object has a deletion timestamp after dry-run delete")
	}
}

// TestDryRun tests dry-run on all types.
func TestDryRun(t *testing.T) {
	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.DryRun, true)()

	// start API server
	s, err := kubeapiservertesting.StartTestServer(t, kubeapiservertesting.NewDefaultTestServerOptions(), []string{
		"--disable-admission-plugins=ServiceAccount,StorageObjectInUseProtection",
		"--runtime-config=api/all=true",
	}, framework.SharedEtcd())
	if err != nil {
		t.Fatal(err)
	}
	defer s.TearDownFn()

	client, err := kubernetes.NewForConfig(s.ClientConfig)
	if err != nil {
		t.Fatal(err)
	}
	dynamicClient, err := dynamic.NewForConfig(s.ClientConfig)
	if err != nil {
		t.Fatal(err)
	}

	// create CRDs so we can make sure that custom resources do not get lost
	etcd.CreateTestCRDs(t, apiextensionsclientset.NewForConfigOrDie(s.ClientConfig), false, etcd.GetCustomResourceDefinitionData()...)

	if _, err := client.CoreV1().Namespaces().Create(context.TODO(), &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: testNamespace}}, metav1.CreateOptions{}); err != nil {
		t.Fatal(err)
	}

	dryrunData := etcd.GetEtcdStorageData()

	// dry run specific stub overrides
	for resource, stub := range map[schema.GroupVersionResource]string{
		// need to change event's namespace field to match dry run test
		gvr("", "v1", "events"): `{"involvedObject": {"namespace": "dryrunnamespace"}, "message": "some data here", "metadata": {"name": "event1"}}`,
	} {
		data := dryrunData[resource]
		data.Stub = stub
		dryrunData[resource] = data
	}

	// gather resources to test
	_, resources, err := client.Discovery().ServerGroupsAndResources()
	if err != nil {
		t.Fatalf("Failed to get ServerGroupsAndResources with error: %+v", err)
	}

	for _, resourceToTest := range etcd.GetResources(t, resources) {
		t.Run(resourceToTest.Mapping.Resource.String(), func(t *testing.T) {
			mapping := resourceToTest.Mapping
			gvk := resourceToTest.Mapping.GroupVersionKind
			gvResource := resourceToTest.Mapping.Resource
			kind := gvk.Kind

			if kindAllowList.Has(kind) {
				t.Skip("allowlisted")
			}

			testData, hasTest := dryrunData[gvResource]

			if !hasTest {
				t.Fatalf("no test data for %s.  Please add a test for your new type to etcd.GetEtcdStorageData().", gvResource)
			}

			rsc, obj, err := etcd.JSONToUnstructured(testData.Stub, testNamespace, mapping, dynamicClient)
			if err != nil {
				t.Fatalf("failed to unmarshal stub (%v): %v", testData.Stub, err)
			}

			name := obj.GetName()

			DryRunCreateTest(t, rsc, obj, gvResource)

			if _, err := rsc.Create(context.TODO(), obj, metav1.CreateOptions{}); err != nil {
				t.Fatalf("failed to create stub for %s: %#v", gvResource, err)
			}

			DryRunUpdateTest(t, rsc, name)
			DryRunPatchTest(t, rsc, name)
			DryRunScalePatchTest(t, rsc, name)
			DryRunScaleUpdateTest(t, rsc, name)
			if resourceToTest.HasDeleteCollection {
				DryRunDeleteCollectionTest(t, rsc, name)
			}
			DryRunDeleteTest(t, rsc, name)

			if err = rsc.Delete(context.TODO(), obj.GetName(), *metav1.NewDeleteOptions(0)); err != nil {
				t.Fatalf("deleting final object failed: %v", err)
			}
		})
	}
}

func gvr(g, v, r string) schema.GroupVersionResource {
	return schema.GroupVersionResource{Group: g, Version: v, Resource: r}
}
<commit_msg>add test to dry-run for unwanted generated values<commit_after>/*
Copyright 2018 The Kubernetes Authors.

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

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

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

package dryrun

import (
	"context"
	"testing"

	v1 "k8s.io/api/core/v1"
	apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/util/sets"
	"k8s.io/apiserver/pkg/features"
	utilfeature "k8s.io/apiserver/pkg/util/feature"
	"k8s.io/client-go/dynamic"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/util/retry"
	featuregatetesting "k8s.io/component-base/featuregate/testing"
	kubeapiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
	"k8s.io/kubernetes/test/integration/etcd"
	"k8s.io/kubernetes/test/integration/framework"
)

// Only add kinds to this list when this a virtual resource with get and create verbs that doesn't actually
// store into it's kind.  We've used this downstream for mappings before.
var kindAllowList = sets.NewString()

// namespace used for all tests, do not change this
const testNamespace = "dryrunnamespace"

func DryRunCreateWithGenerateNameTest(t *testing.T, rsc dynamic.ResourceInterface, obj *unstructured.Unstructured, gvResource schema.GroupVersionResource) {
	// Create a new object with generateName
	gnObj := obj.DeepCopy()
	gnObj.SetGenerateName(obj.GetName() + "-")
	gnObj.SetName("")
	DryRunCreateTest(t, rsc, gnObj, gvResource)
}

func DryRunCreateTest(t *testing.T, rsc dynamic.ResourceInterface, obj *unstructured.Unstructured, gvResource schema.GroupVersionResource) {
	createdObj, err := rsc.Create(context.TODO(), obj, metav1.CreateOptions{DryRun: []string{metav1.DryRunAll}})
	if err != nil {
		t.Fatalf("failed to dry-run create stub for %s: %#v: %v", gvResource, err, obj)
	}
	if obj.GroupVersionKind() != createdObj.GroupVersionKind() {
		t.Fatalf("created object doesn't have the same gvk as original object: got %v, expected %v",
			createdObj.GroupVersionKind(),
			obj.GroupVersionKind())
	}
	if createdObj.GetUID() != "" {
		t.Fatalf("created object shouldn't have a uid: %v", createdObj)
	}
	if createdObj.GetResourceVersion() != "" {
		t.Fatalf("created object shouldn't have a resource version: %v", createdObj)
	}
	if obj.GetGenerateName() != "" && createdObj.GetName() != "" {
		t.Fatalf("created object's name should be an empty string if using GenerateName: %v", createdObj)
	}

	if _, err := rsc.Get(context.TODO(), obj.GetName(), metav1.GetOptions{}); !apierrors.IsNotFound(err) {
		t.Fatalf("object shouldn't exist: %v", err)
	}
}

func DryRunPatchTest(t *testing.T, rsc dynamic.ResourceInterface, name string) {
	patch := []byte(`{"metadata":{"annotations":{"patch": "true"}}}`)
	obj, err := rsc.Patch(context.TODO(), name, types.MergePatchType, patch, metav1.PatchOptions{DryRun: []string{metav1.DryRunAll}})
	if err != nil {
		t.Fatalf("failed to dry-run patch object: %v", err)
	}
	if v := obj.GetAnnotations()["patch"]; v != "true" {
		t.Fatalf("dry-run patched annotations should be returned, got: %v", obj.GetAnnotations())
	}
	obj, err = rsc.Get(context.TODO(), obj.GetName(), metav1.GetOptions{})
	if err != nil {
		t.Fatalf("failed to get object: %v", err)
	}
	if v := obj.GetAnnotations()["patch"]; v == "true" {
		t.Fatalf("dry-run patched annotations should not be persisted, got: %v", obj.GetAnnotations())
	}
}

func getReplicasOrFail(t *testing.T, obj *unstructured.Unstructured) int64 {
	t.Helper()
	replicas, found, err := unstructured.NestedInt64(obj.UnstructuredContent(), "spec", "replicas")
	if err != nil {
		t.Fatalf("failed to get int64 for replicas: %v", err)
	}
	if !found {
		t.Fatal("object doesn't have spec.replicas")
	}
	return replicas
}

func DryRunScalePatchTest(t *testing.T, rsc dynamic.ResourceInterface, name string) {
	obj, err := rsc.Get(context.TODO(), name, metav1.GetOptions{}, "scale")
	if apierrors.IsNotFound(err) {
		return
	}
	if err != nil {
		t.Fatalf("failed to get object: %v", err)
	}

	replicas := getReplicasOrFail(t, obj)
	patch := []byte(`{"spec":{"replicas":10}}`)
	patchedObj, err := rsc.Patch(context.TODO(), name, types.MergePatchType, patch, metav1.PatchOptions{DryRun: []string{metav1.DryRunAll}}, "scale")
	if err != nil {
		t.Fatalf("failed to dry-run patch object: %v", err)
	}
	if newReplicas := getReplicasOrFail(t, patchedObj); newReplicas != 10 {
		t.Fatalf("dry-run patch to replicas didn't return new value: %v", newReplicas)
	}
	persistedObj, err := rsc.Get(context.TODO(), name, metav1.GetOptions{}, "scale")
	if err != nil {
		t.Fatalf("failed to get scale sub-resource")
	}
	if newReplicas := getReplicasOrFail(t, persistedObj); newReplicas != replicas {
		t.Fatalf("number of replicas changed, expected %v, got %v", replicas, newReplicas)
	}
}

func DryRunScaleUpdateTest(t *testing.T, rsc dynamic.ResourceInterface, name string) {
	obj, err := rsc.Get(context.TODO(), name, metav1.GetOptions{}, "scale")
	if apierrors.IsNotFound(err) {
		return
	}
	if err != nil {
		t.Fatalf("failed to get object: %v", err)
	}

	replicas := getReplicasOrFail(t, obj)
	if err := unstructured.SetNestedField(obj.Object, int64(10), "spec", "replicas"); err != nil {
		t.Fatalf("failed to set spec.replicas: %v", err)
	}
	updatedObj, err := rsc.Update(context.TODO(), obj, metav1.UpdateOptions{DryRun: []string{metav1.DryRunAll}}, "scale")
	if err != nil {
		t.Fatalf("failed to dry-run update scale sub-resource: %v", err)
	}
	if newReplicas := getReplicasOrFail(t, updatedObj); newReplicas != 10 {
		t.Fatalf("dry-run update to replicas didn't return new value: %v", newReplicas)
	}
	persistedObj, err := rsc.Get(context.TODO(), name, metav1.GetOptions{}, "scale")
	if err != nil {
		t.Fatalf("failed to get scale sub-resource")
	}
	if newReplicas := getReplicasOrFail(t, persistedObj); newReplicas != replicas {
		t.Fatalf("number of replicas changed, expected %v, got %v", replicas, newReplicas)
	}
}

func DryRunUpdateTest(t *testing.T, rsc dynamic.ResourceInterface, name string) {
	var err error
	var obj *unstructured.Unstructured
	err = retry.RetryOnConflict(retry.DefaultBackoff, func() error {
		obj, err = rsc.Get(context.TODO(), name, metav1.GetOptions{})
		if err != nil {
			t.Fatalf("failed to retrieve object: %v", err)
		}
		obj.SetAnnotations(map[string]string{"update": "true"})
		obj, err = rsc.Update(context.TODO(), obj, metav1.UpdateOptions{DryRun: []string{metav1.DryRunAll}})
		if apierrors.IsConflict(err) {
			t.Logf("conflict error: %v", err)
		}
		return err
	})
	if err != nil {
		t.Fatalf("failed to dry-run update resource: %v", err)
	}
	if v := obj.GetAnnotations()["update"]; v != "true" {
		t.Fatalf("dry-run updated annotations should be returned, got: %v", obj.GetAnnotations())
	}

	obj, err = rsc.Get(context.TODO(), obj.GetName(), metav1.GetOptions{})
	if err != nil {
		t.Fatalf("failed to get object: %v", err)
	}
	if v := obj.GetAnnotations()["update"]; v == "true" {
		t.Fatalf("dry-run updated annotations should not be persisted, got: %v", obj.GetAnnotations())
	}
}

func DryRunDeleteCollectionTest(t *testing.T, rsc dynamic.ResourceInterface, name string) {
	err := rsc.DeleteCollection(context.TODO(), metav1.DeleteOptions{DryRun: []string{metav1.DryRunAll}}, metav1.ListOptions{})
	if err != nil {
		t.Fatalf("dry-run delete collection failed: %v", err)
	}
	obj, err := rsc.Get(context.TODO(), name, metav1.GetOptions{})
	if err != nil {
		t.Fatalf("failed to get object: %v", err)
	}
	ts := obj.GetDeletionTimestamp()
	if ts != nil {
		t.Fatalf("object has a deletion timestamp after dry-run delete collection")
	}
}

func DryRunDeleteTest(t *testing.T, rsc dynamic.ResourceInterface, name string) {
	err := rsc.Delete(context.TODO(), name, metav1.DeleteOptions{DryRun: []string{metav1.DryRunAll}})
	if err != nil {
		t.Fatalf("dry-run delete failed: %v", err)
	}
	obj, err := rsc.Get(context.TODO(), name, metav1.GetOptions{})
	if err != nil {
		t.Fatalf("failed to get object: %v", err)
	}
	ts := obj.GetDeletionTimestamp()
	if ts != nil {
		t.Fatalf("object has a deletion timestamp after dry-run delete")
	}
}

// TestDryRun tests dry-run on all types.
func TestDryRun(t *testing.T) {
	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.DryRun, true)()

	// start API server
	s, err := kubeapiservertesting.StartTestServer(t, kubeapiservertesting.NewDefaultTestServerOptions(), []string{
		"--disable-admission-plugins=ServiceAccount,StorageObjectInUseProtection",
		"--runtime-config=api/all=true",
	}, framework.SharedEtcd())
	if err != nil {
		t.Fatal(err)
	}
	defer s.TearDownFn()

	client, err := kubernetes.NewForConfig(s.ClientConfig)
	if err != nil {
		t.Fatal(err)
	}
	dynamicClient, err := dynamic.NewForConfig(s.ClientConfig)
	if err != nil {
		t.Fatal(err)
	}

	// create CRDs so we can make sure that custom resources do not get lost
	etcd.CreateTestCRDs(t, apiextensionsclientset.NewForConfigOrDie(s.ClientConfig), false, etcd.GetCustomResourceDefinitionData()...)

	if _, err := client.CoreV1().Namespaces().Create(context.TODO(), &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: testNamespace}}, metav1.CreateOptions{}); err != nil {
		t.Fatal(err)
	}

	dryrunData := etcd.GetEtcdStorageData()

	// dry run specific stub overrides
	for resource, stub := range map[schema.GroupVersionResource]string{
		// need to change event's namespace field to match dry run test
		gvr("", "v1", "events"): `{"involvedObject": {"namespace": "dryrunnamespace"}, "message": "some data here", "metadata": {"name": "event1"}}`,
	} {
		data := dryrunData[resource]
		data.Stub = stub
		dryrunData[resource] = data
	}

	// gather resources to test
	_, resources, err := client.Discovery().ServerGroupsAndResources()
	if err != nil {
		t.Fatalf("Failed to get ServerGroupsAndResources with error: %+v", err)
	}

	for _, resourceToTest := range etcd.GetResources(t, resources) {
		t.Run(resourceToTest.Mapping.Resource.String(), func(t *testing.T) {
			mapping := resourceToTest.Mapping
			gvk := resourceToTest.Mapping.GroupVersionKind
			gvResource := resourceToTest.Mapping.Resource
			kind := gvk.Kind

			if kindAllowList.Has(kind) {
				t.Skip("allowlisted")
			}

			testData, hasTest := dryrunData[gvResource]

			if !hasTest {
				t.Fatalf("no test data for %s.  Please add a test for your new type to etcd.GetEtcdStorageData().", gvResource)
			}

			rsc, obj, err := etcd.JSONToUnstructured(testData.Stub, testNamespace, mapping, dynamicClient)
			if err != nil {
				t.Fatalf("failed to unmarshal stub (%v): %v", testData.Stub, err)
			}

			name := obj.GetName()

			DryRunCreateTest(t, rsc, obj, gvResource)
			DryRunCreateWithGenerateNameTest(t, rsc, obj, gvResource)

			if _, err := rsc.Create(context.TODO(), obj, metav1.CreateOptions{}); err != nil {
				t.Fatalf("failed to create stub for %s: %#v", gvResource, err)
			}

			DryRunUpdateTest(t, rsc, name)
			DryRunPatchTest(t, rsc, name)
			DryRunScalePatchTest(t, rsc, name)
			DryRunScaleUpdateTest(t, rsc, name)
			if resourceToTest.HasDeleteCollection {
				DryRunDeleteCollectionTest(t, rsc, name)
			}
			DryRunDeleteTest(t, rsc, name)

			if err = rsc.Delete(context.TODO(), obj.GetName(), *metav1.NewDeleteOptions(0)); err != nil {
				t.Fatalf("deleting final object failed: %v", err)
			}
		})
	}
}

func gvr(g, v, r string) schema.GroupVersionResource {
	return schema.GroupVersionResource{Group: g, Version: v, Resource: r}
}
<|endoftext|>


<commit_before>package consumergroup

import (
	"errors"
	"sync"

	"github.com/Shopify/sarama"
	"github.com/sirupsen/logrus"
)

type topicConsumer struct {
	group              string
	name               string
	owner              *ConsumerGroup
	errors             chan *sarama.ConsumerError
	messages           chan *sarama.ConsumerMessage
	partitionConsumers map[int32]*partitionConsumer
	wg                 sync.WaitGroup
}

func newTopicConsumer(owner *ConsumerGroup, topic string) *topicConsumer {
	tc := new(topicConsumer)
	tc.owner = owner
	tc.group = owner.name
	tc.name = topic
	tc.errors = make(chan *sarama.ConsumerError)
	tc.messages = make(chan *sarama.ConsumerMessage)
	return tc
}

func (tc *topicConsumer) start() {

	cg := tc.owner
	topic := tc.name

	cg.logger.WithFields(logrus.Fields{
		"group": tc.group,
		"topic": topic,
	}).Info("Start the topic consumer")

	partitions, err := tc.assignPartitions()
	if err != nil {
		cg.logger.WithFields(logrus.Fields{
			"group": tc.group,
			"topic": topic,
			"err":   err,
		}).Error("Failed to assign partitions to topic consumer")
		return
	}

	cg.logger.WithFields(logrus.Fields{
		"group":      tc.group,
		"topic":      topic,
		"partitions": partitions,
	}).Info("The partitions was assigned to current topic consumer")
	tc.partitionConsumers = make(map[int32]*partitionConsumer)
	for _, partition := range partitions {
		tc.partitionConsumers[partition] = newPartitionConsumer(tc, partition)
	}
	for partition, consumer := range tc.partitionConsumers {
		tc.wg.Add(1)
		go func(pc *partitionConsumer) {
			defer cg.callRecover()
			defer tc.wg.Done()
			pc.start()
		}(consumer)
		cg.logger.WithFields(logrus.Fields{
			"group":     tc.group,
			"topic":     topic,
			"partition": partition,
		}).Info("Topic consumer start to consume the partition")
	}
}

func (tc *topicConsumer) assignPartitions() ([]int32, error) {
	var partitions []int32

	cg := tc.owner
	partNum, err := tc.getPartitionNum()
	if err != nil || partNum == 0 {
		return nil, err
	}
	consumerList, err := cg.storage.getConsumerList(cg.name)
	if err != nil {
		return nil, err
	}
	consumerNum := len(consumerList)
	if consumerNum == 0 {
		return nil, errors.New("no consumer was found")
	}
	for i := int32(0); i < partNum; i++ {
		id := consumerList[i%int32(consumerNum)]
		cg.owners[tc.name][i] = id
		if id == cg.id {
			partitions = append(partitions, i)
		}
	}
	return partitions, nil
}

func (tc *topicConsumer) getPartitionNum() (int32, error) {
	if saramaConsumer, ok := tc.owner.saramaConsumers[tc.name]; !ok {
		return 0, errors.New("sarama conumser was not found")
	} else {
		partitions, err := saramaConsumer.Partitions(tc.name)
		if err != nil {
			return 0, err
		}
		return int32(len(partitions)), nil
	}
}

func (tc *topicConsumer) getOffsets() map[int32]interface{} {
	partitions := make(map[int32]interface{})
	for partition, pc := range tc.partitionConsumers {
		partitions[partition] = pc.getOffset()
	}
	return partitions
}
<commit_msg>FIX: make lint error<commit_after>package consumergroup

import (
	"errors"
	"sync"

	"github.com/Shopify/sarama"
	"github.com/sirupsen/logrus"
)

type topicConsumer struct {
	group              string
	name               string
	owner              *ConsumerGroup
	errors             chan *sarama.ConsumerError
	messages           chan *sarama.ConsumerMessage
	partitionConsumers map[int32]*partitionConsumer
	wg                 sync.WaitGroup
}

func newTopicConsumer(owner *ConsumerGroup, topic string) *topicConsumer {
	tc := new(topicConsumer)
	tc.owner = owner
	tc.group = owner.name
	tc.name = topic
	tc.errors = make(chan *sarama.ConsumerError)
	tc.messages = make(chan *sarama.ConsumerMessage)
	return tc
}

func (tc *topicConsumer) start() {

	cg := tc.owner
	topic := tc.name

	cg.logger.WithFields(logrus.Fields{
		"group": tc.group,
		"topic": topic,
	}).Info("Start the topic consumer")

	partitions, err := tc.assignPartitions()
	if err != nil {
		cg.logger.WithFields(logrus.Fields{
			"group": tc.group,
			"topic": topic,
			"err":   err,
		}).Error("Failed to assign partitions to topic consumer")
		return
	}

	cg.logger.WithFields(logrus.Fields{
		"group":      tc.group,
		"topic":      topic,
		"partitions": partitions,
	}).Info("The partitions was assigned to current topic consumer")
	tc.partitionConsumers = make(map[int32]*partitionConsumer)
	for _, partition := range partitions {
		tc.partitionConsumers[partition] = newPartitionConsumer(tc, partition)
	}
	for partition, consumer := range tc.partitionConsumers {
		tc.wg.Add(1)
		go func(pc *partitionConsumer) {
			defer cg.callRecover()
			defer tc.wg.Done()
			pc.start()
		}(consumer)
		cg.logger.WithFields(logrus.Fields{
			"group":     tc.group,
			"topic":     topic,
			"partition": partition,
		}).Info("Topic consumer start to consume the partition")
	}
}

func (tc *topicConsumer) assignPartitions() ([]int32, error) {
	var partitions []int32

	cg := tc.owner
	partNum, err := tc.getPartitionNum()
	if err != nil || partNum == 0 {
		return nil, err
	}
	consumerList, err := cg.storage.getConsumerList(cg.name)
	if err != nil {
		return nil, err
	}
	consumerNum := len(consumerList)
	if consumerNum == 0 {
		return nil, errors.New("no consumer was found")
	}
	for i := int32(0); i < partNum; i++ {
		id := consumerList[i%int32(consumerNum)]
		cg.owners[tc.name][i] = id
		if id == cg.id {
			partitions = append(partitions, i)
		}
	}
	return partitions, nil
}

func (tc *topicConsumer) getPartitionNum() (int32, error) {
	saramaConsumer, ok := tc.owner.saramaConsumers[tc.name]
	if !ok {
		return 0, errors.New("sarama conumser was not found")
	}
	partitions, err := saramaConsumer.Partitions(tc.name)
	if err != nil {
		return 0, err
	}
	return int32(len(partitions)), nil
}

func (tc *topicConsumer) getOffsets() map[int32]interface{} {
	partitions := make(map[int32]interface{})
	for partition, pc := range tc.partitionConsumers {
		partitions[partition] = pc.getOffset()
	}
	return partitions
}
<|endoftext|>


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

package otel // import "go.opentelemetry.io/otel"

import (
	"go.opentelemetry.io/otel/internal/global"
	"go.opentelemetry.io/otel/trace"
)

// Tracer creates a named tracer that implements Tracer interface.
// If the name is an empty string then provider uses default name.
//
// This is short for GetTracerProvider().Tracer(name, opts...)
func Tracer(name string, opts ...trace.TracerOption) trace.Tracer {
	return GetTracerProvider().Tracer(name, opts...)
}

// GetTracerProvider returns the registered global trace provider.
// If none is registered then an instance of NoopTracerProvider is returned.
//
// Use the trace provider to create a named tracer. E.g.
//     tracer := global.GetTracerProvider().Tracer("example.com/foo")
// or
//     tracer := global.Tracer("example.com/foo")
func GetTracerProvider() trace.TracerProvider {
	return global.TracerProvider()
}

// SetTracerProvider registers `tp` as the global trace provider.
func SetTracerProvider(tp trace.TracerProvider) {
	global.SetTracerProvider(tp)
}
<commit_msg>Fix code sample in otel.GetTraceProvider (#2147)<commit_after>// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package otel // import "go.opentelemetry.io/otel"

import (
	"go.opentelemetry.io/otel/internal/global"
	"go.opentelemetry.io/otel/trace"
)

// Tracer creates a named tracer that implements Tracer interface.
// If the name is an empty string then provider uses default name.
//
// This is short for GetTracerProvider().Tracer(name, opts...)
func Tracer(name string, opts ...trace.TracerOption) trace.Tracer {
	return GetTracerProvider().Tracer(name, opts...)
}

// GetTracerProvider returns the registered global trace provider.
// If none is registered then an instance of NoopTracerProvider is returned.
//
// Use the trace provider to create a named tracer. E.g.
//     tracer := otel.GetTracerProvider().Tracer("example.com/foo")
// or
//     tracer := otel.Tracer("example.com/foo")
func GetTracerProvider() trace.TracerProvider {
	return global.TracerProvider()
}

// SetTracerProvider registers `tp` as the global trace provider.
func SetTracerProvider(tp trace.TracerProvider) {
	global.SetTracerProvider(tp)
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"encoding/json"
	"log"
	"os"

	_ "github.com/lib/pq"
	"github.com/thedadams/telegram-bot-api"
)

// CAHBot inherits from tgbotapi.
type CAHBot struct {
	*tgbotapi.BotAPI
	DBConn           *sql.DB
	AllQuestionCards []QuestionCard `json:"all_question_cards"`
	AllAnswerCards   []AnswerCard   `json:"all_answer_cards"`
	Settings         []Setting      `json:"settings"`
}

// NewCAHBot creates a new CAHBot.
func NewCAHBot(token string) (*CAHBot, error) {
	GenericBot, err := tgbotapi.NewBotAPI(os.Getenv("TOKEN"))
	// Need to get the card data
	var AllQuestionCards []QuestionCard
	err = json.Unmarshal(AllQuestions, &AllQuestionCards)
	if err != nil {
		log.Printf("%v", err)
	}
	var AllAnswerCards []AnswerCard
	err = json.Unmarshal(AllAnswers, &AllAnswerCards)
	if err != nil {
		log.Printf("%v", err)
	}
	var Settings []Setting
	err = json.Unmarshal(AllSettings, &Settings)
	if err != nil {
		log.Printf("%v", err)
	}
	db, err := sql.Open("postgres", os.Getenv("DATABASE_URL"))
	if err != nil {
		log.Fatal(err)
	}
	return &CAHBot{GenericBot, db, AllQuestionCards, AllAnswerCards, Settings}, err
}

// QuestionCard represents a white card in CAH.
type QuestionCard struct {
	ID         int    `json:"id"`
	Text       string `json:"text"`
	NumAnswers int    `json:"numAnswers"`
	Expansion  string `json:"expansion"`
}

// AnswerCard represents a black card in CAH.
type AnswerCard struct {
	ID        int    `json:"id"`
	Text      string `json:"text"`
	Expansion string `json:"expansion"`
}

// Setting represents a setting in the game that can be changed.
type Setting struct {
	Name    string    `json:"name"`
	CData   string    `json:"cdata"`
	Options []Setting `json:"options"` // optional
}
<commit_msg>Better error handling for creating a bot<commit_after>package main

import (
	"database/sql"
	"encoding/json"
	"log"
	"os"

	_ "github.com/lib/pq"
	"github.com/thedadams/telegram-bot-api"
)

// CAHBot inherits from tgbotapi.
type CAHBot struct {
	*tgbotapi.BotAPI
	DBConn           *sql.DB
	AllQuestionCards []QuestionCard `json:"all_question_cards"`
	AllAnswerCards   []AnswerCard   `json:"all_answer_cards"`
	Settings         []Setting      `json:"settings"`
}

// NewCAHBot creates a new CAHBot.
func NewCAHBot(token string) (*CAHBot, error) {
	GenericBot, err := tgbotapi.NewBotAPI(os.Getenv("TOKEN"))
	if err != nil {
		log.Printf("Error initializing bot: %v", err)
		return nil, err
	}
	// Need to get the card data
	var AllQuestionCards []QuestionCard
	err = json.Unmarshal(AllQuestions, &AllQuestionCards)
	if err != nil {
		log.Printf("%v", err)
		return nil, err
	}
	var AllAnswerCards []AnswerCard
	err = json.Unmarshal(AllAnswers, &AllAnswerCards)
	if err != nil {
		log.Printf("%v", err)
		return nil, err
	}
	var Settings []Setting
	err = json.Unmarshal(AllSettings, &Settings)
	if err != nil {
		log.Printf("%v", err)
		return nil, err
	}
	db, err := sql.Open("postgres", os.Getenv("DATABASE_URL"))
	if err != nil {
		log.Printf("%v", err)
	}
	return &CAHBot{GenericBot, db, AllQuestionCards, AllAnswerCards, Settings}, err
}

// QuestionCard represents a white card in CAH.
type QuestionCard struct {
	ID         int    `json:"id"`
	Text       string `json:"text"`
	NumAnswers int    `json:"numAnswers"`
	Expansion  string `json:"expansion"`
}

// AnswerCard represents a black card in CAH.
type AnswerCard struct {
	ID        int    `json:"id"`
	Text      string `json:"text"`
	Expansion string `json:"expansion"`
}

// Setting represents a setting in the game that can be changed.
type Setting struct {
	Name    string    `json:"name"`
	CData   string    `json:"cdata"`
	Options []Setting `json:"options"` // optional
}
<|endoftext|>


<commit_before>package	gearman // import "github.com/nathanaelle/gearman"

import	(
	"errors"
	"encoding/base64"
)

type	(
	MarshalerGearman interface {
		MarshalGearman() ([]byte,error)
		Len()	int
	}

	UnmarshalerGearman interface {
		UnmarshalGearman([]byte) error
	}

	Opaque		interface {
		MarshalerGearman
		UnmarshalerGearman
		Cast(UnmarshalerGearman) error
		Bytes()	[]byte
	}

	TaskID		[64]byte

	Function	[]byte
	ClientId	[]byte

	opaque		[]byte

	opaque0size	struct {}
)

var empty_opaque	*opaque0size = &opaque0size{}

func Opacify(b []byte) Opaque {
	if len(b) == 0 {
		return empty_opaque
	}

	o := opaque(b)

	return &o
}

func (o *opaque)UnmarshalGearman(d []byte) error {
	*o = d
	return	nil
}

func (o *opaque)MarshalGearman() ([]byte,error) {
	return o.Bytes(), nil
}

func (o *opaque)Bytes()	[]byte {
	return	[]byte(*o)
}

func (o *opaque)Len() int {
	return	len(o.Bytes())
}

func (o *opaque)Cast(um UnmarshalerGearman) error {
	return	um.UnmarshalGearman([]byte(*o))
}

func (_ *opaque0size)UnmarshalGearman(d []byte) error {
	if len(d) > 0 {
		return errors.New("empty_opaque can't unmarshal data")
	}
	return	nil
}

func (_ *opaque0size)MarshalGearman() ([]byte,error) {
	return []byte{}, nil
}

func (_ *opaque0size)Bytes() []byte {
	return []byte{}
}

func (_ *opaque0size)Len() int {
	return	0
}

func (_ *opaque0size)Cast(um UnmarshalerGearman) error {
	return	um.UnmarshalGearman([]byte{})
}

func (tid TaskID)MarshalGearman() ([]byte,error) {
	return	tid[0:tid.Len()],nil
}

func (tid TaskID)Len() int {
	end := 63
	for tid[end] == 0 {
		end--
	}

	return end+1
}

func (tid *TaskID)UnmarshalGearman(d []byte) error {
	if len(d) > 64 {
		return	errors.New("tid too long")
	}

	for _,v := range d {
		if v == 0 {
			return errors.New("invalid TaskID")
		}
	}

	copy(tid[0:len(d)], d[:])
	return	nil
}

func (fn *Function)UnmarshalGearman(d []byte) error {
	*fn = Function(d)
	return	nil
}

func (fn Function)MarshalGearman() ([]byte,error) {
	return fn, nil
}

func (fn Function)Len() int {
	return	len(fn)
}

func (fn Function)String() string {
	return	base64.RawURLEncoding.EncodeToString([]byte(fn))
}

func (clid *ClientId)UnmarshalGearman(d []byte) error {
	*clid = d
	return	nil
}

func (clid ClientId)MarshalGearman() ([]byte,error) {
	return clid, nil
}

func (clid ClientId)Len() int {
	return	len([]byte(clid))
}
<commit_msg>add IsEqual(Function)(bool) to Function vanity type<commit_after>package	gearman // import "github.com/nathanaelle/gearman"

import	(
	"bytes"
	"errors"
	"encoding/base64"
)

type	(
	MarshalerGearman interface {
		MarshalGearman() ([]byte,error)
		Len()	int
	}

	UnmarshalerGearman interface {
		UnmarshalGearman([]byte) error
	}

	Opaque		interface {
		MarshalerGearman
		UnmarshalerGearman
		Cast(UnmarshalerGearman) error
		Bytes()	[]byte
	}

	TaskID		[64]byte

	Function	[]byte
	ClientId	[]byte

	opaque		[]byte

	opaque0size	struct {}
)

var empty_opaque	*opaque0size = &opaque0size{}

func Opacify(b []byte) Opaque {
	if len(b) == 0 {
		return empty_opaque
	}

	o := opaque(b)

	return &o
}

func (o *opaque)UnmarshalGearman(d []byte) error {
	*o = d
	return	nil
}

func (o *opaque)MarshalGearman() ([]byte,error) {
	return o.Bytes(), nil
}

func (o *opaque)Bytes()	[]byte {
	return	[]byte(*o)
}

func (o *opaque)Len() int {
	return	len(o.Bytes())
}

func (o *opaque)Cast(um UnmarshalerGearman) error {
	return	um.UnmarshalGearman([]byte(*o))
}

func (_ *opaque0size)UnmarshalGearman(d []byte) error {
	if len(d) > 0 {
		return errors.New("empty_opaque can't unmarshal data")
	}
	return	nil
}

func (_ *opaque0size)MarshalGearman() ([]byte,error) {
	return []byte{}, nil
}

func (_ *opaque0size)Bytes() []byte {
	return []byte{}
}

func (_ *opaque0size)Len() int {
	return	0
}

func (_ *opaque0size)Cast(um UnmarshalerGearman) error {
	return	um.UnmarshalGearman([]byte{})
}

func (tid TaskID)MarshalGearman() ([]byte,error) {
	return	tid[0:tid.Len()],nil
}

func (tid TaskID)Len() int {
	end := 63
	for tid[end] == 0 {
		end--
	}

	return end+1
}

func (tid *TaskID)UnmarshalGearman(d []byte) error {
	if len(d) > 64 {
		return	errors.New("tid too long")
	}

	for _,v := range d {
		if v == 0 {
			return errors.New("invalid TaskID")
		}
	}

	copy(tid[0:len(d)], d[:])
	return	nil
}

func (fn *Function)UnmarshalGearman(d []byte) error {
	*fn = Function(d)
	return	nil
}

func (fn Function)MarshalGearman() ([]byte,error) {
	return fn, nil
}

func (fn Function)Len() int {
	return	len(fn)
}

func (fn Function)String() string {
	return	base64.RawURLEncoding.EncodeToString([]byte(fn))
}

func (f1 Function)IsEqual(f2 Function) bool {
	return	bytes.Equal(f1, f2)
}

func (clid *ClientId)UnmarshalGearman(d []byte) error {
	*clid = d
	return	nil
}

func (clid ClientId)MarshalGearman() ([]byte,error) {
	return clid, nil
}

func (clid ClientId)Len() int {
	return	len([]byte(clid))
}
<|endoftext|>


<commit_before>package megos

// State represents the JSON from the state.json of a mesos node
type State struct {
	ActivatedSlaves        float32     `json:"activated_slaves"`
	BuildDate              string      `json:"build_date"`
	BuildTime              float32     `json:"build_time"`
	BuildUser              string      `json:"build_user"`
	Cluster                string      `json:"cluster"`
	CompletedFrameworks    []Framework `json:"completed_frameworks"`
	DeactivatedSlaves      float32     `json:"deactivated_slaves"`
	ElectedTime            float32     `json:"elected_time"`
	Flags                  Flags       `json:"flags"`
	Frameworks             []Framework `json:"frameworks"`
	GitSHA                 string      `json:"git_sha"`
	GitBranch              string      `json:"git_branch"`
	GitTag                 string      `json:"git_tag"`
	Hostname               string      `json:"hostname"`
	ID                     string      `json:"id"`
	Leader                 string      `json:"leader"`
	LogDir                 string      `json:"log_dir"`
	ExternalLogFile        string      `json:"external_log_file"`
	OrphanTasks            []Task      `json:"orphan_tasks"`
	PID                    string      `json:"pid"`
	Slaves                 []Slave     `json:"slaves"`
	StartTime              float32     `json:"start_time"`
	UnregisteredFrameworks []string    `json:"unregistered_frameworks"`
	Version                string      `json:"version"`
}

// Flags represents the flags of a mesos state
type Flags struct {
	AllocationInterval          string `json:"allocation_interval"`
	Allocator                   string `json:"allocator"`
	Authenticate                string `json:"authenticate"`
	Authenticatee               string `json:"authenticatee"`
	AuthenticateSlaves          string `json:"authenticate_slaves"`
	Authenticators              string `json:"authenticators"`
	Authorizers                 string `json:"authorizers"`
	CgroupsEnableCfs            string `json:"cgroups_enable_cfs"`
	CgroupsHierarchy            string `json:"cgroups_hierarchy"`
	CgroupsLimitSwap            string `json:"cgroups_limit_swap"`
	CgroupsRoot                 string `json:"cgroups_root"`
	Cluster                     string `json:"cluster"`
	ContainerDiskWatchInterval  string `json:"container_disk_watch_interval"`
	Containerizers              string `json:"containerizers"`
	DefaultRole                 string `json:"default_role"`
	DiskWatchInterval           string `json:"disk_watch_interval"`
	Docker                      string `json:"docker"`
	DockerRemoveDelay           string `json:"docker_remove_delay"`
	DockerSandboxDirectory      string `json:"docker_sandbox_directory"`
	DockerStopTimeout           string `json:"docker_stop_timeout"`
	EnforceContainerDiskQuota   string `json:"enforce_container_disk_quota"`
	ExecutorRegistrationTimeout string `json:"executor_registration_timeout"`
	ExecutorShutdownGracePeriod string `json:"executor_shutdown_grace_period"`
	FrameworksHome              string `json:"frameworks_home"`
	FrameworkSorter             string `json:"framework_sorter"`
	GCDelay                     string `json:"gc_delay"`
	GCDiskHeadroom              string `json:"gc_disk_headroom"`
	HadoopHome                  string `json:"hadoop_home"`
	Help                        string `json:"help"`
	Hostname                    string `json:"hostname"`
	InitializeDriverLogging     string `json:"initialize_driver_logging"`
	IP                          string `json:"ip"`
	Isolation                   string `json:"isolation"`
	LauncherDir                 string `json:"launcher_dir"`
	LogAutoInitialize           string `json:"log_auto_initialize"`
	LogDir                      string `json:"log_dir"`
	Logbufsecs                  string `json:"logbufsecs"`
	LoggingLevel                string `json:"logging_level"`
	MaxSlavePingTimeouts        string `json:"max_slave_ping_timeouts"`
	Master                      string `json:"master"`
	PerfDuration                string `json:"perf_duration"`
	PerfInterval                string `json:"perf_interval"`
	Port                        string `json:"port"`
	Quiet                       string `json:"quiet"`
	Quorum                      string `json:"quorum"`
	Recover                     string `json:"recover"`
	RecoverySlaveRemovalLimit   string `json:"recovery_slave_removal_limit"`
	RecoveryTimeout             string `json:"recovery_timeout"`
	RegistrationBackoffFactor   string `json:"registration_backoff_factor"`
	Registry                    string `json:"registry"`
	RegistryFetchTimeout        string `json:"registry_fetch_timeout"`
	RegistryStoreTimeout        string `json:"registry_store_timeout"`
	RegistryStrict              string `json:"registry_strict"`
	ResourceMonitoringInterval  string `json:"resource_monitoring_interval"`
	RootSubmissions             string `json:"root_submissions"`
	SlavePingTimeout            string `json:"slave_ping_timeout"`
	SlaveReregisterTimeout      string `json:"slave_reregister_timeout"`
	Strict                      string `json:"strict"`
	SwitchUser                  string `json:"switch_user"`
	UserSorter                  string `json:"user_sorter"`
	Version                     string `json:"version"`
	WebuiDir                    string `json:"webui_dir"`
	WorkDir                     string `json:"work_dir"`
	ZK                          string `json:"zk"`
	ZKSessionTimeout            string `json:"zk_session_timeout"`
}

// Framework represent a single framework of a mesos node
type Framework struct {
	Active           bool       `json:"active"`
	Checkpoint       bool       `json:"checkpoint"`
	CompletedTasks   []Task     `json:"completed_tasks"`
	Executors        []Executor `json:"executors"`
	FailoverTimeout  float32    `json:"failover_timeout"`
	Hostname         string     `json:"hostname"`
	ID               string     `json:"id"`
	Name             string     `json:"name"`
	OfferedResources Resources  `json:"offered_resources"`
	Offers           []Offer    `json:"offers"`
	RegisteredTime   float32    `json:"registered_time"`
	ReregisteredTime float32    `json:"reregistered_time"`
	Resources        Resources  `json:"resources"`
	Role             string     `json:"role"`
	Tasks            []Task     `json:"tasks"`
	UnregisteredTime float32    `json:"unregistered_time"`
	UsedResources    Resources  `json:"used_resources"`
	User             string     `json:"user"`
	WebuiURL         string     `json:"webui_url"`
	Labels           []Label    `json:"label"`
}

type Offer struct {
	ID          string            `json:"id"`
	FrameworkID string            `json:"framework_id"`
	SlaveID     string            `json:"slave_id"`
	Hostname    string            `json:"hostname"`
	URL         URL               `json:"url"`
	Resources   Resources         `json:"resources"`
	Attributes  map[string]string `json:"attributes"`
}

type URL struct {
	Scheme     string      `json:"scheme"`
	Address    Address     `json:"address"`
	Path       string      `json:"path"`
	Parameters []Parameter `json:"parameters"`
}

type Address struct {
	Hostname string `json:"hostname"`
	IP       string `json:"ip"`
	Port     int    `json:"port"`
}

type Parameter struct {
	Key   string `json:"key"`
	Value string `json:"value"`
}

type Label struct {
	Key   string `json:"key"`
	Value string `json:"value"`
}

// Task represent a single Mesos task
type Task struct {
	// Missing fields
	// TODO: "labels": [],
	ExecutorID  string       `json:"executor_id"`
	FrameworkID string       `json:"framework_id"`
	ID          string       `json:"id"`
	Name        string       `json:"name"`
	Resources   Resources    `json:"resources"`
	SlaveID     string       `json:"slave_id"`
	State       string       `json:"state"`
	Statuses    []TaskStatus `json:"statuses"`
}

// Resources represents a resource type for a task
type Resources struct {
	CPUs  float32 `json:"cpus"`
	Disk  float64 `json:"disk"`
	Mem   float64 `json:"mem"`
	Ports string  `json:"ports"`
}

// TaskStatus represents the status of a single task
type TaskStatus struct {
	State     string  `json:"state"`
	Timestamp float32 `json:"timestamp"`
}

// Slave represents a single mesos slave node
type Slave struct {
	Active         bool              `json:"active"`
	Hostname       string            `json:"hostname"`
	ID             string            `json:"id"`
	PID            string            `json:"pid"`
	RegisteredTime float32           `json:"registered_time"`
	Resources      Resources         `json:"resources"`
	Attributes     map[string]string `json:"attributes"`
}

// Executor represents a single executor of a framework
type Executor struct {
	// Missing fields
	// TODO "queued_tasks": [],
	// TODO "tasks": []
	CompletedTasks []Task    `json:"completed_tasks"`
	Container      string    `json:"container"`
	Directory      string    `json:"directory"`
	ID             string    `json:"id"`
	Name           string    `json:"name"`
	Resources      Resources `json:"resources"`
	Source         string    `json:"source"`
}
<commit_msg>Add a few more comments<commit_after>package megos

// State represents the JSON from the state.json of a mesos node
type State struct {
	ActivatedSlaves        float32     `json:"activated_slaves"`
	BuildDate              string      `json:"build_date"`
	BuildTime              float32     `json:"build_time"`
	BuildUser              string      `json:"build_user"`
	Cluster                string      `json:"cluster"`
	CompletedFrameworks    []Framework `json:"completed_frameworks"`
	DeactivatedSlaves      float32     `json:"deactivated_slaves"`
	ElectedTime            float32     `json:"elected_time"`
	Flags                  Flags       `json:"flags"`
	Frameworks             []Framework `json:"frameworks"`
	GitSHA                 string      `json:"git_sha"`
	GitBranch              string      `json:"git_branch"`
	GitTag                 string      `json:"git_tag"`
	Hostname               string      `json:"hostname"`
	ID                     string      `json:"id"`
	Leader                 string      `json:"leader"`
	LogDir                 string      `json:"log_dir"`
	ExternalLogFile        string      `json:"external_log_file"`
	OrphanTasks            []Task      `json:"orphan_tasks"`
	PID                    string      `json:"pid"`
	Slaves                 []Slave     `json:"slaves"`
	StartTime              float32     `json:"start_time"`
	UnregisteredFrameworks []string    `json:"unregistered_frameworks"`
	Version                string      `json:"version"`
}

// Flags represents the flags of a mesos state
type Flags struct {
	AllocationInterval          string `json:"allocation_interval"`
	Allocator                   string `json:"allocator"`
	Authenticate                string `json:"authenticate"`
	Authenticatee               string `json:"authenticatee"`
	AuthenticateSlaves          string `json:"authenticate_slaves"`
	Authenticators              string `json:"authenticators"`
	Authorizers                 string `json:"authorizers"`
	CgroupsEnableCfs            string `json:"cgroups_enable_cfs"`
	CgroupsHierarchy            string `json:"cgroups_hierarchy"`
	CgroupsLimitSwap            string `json:"cgroups_limit_swap"`
	CgroupsRoot                 string `json:"cgroups_root"`
	Cluster                     string `json:"cluster"`
	ContainerDiskWatchInterval  string `json:"container_disk_watch_interval"`
	Containerizers              string `json:"containerizers"`
	DefaultRole                 string `json:"default_role"`
	DiskWatchInterval           string `json:"disk_watch_interval"`
	Docker                      string `json:"docker"`
	DockerRemoveDelay           string `json:"docker_remove_delay"`
	DockerSandboxDirectory      string `json:"docker_sandbox_directory"`
	DockerStopTimeout           string `json:"docker_stop_timeout"`
	EnforceContainerDiskQuota   string `json:"enforce_container_disk_quota"`
	ExecutorRegistrationTimeout string `json:"executor_registration_timeout"`
	ExecutorShutdownGracePeriod string `json:"executor_shutdown_grace_period"`
	FrameworksHome              string `json:"frameworks_home"`
	FrameworkSorter             string `json:"framework_sorter"`
	GCDelay                     string `json:"gc_delay"`
	GCDiskHeadroom              string `json:"gc_disk_headroom"`
	HadoopHome                  string `json:"hadoop_home"`
	Help                        string `json:"help"`
	Hostname                    string `json:"hostname"`
	InitializeDriverLogging     string `json:"initialize_driver_logging"`
	IP                          string `json:"ip"`
	Isolation                   string `json:"isolation"`
	LauncherDir                 string `json:"launcher_dir"`
	LogAutoInitialize           string `json:"log_auto_initialize"`
	LogDir                      string `json:"log_dir"`
	Logbufsecs                  string `json:"logbufsecs"`
	LoggingLevel                string `json:"logging_level"`
	MaxSlavePingTimeouts        string `json:"max_slave_ping_timeouts"`
	Master                      string `json:"master"`
	PerfDuration                string `json:"perf_duration"`
	PerfInterval                string `json:"perf_interval"`
	Port                        string `json:"port"`
	Quiet                       string `json:"quiet"`
	Quorum                      string `json:"quorum"`
	Recover                     string `json:"recover"`
	RecoverySlaveRemovalLimit   string `json:"recovery_slave_removal_limit"`
	RecoveryTimeout             string `json:"recovery_timeout"`
	RegistrationBackoffFactor   string `json:"registration_backoff_factor"`
	Registry                    string `json:"registry"`
	RegistryFetchTimeout        string `json:"registry_fetch_timeout"`
	RegistryStoreTimeout        string `json:"registry_store_timeout"`
	RegistryStrict              string `json:"registry_strict"`
	ResourceMonitoringInterval  string `json:"resource_monitoring_interval"`
	RootSubmissions             string `json:"root_submissions"`
	SlavePingTimeout            string `json:"slave_ping_timeout"`
	SlaveReregisterTimeout      string `json:"slave_reregister_timeout"`
	Strict                      string `json:"strict"`
	SwitchUser                  string `json:"switch_user"`
	UserSorter                  string `json:"user_sorter"`
	Version                     string `json:"version"`
	WebuiDir                    string `json:"webui_dir"`
	WorkDir                     string `json:"work_dir"`
	ZK                          string `json:"zk"`
	ZKSessionTimeout            string `json:"zk_session_timeout"`
}

// Framework represent a single framework of a mesos node
type Framework struct {
	Active           bool       `json:"active"`
	Checkpoint       bool       `json:"checkpoint"`
	CompletedTasks   []Task     `json:"completed_tasks"`
	Executors        []Executor `json:"executors"`
	FailoverTimeout  float32    `json:"failover_timeout"`
	Hostname         string     `json:"hostname"`
	ID               string     `json:"id"`
	Name             string     `json:"name"`
	OfferedResources Resources  `json:"offered_resources"`
	Offers           []Offer    `json:"offers"`
	RegisteredTime   float32    `json:"registered_time"`
	ReregisteredTime float32    `json:"reregistered_time"`
	Resources        Resources  `json:"resources"`
	Role             string     `json:"role"`
	Tasks            []Task     `json:"tasks"`
	UnregisteredTime float32    `json:"unregistered_time"`
	UsedResources    Resources  `json:"used_resources"`
	User             string     `json:"user"`
	WebuiURL         string     `json:"webui_url"`
	Labels           []Label    `json:"label"`
}

// Offer represents a single offer from a Mesos Slave to a Mesos master
type Offer struct {
	ID          string            `json:"id"`
	FrameworkID string            `json:"framework_id"`
	SlaveID     string            `json:"slave_id"`
	Hostname    string            `json:"hostname"`
	URL         URL               `json:"url"`
	Resources   Resources         `json:"resources"`
	Attributes  map[string]string `json:"attributes"`
}

// URL represents a single URL
type URL struct {
	Scheme     string      `json:"scheme"`
	Address    Address     `json:"address"`
	Path       string      `json:"path"`
	Parameters []Parameter `json:"parameters"`
}

// Address represents a single address.
// e.g. from a Slave or from a Master
type Address struct {
	Hostname string `json:"hostname"`
	IP       string `json:"ip"`
	Port     int    `json:"port"`
}

// Parameter represents a single key / value pair for parameters
type Parameter struct {
	Key   string `json:"key"`
	Value string `json:"value"`
}

// Label represents a single key / value pair for labeling
type Label struct {
	Key   string `json:"key"`
	Value string `json:"value"`
}

// Task represent a single Mesos task
type Task struct {
	// Missing fields
	// TODO: "labels": [],
	ExecutorID  string       `json:"executor_id"`
	FrameworkID string       `json:"framework_id"`
	ID          string       `json:"id"`
	Name        string       `json:"name"`
	Resources   Resources    `json:"resources"`
	SlaveID     string       `json:"slave_id"`
	State       string       `json:"state"`
	Statuses    []TaskStatus `json:"statuses"`
}

// Resources represents a resource type for a task
type Resources struct {
	CPUs  float32 `json:"cpus"`
	Disk  float64 `json:"disk"`
	Mem   float64 `json:"mem"`
	Ports string  `json:"ports"`
}

// TaskStatus represents the status of a single task
type TaskStatus struct {
	State     string  `json:"state"`
	Timestamp float32 `json:"timestamp"`
}

// Slave represents a single mesos slave node
type Slave struct {
	Active         bool              `json:"active"`
	Hostname       string            `json:"hostname"`
	ID             string            `json:"id"`
	PID            string            `json:"pid"`
	RegisteredTime float32           `json:"registered_time"`
	Resources      Resources         `json:"resources"`
	Attributes     map[string]string `json:"attributes"`
}

// Executor represents a single executor of a framework
type Executor struct {
	// Missing fields
	// TODO "queued_tasks": [],
	// TODO "tasks": []
	CompletedTasks []Task    `json:"completed_tasks"`
	Container      string    `json:"container"`
	Directory      string    `json:"directory"`
	ID             string    `json:"id"`
	Name           string    `json:"name"`
	Resources      Resources `json:"resources"`
	Source         string    `json:"source"`
}
<|endoftext|>


<commit_before>// All names loose the CK_ prefix
// All names loose the hungarian notation
// All the defines are kept from the C package so: C.CKM_RSA_X_509
// All struct's get a Go variant
//
package pkcs11

/*
#define CK_PTR *
#ifndef NULL_PTR
#define NULL_PTR 0
#endif
#define CK_DEFINE_FUNCTION(returnType, name) returnType name
#define CK_DECLARE_FUNCTION(returnType, name) returnType name
#define CK_DECLARE_FUNCTION_POINTER(returnType, name) returnType (* name)
#define CK_CALLBACK_FUNCTION(returnType, name) returnType (* name)

#include <stdlib.h>
#include "pkcs11.h"

CK_ULONG Index(CK_ULONG_PTR array, CK_ULONG i) { return array[i]; }
CK_ULONG SizeOf() { return sizeof(CK_ULONG); }

*/
import "C"

import (
	"fmt"
	"unsafe"
)

// List is used as a "generic" list as all object from PKCS#11 hold a uint (CK_ULONG).
type List []uint

// ToList converts from a C style array to a List.
func toList(clist C.CK_ULONG_PTR, size C.CK_ULONG) List {
	l := make(List, int(size))
	for i := 0; i < len(l); i++ {
		l[i] = uint(C.Index(clist, C.CK_ULONG(i)))
	}
	defer C.free(unsafe.Pointer(clist))
	return l
}

// CBBool converts a bool to a CK_BBOOL.
func cBBool(x bool) C.CK_BBOOL {
	if x {
		return C.CK_BBOOL(C.CK_TRUE)
	}
	return C.CK_BBOOL(C.CK_FALSE)
}

type Error uint

func (e Error) Error() string { return "pkcs11: " + fmt.Sprintf("0x%X", int(e)) }

func toError(e C.CK_RV) error {
	if e == C.CKR_OK {
		return nil
	}
	return Error(e)
}

type SessionHandle uint

type ObjectHandle uint

type Version struct {
	Major byte
	Minor byte
}

type Info struct {
	// TODO
}

type SlotInfo struct {
	SlotDescription [64]byte
	ManufacturerID  [32]byte
	Flags           uint
	HardwareVersion Version
	FirmwareVersion Version
}

type TokenInfo struct {
	Label              [32]byte
	ManufacturerID     [32]byte
	Model              [16]byte
	SerialNumber       [16]byte
	Flags              uint
	MaxSessionCount    uint
	SessionCount       uint
	MaxRwSessionCount  uint
	RwSessionCount     uint
	MaxPinLen          uint
	MinPinLen          uint
	TotalPublicMemory  uint
	FreePublicMemory   uint
	TotalPrivateMemory uint
	FreePrivateMemory  uint
	hardwareVersion    Version
	firmwareVersion    Version
	UTCTime            [16]byte
}

type SessionInfo struct {
	SlotID      uint
	Sate        uint
	Flags       uint
	DeviceError uint
}

type Attribute struct {
	Type  uint
	Value []byte
}

//
func NewAttribute(typ uint, x interface{}) Attribute {
	var a Attribute
	a.Type = typ
	if x == nil {
		a.Value = nil
		return a
	}
	switch x.(type) {
	case bool: // create bbool
		if x.(bool) {
			a.Value = []byte{1}
			break
		}
		a.Value = []byte{0}
	case uint:
		switch int(C.SizeOf()) {
		case 4:
			a.Value = make([]byte, 4)
			a.Value[3] = byte(x.(uint))	// Is this intel??
			a.Value[2] = byte(x.(uint) >> 8)
			a.Value[1] = byte(x.(uint) >> 16)
			a.Value[0] = byte(x.(uint) >> 24)
			println("POINTER", typ, &(a.Value[0]), a.Value[0])
			println("POINTER", typ, &a.Value[1], a.Value[1])
			println("POINTER", typ, &a.Value[2], a.Value[2])
			println("POINTER", typ, &a.Value[3], a.Value[3])
		case 8:
			a.Value = make([]byte, 8)
			a.Value[7] = byte(x.(uint) >> 56)
			a.Value[6] = byte(x.(uint) >> 48)
			a.Value[5] = byte(x.(uint) >> 40)
			a.Value[4] = byte(x.(uint) >> 32)
			a.Value[3] = byte(x.(uint) >> 24)
			a.Value[2] = byte(x.(uint) >> 16)
			a.Value[1] = byte(x.(uint) >> 8)
			a.Value[0] = byte(x.(uint))
		}
	case []byte: // just copy
		a.Value = x.([]byte)
	default:
		panic("pkcs11: unhandled attribute type")
	}
	return a
}

// cAttribute returns the start address and the length of an attribute list.
func cAttributeList(a []Attribute) (C.CK_ATTRIBUTE_PTR, C.CK_ULONG) {
	if len(a) == 0 {
		return nil, 0
	}
	cp := make([]C.CK_ATTRIBUTE, len(a))
	for i := 0; i < len(a); i++ {
		var l C.CK_ATTRIBUTE
		l._type = C.CK_ATTRIBUTE_TYPE(a[i].Type)
		l.pValue = C.CK_VOID_PTR(&(a[i].Value[0]))
		println("pValue", l.pValue)
		println("Value", *C.CK_ULONG_PTR(l.pValue))
		l.ulValueLen = C.CK_ULONG(len(a[i].Value))
		cp[i] = l
	}
	return C.CK_ATTRIBUTE_PTR(&cp[0]), C.CK_ULONG(len(a))
}

type Date struct {
	// TODO
}

type Mechanism struct {
	Mechanism uint
	Parameter []byte
}

func NewMechanism(mech uint, x interface{}) Mechanism {
	var m Mechanism
	m.Mechanism = mech
	if x == nil {
		m.Parameter = nil
		return m
	}
	// Add specific types? Ala Attributes?
	return m
}

// cMechanismList

// cMechanism returns a C pointer to the mechanism m.
func cMechanism(m Mechanism) C.CK_MECHANISM_PTR {
	var m1 C.CK_MECHANISM
	m1.mechanism = C.CK_MECHANISM_TYPE(m.Mechanism)
	if len(m.Parameter) == 0 {
		m1.pParameter = C.CK_VOID_PTR(nil)
	} else {
		m1.pParameter = C.CK_VOID_PTR(&(m.Parameter[0]))
	}
	m1.ulParameterLen = C.CK_ULONG(len(m.Parameter))
	return C.CK_MECHANISM_PTR(&m1)
}

//func toMechanismList(clist C.CK_MECHANISM_TYPE_PTR, size C.CK_ULONG) []Mechanism {
//	m := make([]Mechanism, int(size))
//	for i := 0; i < len(m); i++ {
//		cm := C.Index(clist, C.(i))
//		m[i] = Mechanism{Mechanism: uint(cm.mechanism),
//	}
//	defer C.free(unsafe.Pointer(clist))
//	return m
//}

type MechanismInfo struct {
	MinKeySize uint
	MaxKeySize uint
	Flags      uint
}

// stopped after this one
<commit_msg>little endian/big endian? *ugh*<commit_after>// All names loose the CK_ prefix
// All names loose the hungarian notation
// All the defines are kept from the C package so: C.CKM_RSA_X_509
// All struct's get a Go variant
//
package pkcs11

/*
#define CK_PTR *
#ifndef NULL_PTR
#define NULL_PTR 0
#endif
#define CK_DEFINE_FUNCTION(returnType, name) returnType name
#define CK_DECLARE_FUNCTION(returnType, name) returnType name
#define CK_DECLARE_FUNCTION_POINTER(returnType, name) returnType (* name)
#define CK_CALLBACK_FUNCTION(returnType, name) returnType (* name)

#include <stdlib.h>
#include "pkcs11.h"

CK_ULONG Index(CK_ULONG_PTR array, CK_ULONG i) { return array[i]; }
CK_ULONG SizeOf() { return sizeof(CK_ULONG); }

*/
import "C"

import (
	"fmt"
	"unsafe"
)

// List is used as a "generic" list as all object from PKCS#11 hold a uint (CK_ULONG).
type List []uint

// ToList converts from a C style array to a List.
func toList(clist C.CK_ULONG_PTR, size C.CK_ULONG) List {
	l := make(List, int(size))
	for i := 0; i < len(l); i++ {
		l[i] = uint(C.Index(clist, C.CK_ULONG(i)))
	}
	defer C.free(unsafe.Pointer(clist))
	return l
}

// CBBool converts a bool to a CK_BBOOL.
func cBBool(x bool) C.CK_BBOOL {
	if x {
		return C.CK_BBOOL(C.CK_TRUE)
	}
	return C.CK_BBOOL(C.CK_FALSE)
}

type Error uint

func (e Error) Error() string { return "pkcs11: " + fmt.Sprintf("0x%X", int(e)) }

func toError(e C.CK_RV) error {
	if e == C.CKR_OK {
		return nil
	}
	return Error(e)
}

type SessionHandle uint

type ObjectHandle uint

type Version struct {
	Major byte
	Minor byte
}

type Info struct {
	// TODO
}

type SlotInfo struct {
	SlotDescription [64]byte
	ManufacturerID  [32]byte
	Flags           uint
	HardwareVersion Version
	FirmwareVersion Version
}

type TokenInfo struct {
	Label              [32]byte
	ManufacturerID     [32]byte
	Model              [16]byte
	SerialNumber       [16]byte
	Flags              uint
	MaxSessionCount    uint
	SessionCount       uint
	MaxRwSessionCount  uint
	RwSessionCount     uint
	MaxPinLen          uint
	MinPinLen          uint
	TotalPublicMemory  uint
	FreePublicMemory   uint
	TotalPrivateMemory uint
	FreePrivateMemory  uint
	hardwareVersion    Version
	firmwareVersion    Version
	UTCTime            [16]byte
}

type SessionInfo struct {
	SlotID      uint
	Sate        uint
	Flags       uint
	DeviceError uint
}

type Attribute struct {
	Type  uint
	Value []byte
}

//
func NewAttribute(typ uint, x interface{}) Attribute {
	var a Attribute
	a.Type = typ
	if x == nil {
		a.Value = nil
		return a
	}
	switch x.(type) {
	case bool: // create bbool
		if x.(bool) {
			a.Value = []byte{1}
			break
		}
		a.Value = []byte{0}
	case uint:
		switch int(C.SizeOf()) {
		case 4:
			a.Value = make([]byte, 4)
			a.Value[0] = byte(x.(uint))	// Is this intel??
			a.Value[1] = byte(x.(uint) >> 8)
			a.Value[2] = byte(x.(uint) >> 16)
			a.Value[3] = byte(x.(uint) >> 24)
			println("POINTER", typ, &(a.Value[0]), a.Value[0])
			println("POINTER", typ, &a.Value[1], a.Value[1])
			println("POINTER", typ, &a.Value[2], a.Value[2])
			println("POINTER", typ, &a.Value[3], a.Value[3])
		case 8:
			a.Value = make([]byte, 8)
			a.Value[0] = byte(x.(uint))
			a.Value[1] = byte(x.(uint) >> 8)
			a.Value[2] = byte(x.(uint) >> 16)
			a.Value[3] = byte(x.(uint) >> 24)
			a.Value[4] = byte(x.(uint) >> 32)
			a.Value[5] = byte(x.(uint) >> 40)
			a.Value[6] = byte(x.(uint) >> 48)
			a.Value[7] = byte(x.(uint) >> 56)
		}
	case []byte: // just copy
		a.Value = x.([]byte)
	default:
		panic("pkcs11: unhandled attribute type")
	}
	return a
}

// cAttribute returns the start address and the length of an attribute list.
func cAttributeList(a []Attribute) (C.CK_ATTRIBUTE_PTR, C.CK_ULONG) {
	if len(a) == 0 {
		return nil, 0
	}
	cp := make([]C.CK_ATTRIBUTE, len(a))
	for i := 0; i < len(a); i++ {
		var l C.CK_ATTRIBUTE
		l._type = C.CK_ATTRIBUTE_TYPE(a[i].Type)
		l.pValue = C.CK_VOID_PTR(&(a[i].Value[0]))
		println("pValue", l.pValue)
		println("Value", *C.CK_ULONG_PTR(l.pValue))
		l.ulValueLen = C.CK_ULONG(len(a[i].Value))
		cp[i] = l
	}
	return C.CK_ATTRIBUTE_PTR(&cp[0]), C.CK_ULONG(len(a))
}

type Date struct {
	// TODO
}

type Mechanism struct {
	Mechanism uint
	Parameter []byte
}

func NewMechanism(mech uint, x interface{}) Mechanism {
	var m Mechanism
	m.Mechanism = mech
	if x == nil {
		m.Parameter = nil
		return m
	}
	// Add specific types? Ala Attributes?
	return m
}

// cMechanismList

// cMechanism returns a C pointer to the mechanism m.
func cMechanism(m Mechanism) C.CK_MECHANISM_PTR {
	var m1 C.CK_MECHANISM
	m1.mechanism = C.CK_MECHANISM_TYPE(m.Mechanism)
	if len(m.Parameter) == 0 {
		m1.pParameter = C.CK_VOID_PTR(nil)
	} else {
		m1.pParameter = C.CK_VOID_PTR(&(m.Parameter[0]))
	}
	m1.ulParameterLen = C.CK_ULONG(len(m.Parameter))
	return C.CK_MECHANISM_PTR(&m1)
}

//func toMechanismList(clist C.CK_MECHANISM_TYPE_PTR, size C.CK_ULONG) []Mechanism {
//	m := make([]Mechanism, int(size))
//	for i := 0; i < len(m); i++ {
//		cm := C.Index(clist, C.(i))
//		m[i] = Mechanism{Mechanism: uint(cm.mechanism),
//	}
//	defer C.free(unsafe.Pointer(clist))
//	return m
//}

type MechanismInfo struct {
	MinKeySize uint
	MaxKeySize uint
	Flags      uint
}

// stopped after this one
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016, Randy Westlund. All rights reserved.
 * This code is under the BSD-2-Clause license.
 *
 * This file contains struct definitions.
 */
package main

import (
	"time"
)

/* The status object returned from launching a child in a goroutine. */
type LaunchStatus struct {
	Name string
	Pid  int
	/* If the process failed for any reason, that reason is here. */
	Err error
	/* The duration for which the process ran. */
	Duration time.Duration
}

type Process struct {
	// The process config object from the config file.
	Config ProcessConfig
	// The most recent launch status.
	Status LaunchStatus
	// Whether it's currently running or not.
	Running bool
}

type Global struct {
	/* A dictionary of all processes. */
	Procs map[string]*Process
	/* Count the total number of children we have active so we know when to
	 * exit. */
	RunningProcesses int
	/* Listen on this channel to know when a program has started. */
	RunningChan chan LaunchStatus
	/* Listen on this channel to know when a program is done. */
	DoneChan chan LaunchStatus
}

/* A process definition, as read directly from the config file. */
type ProcessConfig struct {
	/* A human-readable tag for process. */
	Name string
	/* The path to the actual executable to run. */
	Path string
	/* A string with arguments to be passed to the process. */
	Args string
	/* Filenames for writing stdout and stderr. Defaults to /dev/null. */
	Stdout string
	Stderr string
	/* The number of milliseconds to wait before restarting a process. */
	RestartDelay uint64 `tome:"restart_delay"`
	/* Whether to disable restarting on failure. */
	IgnoreFailure bool `toml:"ignore_failure"`
	/* If a process exits within this many milliseconds, don't restart it. A
	 * value of 0 disables this check.
	 */
	MinRuntime  int      `toml:"min_runtime"`
	SoftDepends []string `toml:"soft_depends"`
	User        string
	Group       string
}

/* The config file definition. Currently, there are only [[process]] blocks,
 * but global options may be added in the future.
 */
type Config struct {
	/* This must be named after the [[process]] block in the config file. */
	Process []ProcessConfig
	// Where to send paladin's logging output. Defaults to stderr.
	LogFile string `toml:"log_file"`
}
<commit_msg>Fix restart_delay<commit_after>/*
 * Copyright (c) 2016, Randy Westlund. All rights reserved.
 * This code is under the BSD-2-Clause license.
 *
 * This file contains struct definitions.
 */
package main

import (
	"time"
)

/* The status object returned from launching a child in a goroutine. */
type LaunchStatus struct {
	Name string
	Pid  int
	/* If the process failed for any reason, that reason is here. */
	Err error
	/* The duration for which the process ran. */
	Duration time.Duration
}

type Process struct {
	// The process config object from the config file.
	Config ProcessConfig
	// The most recent launch status.
	Status LaunchStatus
	// Whether it's currently running or not.
	Running bool
}

type Global struct {
	/* A dictionary of all processes. */
	Procs map[string]*Process
	/* Count the total number of children we have active so we know when to
	 * exit. */
	RunningProcesses int
	/* Listen on this channel to know when a program has started. */
	RunningChan chan LaunchStatus
	/* Listen on this channel to know when a program is done. */
	DoneChan chan LaunchStatus
}

/* A process definition, as read directly from the config file. */
type ProcessConfig struct {
	/* A human-readable tag for process. */
	Name string
	/* The path to the actual executable to run. */
	Path string
	/* A string with arguments to be passed to the process. */
	Args string
	/* Filenames for writing stdout and stderr. Defaults to /dev/null. */
	Stdout string
	Stderr string
	/* The number of milliseconds to wait before restarting a process. */
	RestartDelay uint64 `toml:"restart_delay"`
	/* Whether to disable restarting on failure. */
	IgnoreFailure bool `toml:"ignore_failure"`
	/* If a process exits within this many milliseconds, don't restart it. A
	 * value of 0 disables this check.
	 */
	MinRuntime  int      `toml:"min_runtime"`
	SoftDepends []string `toml:"soft_depends"`
	User        string
	Group       string
}

/* The config file definition. Currently, there are only [[process]] blocks,
 * but global options may be added in the future.
 */
type Config struct {
	/* This must be named after the [[process]] block in the config file. */
	Process []ProcessConfig
	// Where to send paladin's logging output. Defaults to stderr.
	LogFile string `toml:"log_file"`
}
<|endoftext|>


<commit_before>package usage

import (
	"log"
	"os"
	"time"

	sigar "github.com/cloudfoundry/gosigar"
)

type ProcessMonitor struct {
	lastPtimeUser  uint64
	lastPtimeSys   uint64
	lastPtimeTotal uint64
}

type CpuUsage struct {
	User  float64
	Sys   float64
	Total float64
}

type MemoryUsage struct {
	Size       uint64
	Resident   uint64
	Share      uint64
	PageFaults uint64
}

// create a process monitor for this process
func CreateProcessMonitor() *ProcessMonitor {
	p := &ProcessMonitor{}

	pid := os.Getpid()

	curPtime := sigar.ProcTime{}
	err := curPtime.Get(pid)

	if err != nil {
		log.Fatalf("Issue loading process monitor - %v", err)
	}

	// seed cpu time
	p.lastPtimeUser = curPtime.User
	p.lastPtimeSys = curPtime.Sys
	p.lastPtimeTotal = curPtime.Total

	return p
}

// query the cpu usage, this is calculated for period between requests so if you
// poll ever second you will get % of cpu used per second.
func (p *ProcessMonitor) GetCpuUsage() *CpuUsage {

	pid := os.Getpid()

	curPtime := sigar.ProcTime{}

	err := curPtime.Get(pid)

	if err != nil {
		log.Fatalf("[Error] error retrieving process cpu info %v", err)
		return nil
	}

	totalDelta := p.lastPtimeTotal - curPtime.Total
	userUsage := calcTime(p.lastPtimeUser, curPtime.User, totalDelta)
	systemUsage := calcTime(p.lastPtimeSys, curPtime.Sys, totalDelta)

	p.lastPtimeUser = curPtime.User
	p.lastPtimeSys = curPtime.Sys
	p.lastPtimeTotal = curPtime.Total

	return &CpuUsage{
		Sys:   systemUsage,
		User:  userUsage,
		Total: userUsage + systemUsage,
	}
}

// query the memory usage of the current process
func (p *ProcessMonitor) GetMemoryUsage() *MemoryUsage {

	pid := os.Getpid()

	curMemory := sigar.ProcMem{}

	err := curMemory.Get(pid)

	if err != nil {
		log.Fatalf("[Error] error retrieving memory info %v", err)
		return nil
	}

	return &MemoryUsage{curMemory.Size, curMemory.Resident, curMemory.Share, curMemory.PageFaults}

}

// covers either zero activity or zero time between requests
func calcTime(usageLast uint64, usageCur uint64, totalDelta uint64) float64 {

	usageDelta := usageCur - usageLast

	if usageDelta == 0 || totalDelta == 0 {
		return 0
	} else {
		return 100 * (float64(usageDelta)) / float64(totalDelta)
	}
}

func UnixTimeMs() uint64 {
	return uint64(time.Now().UnixNano() / 1e6)
}
<commit_msg>Almost had it right the first time, layers of inderction ftl.<commit_after>package usage

import (
	"log"
	"os"
	"time"

	sigar "github.com/cloudfoundry/gosigar"
)

type ProcessMonitor struct {
	lastPtimeUser  uint64
	lastPtimeSys   uint64
	lastPtimeTotal uint64
	lastSnapshot   uint64
}

type CpuUsage struct {
	User  float64
	Sys   float64
	Total float64
}

type MemoryUsage struct {
	Size       uint64
	Resident   uint64
	Share      uint64
	PageFaults uint64
}

// create a process monitor for this process
func CreateProcessMonitor() *ProcessMonitor {
	p := &ProcessMonitor{}

	pid := os.Getpid()

	curPtime := sigar.ProcTime{}
	err := curPtime.Get(pid)

	if err != nil {
		log.Fatalf("Issue loading process monitor - %v", err)
	}

	// seed cpu time
	p.lastPtimeUser = curPtime.User
	p.lastPtimeSys = curPtime.Sys
	p.lastPtimeTotal = curPtime.Total
	p.lastSnapshot = UnixTimeMs()

	return p
}

// query the cpu usage, this is calculated for period between requests so if you
// poll ever second you will get % of cpu used per second.
func (p *ProcessMonitor) GetCpuUsage() *CpuUsage {

	pid := os.Getpid()

	curPtime := sigar.ProcTime{}

	err := curPtime.Get(pid)

	if err != nil {
		log.Fatalf("[Error] error retrieving process cpu info %v", err)
		return nil
	}

	currentTime := UnixTimeMs()

	timeDelta := currentTime - p.lastSnapshot

	userUsage := calcTime(p.lastPtimeUser, curPtime.User, timeDelta)
	systemUsage := calcTime(p.lastPtimeSys, curPtime.Sys, timeDelta)
	totalUsage := calcTime(p.lastPtimeTotal, curPtime.Total, timeDelta)

	// update snapshots
	p.lastPtimeUser = curPtime.User
	p.lastPtimeSys = curPtime.Sys
	p.lastPtimeTotal = curPtime.Total
	p.lastSnapshot = currentTime

	return &CpuUsage{
		Sys:   systemUsage,
		User:  userUsage,
		Total: totalUsage,
	}
}

// query the memory usage of the current process
func (p *ProcessMonitor) GetMemoryUsage() *MemoryUsage {

	pid := os.Getpid()

	curMemory := sigar.ProcMem{}

	err := curMemory.Get(pid)

	if err != nil {
		log.Fatalf("[Error] error retrieving memory info %v", err)
		return nil
	}

	return &MemoryUsage{curMemory.Size, curMemory.Resident, curMemory.Share, curMemory.PageFaults}

}

// covers either zero activity or zero time between requests
func calcTime(usageLast uint64, usageCur uint64, timeDelta uint64) float64 {

	usageDelta := usageCur - usageLast

	if usageDelta == 0 || timeDelta == 0 {
		return 0
	} else {
		return 100.0 * (float64(usageDelta)) / float64(timeDelta)
	}
}

func UnixTimeMs() uint64 {
	return uint64(time.Now().UnixNano() / 1e6)
}
<|endoftext|>


<commit_before>package index

import (
	"html/template"
	"net/http"
	"net/url"

	"github.com/concourse/atc/web"
	"github.com/concourse/atc/web/pipeline"
	"github.com/pivotal-golang/lager"
)

type TemplateData struct{}

type Handler struct {
	logger           lager.Logger
	clientFactory    web.ClientFactory
	pipelineHandler  *pipeline.Handler
	noBuildsTemplate *template.Template
}

func NewHandler(
	logger lager.Logger,
	clientFactory web.ClientFactory,
	pipelineHandler *pipeline.Handler,
	noBuildsTemplate *template.Template,
) *Handler {
	return &Handler{
		logger:           logger,
		clientFactory:    clientFactory,
		pipelineHandler:  pipelineHandler,
		noBuildsTemplate: noBuildsTemplate,
	}
}

func (handler *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) error {
	log := handler.logger.Session("index")

	client := handler.clientFactory.Build(r)

	pipelines, err := client.ListPipelines()
	if err != nil {
		log.Error("failed-to-load-pipelinedb", err)
		return err
	}

	if len(pipelines) == 0 {
		err := handler.noBuildsTemplate.Execute(w, TemplateData{})
		if err != nil {
			log.Fatal("failed-to-build-template", err, lager.Data{})
			return err
		}

		return nil
	}

	if r.Form == nil {
		r.Form = url.Values{}
	}

	r.Form[":pipeline"] = []string{pipelines[0].Name}

	return handler.pipelineHandler.ServeHTTP(w, r)
}
<commit_msg>fix log line<commit_after>package index

import (
	"html/template"
	"net/http"
	"net/url"

	"github.com/concourse/atc/web"
	"github.com/concourse/atc/web/pipeline"
	"github.com/pivotal-golang/lager"
)

type TemplateData struct{}

type Handler struct {
	logger           lager.Logger
	clientFactory    web.ClientFactory
	pipelineHandler  *pipeline.Handler
	noBuildsTemplate *template.Template
}

func NewHandler(
	logger lager.Logger,
	clientFactory web.ClientFactory,
	pipelineHandler *pipeline.Handler,
	noBuildsTemplate *template.Template,
) *Handler {
	return &Handler{
		logger:           logger,
		clientFactory:    clientFactory,
		pipelineHandler:  pipelineHandler,
		noBuildsTemplate: noBuildsTemplate,
	}
}

func (handler *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) error {
	log := handler.logger.Session("index")

	client := handler.clientFactory.Build(r)

	pipelines, err := client.ListPipelines()
	if err != nil {
		log.Error("failed-to-list-pipelines", err)
		return err
	}

	if len(pipelines) == 0 {
		err := handler.noBuildsTemplate.Execute(w, TemplateData{})
		if err != nil {
			log.Fatal("failed-to-build-template", err, lager.Data{})
			return err
		}

		return nil
	}

	if r.Form == nil {
		r.Form = url.Values{}
	}

	r.Form[":pipeline"] = []string{pipelines[0].Name}

	return handler.pipelineHandler.ServeHTTP(w, r)
}
<|endoftext|>