<commit_before>package schedops

import (
	"fmt"
	"regexp"
	"strings"
	"time"

	"github.com/libopenstorage/openstorage/api"
	"github.com/portworx/sched-ops/k8s"
	"github.com/portworx/sched-ops/task"
	"github.com/portworx/torpedo/drivers/node"
	"github.com/portworx/torpedo/drivers/volume"
	"github.com/portworx/torpedo/pkg/errors"
	"k8s.io/api/core/v1"
)

const (
	// PXServiceName is the name of the portworx service in kubernetes
	PXServiceName = "portworx-service"
	// PXNamespace is the kubernetes namespace in which portworx daemon set runs
	PXNamespace = "kube-system"
	// PXDaemonSet is the name of portworx daemon set in k8s deployment
	PXDaemonSet = "portworx"
	// PXImage is the image for portworx driver
	PXImage = "portworx/px-enterprise"
	// k8sPxRunningLabelKey is the label key used for px state
	k8sPxRunningLabelKey = "px/enabled"
	// k8sPxNotRunningLabelValue is label value for a not running px state
	k8sPxNotRunningLabelValue = "false"
	// k8sPodsRootDir is the directory under which k8s keeps all pods data
	k8sPodsRootDir = "/var/lib/kubelet/pods"
	// pxImageEnvVar is the env variable in portworx daemon set specifying portworx image to be used
	pxImageEnvVar = "PX_IMAGE"
)

// errLabelPresent error type for a label being present on a node
type errLabelPresent struct {
	// label is the label key
	label string
	// node is the k8s node where the label is present
	node string
}

func (e *errLabelPresent) Error() string {
	return fmt.Sprintf("label %s is present on node %s", e.label, e.node)
}

// errLabelAbsent error type for a label absent on a node
type errLabelAbsent struct {
	// label is the label key
	label string
	// node is the k8s node where the label is absent
	node string
}

func (e *errLabelAbsent) Error() string {
	return fmt.Sprintf("label %s is absent on node %s", e.label, e.node)
}

type k8sSchedOps struct{}

func (k *k8sSchedOps) DisableOnNode(n node.Node, _ node.Driver) error {
	return k8s.Instance().AddLabelOnNode(n.Name, k8sPxRunningLabelKey, k8sPxNotRunningLabelValue)
}

func (k *k8sSchedOps) ValidateOnNode(n node.Node) error {
	return &errors.ErrNotSupported{
		Type:      "Function",
		Operation: "ValidateOnNode",
	}
}

func (k *k8sSchedOps) EnableOnNode(n node.Node, _ node.Driver) error {
	return k8s.Instance().RemoveLabelOnNode(n.Name, k8sPxRunningLabelKey)
}

func (k *k8sSchedOps) ValidateAddLabels(replicaNodes []api.Node, vol *api.Volume) error {
	pvc, ok := vol.Locator.VolumeLabels["pvc"]
	if !ok {
		return nil
	}

	var missingLabelNodes []string
	for _, rs := range replicaNodes {
		t := func() (interface{}, bool, error) {
			n, err := k8s.Instance().GetNodeByName(rs.Id)
			if err != nil || n == nil {
				addrs := []string{rs.DataIp, rs.MgmtIp}
				n, err = k8s.Instance().SearchNodeByAddresses(addrs)
				if err != nil || n == nil {
					return nil, true, fmt.Errorf("failed to locate node using id: %s and addresses: %v",
						rs.Id, addrs)
				}
			}

			if _, ok := n.Labels[pvc]; !ok {
				return nil, true, &errLabelAbsent{
					node:  n.Name,
					label: pvc,
				}
			}
			return nil, false, nil
		}

		if _, err := task.DoRetryWithTimeout(t, 2*time.Minute, 10*time.Second); err != nil {
			if _, ok := err.(*errLabelAbsent); ok {
				missingLabelNodes = append(missingLabelNodes, rs.Id)
			} else {
				return err
			}
		}
	}

	if len(missingLabelNodes) > 0 {
		return &ErrLabelMissingOnNode{
			Label: pvc,
			Nodes: missingLabelNodes,
		}
	}
	return nil
}

func (k *k8sSchedOps) ValidateRemoveLabels(vol *volume.Volume) error {
	pvcLabel := vol.Name
	var staleLabelNodes []string
	for _, n := range node.GetWorkerNodes() {
		t := func() (interface{}, bool, error) {
			nodeLabels, err := k8s.Instance().GetLabelsOnNode(n.Name)
			if err != nil {
				return nil, true, err
			}

			if _, ok := nodeLabels[pvcLabel]; ok {
				return nil, true, &errLabelPresent{
					node:  n.Name,
					label: pvcLabel,
				}
			}
			return nil, false, nil
		}

		if _, err := task.DoRetryWithTimeout(t, 5*time.Minute, 10*time.Second); err != nil {
			if _, ok := err.(*errLabelPresent); ok {
				staleLabelNodes = append(staleLabelNodes, n.Name)
			} else {
				return err
			}
		}
	}

	if len(staleLabelNodes) > 0 {
		return &ErrLabelNotRemovedFromNode{
			Label: pvcLabel,
			Nodes: staleLabelNodes,
		}
	}

	return nil
}

func (k *k8sSchedOps) GetVolumeName(vol *volume.Volume) string {
	if vol != nil && vol.ID != "" {
		return fmt.Sprintf("pvc-%s", vol.ID)
	}
	return ""
}

func (k *k8sSchedOps) ValidateVolumeCleanup(d node.Driver) error {
	nodeToPodsMap := make(map[string][]string)
	nodeMap := make(map[string]node.Node)

	connOpts := node.ConnectionOpts{
		Timeout:         1 * time.Minute,
		TimeBeforeRetry: 10 * time.Second,
	}
	listVolOpts := node.FindOpts{
		ConnectionOpts: connOpts,
		Name:           "*portworx-volume",
	}

	for _, n := range node.GetWorkerNodes() {
		volDirList, _ := d.FindFiles(k8sPodsRootDir, n, listVolOpts)
		nodeToPodsMap[n.Name] = separateFilePaths(volDirList)
		nodeMap[n.Name] = n
	}

	existingPods, _ := k8s.Instance().GetPods("")

	orphanPodsMap := make(map[string][]string)
	dirtyVolPodsMap := make(map[string][]string)

	for nodeName, volDirPaths := range nodeToPodsMap {
		var orphanPods []string
		var dirtyVolPods []string

		for _, path := range volDirPaths {
			podUID := extractPodUID(path)
			found := false
			for _, existingPod := range existingPods.Items {
				if podUID == string(existingPod.UID) {
					found = true
					break
				}
			}
			if found {
				continue
			}
			orphanPods = append(orphanPods, podUID)

			// Check if there are files under portworx volume
			// We use a depth of 2 because the files stored in the volume are in the pvc
			// directory under the portworx-volume folder for that pod. For instance,
			// ../kubernetes-io~portworx-volume/pvc-<id>/<all_user_files>
			n := nodeMap[nodeName]
			findFileOpts := node.FindOpts{
				ConnectionOpts: connOpts,
				MinDepth:       2,
				MaxDepth:       2,
			}
			files, _ := d.FindFiles(path, n, findFileOpts)
			if len(strings.TrimSpace(files)) > 0 {
				dirtyVolPods = append(dirtyVolPods, podUID)
			}
		}

		if len(orphanPods) > 0 {
			orphanPodsMap[nodeName] = orphanPods
			if len(dirtyVolPods) > 0 {
				dirtyVolPodsMap[nodeName] = dirtyVolPods
			}
		}
	}

	if len(orphanPodsMap) == 0 {
		return nil
	}
	return &ErrFailedToCleanupVolume{
		OrphanPods:   orphanPodsMap,
		DirtyVolPods: dirtyVolPodsMap,
	}
}

func (k *k8sSchedOps) GetServiceEndpoint() (string, error) {
	svc, err := k8s.Instance().GetService(PXServiceName, PXNamespace)
	if err == nil {
		return svc.Spec.ClusterIP, nil
	}
	return "", err
}

func (k *k8sSchedOps) UpgradePortworx(version string) error {
	k8sOps := k8s.Instance()
	ds, err := k8sOps.GetDaemonSet(PXDaemonSet, PXNamespace)
	if err != nil {
		return err
	}

	image := fmt.Sprintf("%s:%s", PXImage, version)

	found := false
	envList := ds.Spec.Template.Spec.Containers[0].Env
	for i := range envList {
		envVar := &envList[i]
		if envVar.Name == pxImageEnvVar {
			envVar.Value = image
			found = true
			break
		}
	}
	if !found {
		imageEnv := v1.EnvVar{Name: pxImageEnvVar, Value: image}
		ds.Spec.Template.Spec.Containers[0].Env = append(ds.Spec.Template.Spec.Containers[0].Env, imageEnv)
	}

	if err := k8sOps.UpdateDaemonSet(ds); err != nil {
		return err
	}

	// Sleep for a short duration so that the daemon set updates its status
	time.Sleep(10 * time.Second)

	t := func() (interface{}, bool, error) {
		ds, err := k8sOps.GetDaemonSet(PXDaemonSet, PXNamespace)
		if err != nil {
			return nil, true, err
		}

		if ds.Status.DesiredNumberScheduled == ds.Status.UpdatedNumberScheduled {
			return nil, false, nil
		}
		return nil, true, fmt.Errorf("Only %v nodes have been updated out of %v nodes",
			ds.Status.UpdatedNumberScheduled, ds.Status.DesiredNumberScheduled)
	}

	if _, err := task.DoRetryWithTimeout(t, 20*time.Minute, 30*time.Second); err != nil {
		return err
	}
	return nil
}

func separateFilePaths(volDirList string) []string {
	trimmedList := strings.TrimSpace(volDirList)
	if trimmedList == "" {
		return []string{}
	}
	return strings.Split(trimmedList, "\n")
}

func extractPodUID(volDirPath string) string {
	re := regexp.MustCompile(k8sPodsRootDir +
		"/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/.*")
	match := re.FindStringSubmatch(volDirPath)
	if len(match) > 1 {
		return match[1]
	}
	return ""
}

func init() {
	k := &k8sSchedOps{}
	Register("k8s", k)
}
<commit_msg>Update logic to start and stop portworx on a node (#86)<commit_after>package schedops

import (
	"fmt"
	"regexp"
	"strings"
	"time"

	"github.com/libopenstorage/openstorage/api"
	"github.com/portworx/sched-ops/k8s"
	"github.com/portworx/sched-ops/task"
	"github.com/portworx/torpedo/drivers/node"
	"github.com/portworx/torpedo/drivers/volume"
	"github.com/portworx/torpedo/pkg/errors"
	"k8s.io/api/core/v1"
)

const (
	// PXServiceName is the name of the portworx service in kubernetes
	PXServiceName = "portworx-service"
	// PXNamespace is the kubernetes namespace in which portworx daemon set runs
	PXNamespace = "kube-system"
	// PXDaemonSet is the name of portworx daemon set in k8s deployment
	PXDaemonSet = "portworx"
	// PXImage is the image for portworx driver
	PXImage = "portworx/px-enterprise"
	// k8sPxServiceLabelKey is the label key used for px systemd service control
	k8sPxServiceLabelKey = "px/service"
	// k8sServiceOperationStart is label value for starting Portworx service
	k8sServiceOperationStart = "start"
	// k8sServiceOperationStop is label value for stopping Portworx service
	k8sServiceOperationStop = "stop"
	// k8sPodsRootDir is the directory under which k8s keeps all pods data
	k8sPodsRootDir = "/var/lib/kubelet/pods"
	// pxImageEnvVar is the env variable in portworx daemon set specifying portworx image to be used
	pxImageEnvVar = "PX_IMAGE"
)

// errLabelPresent error type for a label being present on a node
type errLabelPresent struct {
	// label is the label key
	label string
	// node is the k8s node where the label is present
	node string
}

func (e *errLabelPresent) Error() string {
	return fmt.Sprintf("label %s is present on node %s", e.label, e.node)
}

// errLabelAbsent error type for a label absent on a node
type errLabelAbsent struct {
	// label is the label key
	label string
	// node is the k8s node where the label is absent
	node string
}

func (e *errLabelAbsent) Error() string {
	return fmt.Sprintf("label %s is absent on node %s", e.label, e.node)
}

type k8sSchedOps struct{}

func (k *k8sSchedOps) DisableOnNode(n node.Node, _ node.Driver) error {
	return k8s.Instance().AddLabelOnNode(n.Name, k8sPxServiceLabelKey, k8sServiceOperationStop)
}

func (k *k8sSchedOps) ValidateOnNode(n node.Node) error {
	return &errors.ErrNotSupported{
		Type:      "Function",
		Operation: "ValidateOnNode",
	}
}

func (k *k8sSchedOps) EnableOnNode(n node.Node, _ node.Driver) error {
	return k8s.Instance().AddLabelOnNode(n.Name, k8sPxServiceLabelKey, k8sServiceOperationStart)
}

func (k *k8sSchedOps) ValidateAddLabels(replicaNodes []api.Node, vol *api.Volume) error {
	pvc, ok := vol.Locator.VolumeLabels["pvc"]
	if !ok {
		return nil
	}

	var missingLabelNodes []string
	for _, rs := range replicaNodes {
		t := func() (interface{}, bool, error) {
			n, err := k8s.Instance().GetNodeByName(rs.Id)
			if err != nil || n == nil {
				addrs := []string{rs.DataIp, rs.MgmtIp}
				n, err = k8s.Instance().SearchNodeByAddresses(addrs)
				if err != nil || n == nil {
					return nil, true, fmt.Errorf("failed to locate node using id: %s and addresses: %v",
						rs.Id, addrs)
				}
			}

			if _, ok := n.Labels[pvc]; !ok {
				return nil, true, &errLabelAbsent{
					node:  n.Name,
					label: pvc,
				}
			}
			return nil, false, nil
		}

		if _, err := task.DoRetryWithTimeout(t, 2*time.Minute, 10*time.Second); err != nil {
			if _, ok := err.(*errLabelAbsent); ok {
				missingLabelNodes = append(missingLabelNodes, rs.Id)
			} else {
				return err
			}
		}
	}

	if len(missingLabelNodes) > 0 {
		return &ErrLabelMissingOnNode{
			Label: pvc,
			Nodes: missingLabelNodes,
		}
	}
	return nil
}

func (k *k8sSchedOps) ValidateRemoveLabels(vol *volume.Volume) error {
	pvcLabel := vol.Name
	var staleLabelNodes []string
	for _, n := range node.GetWorkerNodes() {
		t := func() (interface{}, bool, error) {
			nodeLabels, err := k8s.Instance().GetLabelsOnNode(n.Name)
			if err != nil {
				return nil, true, err
			}

			if _, ok := nodeLabels[pvcLabel]; ok {
				return nil, true, &errLabelPresent{
					node:  n.Name,
					label: pvcLabel,
				}
			}
			return nil, false, nil
		}

		if _, err := task.DoRetryWithTimeout(t, 5*time.Minute, 10*time.Second); err != nil {
			if _, ok := err.(*errLabelPresent); ok {
				staleLabelNodes = append(staleLabelNodes, n.Name)
			} else {
				return err
			}
		}
	}

	if len(staleLabelNodes) > 0 {
		return &ErrLabelNotRemovedFromNode{
			Label: pvcLabel,
			Nodes: staleLabelNodes,
		}
	}

	return nil
}

func (k *k8sSchedOps) GetVolumeName(vol *volume.Volume) string {
	if vol != nil && vol.ID != "" {
		return fmt.Sprintf("pvc-%s", vol.ID)
	}
	return ""
}

func (k *k8sSchedOps) ValidateVolumeCleanup(d node.Driver) error {
	nodeToPodsMap := make(map[string][]string)
	nodeMap := make(map[string]node.Node)

	connOpts := node.ConnectionOpts{
		Timeout:         1 * time.Minute,
		TimeBeforeRetry: 10 * time.Second,
	}
	listVolOpts := node.FindOpts{
		ConnectionOpts: connOpts,
		Name:           "*portworx-volume",
	}

	for _, n := range node.GetWorkerNodes() {
		volDirList, _ := d.FindFiles(k8sPodsRootDir, n, listVolOpts)
		nodeToPodsMap[n.Name] = separateFilePaths(volDirList)
		nodeMap[n.Name] = n
	}

	existingPods, _ := k8s.Instance().GetPods("")

	orphanPodsMap := make(map[string][]string)
	dirtyVolPodsMap := make(map[string][]string)

	for nodeName, volDirPaths := range nodeToPodsMap {
		var orphanPods []string
		var dirtyVolPods []string

		for _, path := range volDirPaths {
			podUID := extractPodUID(path)
			found := false
			for _, existingPod := range existingPods.Items {
				if podUID == string(existingPod.UID) {
					found = true
					break
				}
			}
			if found {
				continue
			}
			orphanPods = append(orphanPods, podUID)

			// Check if there are files under portworx volume
			// We use a depth of 2 because the files stored in the volume are in the pvc
			// directory under the portworx-volume folder for that pod. For instance,
			// ../kubernetes-io~portworx-volume/pvc-<id>/<all_user_files>
			n := nodeMap[nodeName]
			findFileOpts := node.FindOpts{
				ConnectionOpts: connOpts,
				MinDepth:       2,
				MaxDepth:       2,
			}
			files, _ := d.FindFiles(path, n, findFileOpts)
			if len(strings.TrimSpace(files)) > 0 {
				dirtyVolPods = append(dirtyVolPods, podUID)
			}
		}

		if len(orphanPods) > 0 {
			orphanPodsMap[nodeName] = orphanPods
			if len(dirtyVolPods) > 0 {
				dirtyVolPodsMap[nodeName] = dirtyVolPods
			}
		}
	}

	if len(orphanPodsMap) == 0 {
		return nil
	}
	return &ErrFailedToCleanupVolume{
		OrphanPods:   orphanPodsMap,
		DirtyVolPods: dirtyVolPodsMap,
	}
}

func (k *k8sSchedOps) GetServiceEndpoint() (string, error) {
	svc, err := k8s.Instance().GetService(PXServiceName, PXNamespace)
	if err == nil {
		return svc.Spec.ClusterIP, nil
	}
	return "", err
}

func (k *k8sSchedOps) UpgradePortworx(version string) error {
	k8sOps := k8s.Instance()
	ds, err := k8sOps.GetDaemonSet(PXDaemonSet, PXNamespace)
	if err != nil {
		return err
	}

	image := fmt.Sprintf("%s:%s", PXImage, version)

	found := false
	envList := ds.Spec.Template.Spec.Containers[0].Env
	for i := range envList {
		envVar := &envList[i]
		if envVar.Name == pxImageEnvVar {
			envVar.Value = image
			found = true
			break
		}
	}
	if !found {
		imageEnv := v1.EnvVar{Name: pxImageEnvVar, Value: image}
		ds.Spec.Template.Spec.Containers[0].Env = append(ds.Spec.Template.Spec.Containers[0].Env, imageEnv)
	}

	if err := k8sOps.UpdateDaemonSet(ds); err != nil {
		return err
	}

	// Sleep for a short duration so that the daemon set updates its status
	time.Sleep(10 * time.Second)

	t := func() (interface{}, bool, error) {
		ds, err := k8sOps.GetDaemonSet(PXDaemonSet, PXNamespace)
		if err != nil {
			return nil, true, err
		}

		if ds.Status.DesiredNumberScheduled == ds.Status.UpdatedNumberScheduled {
			return nil, false, nil
		}
		return nil, true, fmt.Errorf("Only %v nodes have been updated out of %v nodes",
			ds.Status.UpdatedNumberScheduled, ds.Status.DesiredNumberScheduled)
	}

	if _, err := task.DoRetryWithTimeout(t, 20*time.Minute, 30*time.Second); err != nil {
		return err
	}
	return nil
}

func separateFilePaths(volDirList string) []string {
	trimmedList := strings.TrimSpace(volDirList)
	if trimmedList == "" {
		return []string{}
	}
	return strings.Split(trimmedList, "\n")
}

func extractPodUID(volDirPath string) string {
	re := regexp.MustCompile(k8sPodsRootDir +
		"/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/.*")
	match := re.FindStringSubmatch(volDirPath)
	if len(match) > 1 {
		return match[1]
	}
	return ""
}

func init() {
	k := &k8sSchedOps{}
	Register("k8s", k)
}
<|endoftext|>


<commit_before>package controllers

import (
	"context"
	"fmt"
	"reflect"
	"time"

	"github.com/libopenstorage/stork/drivers/volume"
	"github.com/libopenstorage/stork/pkg/apis/stork"
	storkv1 "github.com/libopenstorage/stork/pkg/apis/stork/v1alpha1"
	"github.com/libopenstorage/stork/pkg/controller"
	"github.com/operator-framework/operator-sdk/pkg/sdk"
	"github.com/portworx/sched-ops/k8s"
	"github.com/portworx/sched-ops/task"
	"github.com/sirupsen/logrus"
	v1 "k8s.io/api/core/v1"
	apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/client-go/tools/record"
)

const (
	validateCRDInterval    time.Duration = 5 * time.Second
	validateCRDTimeout     time.Duration = 1 * time.Minute
	resyncPeriod                         = 1 * time.Minute
	createCdsTimeout                     = 30 * time.Minute
	createCdsRetryInterval               = 10 * time.Second
)

// ClusterDomainsStatusController clusterdomainsstatus controller
type ClusterDomainsStatusController struct {
	Driver   volume.Driver
	Recorder record.EventRecorder
}

// Init initialize the clusterdomainsstatus controller
func (c *ClusterDomainsStatusController) Init() error {
	err := c.createCRD()
	if err != nil {
		return err
	}

	if err := controller.Register(
		&schema.GroupVersionKind{
			Group:   stork.GroupName,
			Version: storkv1.SchemeGroupVersion.Version,
			Kind:    reflect.TypeOf(storkv1.ClusterDomainsStatus{}).Name(),
		},
		"",
		resyncPeriod,
		c,
	); err != nil {
		return err
	}

	go func() { c.createClusterDomainsStatusObject() }()

	return nil
}

// Handle updates the cluster about the changes in the ClusterDomainsStatus CRD
func (c *ClusterDomainsStatusController) Handle(ctx context.Context, event sdk.Event) error {
	switch obj := event.Object.(type) {
	case *storkv1.ClusterDomainsStatus:
		clusterDomainsStatus := obj
		if event.Deleted {
			go func() { c.createClusterDomainsStatusObject() }()
		}
		clusterDomainsInfo, err := c.Driver.GetClusterDomains()
		updated := false
		if err != nil {
			c.Recorder.Event(
				clusterDomainsStatus,
				v1.EventTypeWarning,
				err.Error(),
				fmt.Sprintf("Failed to update ClusterDomainsStatuses"),
			)
		} else {
			if len(clusterDomainsInfo.Active) != len(clusterDomainsStatus.Status.Active) ||
				len(clusterDomainsInfo.Inactive) != len(clusterDomainsStatus.Status.Inactive) {
				updated = true
			} else {
				// Check active list
				if !c.doListsMatch(clusterDomainsInfo.Active, clusterDomainsStatus.Status.Active) ||
					!c.doListsMatch(clusterDomainsInfo.Inactive, clusterDomainsStatus.Status.Inactive) {
					updated = true
				}
			}
		}
		if updated {
			clusterDomainsStatus.Status.Active = clusterDomainsInfo.Active
			clusterDomainsStatus.Status.Inactive = clusterDomainsInfo.Inactive
			if err := sdk.Update(clusterDomainsStatus); err != nil {
				return err
			}
		}
	}
	return nil
}

func (c *ClusterDomainsStatusController) doListsMatch(domainListSDK, domainListCRD []string) bool {
	for _, sdkDomain := range domainListSDK {
		for _, crdDomain := range domainListCRD {
			if crdDomain == sdkDomain {
				continue
			}
			// could not find a match
			return false
		}
	}
	return true
}

func (c *ClusterDomainsStatusController) createClusterDomainsStatusObject() {
	t := func() (interface{}, bool, error) {

		clusterID, err := c.Driver.GetClusterID()
		if err != nil {
			return nil, true, fmt.Errorf("Failed to create cluster "+
				"domains status object for driver %v: %v", c.Driver.String(), err)
		}
		clusterDomainStatus := &storkv1.ClusterDomainsStatus{
			ObjectMeta: metav1.ObjectMeta{
				Name: clusterID,
			},
		}
		if _, err := k8s.Instance().CreateClusterDomainsStatus(clusterDomainStatus); err != nil {
			return nil, true, fmt.Errorf("Failed to create cluster domain"+
				" status object for driver %v: %v", c.Driver.String(), err)
		}
		return nil, false, nil
	}

	if _, err := task.DoRetryWithTimeout(t, createCdsTimeout, createCdsRetryInterval); err != nil {
		logrus.Errorf("Failed to start the task for creating cluster domain status object: %v", err)
	}

}

// createCRD creates the CRD for ClusterDomainsStatus object
func (c *ClusterDomainsStatusController) createCRD() error {
	resource := k8s.CustomResource{
		Name:       storkv1.ClusterDomainsStatusResourceName,
		Plural:     storkv1.ClusterDomainsStatusPlural,
		Group:      stork.GroupName,
		Version:    storkv1.SchemeGroupVersion.Version,
		Scope:      apiextensionsv1beta1.ClusterScoped,
		Kind:       reflect.TypeOf(storkv1.ClusterDomainsStatus{}).Name(),
		ShortNames: []string{storkv1.ClusterDomainsStatusShortName},
	}
	err := k8s.Instance().CreateCRD(resource)
	if err != nil && !errors.IsAlreadyExists(err) {
		return err
	}

	return k8s.Instance().ValidateCRD(resource, validateCRDTimeout, validateCRDInterval)
}
<commit_msg>Ignore already exists error when creating clusterdomainsstatus CRD<commit_after>package controllers

import (
	"context"
	"fmt"
	"reflect"
	"time"

	"github.com/libopenstorage/stork/drivers/volume"
	"github.com/libopenstorage/stork/pkg/apis/stork"
	storkv1 "github.com/libopenstorage/stork/pkg/apis/stork/v1alpha1"
	"github.com/libopenstorage/stork/pkg/controller"
	"github.com/operator-framework/operator-sdk/pkg/sdk"
	"github.com/portworx/sched-ops/k8s"
	"github.com/portworx/sched-ops/task"
	"github.com/sirupsen/logrus"
	v1 "k8s.io/api/core/v1"
	apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/client-go/tools/record"
)

const (
	validateCRDInterval    time.Duration = 5 * time.Second
	validateCRDTimeout     time.Duration = 1 * time.Minute
	resyncPeriod                         = 1 * time.Minute
	createCdsTimeout                     = 30 * time.Minute
	createCdsRetryInterval               = 10 * time.Second
)

// ClusterDomainsStatusController clusterdomainsstatus controller
type ClusterDomainsStatusController struct {
	Driver   volume.Driver
	Recorder record.EventRecorder
}

// Init initialize the clusterdomainsstatus controller
func (c *ClusterDomainsStatusController) Init() error {
	err := c.createCRD()
	if err != nil {
		return err
	}

	if err := controller.Register(
		&schema.GroupVersionKind{
			Group:   stork.GroupName,
			Version: storkv1.SchemeGroupVersion.Version,
			Kind:    reflect.TypeOf(storkv1.ClusterDomainsStatus{}).Name(),
		},
		"",
		resyncPeriod,
		c,
	); err != nil {
		return err
	}

	go func() { c.createClusterDomainsStatusObject() }()

	return nil
}

// Handle updates the cluster about the changes in the ClusterDomainsStatus CRD
func (c *ClusterDomainsStatusController) Handle(ctx context.Context, event sdk.Event) error {
	switch obj := event.Object.(type) {
	case *storkv1.ClusterDomainsStatus:
		clusterDomainsStatus := obj
		if event.Deleted {
			go func() { c.createClusterDomainsStatusObject() }()
		}
		clusterDomainsInfo, err := c.Driver.GetClusterDomains()
		updated := false
		if err != nil {
			c.Recorder.Event(
				clusterDomainsStatus,
				v1.EventTypeWarning,
				err.Error(),
				fmt.Sprintf("Failed to update ClusterDomainsStatuses"),
			)
		} else {
			if len(clusterDomainsInfo.Active) != len(clusterDomainsStatus.Status.Active) ||
				len(clusterDomainsInfo.Inactive) != len(clusterDomainsStatus.Status.Inactive) {
				updated = true
			} else {
				// Check active list
				if !c.doListsMatch(clusterDomainsInfo.Active, clusterDomainsStatus.Status.Active) ||
					!c.doListsMatch(clusterDomainsInfo.Inactive, clusterDomainsStatus.Status.Inactive) {
					updated = true
				}
			}
		}
		if updated {
			clusterDomainsStatus.Status.Active = clusterDomainsInfo.Active
			clusterDomainsStatus.Status.Inactive = clusterDomainsInfo.Inactive
			if err := sdk.Update(clusterDomainsStatus); err != nil {
				return err
			}
		}
	}
	return nil
}

func (c *ClusterDomainsStatusController) doListsMatch(domainListSDK, domainListCRD []string) bool {
	for _, sdkDomain := range domainListSDK {
		for _, crdDomain := range domainListCRD {
			if crdDomain == sdkDomain {
				continue
			}
			// could not find a match
			return false
		}
	}
	return true
}

func (c *ClusterDomainsStatusController) createClusterDomainsStatusObject() {
	t := func() (interface{}, bool, error) {

		clusterID, err := c.Driver.GetClusterID()
		if err != nil {
			return nil, true, fmt.Errorf("Failed to create cluster "+
				"domains status object for driver %v: %v", c.Driver.String(), err)
		}
		clusterDomainStatus := &storkv1.ClusterDomainsStatus{
			ObjectMeta: metav1.ObjectMeta{
				Name: clusterID,
			},
		}
		if _, err := k8s.Instance().CreateClusterDomainsStatus(clusterDomainStatus); err != nil && !errors.IsAlreadyExists(err) {
			return nil, true, fmt.Errorf("Failed to create cluster domain"+
				" status object for driver %v: %v", c.Driver.String(), err)
		}
		return nil, false, nil
	}

	if _, err := task.DoRetryWithTimeout(t, createCdsTimeout, createCdsRetryInterval); err != nil {
		logrus.Errorf("Failed to start the task for creating cluster domain status object: %v", err)
	}

}

// createCRD creates the CRD for ClusterDomainsStatus object
func (c *ClusterDomainsStatusController) createCRD() error {
	resource := k8s.CustomResource{
		Name:       storkv1.ClusterDomainsStatusResourceName,
		Plural:     storkv1.ClusterDomainsStatusPlural,
		Group:      stork.GroupName,
		Version:    storkv1.SchemeGroupVersion.Version,
		Scope:      apiextensionsv1beta1.ClusterScoped,
		Kind:       reflect.TypeOf(storkv1.ClusterDomainsStatus{}).Name(),
		ShortNames: []string{storkv1.ClusterDomainsStatusShortName},
	}
	err := k8s.Instance().CreateCRD(resource)
	if err != nil && !errors.IsAlreadyExists(err) {
		return err
	}

	return k8s.Instance().ValidateCRD(resource, validateCRDTimeout, validateCRDInterval)
}
<|endoftext|>


<commit_before>/*
 * Copyright 2019, EnMasse authors.
 * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
 */

package address_space_controller

import (
	"context"
	"os"
	"time"

	"github.com/enmasseproject/enmasse/pkg/util"
	"github.com/enmasseproject/enmasse/pkg/util/images"
	"github.com/enmasseproject/enmasse/pkg/util/install"

	"github.com/go-logr/logr"

	"sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/controller-runtime/pkg/controller"
	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
	"sigs.k8s.io/controller-runtime/pkg/handler"
	"sigs.k8s.io/controller-runtime/pkg/manager"
	"sigs.k8s.io/controller-runtime/pkg/reconcile"
	logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
	"sigs.k8s.io/controller-runtime/pkg/source"

	appsv1 "k8s.io/api/apps/v1"
	corev1 "k8s.io/api/core/v1"
	k8errors "k8s.io/apimachinery/pkg/api/errors"
	resource "k8s.io/apimachinery/pkg/api/resource"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	runtime "k8s.io/apimachinery/pkg/runtime"
	controllertypes "k8s.io/apimachinery/pkg/types"
	intstr "k8s.io/apimachinery/pkg/util/intstr"
)

var log = logf.Log.WithName("controller_address_space_controller")

const ADDRESS_SPACE_CONTROLLER_NAME = "address-space-controller"
const ANNOTATION_VERSION = "enmasse.io/version"
const ENV_VERSION = "VERSION"

var _ reconcile.Reconciler = &ReconcileAddressSpaceController{}

type ReconcileAddressSpaceController struct {
	client    client.Client
	reader    client.Reader
	scheme    *runtime.Scheme
	namespace string
}

// Gets called by parent "init", adding as to the manager
func Add(mgr manager.Manager) error {
	reconciler, err := newReconciler(mgr)
	if err != nil {
		return err
	}
	return add(mgr, reconciler)
}

func newReconciler(mgr manager.Manager) (*ReconcileAddressSpaceController, error) {
	return &ReconcileAddressSpaceController{
		client:    mgr.GetClient(),
		reader:    mgr.GetAPIReader(),
		scheme:    mgr.GetScheme(),
		namespace: util.GetEnvOrDefault("NAMESPACE", "enmasse-infra"),
	}, nil
}

func add(mgr manager.Manager, r *ReconcileAddressSpaceController) error {

	// Create initial deployment if it does not exist. We cannot yet rely on
	// the controller-runtime client cache (CreateOrUpdate), as the runtime has not yet started.
	deployment := &appsv1.Deployment{}
	err := r.reader.Get(context.TODO(), controllertypes.NamespacedName{Namespace: r.namespace, Name: ADDRESS_SPACE_CONTROLLER_NAME}, deployment)
	if err != nil {
		if k8errors.IsNotFound(err) {
			deployment = &appsv1.Deployment{
				ObjectMeta: metav1.ObjectMeta{
					Namespace: r.namespace,
					Name:      ADDRESS_SPACE_CONTROLLER_NAME,
				},
			}
			err = ApplyDeployment(deployment)
			if err != nil {
				return err
			}
			err = r.client.Create(context.TODO(), deployment)
			if err != nil {
				return err
			}
		} else {
			return err
		}
	}

	service := &corev1.Service{}
	err = r.reader.Get(context.TODO(), controllertypes.NamespacedName{Namespace: r.namespace, Name: ADDRESS_SPACE_CONTROLLER_NAME}, service)
	if err != nil {
		if k8errors.IsNotFound(err) {
			service = &corev1.Service{
				ObjectMeta: metav1.ObjectMeta{
					Namespace: r.namespace,
					Name:      ADDRESS_SPACE_CONTROLLER_NAME,
				},
			}
			err = applyService(service)
			if err != nil {
				return err
			}
			err = r.client.Create(context.TODO(), service)
			if err != nil {
				return err
			}
		} else {
			return err
		}
	}

	// Start reconciler for address-space-controller deployment
	c, err := controller.New("address-space-controller-controller", mgr, controller.Options{Reconciler: r})
	if err != nil {
		return err
	}

	return c.Watch(&source.Kind{Type: &appsv1.Deployment{}}, &handler.EnqueueRequestForObject{})
}

func (r *ReconcileAddressSpaceController) Reconcile(request reconcile.Request) (reconcile.Result, error) {

	expectedName := controllertypes.NamespacedName{
		Namespace: r.namespace,
		Name:      ADDRESS_SPACE_CONTROLLER_NAME,
	}

	if expectedName == request.NamespacedName {
		reqLogger := log.WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name)
		reqLogger.Info("Reconciling Address Space Controller")

		ctx := context.TODO()

		_, err := r.ensureDeployment(ctx, request, reqLogger)
		if err != nil {
			reqLogger.Error(err, "Error creating address space controller deployment")
			return reconcile.Result{}, err
		}

		_, err = r.ensureService(ctx, request, reqLogger)
		if err != nil {
			reqLogger.Error(err, "Error creating address space controller service")
			return reconcile.Result{}, err
		}
	}
	return reconcile.Result{RequeueAfter: 30 * time.Second}, nil
}

func (r *ReconcileAddressSpaceController) ensureDeployment(ctx context.Context, request reconcile.Request, reqLogger logr.Logger) (reconcile.Result, error) {

	deployment := &appsv1.Deployment{
		ObjectMeta: metav1.ObjectMeta{
			Name:      request.NamespacedName.Name,
			Namespace: request.NamespacedName.Namespace,
		},
	}

	_, err := controllerutil.CreateOrUpdate(ctx, r.client, deployment, func() error {
		return ApplyDeployment(deployment)
	})

	return reconcile.Result{}, err
}

func ApplyDeployment(deployment *appsv1.Deployment) error {
	install.ApplyDeploymentDefaults(deployment, "address-space-controller", deployment.Name)
	err := install.ApplyDeploymentContainerWithError(deployment, "address-space-controller", func(container *corev1.Container) error {
		install.ApplyContainerImage(container, "address-space-controller", nil)
		container.LivenessProbe = install.ApplyHttpProbe(container.LivenessProbe, 30, "/healthz", 8080)
		container.ReadinessProbe = install.ApplyHttpProbe(container.ReadinessProbe, 30, "/healthz", 8080)
		container.Ports = []corev1.ContainerPort{
			{Name: "http", ContainerPort: 8080, Protocol: corev1.ProtocolTCP},
		}
		install.ApplyEnvSimple(container, "JAVA_OPTS", "-verbose:gc")
		install.ApplyEnvSimple(container, "ENABLE_EVENT_LOGGER", "true")
		install.ApplyEnvSimple(container, "TEMPLATE_DIR", "/opt/templates")
		install.ApplyEnvSimple(container, "RESOURCES_DIR", "/opt")
		if value, ok := os.LookupEnv("FS_GROUP_FALLBACK_MAP"); ok {
			install.ApplyOrRemoveEnvSimple(container, "FS_GROUP_FALLBACK_MAP", value)
		}

		t := true
		install.ApplyEnvConfigMap(container, "WILDCARD_ENDPOINT_CERT_SECRET", "wildcardEndpointCertSecret", "address-space-controller-config", &t)
		install.ApplyEnvConfigMap(container, "RESYNC_INTERVAL", "resyncInterval", "address-space-controller-config", &t)
		install.ApplyEnvConfigMap(container, "RECHECK_INTERVAL", "recheckInterval", "address-space-controller-config", &t)
		install.ApplyEnvConfigMap(container, "ROUTER_STATUS_CHECK_INTERVAL", "routerStatusCheckInterval", "address-space-controller-config", &t)
		install.ApplyEnvConfigMap(container, "EXPOSE_ENDPOINTS_BY_DEFAULT", "exposeEndpointsByDefault", "address-space-controller-config", &t)
		install.ApplyEnvConfigMap(container, "DISABLE_EXTERNAL_CERT_PROVISIONING", "disableExternalCertProvisioning", "address-space-controller-config", &t)

		install.ApplyEnvSimple(container, "IMAGE_PULL_POLICY", string(images.PullPolicyFromImageName(container.Image)))
		applyImageEnv(container, "ROUTER_IMAGE", "router")
		applyImageEnv(container, "STANDARD_CONTROLLER_IMAGE", "standard-controller")
		applyImageEnv(container, "AGENT_IMAGE", "agent")
		applyImageEnv(container, "BROKER_IMAGE", "broker")
		applyImageEnv(container, "BROKER_PLUGIN_IMAGE", "broker-plugin")
		applyImageEnv(container, "TOPIC_FORWARDER_IMAGE", "topic-forwarder")
		applyImageEnv(container, "MQTT_GATEWAY_IMAGE", "mqtt-gateway")
		applyImageEnv(container, "MQTT_LWT_IMAGE", "mqtt-lwt")

		if value, ok := os.LookupEnv("ENABLE_MONITORING_ANNOTATIONS"); ok && value == "true" {
			deployment.ObjectMeta.Annotations["prometheus.io/scrape"] = "true"
			deployment.ObjectMeta.Annotations["prometheus.io/path"] = "/metrics"
			deployment.ObjectMeta.Annotations["prometheus.io/port"] = "8080"
		}

		cpuEnv, ok := os.LookupEnv("ADDRESS_SPACE_CONTROLLER_CPU_LIMIT")
		if ok {
			cpuLimit, err := resource.ParseQuantity(cpuEnv)
			if err != nil {
				return err
			}
			container.Resources.Requests[corev1.ResourceCPU] = cpuLimit
			container.Resources.Limits[corev1.ResourceCPU] = cpuLimit
		} else {
			delete(container.Resources.Requests, corev1.ResourceCPU)
			delete(container.Resources.Limits, corev1.ResourceCPU)
		}

		memoryEnv, ok := os.LookupEnv("ADDRESS_SPACE_CONTROLLER_MEMORY_LIMIT")
		if ok {
			memoryLimit, err := resource.ParseQuantity(memoryEnv)
			if err != nil {
				return err
			}
			container.Resources.Requests[corev1.ResourceMemory] = memoryLimit
			container.Resources.Limits[corev1.ResourceMemory] = memoryLimit
		} else {
			delete(container.Resources.Requests, corev1.ResourceMemory)
			delete(container.Resources.Limits, corev1.ResourceMemory)
		}
		return nil
	})
	if err != nil {
		return err
	}
	// This means we are running
	version, ok := os.LookupEnv(ENV_VERSION)
	if ok {
		deployment.Annotations[ANNOTATION_VERSION] = version
	}

	var one int32 = 1
	deployment.Spec.Template.Spec.ServiceAccountName = "address-space-controller"
	deployment.Spec.Replicas = &one
	install.ApplyNodeAffinity(&deployment.Spec.Template, "node-role.enmasse.io/operator-infra")

	return nil
}

func applyImageEnv(container *corev1.Container, env string, imageName string) error {
	image, err := images.GetImage(imageName)
	if err != nil {
		return err
	}
	install.ApplyEnvSimple(container, env, image)
	return nil
}

func (r *ReconcileAddressSpaceController) ensureService(ctx context.Context, request reconcile.Request, reqLogger logr.Logger) (reconcile.Result, error) {

	service := &corev1.Service{
		ObjectMeta: metav1.ObjectMeta{
			Name:      request.NamespacedName.Name,
			Namespace: request.NamespacedName.Namespace,
		},
	}

	_, err := controllerutil.CreateOrUpdate(ctx, r.client, service, func() error {
		return applyService(service)
	})

	return reconcile.Result{}, err
}

func applyService(service *corev1.Service) error {
	install.ApplyServiceDefaults(service, service.Name, service.Name)
	install.ApplyCustomLabel(&service.ObjectMeta, "monitoring-key", "enmasse-tenants")
	service.Spec.Ports = []corev1.ServicePort{
		{
			Port:       8080,
			Protocol:   corev1.ProtocolTCP,
			TargetPort: intstr.FromString("http"),
			Name:       "health",
		},
	}
	return nil
}
<commit_msg>Initialize resource maps if they are not set (#4687)<commit_after>/*
 * Copyright 2019, EnMasse authors.
 * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
 */

package address_space_controller

import (
	"context"
	"os"
	"time"

	"github.com/enmasseproject/enmasse/pkg/util"
	"github.com/enmasseproject/enmasse/pkg/util/images"
	"github.com/enmasseproject/enmasse/pkg/util/install"

	"github.com/go-logr/logr"

	"sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/controller-runtime/pkg/controller"
	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
	"sigs.k8s.io/controller-runtime/pkg/handler"
	"sigs.k8s.io/controller-runtime/pkg/manager"
	"sigs.k8s.io/controller-runtime/pkg/reconcile"
	logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
	"sigs.k8s.io/controller-runtime/pkg/source"

	appsv1 "k8s.io/api/apps/v1"
	corev1 "k8s.io/api/core/v1"
	k8errors "k8s.io/apimachinery/pkg/api/errors"
	resource "k8s.io/apimachinery/pkg/api/resource"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	runtime "k8s.io/apimachinery/pkg/runtime"
	controllertypes "k8s.io/apimachinery/pkg/types"
	intstr "k8s.io/apimachinery/pkg/util/intstr"
)

var log = logf.Log.WithName("controller_address_space_controller")

const ADDRESS_SPACE_CONTROLLER_NAME = "address-space-controller"
const ANNOTATION_VERSION = "enmasse.io/version"
const ENV_VERSION = "VERSION"

var _ reconcile.Reconciler = &ReconcileAddressSpaceController{}

type ReconcileAddressSpaceController struct {
	client    client.Client
	reader    client.Reader
	scheme    *runtime.Scheme
	namespace string
}

// Gets called by parent "init", adding as to the manager
func Add(mgr manager.Manager) error {
	reconciler, err := newReconciler(mgr)
	if err != nil {
		return err
	}
	return add(mgr, reconciler)
}

func newReconciler(mgr manager.Manager) (*ReconcileAddressSpaceController, error) {
	return &ReconcileAddressSpaceController{
		client:    mgr.GetClient(),
		reader:    mgr.GetAPIReader(),
		scheme:    mgr.GetScheme(),
		namespace: util.GetEnvOrDefault("NAMESPACE", "enmasse-infra"),
	}, nil
}

func add(mgr manager.Manager, r *ReconcileAddressSpaceController) error {

	// Create initial deployment if it does not exist. We cannot yet rely on
	// the controller-runtime client cache (CreateOrUpdate), as the runtime has not yet started.
	deployment := &appsv1.Deployment{}
	err := r.reader.Get(context.TODO(), controllertypes.NamespacedName{Namespace: r.namespace, Name: ADDRESS_SPACE_CONTROLLER_NAME}, deployment)
	if err != nil {
		if k8errors.IsNotFound(err) {
			deployment = &appsv1.Deployment{
				ObjectMeta: metav1.ObjectMeta{
					Namespace: r.namespace,
					Name:      ADDRESS_SPACE_CONTROLLER_NAME,
				},
			}
			err = ApplyDeployment(deployment)
			if err != nil {
				return err
			}
			err = r.client.Create(context.TODO(), deployment)
			if err != nil {
				return err
			}
		} else {
			return err
		}
	}

	service := &corev1.Service{}
	err = r.reader.Get(context.TODO(), controllertypes.NamespacedName{Namespace: r.namespace, Name: ADDRESS_SPACE_CONTROLLER_NAME}, service)
	if err != nil {
		if k8errors.IsNotFound(err) {
			service = &corev1.Service{
				ObjectMeta: metav1.ObjectMeta{
					Namespace: r.namespace,
					Name:      ADDRESS_SPACE_CONTROLLER_NAME,
				},
			}
			err = applyService(service)
			if err != nil {
				return err
			}
			err = r.client.Create(context.TODO(), service)
			if err != nil {
				return err
			}
		} else {
			return err
		}
	}

	// Start reconciler for address-space-controller deployment
	c, err := controller.New("address-space-controller-controller", mgr, controller.Options{Reconciler: r})
	if err != nil {
		return err
	}

	return c.Watch(&source.Kind{Type: &appsv1.Deployment{}}, &handler.EnqueueRequestForObject{})
}

func (r *ReconcileAddressSpaceController) Reconcile(request reconcile.Request) (reconcile.Result, error) {

	expectedName := controllertypes.NamespacedName{
		Namespace: r.namespace,
		Name:      ADDRESS_SPACE_CONTROLLER_NAME,
	}

	if expectedName == request.NamespacedName {
		reqLogger := log.WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name)
		reqLogger.Info("Reconciling Address Space Controller")

		ctx := context.TODO()

		_, err := r.ensureDeployment(ctx, request, reqLogger)
		if err != nil {
			reqLogger.Error(err, "Error creating address space controller deployment")
			return reconcile.Result{}, err
		}

		_, err = r.ensureService(ctx, request, reqLogger)
		if err != nil {
			reqLogger.Error(err, "Error creating address space controller service")
			return reconcile.Result{}, err
		}
	}
	return reconcile.Result{RequeueAfter: 30 * time.Second}, nil
}

func (r *ReconcileAddressSpaceController) ensureDeployment(ctx context.Context, request reconcile.Request, reqLogger logr.Logger) (reconcile.Result, error) {

	deployment := &appsv1.Deployment{
		ObjectMeta: metav1.ObjectMeta{
			Name:      request.NamespacedName.Name,
			Namespace: request.NamespacedName.Namespace,
		},
	}

	_, err := controllerutil.CreateOrUpdate(ctx, r.client, deployment, func() error {
		return ApplyDeployment(deployment)
	})

	return reconcile.Result{}, err
}

func ApplyDeployment(deployment *appsv1.Deployment) error {
	install.ApplyDeploymentDefaults(deployment, "address-space-controller", deployment.Name)
	err := install.ApplyDeploymentContainerWithError(deployment, "address-space-controller", func(container *corev1.Container) error {
		install.ApplyContainerImage(container, "address-space-controller", nil)
		container.LivenessProbe = install.ApplyHttpProbe(container.LivenessProbe, 30, "/healthz", 8080)
		container.ReadinessProbe = install.ApplyHttpProbe(container.ReadinessProbe, 30, "/healthz", 8080)
		container.Ports = []corev1.ContainerPort{
			{Name: "http", ContainerPort: 8080, Protocol: corev1.ProtocolTCP},
		}
		install.ApplyEnvSimple(container, "JAVA_OPTS", "-verbose:gc")
		install.ApplyEnvSimple(container, "ENABLE_EVENT_LOGGER", "true")
		install.ApplyEnvSimple(container, "TEMPLATE_DIR", "/opt/templates")
		install.ApplyEnvSimple(container, "RESOURCES_DIR", "/opt")
		if value, ok := os.LookupEnv("FS_GROUP_FALLBACK_MAP"); ok {
			install.ApplyOrRemoveEnvSimple(container, "FS_GROUP_FALLBACK_MAP", value)
		}

		t := true
		install.ApplyEnvConfigMap(container, "WILDCARD_ENDPOINT_CERT_SECRET", "wildcardEndpointCertSecret", "address-space-controller-config", &t)
		install.ApplyEnvConfigMap(container, "RESYNC_INTERVAL", "resyncInterval", "address-space-controller-config", &t)
		install.ApplyEnvConfigMap(container, "RECHECK_INTERVAL", "recheckInterval", "address-space-controller-config", &t)
		install.ApplyEnvConfigMap(container, "ROUTER_STATUS_CHECK_INTERVAL", "routerStatusCheckInterval", "address-space-controller-config", &t)
		install.ApplyEnvConfigMap(container, "EXPOSE_ENDPOINTS_BY_DEFAULT", "exposeEndpointsByDefault", "address-space-controller-config", &t)
		install.ApplyEnvConfigMap(container, "DISABLE_EXTERNAL_CERT_PROVISIONING", "disableExternalCertProvisioning", "address-space-controller-config", &t)

		install.ApplyEnvSimple(container, "IMAGE_PULL_POLICY", string(images.PullPolicyFromImageName(container.Image)))
		applyImageEnv(container, "ROUTER_IMAGE", "router")
		applyImageEnv(container, "STANDARD_CONTROLLER_IMAGE", "standard-controller")
		applyImageEnv(container, "AGENT_IMAGE", "agent")
		applyImageEnv(container, "BROKER_IMAGE", "broker")
		applyImageEnv(container, "BROKER_PLUGIN_IMAGE", "broker-plugin")
		applyImageEnv(container, "TOPIC_FORWARDER_IMAGE", "topic-forwarder")
		applyImageEnv(container, "MQTT_GATEWAY_IMAGE", "mqtt-gateway")
		applyImageEnv(container, "MQTT_LWT_IMAGE", "mqtt-lwt")

		if value, ok := os.LookupEnv("ENABLE_MONITORING_ANNOTATIONS"); ok && value == "true" {
			deployment.ObjectMeta.Annotations["prometheus.io/scrape"] = "true"
			deployment.ObjectMeta.Annotations["prometheus.io/path"] = "/metrics"
			deployment.ObjectMeta.Annotations["prometheus.io/port"] = "8080"
		}

		if container.Resources.Requests == nil {
			container.Resources.Requests = make(map[corev1.ResourceName]resource.Quantity, 0)
		}

		if container.Resources.Limits == nil {
			container.Resources.Limits = make(map[corev1.ResourceName]resource.Quantity, 0)
		}

		cpuEnv, ok := os.LookupEnv("ADDRESS_SPACE_CONTROLLER_CPU_LIMIT")
		if ok {
			cpuLimit, err := resource.ParseQuantity(cpuEnv)
			if err != nil {
				return err
			}
			container.Resources.Requests[corev1.ResourceCPU] = cpuLimit
			container.Resources.Limits[corev1.ResourceCPU] = cpuLimit
		} else {
			delete(container.Resources.Requests, corev1.ResourceCPU)
			delete(container.Resources.Limits, corev1.ResourceCPU)
		}

		memoryEnv, ok := os.LookupEnv("ADDRESS_SPACE_CONTROLLER_MEMORY_LIMIT")
		if ok {
			memoryLimit, err := resource.ParseQuantity(memoryEnv)
			if err != nil {
				return err
			}
			container.Resources.Requests[corev1.ResourceMemory] = memoryLimit
			container.Resources.Limits[corev1.ResourceMemory] = memoryLimit
		} else {
			delete(container.Resources.Requests, corev1.ResourceMemory)
			delete(container.Resources.Limits, corev1.ResourceMemory)
		}
		return nil
	})
	if err != nil {
		return err
	}
	// This means we are running
	version, ok := os.LookupEnv(ENV_VERSION)
	if ok {
		deployment.Annotations[ANNOTATION_VERSION] = version
	}

	var one int32 = 1
	deployment.Spec.Template.Spec.ServiceAccountName = "address-space-controller"
	deployment.Spec.Replicas = &one
	install.ApplyNodeAffinity(&deployment.Spec.Template, "node-role.enmasse.io/operator-infra")

	return nil
}

func applyImageEnv(container *corev1.Container, env string, imageName string) error {
	image, err := images.GetImage(imageName)
	if err != nil {
		return err
	}
	install.ApplyEnvSimple(container, env, image)
	return nil
}

func (r *ReconcileAddressSpaceController) ensureService(ctx context.Context, request reconcile.Request, reqLogger logr.Logger) (reconcile.Result, error) {

	service := &corev1.Service{
		ObjectMeta: metav1.ObjectMeta{
			Name:      request.NamespacedName.Name,
			Namespace: request.NamespacedName.Namespace,
		},
	}

	_, err := controllerutil.CreateOrUpdate(ctx, r.client, service, func() error {
		return applyService(service)
	})

	return reconcile.Result{}, err
}

func applyService(service *corev1.Service) error {
	install.ApplyServiceDefaults(service, service.Name, service.Name)
	install.ApplyCustomLabel(&service.ObjectMeta, "monitoring-key", "enmasse-tenants")
	service.Spec.Ports = []corev1.ServicePort{
		{
			Port:       8080,
			Protocol:   corev1.ProtocolTCP,
			TargetPort: intstr.FromString("http"),
			Name:       "health",
		},
	}
	return nil
}
<|endoftext|>


<commit_before>package role

import (
	"testing"
	"time"

	rbac "k8s.io/api/rbac/v1beta1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/util/uuid"
	kubeinformers "k8s.io/client-go/informers"
	kubefake "k8s.io/client-go/kubernetes/fake"
	core "k8s.io/client-go/testing"

	navigator "github.com/jetstack/navigator/pkg/apis/navigator/v1alpha1"
)

var (
	alwaysReady        = func() bool { return true }
	noResyncPeriodFunc = func() time.Duration { return 0 }
)

type fixture struct {
	t *testing.T

	kubeClient *kubefake.Clientset
	// Objects to put in the store.
	roleLister []*rbac.Role

	// Actions expected to happen on the client.
	kubeActions []core.Action

	// Objects from here preloaded into NewSimpleFake.
	kubeObjects []runtime.Object
}

func newFixture(t *testing.T) *fixture {
	f := &fixture{}
	f.t = t
	f.kubeObjects = []runtime.Object{}
	return f
}

func newESCluster(name string) *navigator.ElasticsearchCluster {
	return &navigator.ElasticsearchCluster{
		TypeMeta: metav1.TypeMeta{APIVersion: navigator.SchemeGroupVersion.String()},
		ObjectMeta: metav1.ObjectMeta{
			UID:       uuid.NewUUID(),
			Name:      name,
			Namespace: metav1.NamespaceDefault,
		},
		Spec: navigator.ElasticsearchClusterSpec{},
	}
}

func (f *fixture) newController() (Interface, kubeinformers.SharedInformerFactory) {
	f.kubeClient = kubefake.NewSimpleClientset(f.kubeObjects...)

	k8sI := kubeinformers.NewSharedInformerFactory(f.kubeClient, noResyncPeriodFunc())

	c := NewController(f.kubeClient, k8sI.Rbac().V1beta1().Roles().Lister(), nil)

	for _, f := range f.roleLister {
		k8sI.Rbac().V1beta1().Roles().Informer().GetIndexer().Add(f)
	}

	return c, k8sI
}

func (f *fixture) run(cluster *navigator.ElasticsearchCluster) {
	f.runController(cluster, true, false)
}

func (f *fixture) runExpectError(cluster *navigator.ElasticsearchCluster) {
	f.runController(cluster, true, true)
}

func (f *fixture) runController(cluster *navigator.ElasticsearchCluster, startInformers bool, expectError bool) {
	c, k8sI := f.newController()
	if startInformers {
		stopCh := make(chan struct{})
		defer close(stopCh)
		k8sI.Start(stopCh)
	}

	err := c.Sync(cluster)
	if !expectError && err != nil {
		f.t.Errorf("error syncing ElasticsearchCluster: %v", err)
	} else if expectError && err == nil {
		f.t.Error("expected error syncing ElasticsearchCluster, got nil")
	}

	k8sActions := filterInformerActions(f.kubeClient.Actions())
	for i, action := range k8sActions {
		if len(f.kubeActions) < i+1 {
			f.t.Errorf("%d unexpected actions: %+v", len(k8sActions)-len(f.kubeActions), k8sActions[i:])
			break
		}

		expectedAction := f.kubeActions[i]
		if !(expectedAction.Matches(action.GetVerb(), action.GetResource().Resource) && action.GetSubresource() == expectedAction.GetSubresource()) {
			f.t.Errorf("Expected\n\t%#v\ngot\n\t%#v", expectedAction, action)
			continue
		}
	}

	if len(f.kubeActions) > len(k8sActions) {
		f.t.Errorf("%d additional expected actions:%+v", len(f.kubeActions)-len(k8sActions), f.kubeActions[len(k8sActions):])
	}
}

func filterInformerActions(actions []core.Action) []core.Action {
	ret := []core.Action{}
	for _, action := range actions {
		if len(action.GetNamespace()) == 0 &&
			(action.Matches("list", "foos") ||
				action.Matches("watch", "foos") ||
				action.Matches("list", "deployments") ||
				action.Matches("watch", "deployments")) {
			continue
		}
		ret = append(ret, action)
	}

	return ret
}

func (f *fixture) expectCreateRoleAction(d *rbac.Role) {
	f.kubeActions = append(f.kubeActions, core.NewCreateAction(schema.GroupVersionResource{Resource: "roles"}, d.Namespace, d))
}

func (f *fixture) expectUpdateRoleAction(d *rbac.Role) {
	f.kubeActions = append(f.kubeActions, core.NewUpdateAction(schema.GroupVersionResource{Resource: "roles"}, d.Namespace, d))
}

func TestCreatesRole(t *testing.T) {
	f := newFixture(t)
	cluster := newESCluster("test")
	role := roleForCluster(cluster)

	f.expectCreateRoleAction(role)

	// TODO: invent some way to neatly check the status of the 'cluster' after running
	f.run(cluster)
}

func TestDoNothing(t *testing.T) {
	f := newFixture(t)
	cluster := newESCluster("test")
	role := roleForCluster(cluster)

	f.roleLister = append(f.roleLister, role)
	f.kubeObjects = append(f.kubeObjects, role)

	// TODO: invent some way to neatly check the status of the 'cluster' after running
	f.run(cluster)
}

func TestUpdateRole(t *testing.T) {
	f := newFixture(t)
	cluster := newESCluster("test")
	role := roleForCluster(cluster)
	role.Rules = []rbac.PolicyRule{}
	f.roleLister = append(f.roleLister, role)
	f.kubeObjects = append(f.kubeObjects, role)

	// TODO: make this actually verify that the role now has the correct PolicyRules
	f.expectUpdateRoleAction(role)
	// TODO: invent some way to neatly check the status of the 'cluster' after running
	f.run(cluster)
}

func TestNotControlledByUs(t *testing.T) {
	f := newFixture(t)
	cluster := newESCluster("test")
	role := roleForCluster(cluster)
	role.ObjectMeta.OwnerReferences = []metav1.OwnerReference{}

	f.roleLister = append(f.roleLister, role)
	f.kubeObjects = append(f.kubeObjects, role)

	// TODO: invent some way to neatly check the status of the 'cluster' after running
	f.runExpectError(cluster)
}

func int32Ptr(i int32) *int32 { return &i }
<commit_msg>Fix ES cluster Role controller test flake<commit_after>package role

import (
	"testing"
	"time"

	rbac "k8s.io/api/rbac/v1beta1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/util/uuid"
	kubeinformers "k8s.io/client-go/informers"
	kubefake "k8s.io/client-go/kubernetes/fake"
	core "k8s.io/client-go/testing"

	navigator "github.com/jetstack/navigator/pkg/apis/navigator/v1alpha1"
)

var (
	alwaysReady        = func() bool { return true }
	noResyncPeriodFunc = func() time.Duration { return 0 }
)

type fixture struct {
	t *testing.T

	kubeClient *kubefake.Clientset
	// Objects to put in the store.
	roleLister []*rbac.Role

	// Actions expected to happen on the client.
	kubeActions []core.Action

	// Objects from here preloaded into NewSimpleFake.
	kubeObjects []runtime.Object
}

func newFixture(t *testing.T) *fixture {
	f := &fixture{}
	f.t = t
	f.kubeObjects = []runtime.Object{}
	return f
}

func newESCluster(name string) *navigator.ElasticsearchCluster {
	return &navigator.ElasticsearchCluster{
		TypeMeta: metav1.TypeMeta{APIVersion: navigator.SchemeGroupVersion.String()},
		ObjectMeta: metav1.ObjectMeta{
			UID:       uuid.NewUUID(),
			Name:      name,
			Namespace: metav1.NamespaceDefault,
		},
		Spec: navigator.ElasticsearchClusterSpec{},
	}
}

func (f *fixture) newController() (Interface, kubeinformers.SharedInformerFactory) {
	f.kubeClient = kubefake.NewSimpleClientset(f.kubeObjects...)

	k8sI := kubeinformers.NewSharedInformerFactory(f.kubeClient, noResyncPeriodFunc())

	c := NewController(f.kubeClient, k8sI.Rbac().V1beta1().Roles().Lister(), nil)

	for _, f := range f.roleLister {
		k8sI.Rbac().V1beta1().Roles().Informer().GetIndexer().Add(f)
	}

	return c, k8sI
}

func (f *fixture) run(cluster *navigator.ElasticsearchCluster) {
	f.runController(cluster, true, false)
}

func (f *fixture) runExpectError(cluster *navigator.ElasticsearchCluster) {
	f.runController(cluster, true, true)
}

func (f *fixture) runController(cluster *navigator.ElasticsearchCluster, startInformers bool, expectError bool) {
	c, k8sI := f.newController()
	if startInformers {
		stopCh := make(chan struct{})
		defer close(stopCh)
		k8sI.Start(stopCh)
	}

	err := c.Sync(cluster)
	if !expectError && err != nil {
		f.t.Errorf("error syncing ElasticsearchCluster: %v", err)
	} else if expectError && err == nil {
		f.t.Error("expected error syncing ElasticsearchCluster, got nil")
	}

	k8sActions := filterInformerActions(f.kubeClient.Actions())
	for i, action := range k8sActions {
		if len(f.kubeActions) < i+1 {
			f.t.Errorf("%d unexpected actions: %+v", len(k8sActions)-len(f.kubeActions), k8sActions[i:])
			break
		}

		expectedAction := f.kubeActions[i]
		if !(expectedAction.Matches(action.GetVerb(), action.GetResource().Resource) && action.GetSubresource() == expectedAction.GetSubresource()) {
			f.t.Errorf("Expected\n\t%#v\ngot\n\t%#v", expectedAction, action)
			continue
		}
	}

	if len(f.kubeActions) > len(k8sActions) {
		f.t.Errorf("%d additional expected actions:%+v", len(f.kubeActions)-len(k8sActions), f.kubeActions[len(k8sActions):])
	}
}

func filterInformerActions(actions []core.Action) []core.Action {
	ret := []core.Action{}
	for _, action := range actions {
		if len(action.GetNamespace()) == 0 &&
			(action.Matches("list", "roles") ||
				action.Matches("watch", "roles")) {
			continue
		}
		ret = append(ret, action)
	}

	return ret
}

func (f *fixture) expectCreateRoleAction(d *rbac.Role) {
	f.kubeActions = append(f.kubeActions, core.NewCreateAction(schema.GroupVersionResource{Resource: "roles"}, d.Namespace, d))
}

func (f *fixture) expectUpdateRoleAction(d *rbac.Role) {
	f.kubeActions = append(f.kubeActions, core.NewUpdateAction(schema.GroupVersionResource{Resource: "roles"}, d.Namespace, d))
}

func TestCreatesRole(t *testing.T) {
	f := newFixture(t)
	cluster := newESCluster("test")
	role := roleForCluster(cluster)

	f.expectCreateRoleAction(role)

	// TODO: invent some way to neatly check the status of the 'cluster' after running
	f.run(cluster)
}

func TestDoNothing(t *testing.T) {
	f := newFixture(t)
	cluster := newESCluster("test")
	role := roleForCluster(cluster)

	f.roleLister = append(f.roleLister, role)
	f.kubeObjects = append(f.kubeObjects, role)

	// TODO: invent some way to neatly check the status of the 'cluster' after running
	f.run(cluster)
}

func TestUpdateRole(t *testing.T) {
	f := newFixture(t)
	cluster := newESCluster("test")
	role := roleForCluster(cluster)
	role.Rules = []rbac.PolicyRule{}
	f.roleLister = append(f.roleLister, role)
	f.kubeObjects = append(f.kubeObjects, role)

	// TODO: make this actually verify that the role now has the correct PolicyRules
	f.expectUpdateRoleAction(role)
	// TODO: invent some way to neatly check the status of the 'cluster' after running
	f.run(cluster)
}

func TestNotControlledByUs(t *testing.T) {
	f := newFixture(t)
	cluster := newESCluster("test")
	role := roleForCluster(cluster)
	role.ObjectMeta.OwnerReferences = []metav1.OwnerReference{}

	f.roleLister = append(f.roleLister, role)
	f.kubeObjects = append(f.kubeObjects, role)

	// TODO: invent some way to neatly check the status of the 'cluster' after running
	f.runExpectError(cluster)
}

func int32Ptr(i int32) *int32 { return &i }
<|endoftext|>


<commit_before>package currency

import (
	"encoding/xml"
	"github.com/mbanzon/simplehttp"
	"time"
)

const (
	ecbResourceUrl = "http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml"
	dateFormat     = "2006-01-02"
)

type currencyEnvelope struct {
	Sender string `xml:"Sender>name"`
	Cube   []cube `xml:"Cube>Cube>Cube"`
}

type timeEnvelope struct {
	Time timeCube `xml:"Cube>Cube"`
}

type timeCube struct {
	Time string `xml:"time,attr"`
}

type cube struct {
	Name string  `xml:"currency,attr"`
	Rate float64 `xml:"rate,attr"`
}

func parseEcbData() (time.Time, map[string]float64, error) {
	r := simplehttp.NewGetRequest(ecbResourceUrl)
	data, err := r.MakeRequest()
	if err != nil {
		return time.Time{}, nil, err
	}

	var c currencyEnvelope
	err = xml.Unmarshal(data, &c)
	if err != nil {
		return time.Time{}, nil, err
	}

	var t timeEnvelope
	err = xml.Unmarshal(data, &t)
	if err != nil {
		return time.Time{}, nil, err
	}

	currencyTime, err := time.Parse(dateFormat, t.Time.Time)
	if err != nil {
		return time.Time{}, nil, err
	}

	currencies := make(map[string]float64)

	currencies[eur] = 1

	for _, currency := range c.Cube {
		currencies[currency.Name] = currency.Rate
	}

	return currencyTime, currencies, nil
}
<commit_msg>Added comments.<commit_after>package currency

import (
	"encoding/xml"
	"github.com/mbanzon/simplehttp"
	"time"
)

const (
	ecbResourceUrl = "http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml"
	dateFormat     = "2006-01-02"
)

type currencyEnvelope struct {
	Sender string `xml:"Sender>name"`
	Cube   []cube `xml:"Cube>Cube>Cube"`
}

type timeEnvelope struct {
	Time timeCube `xml:"Cube>Cube"`
}

type timeCube struct {
	Time string `xml:"time,attr"`
}

type cube struct {
	Name string  `xml:"currency,attr"`
	Rate float64 `xml:"rate,attr"`
}

func parseEcbData() (time.Time, map[string]float64, error) {
	r := simplehttp.NewGetRequest(ecbResourceUrl)
	data, err := r.MakeRequest()
	if err != nil {
		return time.Time{}, nil, err
	}

	var c currencyEnvelope
	err = xml.Unmarshal(data, &c) // first unmarshal to get currencies
	if err != nil {
		return time.Time{}, nil, err
	}

	var t timeEnvelope
	err = xml.Unmarshal(data, &t) // second unmarshal to get time
	if err != nil {
		return time.Time{}, nil, err
	}

	currencyTime, err := time.Parse(dateFormat, t.Time.Time)
	if err != nil {
		return time.Time{}, nil, err
	}

	currencies := make(map[string]float64)

	currencies[eur] = 1

	for _, currency := range c.Cube {
		currencies[currency.Name] = currency.Rate
	}

	return currencyTime, currencies, nil
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"io"
	"log"
	"net"
	"sync"

	pb "github.com/taylorflatt/go-chat"
	context "golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/reflection"
)

// The port the server is listening on.
const (
	port = ":12021"
)

// Server is used to implement the RemoteCommandServer
type server struct{}

type Group struct {
	name      string
	ch        chan pb.ChatMessage
	clients   []string
	WaitGroup *sync.WaitGroup
}

type Client struct {
	name      string
	ch        chan pb.ChatMessage
	WaitGroup *sync.WaitGroup
}

func AddGroup(n string) *Group {

	g := &Group{
		name:      n,
		ch:        make(chan pb.ChatMessage, 100),
		WaitGroup: &sync.WaitGroup{},
	}

	g.WaitGroup.Add(1)
	return g

}

// Clients: A list of unique clients and a channel per client.
// Groups: A list of unique groups and a channel per group.
// GroupClients: A list of Groups and a list of all clients in that group.
// Note: Messages within a group are sent to that group's channel and then routed
//       to each client channel who is part of that group EXCEPT the sender's channel.
var clients = make(map[string]chan pb.ChatMessage, 100)
var groups = make(map[string]chan pb.ChatMessage, 100)
var groupClients = make(map[string][]string)

var lock = &sync.RWMutex{}

// ClientExists checks if a client exists on the server.
// It returns a bool value.
func ClientExists(name string) bool {

	for c := range clients {
		if c == name {
			return true
		}
	}

	return false
}

// GroupExists checks if a group exists on the server.
// It returns a bool value.
func GroupExists(gName string) bool {

	// Changed to just LOCK
	lock.Lock()
	defer lock.Unlock()
	for g := range groups {
		if g == gName {
			return true
		}
	}

	return false
}

// InGroup checks whether a client is currently in a
// specific group.
// It returns a bool value.
func InGroup(name string) bool {

	for _, c := range groupClients {
		for _, s := range c {
			if name == s {
				return true
			}
		}
	}

	return false

}

// AddClient adds a new client to the server.
// It doesn't return anything.
func AddClient(name string) {

	clients[name] = make(chan pb.ChatMessage, 100)
	log.Print("[AddClient]: Registered client " + name)
	log.Print("[AddClient]: Client's channel: ")
	log.Print(clients[name])
}

// AddGroup adds a new group to the server.
// It doesn't return anything.
func AddGroup(gName string) {

	lock.Lock()
	defer lock.Unlock()
	groups[gName] = make(chan pb.ChatMessage, 100)
	log.Print("[AddGroup]: Added group " + gName)
}

// RemoveClient will remove a client from the server as well as any
// groups that they are currently in.
// It returns an error.
func RemoveClient(name string) error {

	lock.Lock()
	defer lock.Unlock()

	if ClientExists(name) {
		delete(clients, name)
		log.Print("[RemoveClient]: Removed client " + name)
		if InGroup(name) {
			RemoveClientFromGroup(name)
		} else {
			log.Print("[RemoveClient]: " + name + " was not in any groups.")
			return nil
		}
	}

	return errors.New("[RemoveClient]: Client (" + name + ") doesn't exist")
}

// AddClientToGroup will add a client to a group.
// It doesn't return anything.
func AddClientToGroup(cName string, gName string) {

	lock.Lock()
	defer lock.Unlock()
	cList := groupClients[gName]
	cList = append(cList, cName)
	groupClients[gName] = cList

	log.Println("[AddClientToGroup] Added " + cName + " to " + gName)
}

// RemoveClientFromGroup will remove a client from a specific group. It will also
// delete a group if the client is the last one leaving it.
// It returns an error.
func RemoveClientFromGroup(name string) error {

	// Look through all the groups.
	for gName, cList := range groupClients {
		listG := cList
		// Look through all the users in the group.
		for i, cName := range listG {
			// Remove the user from the group.
			if cName == name {
				log.Println("[RemoveClientFromGroup]: Removed client " + name + " from " + gName)
				if len(listG) == 1 {
					delete(groups, gName)
					delete(groupClients, gName)
					log.Println("[RemoveClientFromGroup]: No more members in " + gName + ", removing the group.")
					log.Print("List of groups: ")
					for keys := range groups {
						log.Print(keys)
					}
				} else {
					listG[i] = listG[len(listG)-1]
					listG = listG[:len(listG)-1]
					groupClients[gName] = listG
					log.Print(listG)
				}

				return nil
			}
		}
	}

	return errors.New("no user found in the group list. Something went wrong")
}

// GetClientList will get all of the currently connected clients to the server.
// It returns a list of connected clients.
func (s *server) GetClientList(ctx context.Context, in *pb.Empty) (*pb.ClientList, error) {

	var conClients []string
	for key := range clients {
		conClients = append(conClients, key)
	}

	return &pb.ClientList{Clients: conClients}, nil
}

// GetGroupList will get all of the groups currently registered on the server.
// It returns a list of groups.
func (s *server) GetGroupList(ctx context.Context, in *pb.Empty) (*pb.GroupList, error) {

	var g []string
	for gName := range groups {
		g = append(g, gName)
	}

	log.Print("[GetGroupList]: Returned list of current groups ")
	log.Print(g)

	return &pb.GroupList{Groups: g}, nil
}

// GetGroupClientList will get all of the clients who is current part of a specific group.
// It returns a list of clients belonging to a group.
func (s *server) GetGroupClientList(ctx context.Context, in *pb.GroupInfo) (*pb.ClientList, error) {

	gName := in.GroupName

	if !GroupExists(gName) {
		return &pb.ClientList{}, errors.New("that group doesn't exist")
	}

	cList := groupClients[gName]

	log.Print("[GetGroupClientList]: For group " + gName + " returned members ")
	log.Print(cList)

	return &pb.ClientList{Clients: cList}, nil
}

// Register will add the user to the server's collection of users (and by extension restrict the username).
// It returns an empty object and an error.
func (s *server) Register(ctx context.Context, in *pb.ClientInfo) (*pb.Empty, error) {

	n := in.Sender
	if ClientExists(n) {
		return nil, errors.New("that name already exists")
	}

	AddClient(n)
	return &pb.Empty{}, nil
}

// UnRegister removes a user from the server's collection of users and any
// groups the user may have been in.
// It returns an empty object and an error.
func (s *server) UnRegister(ctx context.Context, in *pb.ClientInfo) (*pb.Empty, error) {

	uName := in.Sender

	cChan := clients[uName]
	fmt.Print(cChan)

	log.Print("[UnRegister]: Unregistering client " + uName)

	err := RemoveClient(uName)

	log.Println("[UnRegister]: The following are the remaining clients, ")
	keys := []string{}
	for key := range clients {
		keys = append(keys, key)
	}
	log.Println(keys)

	if err != nil {
		return nil, err
	}

	return &pb.Empty{}, nil
}

// CreateGroup creates a new group provided it doesn't already exist.
// It returns an empty object and an error.
func (s *server) CreateGroup(ctx context.Context, in *pb.GroupInfo) (*pb.Empty, error) {

	cName := in.Client
	gName := in.GroupName

	log.Printf("[CreateGroup] " + cName + " is attempting to create " + gName)

	if !GroupExists(gName) {
		AddGroup(gName)
		return &pb.Empty{}, nil
	}

	return &pb.Empty{}, errors.New("a group with that name already exists")
}

// JoinGroup adds a user to an existing group.
// It returns an empty object and an error.
func (s *server) JoinGroup(ctx context.Context, in *pb.GroupInfo) (*pb.Empty, error) {

	cName := in.Client
	gName := in.GroupName

	log.Printf("[JoinGroup] Attempting to add " + cName + " to " + gName)

	if GroupExists(gName) {
		AddClientToGroup(cName, gName)

		return &pb.Empty{}, nil
	}

	return &pb.Empty{}, errors.New("a group with that name doesn't exist")
}

// LeaveRoom removes the user from their group.
// It returns an empty object and an error.
func (s *server) LeaveRoom(ctx context.Context, in *pb.GroupInfo) (*pb.Empty, error) {

	u := in.Client
	g := in.GroupName

	if !GroupExists(g) {
		return &pb.Empty{}, errors.New("the group " + g + " doesn't exist")
	} else if !ClientExists(u) {
		return &pb.Empty{}, errors.New("the client " + g + " doesn't exist")
	} else {
		die := pb.ChatMessage{Sender: u, Receiver: g, Message: u + " left chat!\n"}
		Broadcast(g, die)
		RemoveClientFromGroup(u)
		return &pb.Empty{}, nil
	}
}

// RouteChat handles the routing of all messages on the stream.
// It returns an error.
func (s *server) RouteChat(stream pb.Chat_RouteChatServer) error {

	msg, err := stream.Recv()

	if err != nil {
		return err
	}

	log.Printf("[RouteChat]: Client " + msg.Sender + " sent " + msg.Receiver + " a message: " + msg.Message)

	outbox := make(chan pb.ChatMessage, 100)

	go ListenToClient(stream, outbox)

	for {
		select {
		case outMsg := <-outbox:
			Broadcast(msg.Receiver, outMsg)
		case inMsg := <-clients[msg.Sender]:
			log.Println("Sending message to channel: ")
			log.Println(clients[msg.Sender])
			log.Println("[LOOK HERE]: Sending message to STREAM: ")
			log.Println(stream)
			stream.Send(&inMsg)
		}
	}
}

// Broadcast takes any messages that need to be sent and sorts them by group. It then
// adds the message to the channel of each member of that group.
// It doesn't return anything.
func Broadcast(gName string, msg pb.ChatMessage) {

	lock.Lock()
	defer lock.Unlock()

	for gn := range groups {
		log.Printf("[Broadcast]: I found " + gn + ".")
		if gn == gName {
			log.Printf("[Broadcast]: Client " + msg.Sender + " sent " + msg.Receiver + " a message: " + msg.Message)
			for _, cName := range groupClients[gn] {
				log.Printf("[Broadcast]: I found " + cName + " in gName")
				if cName == msg.Sender && msg.Message == msg.Sender+" left chat!\n" {
					log.Printf("[Broadcast]: ADDING THE KILL MESSAGE TO " + cName)
					clients[cName] <- msg
				} else if cName != msg.Sender {
					log.Printf("[Broadcast] Adding the message to " + cName + "'s channel.")
					clients[cName] <- msg
				}
			}
		}
	}
}

// ListenToClient listens on the incoming stream for any messages. It adds those messages to the channel.
// It doesn't return anything.
func ListenToClient(stream pb.Chat_RouteChatServer, messages chan<- pb.ChatMessage) {

	for {
		msg, err := stream.Recv()
		if err == io.EOF {
		}
		if err != nil {
		} else {
			log.Printf("[ListenToClient] Client " + msg.Sender + " sent " + msg.Receiver + " a message: " + msg.Message)
			messages <- *msg
		}

	}
}

func main() {

	lis, err := net.Listen("tcp", port)

	if err != nil {
		log.Fatalf("Failed to listen %v", err)
	}

	// Initializes the gRPC server.
	s := grpc.NewServer()

	// Register the server with gRPC.
	pb.RegisterChatServer(s, &server{})

	// Register reflection service on gRPC server.
	reflection.Register(s)

	if err := s.Serve(lis); err != nil {
		log.Fatalf("Failed to serve: %v", err)
	}
}
<commit_msg>Created types for client and group.<commit_after>package main

import (
	"errors"
	"fmt"
	"io"
	"log"
	"net"
	"sync"

	pb "github.com/taylorflatt/go-chat"
	context "golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/reflection"
)

// The port the server is listening on.
const (
	port = ":12021"
)

type server struct{}

type Group struct {
	name      string
	ch        chan pb.ChatMessage
	clients   []string
	WaitGroup *sync.WaitGroup
}

type Client struct {
	name      string
	group     string
	ch        chan pb.ChatMessage
	WaitGroup *sync.WaitGroup
}

var lock = &sync.RWMutex{}
var clients map[string]Client
var groups map[string]Group

// AddClient adds a new client n to the server.
// It doesn't return anything.
func AddClient(n string) {

	lock.Lock()
	defer lock.Unlock()

	c := Client{
		name:      n,
		ch:        make(chan pb.ChatMessage, 100),
		WaitGroup: &sync.WaitGroup{},
	}

	log.Print("[AddClient]: Registered client " + n)
	clients[n] = c
}

// AddGroup adds a new group to the server.
// It doesn't return anything.
func AddGroup(n string) {

	lock.Lock()
	defer lock.Unlock()

	g := Group{
		name:      n,
		ch:        make(chan pb.ChatMessage, 100),
		WaitGroup: &sync.WaitGroup{},
	}

	log.Print("[AddGroup]: Added group " + g.name)
	groups[n] = g
	groups[n].WaitGroup.Add(1)
}

// ClientExists checks if a client exists on the server.
// It returns a bool value.
func ClientExists(name string) bool {

	lock.RLock()
	defer lock.RUnlock()
	for c := range clients {
		if c == name {
			return true
		}
	}

	return false
}

// GroupExists checks if a group exists on the server.
// It returns a bool value.
func GroupExists(gName string) bool {

	lock.RLock()
	defer lock.RUnlock()
	for g := range groups {
		if g == gName {
			return true
		}
	}

	return false
}

// InGroup checks whether a client is currently in a
// specific group.
// It returns a bool value.
func InGroup(n string) bool {

	for _, g := range groups {
		for _, c := range g.clients {
			if n == c {
				return true
			}
		}
	}

	return false
}

// RemoveClient will remove a client from the server as well as any
// groups that they are currently in.
// It returns an error.
func RemoveClient(name string) error {

	lock.Lock()
	defer lock.Unlock()

	if ClientExists(name) {
		delete(clients, name)
		log.Print("[RemoveClient]: Removed client " + name)
		if InGroup(name) {
			RemoveClientFromGroup(name)
		} else {
			log.Print("[RemoveClient]: " + name + " was not in any groups.")
			return nil
		}
	}

	return errors.New("[RemoveClient]: Client (" + name + ") doesn't exist")
}

// AddClientToGroup will add a client to a group.
// It doesn't return anything.
func AddClientToGroup(cName string, gName string) {

	lock.Lock()
	defer lock.Unlock()
	cList := groupClients[gName]
	cList = append(cList, cName)
	groupClients[gName] = cList

	log.Println("[AddClientToGroup] Added " + cName + " to " + gName)
}

// RemoveClientFromGroup will remove a client from a specific group. It will also
// delete a group if the client is the last one leaving it.
// It returns an error.
func RemoveClientFromGroup(name string) error {

	// Look through all the groups.
	for gName, cList := range groupClients {
		listG := cList
		// Look through all the users in the group.
		for i, cName := range listG {
			// Remove the user from the group.
			if cName == name {
				log.Println("[RemoveClientFromGroup]: Removed client " + name + " from " + gName)
				if len(listG) == 1 {
					delete(groups, gName)
					delete(groupClients, gName)
					log.Println("[RemoveClientFromGroup]: No more members in " + gName + ", removing the group.")
					log.Print("List of groups: ")
					for keys := range groups {
						log.Print(keys)
					}
				} else {
					listG[i] = listG[len(listG)-1]
					listG = listG[:len(listG)-1]
					groupClients[gName] = listG
					log.Print(listG)
				}

				return nil
			}
		}
	}

	return errors.New("no user found in the group list. Something went wrong")
}

// GetClientList will get all of the currently connected clients to the server.
// It returns a list of connected clients.
func (s *server) GetClientList(ctx context.Context, in *pb.Empty) (*pb.ClientList, error) {

	var conClients []string
	for key := range clients {
		conClients = append(conClients, key)
	}

	return &pb.ClientList{Clients: conClients}, nil
}

// GetGroupList will get all of the groups currently registered on the server.
// It returns a list of groups.
func (s *server) GetGroupList(ctx context.Context, in *pb.Empty) (*pb.GroupList, error) {

	var g []string
	for gName := range groups {
		g = append(g, gName)
	}

	log.Print("[GetGroupList]: Returned list of current groups ")
	log.Print(g)

	return &pb.GroupList{Groups: g}, nil
}

// GetGroupClientList will get all of the clients who is current part of a specific group.
// It returns a list of clients belonging to a group.
func (s *server) GetGroupClientList(ctx context.Context, in *pb.GroupInfo) (*pb.ClientList, error) {

	gName := in.GroupName

	if !GroupExists(gName) {
		return &pb.ClientList{}, errors.New("that group doesn't exist")
	}

	cList := groupClients[gName]

	log.Print("[GetGroupClientList]: For group " + gName + " returned members ")
	log.Print(cList)

	return &pb.ClientList{Clients: cList}, nil
}

// Register will add the user to the server's collection of users (and by extension restrict the username).
// It returns an empty object and an error.
func (s *server) Register(ctx context.Context, in *pb.ClientInfo) (*pb.Empty, error) {

	n := in.Sender
	if ClientExists(n) {
		return nil, errors.New("that name already exists")
	}

	AddClient(n)
	return &pb.Empty{}, nil
}

// UnRegister removes a user from the server's collection of users and any
// groups the user may have been in.
// It returns an empty object and an error.
func (s *server) UnRegister(ctx context.Context, in *pb.ClientInfo) (*pb.Empty, error) {

	uName := in.Sender

	cChan := clients[uName]
	fmt.Print(cChan)

	log.Print("[UnRegister]: Unregistering client " + uName)

	err := RemoveClient(uName)

	log.Println("[UnRegister]: The following are the remaining clients, ")
	keys := []string{}
	for key := range clients {
		keys = append(keys, key)
	}
	log.Println(keys)

	if err != nil {
		return nil, err
	}

	return &pb.Empty{}, nil
}

// CreateGroup creates a new group provided it doesn't already exist.
// It returns an empty object and an error.
func (s *server) CreateGroup(ctx context.Context, in *pb.GroupInfo) (*pb.Empty, error) {

	cName := in.Client
	gName := in.GroupName

	log.Printf("[CreateGroup] " + cName + " is attempting to create " + gName)

	if !GroupExists(gName) {
		AddGroup(gName)
		return &pb.Empty{}, nil
	}

	return &pb.Empty{}, errors.New("a group with that name already exists")
}

// JoinGroup adds a user to an existing group.
// It returns an empty object and an error.
func (s *server) JoinGroup(ctx context.Context, in *pb.GroupInfo) (*pb.Empty, error) {

	cName := in.Client
	gName := in.GroupName

	log.Printf("[JoinGroup] Attempting to add " + cName + " to " + gName)

	if GroupExists(gName) {
		AddClientToGroup(cName, gName)

		return &pb.Empty{}, nil
	}

	return &pb.Empty{}, errors.New("a group with that name doesn't exist")
}

// LeaveRoom removes the user from their group.
// It returns an empty object and an error.
func (s *server) LeaveRoom(ctx context.Context, in *pb.GroupInfo) (*pb.Empty, error) {

	u := in.Client
	g := in.GroupName

	if !GroupExists(g) {
		return &pb.Empty{}, errors.New("the group " + g + " doesn't exist")
	} else if !ClientExists(u) {
		return &pb.Empty{}, errors.New("the client " + g + " doesn't exist")
	} else {
		die := pb.ChatMessage{Sender: u, Receiver: g, Message: u + " left chat!\n"}
		Broadcast(g, die)
		RemoveClientFromGroup(u)
		return &pb.Empty{}, nil
	}
}

// RouteChat handles the routing of all messages on the stream.
// It returns an error.
func (s *server) RouteChat(stream pb.Chat_RouteChatServer) error {

	msg, err := stream.Recv()

	if err != nil {
		return err
	}

	log.Printf("[RouteChat]: Client " + msg.Sender + " sent " + msg.Receiver + " a message: " + msg.Message)

	outbox := make(chan pb.ChatMessage, 100)

	go ListenToClient(stream, outbox)

	for {
		select {
		case outMsg := <-outbox:
			Broadcast(msg.Receiver, outMsg)
		case inMsg := <-clients[msg.Sender]:
			log.Println("Sending message to channel: ")
			log.Println(clients[msg.Sender])
			log.Println("[LOOK HERE]: Sending message to STREAM: ")
			log.Println(stream)
			stream.Send(&inMsg)
		}
	}
}

// Broadcast takes any messages that need to be sent and sorts them by group. It then
// adds the message to the channel of each member of that group.
// It doesn't return anything.
func Broadcast(gName string, msg pb.ChatMessage) {

	lock.Lock()
	defer lock.Unlock()

	for gn := range groups {
		log.Printf("[Broadcast]: I found " + gn + ".")
		if gn == gName {
			log.Printf("[Broadcast]: Client " + msg.Sender + " sent " + msg.Receiver + " a message: " + msg.Message)
			for _, cName := range groupClients[gn] {
				log.Printf("[Broadcast]: I found " + cName + " in gName")
				if cName == msg.Sender && msg.Message == msg.Sender+" left chat!\n" {
					log.Printf("[Broadcast]: ADDING THE KILL MESSAGE TO " + cName)
					clients[cName] <- msg
				} else if cName != msg.Sender {
					log.Printf("[Broadcast] Adding the message to " + cName + "'s channel.")
					clients[cName] <- msg
				}
			}
		}
	}
}

// ListenToClient listens on the incoming stream for any messages. It adds those messages to the channel.
// It doesn't return anything.
func ListenToClient(stream pb.Chat_RouteChatServer, messages chan<- pb.ChatMessage) {

	for {
		msg, err := stream.Recv()
		if err == io.EOF {
		}
		if err != nil {
		} else {
			log.Printf("[ListenToClient] Client " + msg.Sender + " sent " + msg.Receiver + " a message: " + msg.Message)
			messages <- *msg
		}

	}
}

func main() {

	lis, err := net.Listen("tcp", port)

	if err != nil {
		log.Fatalf("Failed to listen %v", err)
	}

	// Initializes the gRPC server.
	s := grpc.NewServer()

	// Register the server with gRPC.
	pb.RegisterChatServer(s, &server{})

	// Register reflection service on gRPC server.
	reflection.Register(s)

	if err := s.Serve(lis); err != nil {
		log.Fatalf("Failed to serve: %v", err)
	}
}
<|endoftext|>


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

import (
	fedclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_clientset"
	api "k8s.io/kubernetes/pkg/api"
	api_v1 "k8s.io/kubernetes/pkg/api/v1"
	"k8s.io/kubernetes/pkg/client/record"
)

// Implements k8s.io/kubernetes/pkg/client/record.EventSink.
type FederatedEventSink struct {
	clientset fedclientset.Interface
}

// To check if all required functions are implemented.
var _ record.EventSink = &FederatedEventSink{}

func NewFederatedEventSink(clientset fedclientset.Interface) *FederatedEventSink {
	return &FederatedEventSink{
		clientset: clientset,
	}
}

func (fes *FederatedEventSink) Create(event *api_v1.Event) (*api_v1.Event, error) {
	return fes.clientset.Core().Events(event.Namespace).Create(event)
}

func (fes *FederatedEventSink) Update(event *api_v1.Event) (*api_v1.Event, error) {
	return fes.clientset.Core().Events(event.Namespace).Update(event)
}

func (fes *FederatedEventSink) Patch(event *api_v1.Event, data []byte) (*api_v1.Event, error) {
	return fes.clientset.Core().Events(event.Namespace).Patch(event.Name, api.StrategicMergePatchType, data)
}
<commit_msg>move PatchType to apimachinery<commit_after>/*
Copyright 2016 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 eventsink

import (
	"k8s.io/apimachinery/pkg/types"
	fedclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_clientset"
	api_v1 "k8s.io/kubernetes/pkg/api/v1"
	"k8s.io/kubernetes/pkg/client/record"
)

// Implements k8s.io/kubernetes/pkg/client/record.EventSink.
type FederatedEventSink struct {
	clientset fedclientset.Interface
}

// To check if all required functions are implemented.
var _ record.EventSink = &FederatedEventSink{}

func NewFederatedEventSink(clientset fedclientset.Interface) *FederatedEventSink {
	return &FederatedEventSink{
		clientset: clientset,
	}
}

func (fes *FederatedEventSink) Create(event *api_v1.Event) (*api_v1.Event, error) {
	return fes.clientset.Core().Events(event.Namespace).Create(event)
}

func (fes *FederatedEventSink) Update(event *api_v1.Event) (*api_v1.Event, error) {
	return fes.clientset.Core().Events(event.Namespace).Update(event)
}

func (fes *FederatedEventSink) Patch(event *api_v1.Event, data []byte) (*api_v1.Event, error) {
	return fes.clientset.Core().Events(event.Namespace).Patch(event.Name, types.StrategicMergePatchType, data)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
)

func Handle(w http.ResponseWriter, r *http.Request) {
	io.WriteString(w, "OK! I got you Bro! -> ")
	body, _ := ioutil.ReadAll(r.Body)
	fmt.Println(string(body))
}

func main() {
	http.HandleFunc("/", Handle)
	http.ListenAndServe(":9143", nil)
}
<commit_msg>Added the Akamai payload structure + using json.Unmarshal to access it<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
)

type AkamaiPayload struct {
	CP     string            `json:"cp"`
	Format string            `json:"format"`
	Geo    map[string]string `json:"geo"`
	// city
	// country
	// lat
	// long
	// region
	ID      string            `json:"id"`
	Message map[string]string `json:"message"`
	// UA
	// bytes
	// cliIP
	// fwdHost
	// proto
	// protoVer
	// reqHost
	// reqMethod
	// reqPath
	// reqPort
	// respCT
	// respLen
	// status
	NetPerf map[string]string `json:"netPerf"`
	// asnum
	// cacheStatus
	// downloadTime
	// edgeIP
	// firstByte
	// lastByte
	// lastMileRTT
	Network map[string]string `json:"network"`
	// asnum
	// edgeIP
	// network
	// networkType
	ReqHdr map[string]string `json:"reqHdr"`
	// cookie
	RespHdr map[string]string `json:"respHdr"`
	// server
	// contEnc
	Start   string `json:"start"`
	Type    string `json:"type"`
	Version string `json:"version"`
}

func CreateObject(line []byte) []AkamaiPayload {
	var payload []AkamaiPayload
	err := json.Unmarshal(line, &payload)
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(1)
	}
	return payload
}

func Handle(w http.ResponseWriter, r *http.Request) {
	io.WriteString(w, "OK! I got you Bro! -> ")
	body, _ := ioutil.ReadAll(r.Body)
	fmt.Println(string(body))
	payload := CreateObject(body)
	fmt.Println(payload[0].Geo["city"]) // example of accessing the payload
}

func main() {
	http.HandleFunc("/", Handle)
	http.ListenAndServe(":9143", nil)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net"
	"os"
	"regexp"
	"bytes"
)

const (
	CONN_TYPE = "tcp"
	MAX_THREAD_POOL = 10
)

var (
	activeThreads = 0
)

func handleConnection(conn net.Conn) {
	for {
		// fmt.Println("Addr: ", conn.LocalAddr())
		buff := make([]byte, 1024)
		readLen, e := conn.Read(buff)
		//fmt.Println("Message is : ", string(buff))
		handleError(e)
		message := string(buff[:readLen])
		//fmt.Println(message)
		validHello := regexp.MustCompile(`HELO *`)
		validKill := regexp.MustCompile(`KILL_SERVICE *`)
		if validKill.MatchString(message) {
			fmt.Println("Gonna kill the server")
			conn.Close()
			os.Exit(0)
		} else if  validHello.MatchString(message) {
			fmt.Println("Got a helo message")
			// "HELO text\nIP:[ip address]\nPort:[port number]\nStudentID:[your student ID]\n"
			var response bytes.Buffer
			response.WriteString(message)
			response.WriteString("IP:10.62.0.117\n")
			response.WriteString("Port:8000\n")
			response.WriteString("StudentID:13321218\n")
			conn.Write([]byte(response.String()))
			handleError(e)
			//fmt.Println(response.String())
		} else {
			fmt.Println("Got a random message")
			// This would handle all other messages
			//fmt.Println(message)
		}
	}
	//fmt.Println("Handled connection ", activeThreads)
}

func handleError(e error) {
	// if an error exits, exit the program
	if e != nil {
		fmt.Println("An error occurred: %s", e.Error())
		os.Exit(1)
	}
}

func main() {
	// accept command line arguements where args[0] is the port number to run on
	args := os.Args[1:]
	// create the listener
	listener, e := net.Listen(CONN_TYPE, ":" + args[0])
	handleError(e)
	// wait for new clients to connect
	for {
		conn, e := listener.Accept()
		fmt.Println("A new connection")
		handleError(e)
		if activeThreads < MAX_THREAD_POOL {
			//fmt.Println("Less than max number of threads")
			activeThreads += 1
			go handleConnection(conn)
		} else {
			//fmt.Println("Too many threads already")
		}
	}
}

<commit_msg>Abstracted some functionality<commit_after>package main

import (
	"fmt"
	"net"
	"os"
	"regexp"
	"bytes"
)

const (
	CONN_TYPE = "tcp"
	MAX_THREAD_POOL = 10
	IP_ADDR = "10.62.0.117"
	STUDENT_NUMBER = "13321218"
)

var (
	activeThreads = 0
)

func handleKillCommand(conn net.Conn) {
	conn.Close()
	activeThreads -= 1
}

func handleHeloCommand(message string, port string, conn net.Conn) {
	// "HELO text\nIP:[ip address]\nPort:[port number]\nStudentID:[your student ID]\n"
	var response bytes.Buffer
	response.WriteString(message)
	response.WriteString(fmt.Sprintf("IP:%s\n", IP_ADDR))
	response.WriteString(fmt.Sprintf("Port:%s\n", port))
	response.WriteString(fmt.Sprint("StudentID:%s\n", STUDENT_NUMBER))
	conn.Write([]byte(response.String()))
}

func handleOtherCommand() {
	// Stub function
}

func handleConnection(conn net.Conn) {
	validHello := regexp.MustCompile(`HELO *`)
	validKill := regexp.MustCompile(`KILL_SERVICE *`)
	port := conn.LocalAddr().String()[12:]
	// wait for messages on the socket
	going := true
	for going {
		fmt.Println("Addr: ", conn.LocalAddr())
		buff := make([]byte, 1024)
		readLen, e := conn.Read(buff)
		handleError(e)
		message := string(buff[:readLen])
		if validKill.MatchString(message) {
			going = false
			handleKillCommand(conn)
		} else if  validHello.MatchString(message) {
			handleHeloCommand(message, port, conn)
		} else {
			handleOtherCommand()
		}
	}
}

func handleError(e error) {
	// if an error exits, exit the program
	if e != nil {
		fmt.Println("An error occurred: %s", e.Error())
		os.Exit(1)
	}
}

func main() {
	// accept command line arguements where args[0] is the port number to run on
	args := os.Args[1:]
	listener, e := net.Listen(CONN_TYPE, ":" + args[0])
	handleError(e)
	// wait for new clients to connect
	for {
		conn, e := listener.Accept()
		fmt.Println("A new connection")
		handleError(e)
		if activeThreads < MAX_THREAD_POOL {
			activeThreads += 1
			go handleConnection(conn)
		}
	}
}

<|endoftext|>