<commit_before>package server

import (
	"context"
	"fmt"

	client "github.com/pachyderm/pachyderm/src/client"
	"github.com/pachyderm/pachyderm/src/client/enterprise"
	"github.com/pachyderm/pachyderm/src/client/pps"
	"github.com/pachyderm/pachyderm/src/server/pkg/deploy/assets"

	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/resource"
	"k8s.io/kubernetes/pkg/api/unversioned"
	"k8s.io/kubernetes/pkg/util/intstr"
)

// Parameters used when creating the kubernetes replication controller in charge
// of a job or pipeline's workers
type workerOptions struct {
	rcName string // Name of the replication controller managing workers

	userImage        string            // The user's pipeline/job image
	labels           map[string]string // k8s labels attached to the RC and workers
	annotations      map[string]string // k8s annotations attached to the RC and workers
	parallelism      int32             // Number of replicas the RC maintains
	cacheSize        string            // Size of cache that sidecar uses
	resourceRequests *api.ResourceList // Resources requested by pipeline/job pods
	resourceLimits   *api.ResourceList // Resources requested by pipeline/job pods
	workerEnv        []api.EnvVar      // Environment vars set in the user container
	volumes          []api.Volume      // Volumes that we expose to the user container
	volumeMounts     []api.VolumeMount // Paths where we mount each volume in 'volumes'

	// Secrets that we mount in the worker container (e.g. for reading/writing to
	// s3)
	imagePullSecrets []api.LocalObjectReference
	service          *pps.Service
}

func (a *apiServer) workerPodSpec(options *workerOptions) (api.PodSpec, error) {
	pullPolicy := a.workerImagePullPolicy
	if pullPolicy == "" {
		pullPolicy = "IfNotPresent"
	}
	sidecarEnv := []api.EnvVar{{
		Name:  "BLOCK_CACHE_BYTES",
		Value: options.cacheSize,
	}, {
		Name:  "PFS_CACHE_SIZE",
		Value: "16",
	}, {
		Name:  "PACH_ROOT",
		Value: a.storageRoot,
	}, {
		Name:  "STORAGE_BACKEND",
		Value: a.storageBackend,
	}}
	// This only happens in local deployment.  We want the workers to be
	// able to read from/write to the hostpath volume as well.
	storageVolumeName := "pach-disk"
	var sidecarVolumeMounts []api.VolumeMount
	if a.storageHostPath != "" {
		options.volumes = append(options.volumes, api.Volume{
			Name: storageVolumeName,
			VolumeSource: api.VolumeSource{
				HostPath: &api.HostPathVolumeSource{
					Path: a.storageHostPath,
				},
			},
		})

		sidecarVolumeMounts = []api.VolumeMount{
			{
				Name:      storageVolumeName,
				MountPath: a.storageRoot,
			},
		}
	}
	userVolumeMounts := options.volumeMounts
	secretVolume, secretMount := assets.GetSecretVolumeAndMount(a.storageBackend)
	options.volumes = append(options.volumes, secretVolume)
	options.volumeMounts = append(options.volumeMounts, secretMount)
	sidecarVolumeMounts = append(sidecarVolumeMounts, secretMount)
	userVolumeMounts = append(userVolumeMounts, secretMount)

	// Explicitly set CPU and MEM requests to zero because some cloud
	// providers set their own defaults which are usually not what we want.
	cpuZeroQuantity := resource.MustParse("0")
	memZeroQuantity := resource.MustParse("0M")
	memSidecarQuantity := resource.MustParse(options.cacheSize)

	options.volumes = append(options.volumes, api.Volume{
		Name: "docker",
		VolumeSource: api.VolumeSource{
			HostPath: &api.HostPathVolumeSource{
				Path: "/var/run/docker.sock",
			},
		},
	})
	userVolumeMounts = append(userVolumeMounts, api.VolumeMount{
		Name:      "docker",
		MountPath: "/var/run/docker.sock",
	})
	zeroVal := int64(0)
	workerImage := a.workerImage
	pachClient, err := a.getPachClient()
	if err != nil {
		return api.PodSpec{}, err
	}
	resp, err := pachClient.Enterprise.GetState(context.Background(), &enterprise.GetStateRequest{})
	if err != nil {
		return api.PodSpec{}, err
	}
	if resp.State != enterprise.State_ACTIVE {
		workerImage = assets.AddRegistry("", workerImage)
	}
	podSpec := api.PodSpec{
		InitContainers: []api.Container{
			{
				Name:            "init",
				Image:           workerImage,
				Command:         []string{"/pach/worker.sh"},
				ImagePullPolicy: api.PullPolicy(pullPolicy),
				Env:             options.workerEnv,
				VolumeMounts:    options.volumeMounts,
			},
		},
		Containers: []api.Container{
			{
				Name:    client.PPSWorkerUserContainerName,
				Image:   options.userImage,
				Command: []string{"/pach-bin/guest.sh"},
				SecurityContext: &api.SecurityContext{
					Privileged: &trueVal, // god is this dumb
				},
				ImagePullPolicy: api.PullPolicy(pullPolicy),
				Env:             options.workerEnv,
				Resources: api.ResourceRequirements{
					Requests: map[api.ResourceName]resource.Quantity{
						api.ResourceCPU:    cpuZeroQuantity,
						api.ResourceMemory: memZeroQuantity,
					},
				},
				VolumeMounts: userVolumeMounts,
			},
			{
				Name:            client.PPSWorkerSidecarContainerName,
				Image:           a.workerSidecarImage,
				Command:         []string{"/pachd", "--mode", "sidecar"},
				ImagePullPolicy: api.PullPolicy(pullPolicy),
				Env:             sidecarEnv,
				VolumeMounts:    sidecarVolumeMounts,
				Resources: api.ResourceRequirements{
					Requests: map[api.ResourceName]resource.Quantity{
						api.ResourceCPU:    cpuZeroQuantity,
						api.ResourceMemory: memSidecarQuantity,
					},
				},
			},
		},
		RestartPolicy:                 "Always",
		Volumes:                       options.volumes,
		ImagePullSecrets:              options.imagePullSecrets,
		TerminationGracePeriodSeconds: &zeroVal,
		SecurityContext:               &api.PodSecurityContext{RunAsUser: &zeroVal},
	}
	resourceRequirements := api.ResourceRequirements{}
	if options.resourceRequests != nil {
		resourceRequirements.Requests = *options.resourceRequests
	}
	if options.resourceLimits != nil {
		resourceRequirements.Limits = *options.resourceLimits
	}
	podSpec.Containers[0].Resources = resourceRequirements
	return podSpec, nil
}

func (a *apiServer) getWorkerOptions(pipelineName string, rcName string,
	parallelism int32, resourceRequests *api.ResourceList, resourceLimits *api.ResourceList, transform *pps.Transform,
	cacheSize string, service *pps.Service) *workerOptions {
	labels := labels(rcName)
	userImage := transform.Image
	if userImage == "" {
		userImage = DefaultUserImage
	}

	var workerEnv []api.EnvVar
	for name, value := range transform.Env {
		workerEnv = append(
			workerEnv,
			api.EnvVar{
				Name:  name,
				Value: value,
			},
		)
	}
	// We use Kubernetes' "Downward API" so the workers know their IP
	// addresses, which they will then post on etcd so the job managers
	// can discover the workers.
	workerEnv = append(workerEnv, api.EnvVar{
		Name: client.PPSWorkerIPEnv,
		ValueFrom: &api.EnvVarSource{
			FieldRef: &api.ObjectFieldSelector{
				APIVersion: "v1",
				FieldPath:  "status.podIP",
			},
		},
	})
	workerEnv = append(workerEnv, api.EnvVar{
		Name: client.PPSPodNameEnv,
		ValueFrom: &api.EnvVarSource{
			FieldRef: &api.ObjectFieldSelector{
				APIVersion: "v1",
				FieldPath:  "metadata.name",
			},
		},
	})
	// Set the etcd prefix env
	workerEnv = append(workerEnv, api.EnvVar{
		Name:  client.PPSEtcdPrefixEnv,
		Value: a.etcdPrefix,
	})
	// Pass along the namespace
	workerEnv = append(workerEnv, api.EnvVar{
		Name:  client.PPSNamespaceEnv,
		Value: a.namespace,
	})

	var volumes []api.Volume
	var volumeMounts []api.VolumeMount
	for _, secret := range transform.Secrets {
		if secret.MountPath != "" {
			volumes = append(volumes, api.Volume{
				Name: secret.Name,
				VolumeSource: api.VolumeSource{
					Secret: &api.SecretVolumeSource{
						SecretName: secret.Name,
					},
				},
			})
			volumeMounts = append(volumeMounts, api.VolumeMount{
				Name:      secret.Name,
				MountPath: secret.MountPath,
			})
		}
		if secret.EnvVar != "" {
			workerEnv = append(workerEnv, api.EnvVar{
				Name: secret.EnvVar,
				ValueFrom: &api.EnvVarSource{
					SecretKeyRef: &api.SecretKeySelector{
						LocalObjectReference: api.LocalObjectReference{
							Name: secret.Name,
						},
						Key: secret.Key,
					},
				},
			})
		}
	}

	volumes = append(volumes, api.Volume{
		Name: "pach-bin",
		VolumeSource: api.VolumeSource{
			EmptyDir: &api.EmptyDirVolumeSource{},
		},
	})
	volumeMounts = append(volumeMounts, api.VolumeMount{
		Name:      "pach-bin",
		MountPath: "/pach-bin",
	})

	volumes = append(volumes, api.Volume{
		Name: client.PPSWorkerVolume,
		VolumeSource: api.VolumeSource{
			EmptyDir: &api.EmptyDirVolumeSource{},
		},
	})
	volumeMounts = append(volumeMounts, api.VolumeMount{
		Name:      client.PPSWorkerVolume,
		MountPath: client.PPSScratchSpace,
	})
	if resourceLimits != nil && resourceLimits.NvidiaGPU() != nil && !resourceLimits.NvidiaGPU().IsZero() {
		volumes = append(volumes, api.Volume{
			Name: "root-lib",
			VolumeSource: api.VolumeSource{
				HostPath: &api.HostPathVolumeSource{
					Path: "/usr/lib",
				},
			},
		})
		volumeMounts = append(volumeMounts, api.VolumeMount{
			Name:      "root-lib",
			MountPath: "/rootfs/usr/lib",
		})
	}
	var imagePullSecrets []api.LocalObjectReference
	for _, secret := range transform.ImagePullSecrets {
		imagePullSecrets = append(imagePullSecrets, api.LocalObjectReference{Name: secret})
	}
	if a.imagePullSecret != "" {
		imagePullSecrets = append(imagePullSecrets, api.LocalObjectReference{Name: a.imagePullSecret})
	}

	annotations := map[string]string{"pipelineName": pipelineName}
	if a.iamRole != "" {
		annotations["iam.amazonaws.com/role"] = a.iamRole
	}

	return &workerOptions{
		rcName:           rcName,
		labels:           labels,
		annotations:      annotations,
		parallelism:      int32(parallelism),
		resourceRequests: resourceRequests,
		resourceLimits:   resourceLimits,
		userImage:        userImage,
		workerEnv:        workerEnv,
		volumes:          volumes,
		volumeMounts:     volumeMounts,
		imagePullSecrets: imagePullSecrets,
		cacheSize:        cacheSize,
		service:          service,
	}
}

func (a *apiServer) createWorkerRc(options *workerOptions) error {
	podSpec, err := a.workerPodSpec(options)
	if err != nil {
		return err
	}
	rc := &api.ReplicationController{
		TypeMeta: unversioned.TypeMeta{
			Kind:       "ReplicationController",
			APIVersion: "v1",
		},
		ObjectMeta: api.ObjectMeta{
			Name:        options.rcName,
			Labels:      options.labels,
			Annotations: options.annotations,
		},
		Spec: api.ReplicationControllerSpec{
			Selector: options.labels,
			Replicas: options.parallelism,
			Template: &api.PodTemplateSpec{
				ObjectMeta: api.ObjectMeta{
					Name:        options.rcName,
					Labels:      options.labels,
					Annotations: options.annotations,
				},
				Spec: podSpec,
			},
		},
	}
	fmt.Printf("Worker RC:\n%v\n%v\n", rc, podSpec)
	if _, err := a.kubeClient.ReplicationControllers(a.namespace).Create(rc); err != nil {
		if !isAlreadyExistsErr(err) {
			return err
		}
	}

	service := &api.Service{
		TypeMeta: unversioned.TypeMeta{
			Kind:       "Service",
			APIVersion: "v1",
		},
		ObjectMeta: api.ObjectMeta{
			Name:   options.rcName,
			Labels: options.labels,
		},
		Spec: api.ServiceSpec{
			Selector: options.labels,
			Ports: []api.ServicePort{
				{
					Port: client.PPSWorkerPort,
					Name: "grpc-port",
				},
			},
		},
	}
	if _, err := a.kubeClient.Services(a.namespace).Create(service); err != nil {
		if !isAlreadyExistsErr(err) {
			return err
		}
	}

	if options.service != nil {
		service := &api.Service{
			TypeMeta: unversioned.TypeMeta{
				Kind:       "Service",
				APIVersion: "v1",
			},
			ObjectMeta: api.ObjectMeta{
				Name:   options.rcName + "-user",
				Labels: options.labels,
			},
			Spec: api.ServiceSpec{
				Selector: options.labels,
				Type:     api.ServiceTypeNodePort,
				Ports: []api.ServicePort{
					{
						Port:       options.service.ExternalPort,
						TargetPort: intstr.FromInt(int(options.service.InternalPort)),
						Name:       "user-port",
						NodePort:   options.service.ExternalPort,
					},
				},
			},
		}
		if _, err := a.kubeClient.Services(a.namespace).Create(service); err != nil {
			if !isAlreadyExistsErr(err) {
				return err
			}
		}
	}

	return nil
}
<commit_msg>Set GPU on resource requests not limits<commit_after>package server

import (
	"context"
	"fmt"

	client "github.com/pachyderm/pachyderm/src/client"
	"github.com/pachyderm/pachyderm/src/client/enterprise"
	"github.com/pachyderm/pachyderm/src/client/pps"
	"github.com/pachyderm/pachyderm/src/server/pkg/deploy/assets"

	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/resource"
	"k8s.io/kubernetes/pkg/api/unversioned"
	"k8s.io/kubernetes/pkg/util/intstr"
)

// Parameters used when creating the kubernetes replication controller in charge
// of a job or pipeline's workers
type workerOptions struct {
	rcName string // Name of the replication controller managing workers

	userImage        string            // The user's pipeline/job image
	labels           map[string]string // k8s labels attached to the RC and workers
	annotations      map[string]string // k8s annotations attached to the RC and workers
	parallelism      int32             // Number of replicas the RC maintains
	cacheSize        string            // Size of cache that sidecar uses
	resourceRequests *api.ResourceList // Resources requested by pipeline/job pods
	resourceLimits   *api.ResourceList // Resources requested by pipeline/job pods
	workerEnv        []api.EnvVar      // Environment vars set in the user container
	volumes          []api.Volume      // Volumes that we expose to the user container
	volumeMounts     []api.VolumeMount // Paths where we mount each volume in 'volumes'

	// Secrets that we mount in the worker container (e.g. for reading/writing to
	// s3)
	imagePullSecrets []api.LocalObjectReference
	service          *pps.Service
}

func (a *apiServer) workerPodSpec(options *workerOptions) (api.PodSpec, error) {
	pullPolicy := a.workerImagePullPolicy
	if pullPolicy == "" {
		pullPolicy = "IfNotPresent"
	}
	sidecarEnv := []api.EnvVar{{
		Name:  "BLOCK_CACHE_BYTES",
		Value: options.cacheSize,
	}, {
		Name:  "PFS_CACHE_SIZE",
		Value: "16",
	}, {
		Name:  "PACH_ROOT",
		Value: a.storageRoot,
	}, {
		Name:  "STORAGE_BACKEND",
		Value: a.storageBackend,
	}}
	// This only happens in local deployment.  We want the workers to be
	// able to read from/write to the hostpath volume as well.
	storageVolumeName := "pach-disk"
	var sidecarVolumeMounts []api.VolumeMount
	if a.storageHostPath != "" {
		options.volumes = append(options.volumes, api.Volume{
			Name: storageVolumeName,
			VolumeSource: api.VolumeSource{
				HostPath: &api.HostPathVolumeSource{
					Path: a.storageHostPath,
				},
			},
		})

		sidecarVolumeMounts = []api.VolumeMount{
			{
				Name:      storageVolumeName,
				MountPath: a.storageRoot,
			},
		}
	}
	userVolumeMounts := options.volumeMounts
	secretVolume, secretMount := assets.GetSecretVolumeAndMount(a.storageBackend)
	options.volumes = append(options.volumes, secretVolume)
	options.volumeMounts = append(options.volumeMounts, secretMount)
	sidecarVolumeMounts = append(sidecarVolumeMounts, secretMount)
	userVolumeMounts = append(userVolumeMounts, secretMount)

	// Explicitly set CPU and MEM requests to zero because some cloud
	// providers set their own defaults which are usually not what we want.
	cpuZeroQuantity := resource.MustParse("0")
	memZeroQuantity := resource.MustParse("0M")
	memSidecarQuantity := resource.MustParse(options.cacheSize)

	options.volumes = append(options.volumes, api.Volume{
		Name: "docker",
		VolumeSource: api.VolumeSource{
			HostPath: &api.HostPathVolumeSource{
				Path: "/var/run/docker.sock",
			},
		},
	})
	userVolumeMounts = append(userVolumeMounts, api.VolumeMount{
		Name:      "docker",
		MountPath: "/var/run/docker.sock",
	})
	zeroVal := int64(0)
	workerImage := a.workerImage
	pachClient, err := a.getPachClient()
	if err != nil {
		return api.PodSpec{}, err
	}
	resp, err := pachClient.Enterprise.GetState(context.Background(), &enterprise.GetStateRequest{})
	if err != nil {
		return api.PodSpec{}, err
	}
	if resp.State != enterprise.State_ACTIVE {
		workerImage = assets.AddRegistry("", workerImage)
	}
	podSpec := api.PodSpec{
		InitContainers: []api.Container{
			{
				Name:            "init",
				Image:           workerImage,
				Command:         []string{"/pach/worker.sh"},
				ImagePullPolicy: api.PullPolicy(pullPolicy),
				Env:             options.workerEnv,
				VolumeMounts:    options.volumeMounts,
			},
		},
		Containers: []api.Container{
			{
				Name:    client.PPSWorkerUserContainerName,
				Image:   options.userImage,
				Command: []string{"/pach-bin/guest.sh"},
				SecurityContext: &api.SecurityContext{
					Privileged: &trueVal, // god is this dumb
				},
				ImagePullPolicy: api.PullPolicy(pullPolicy),
				Env:             options.workerEnv,
				Resources: api.ResourceRequirements{
					Requests: map[api.ResourceName]resource.Quantity{
						api.ResourceCPU:    cpuZeroQuantity,
						api.ResourceMemory: memZeroQuantity,
					},
				},
				VolumeMounts: userVolumeMounts,
			},
			{
				Name:            client.PPSWorkerSidecarContainerName,
				Image:           a.workerSidecarImage,
				Command:         []string{"/pachd", "--mode", "sidecar"},
				ImagePullPolicy: api.PullPolicy(pullPolicy),
				Env:             sidecarEnv,
				VolumeMounts:    sidecarVolumeMounts,
				Resources: api.ResourceRequirements{
					Requests: map[api.ResourceName]resource.Quantity{
						api.ResourceCPU:    cpuZeroQuantity,
						api.ResourceMemory: memSidecarQuantity,
					},
				},
			},
		},
		RestartPolicy:                 "Always",
		Volumes:                       options.volumes,
		ImagePullSecrets:              options.imagePullSecrets,
		TerminationGracePeriodSeconds: &zeroVal,
		SecurityContext:               &api.PodSecurityContext{RunAsUser: &zeroVal},
	}
	resourceRequirements := api.ResourceRequirements{}
	if options.resourceRequests != nil {
		resourceRequirements.Requests = *options.resourceRequests
	}
	if options.resourceLimits != nil {
		resourceRequirements.Limits = *options.resourceLimits
	}
	podSpec.Containers[0].Resources = resourceRequirements
	return podSpec, nil
}

func (a *apiServer) getWorkerOptions(pipelineName string, rcName string,
	parallelism int32, resourceRequests *api.ResourceList, resourceLimits *api.ResourceList, transform *pps.Transform,
	cacheSize string, service *pps.Service) *workerOptions {
	labels := labels(rcName)
	userImage := transform.Image
	if userImage == "" {
		userImage = DefaultUserImage
	}

	var workerEnv []api.EnvVar
	for name, value := range transform.Env {
		workerEnv = append(
			workerEnv,
			api.EnvVar{
				Name:  name,
				Value: value,
			},
		)
	}
	// We use Kubernetes' "Downward API" so the workers know their IP
	// addresses, which they will then post on etcd so the job managers
	// can discover the workers.
	workerEnv = append(workerEnv, api.EnvVar{
		Name: client.PPSWorkerIPEnv,
		ValueFrom: &api.EnvVarSource{
			FieldRef: &api.ObjectFieldSelector{
				APIVersion: "v1",
				FieldPath:  "status.podIP",
			},
		},
	})
	workerEnv = append(workerEnv, api.EnvVar{
		Name: client.PPSPodNameEnv,
		ValueFrom: &api.EnvVarSource{
			FieldRef: &api.ObjectFieldSelector{
				APIVersion: "v1",
				FieldPath:  "metadata.name",
			},
		},
	})
	// Set the etcd prefix env
	workerEnv = append(workerEnv, api.EnvVar{
		Name:  client.PPSEtcdPrefixEnv,
		Value: a.etcdPrefix,
	})
	// Pass along the namespace
	workerEnv = append(workerEnv, api.EnvVar{
		Name:  client.PPSNamespaceEnv,
		Value: a.namespace,
	})

	var volumes []api.Volume
	var volumeMounts []api.VolumeMount
	for _, secret := range transform.Secrets {
		if secret.MountPath != "" {
			volumes = append(volumes, api.Volume{
				Name: secret.Name,
				VolumeSource: api.VolumeSource{
					Secret: &api.SecretVolumeSource{
						SecretName: secret.Name,
					},
				},
			})
			volumeMounts = append(volumeMounts, api.VolumeMount{
				Name:      secret.Name,
				MountPath: secret.MountPath,
			})
		}
		if secret.EnvVar != "" {
			workerEnv = append(workerEnv, api.EnvVar{
				Name: secret.EnvVar,
				ValueFrom: &api.EnvVarSource{
					SecretKeyRef: &api.SecretKeySelector{
						LocalObjectReference: api.LocalObjectReference{
							Name: secret.Name,
						},
						Key: secret.Key,
					},
				},
			})
		}
	}

	volumes = append(volumes, api.Volume{
		Name: "pach-bin",
		VolumeSource: api.VolumeSource{
			EmptyDir: &api.EmptyDirVolumeSource{},
		},
	})
	volumeMounts = append(volumeMounts, api.VolumeMount{
		Name:      "pach-bin",
		MountPath: "/pach-bin",
	})

	volumes = append(volumes, api.Volume{
		Name: client.PPSWorkerVolume,
		VolumeSource: api.VolumeSource{
			EmptyDir: &api.EmptyDirVolumeSource{},
		},
	})
	volumeMounts = append(volumeMounts, api.VolumeMount{
		Name:      client.PPSWorkerVolume,
		MountPath: client.PPSScratchSpace,
	})
	if resourceRequests != nil && resourceRequests.NvidiaGPU() != nil && !resourceRequests.NvidiaGPU().IsZero() {
		volumes = append(volumes, api.Volume{
			Name: "root-lib",
			VolumeSource: api.VolumeSource{
				HostPath: &api.HostPathVolumeSource{
					Path: "/usr/lib",
				},
			},
		})
		volumeMounts = append(volumeMounts, api.VolumeMount{
			Name:      "root-lib",
			MountPath: "/rootfs/usr/lib",
		})
	}
	var imagePullSecrets []api.LocalObjectReference
	for _, secret := range transform.ImagePullSecrets {
		imagePullSecrets = append(imagePullSecrets, api.LocalObjectReference{Name: secret})
	}
	if a.imagePullSecret != "" {
		imagePullSecrets = append(imagePullSecrets, api.LocalObjectReference{Name: a.imagePullSecret})
	}

	annotations := map[string]string{"pipelineName": pipelineName}
	if a.iamRole != "" {
		annotations["iam.amazonaws.com/role"] = a.iamRole
	}

	return &workerOptions{
		rcName:           rcName,
		labels:           labels,
		annotations:      annotations,
		parallelism:      int32(parallelism),
		resourceRequests: resourceRequests,
		resourceLimits:   resourceLimits,
		userImage:        userImage,
		workerEnv:        workerEnv,
		volumes:          volumes,
		volumeMounts:     volumeMounts,
		imagePullSecrets: imagePullSecrets,
		cacheSize:        cacheSize,
		service:          service,
	}
}

func (a *apiServer) createWorkerRc(options *workerOptions) error {
	podSpec, err := a.workerPodSpec(options)
	if err != nil {
		return err
	}
	rc := &api.ReplicationController{
		TypeMeta: unversioned.TypeMeta{
			Kind:       "ReplicationController",
			APIVersion: "v1",
		},
		ObjectMeta: api.ObjectMeta{
			Name:        options.rcName,
			Labels:      options.labels,
			Annotations: options.annotations,
		},
		Spec: api.ReplicationControllerSpec{
			Selector: options.labels,
			Replicas: options.parallelism,
			Template: &api.PodTemplateSpec{
				ObjectMeta: api.ObjectMeta{
					Name:        options.rcName,
					Labels:      options.labels,
					Annotations: options.annotations,
				},
				Spec: podSpec,
			},
		},
	}
	if _, err := a.kubeClient.ReplicationControllers(a.namespace).Create(rc); err != nil {
		if !isAlreadyExistsErr(err) {
			return err
		}
	}

	service := &api.Service{
		TypeMeta: unversioned.TypeMeta{
			Kind:       "Service",
			APIVersion: "v1",
		},
		ObjectMeta: api.ObjectMeta{
			Name:   options.rcName,
			Labels: options.labels,
		},
		Spec: api.ServiceSpec{
			Selector: options.labels,
			Ports: []api.ServicePort{
				{
					Port: client.PPSWorkerPort,
					Name: "grpc-port",
				},
			},
		},
	}
	if _, err := a.kubeClient.Services(a.namespace).Create(service); err != nil {
		if !isAlreadyExistsErr(err) {
			return err
		}
	}

	if options.service != nil {
		service := &api.Service{
			TypeMeta: unversioned.TypeMeta{
				Kind:       "Service",
				APIVersion: "v1",
			},
			ObjectMeta: api.ObjectMeta{
				Name:   options.rcName + "-user",
				Labels: options.labels,
			},
			Spec: api.ServiceSpec{
				Selector: options.labels,
				Type:     api.ServiceTypeNodePort,
				Ports: []api.ServicePort{
					{
						Port:       options.service.ExternalPort,
						TargetPort: intstr.FromInt(int(options.service.InternalPort)),
						Name:       "user-port",
						NodePort:   options.service.ExternalPort,
					},
				},
			},
		}
		if _, err := a.kubeClient.Services(a.namespace).Create(service); err != nil {
			if !isAlreadyExistsErr(err) {
				return err
			}
		}
	}

	return nil
}
<|endoftext|>


<commit_before>//  ---------------------------------------------------------------------------
//
//  diagjson.go
//
//  Copyright (c) 2013, Jared Chavez.
//  All rights reserved.
//
//  Use of this source code is governed by a BSD-style
//  license that can be found in the LICENSE file.
//
//  -----------

package diag

import(
	"encoding/json"
)

// AsStr aggregates and returns diagnostics information in json format.
// Diagnostic information includes hostname, CPU count, environment data,
// stack traces for all running goroutines, and memory allocation statistics.
func AsJson(err interface{}) string {
	data    := New(err)
	json, _ := json.MarshalIndent(data, "", "    ")

	return string(json)
}
<commit_msg>fix typo<commit_after>//  ---------------------------------------------------------------------------
//
//  diagjson.go
//
//  Copyright (c) 2013, Jared Chavez.
//  All rights reserved.
//
//  Use of this source code is governed by a BSD-style
//  license that can be found in the LICENSE file.
//
//  -----------

package diag

import(
	"encoding/json"
)

// AsJson aggregates and returns diagnostics information in json format.
// Diagnostic information includes hostname, CPU count, environment data,
// stack traces for all running goroutines, and memory allocation statistics.
func AsJson(err interface{}) string {
	data    := New(err)
	json, _ := json.MarshalIndent(data, "", "    ")

	return string(json)
}
<|endoftext|>


<commit_before>package webserver

import (
	"github.com/e154/console"
	"time"
	"math/rand"
	"fmt"
)

type hub struct {
	// зарегистрированные соединения
	connections map[*Client]bool

	// входящие сообщения
	broadcast chan []byte

	// командный канал
	command chan map[*Client][]byte

	// запрос на регистранцию
	Register chan *Client

	// запрос Отменить регистрацию
	unregister chan *Client

	// выход для служб сбора информации
	quit chan bool

	// флаг, сигнализирует что служба сбора информации запущена
//	isProcRead bool
}

func (h *hub) PushRoom() {}

var H = &hub{
	connections: make(map[*Client]bool),
	broadcast:   make(chan []byte, maxMessageSize),
	command:   	 make(chan map[*Client][]byte, maxMessageSize),
	Register:    make(chan *Client, 1),
	unregister:  make(chan *Client, 1),
	quit:		 make(chan bool, 1),
//	isProcRead: false,
}

func (h *hub) Output(text []byte) {
	H.broadcast <- text
}

func (h *hub) run() {

	console := console.GetPtr()
	console.Output(h)

	quitAll := func() {
		if len(h.connections) == 0 {
//			h.isProcRead = false
			h.quit <- true
		}
	}

	for {
		select {
			// запрос на регистранцию
			// отметить что он зарегистрирован
		case c := <-h.Register:
			h.connections[c] = true

            fmt.Printf("client register\n")
            fmt.Printf("total clients: %d\n", len(h.connections))

			// при подулючении запустить, если не запущен сервис сбора информации
//			if !h.isProcRead {
//				h.isProcRead = true
//				go uptime()
//				go timeinfo();
//			}

			// запрос Отменить регистрацию
			// удалить запись о регистрации из массива
			// закрываем канал
		case c := <-h.unregister:
			delete(h.connections, c)

			fmt.Printf("client unregister\n")
			fmt.Printf("total clients: %d\n", len(h.connections))

			close(c.Send)
			quitAll()

			// широковещательные сообщения
			// перебрать всех зарегистрированных,
			// и отправить каждому это сообщение
			// если в канале больше нет сообщений
			// ???? не понял
			// закрыть канал и отменить регистрацию
		case m := <-h.broadcast:
			for c := range h.connections {
				select {
				case c.Send <- m:
				default:
					// если слушателей больше нет, отключим сервис
					quitAll()
					close(c.Send)
					delete(h.connections, c)
				}
			}

		case m := <-h.command:
			for _, val := range m {
				console.Exec(string(val))
			}
		}
	}
}

func init() {
	rand.Seed(time.Now().UTC().UnixNano())
	go H.run()
}
<commit_msg>bug fix, remove excess vars and chanel<commit_after>package webserver

import (
	"github.com/e154/console"
	"time"
	"math/rand"
	"fmt"
)

type hub struct {
	// зарегистрированные соединения
	connections map[*Client]bool

	// входящие сообщения
	broadcast chan []byte

	// командный канал
	command chan map[*Client][]byte

	// запрос на регистранцию
	Register chan *Client

	// запрос Отменить регистрацию
	unregister chan *Client
}

func (h *hub) PushRoom() {}

var H = &hub{
	connections: make(map[*Client]bool),
	broadcast:   make(chan []byte, maxMessageSize),
	command:   	 make(chan map[*Client][]byte, maxMessageSize),
	Register:    make(chan *Client, 1),
	unregister:  make(chan *Client, 1),
}

func (h *hub) Output(text []byte) {
	H.broadcast <- text
}

func (h *hub) run() {

	console := console.GetPtr()
	console.Output(h)

	quitAll := func() {
		if len(h.connections) == 0 {
			fmt.Println("quit all")
			//...
			fmt.Println("ok")
		}
	}

	for {
		select {
			// запрос на регистранцию
			// отметить что он зарегистрирован
		case c := <-h.Register:
			h.connections[c] = true

            fmt.Printf("client register\n")
            fmt.Printf("total clients: %d\n", len(h.connections))

			// запрос Отменить регистрацию
			// удалить запись о регистрации из массива
			// закрываем канал
		case c := <-h.unregister:
			delete(h.connections, c)

			fmt.Printf("client unregister\n")
			fmt.Printf("total clients: %d\n", len(h.connections))

			close(c.Send)
			quitAll()

			// широковещательные сообщения
			// перебрать всех зарегистрированных,
			// и отправить каждому это сообщение
			// если в канале больше нет сообщений
			// ???? не понял
			// закрыть канал и отменить регистрацию
		case m := <-h.broadcast:
			for c := range h.connections {
				select {
				case c.Send <- m:
				default:
					// если слушателей больше нет, отключим сервис
					quitAll()
					close(c.Send)
					delete(h.connections, c)
				}
			}

		case m := <-h.command:
			fmt.Println("command")
			for _, val := range m {
				console.Exec(string(val))
			}
		}
	}
}

func init() {
	rand.Seed(time.Now().UTC().UnixNano())
	go H.run()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"go/ast"
	"go/printer"
	"go/token"
	"os"

	"github.com/goph/stdlib/strings"
)

var types = []struct {
	typ string
	def string
}{
	{"string", `""`},
	{"bool", "false"},
	{"int", "0"},
	{"int32", "0"},
	{"int64", "0"},
	{"float32", "0.0"},
	{"float64", "0.0"},
}

func main() {
	fset := token.NewFileSet()

	decl := []ast.Decl{}

	for _, t := range types {
		decl = append(
			decl,
			typeLookup(t.typ, t.def),
			typeGet(t.typ, t.def),
			typeDefault(t.typ),
		)
	}

	file := &ast.File{
		Name:  ast.NewIdent("ext"),
		Decls: decl,
	}

	f, err := os.OpenFile("args_gen.go", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
	if err != nil {
		fmt.Printf("%x", err)
		return
	}

	f.WriteString("//+build experimental\n\n")

	printer.Fprint(f, fset, file)

	err = f.Close()
	if err != nil {
		fmt.Printf("%x", err)
		return
	}
}

func typeLookup(t string, def string) *ast.FuncDecl {
	return &ast.FuncDecl{
		Name: ast.NewIdent(fmt.Sprintf("Lookup%s", strings.ToCamel(t))),
		Doc: &ast.CommentGroup{
			List: []*ast.Comment{
				{
					Text: fmt.Sprintf(
						"// Lookup%s retrieves an argument of type %s from the list stored under the specified the index.",
						strings.ToCamel(t),
						t,
					),
				},
				{
					Text: "//",
				},
				{
					Text: fmt.Sprintf(
						"// If the index is present in the list and it is of type %s the value is returned and the boolean is true.",
						t,
					),
				},
				{
					Text: "//",
				},
				{
					Text: "// Otherwise the type's zero value and false are returned.",
				},
			},
		},
		Recv: &ast.FieldList{
			List: []*ast.Field{
				{
					Names: []*ast.Ident{
						ast.NewIdent("a"),
					},
					Type: ast.NewIdent("Arguments"),
				},
			},
		},
		Type: &ast.FuncType{
			Params: &ast.FieldList{
				List: []*ast.Field{
					{
						Names: []*ast.Ident{
							ast.NewIdent("index"),
						},
						Type: ast.NewIdent("int"),
					},
				},
			},
			Results: &ast.FieldList{
				List: []*ast.Field{
					{
						Type: ast.NewIdent(t),
					},
					{
						Type: ast.NewIdent("bool"),
					},
				},
			},
		},
		Body: &ast.BlockStmt{
			List: []ast.Stmt{
				&ast.AssignStmt{
					Tok: token.DEFINE,
					Lhs: []ast.Expr{
						ast.NewIdent("arg"),
						ast.NewIdent("ok"),
					},
					Rhs: []ast.Expr{
						&ast.CallExpr{
							Fun: ast.NewIdent("a.Lookup"),
							Args: []ast.Expr{
								ast.NewIdent("index"),
							},
						},
					},
				},
				&ast.IfStmt{
					Cond: &ast.UnaryExpr{
						X:  ast.NewIdent("ok"),
						Op: token.NOT,
					},
					Body: &ast.BlockStmt{
						List: []ast.Stmt{
							&ast.ReturnStmt{
								Results: []ast.Expr{
									&ast.BasicLit{
										Kind:  token.STRING,
										Value: def,
									},
									ast.NewIdent("false"),
								},
							},
						},
					},
				},
				&ast.IfStmt{
					Init: &ast.AssignStmt{
						Tok: token.DEFINE,
						Lhs: []ast.Expr{
							ast.NewIdent("v"),
							ast.NewIdent("ok"),
						},
						Rhs: []ast.Expr{
							&ast.TypeAssertExpr{
								X:    ast.NewIdent("arg"),
								Type: ast.NewIdent(t),
							},
						},
					},
					Cond: ast.NewIdent("ok"),
					Body: &ast.BlockStmt{
						List: []ast.Stmt{
							&ast.ReturnStmt{
								Results: []ast.Expr{
									ast.NewIdent("v"),
									ast.NewIdent("true"),
								},
							},
						},
					},
				},
				&ast.ReturnStmt{
					Results: []ast.Expr{
						&ast.BasicLit{
							Kind:  token.STRING,
							Value: def,
						},
						ast.NewIdent("false"),
					},
				},
			},
		},
	}
}

func typeGet(t string, def string) *ast.FuncDecl {
	return &ast.FuncDecl{
		Name: ast.NewIdent(fmt.Sprintf("%s", strings.ToCamel(t))),
		Doc: &ast.CommentGroup{
			List: []*ast.Comment{
				{
					Text: fmt.Sprintf(
						"// %s retrieves an argument of type %s from the list stored under the specified the index.",
						strings.ToCamel(t),
						t,
					),
				},
				{
					Text: "//",
				},
				{
					Text: fmt.Sprintf(
						"// If the index is present in the list and it is of type %s the value is returned.",
						t,
					),
				},
				{
					Text: "//",
				},
				{
					Text: fmt.Sprintf(
						"// Otherwise the type's zero value is returned. To distinguish between an empty value and an unset value, use Lookup%s.",
						strings.ToCamel(t),
					),
				},
			},
		},
		Recv: &ast.FieldList{
			List: []*ast.Field{
				{
					Names: []*ast.Ident{
						ast.NewIdent("a"),
					},
					Type: ast.NewIdent("Arguments"),
				},
			},
		},
		Type: &ast.FuncType{
			Params: &ast.FieldList{
				List: []*ast.Field{
					{
						Names: []*ast.Ident{
							ast.NewIdent("index"),
						},
						Type: ast.NewIdent("int"),
					},
				},
			},
			Results: &ast.FieldList{
				List: []*ast.Field{
					{
						Type: ast.NewIdent(t),
					},
				},
			},
		},
		Body: &ast.BlockStmt{
			List: []ast.Stmt{
				&ast.IfStmt{
					Init: &ast.AssignStmt{
						Tok: token.DEFINE,
						Lhs: []ast.Expr{
							ast.NewIdent("arg"),
							ast.NewIdent("ok"),
						},
						Rhs: []ast.Expr{
							&ast.CallExpr{
								Fun: ast.NewIdent(fmt.Sprintf("a.Lookup%s", strings.ToCamel(t))),
								Args: []ast.Expr{
									ast.NewIdent("index"),
								},
							},
						},
					},
					Cond: ast.NewIdent("ok"),
					Body: &ast.BlockStmt{
						List: []ast.Stmt{
							&ast.ReturnStmt{
								Results: []ast.Expr{
									ast.NewIdent("arg"),
								},
							},
						},
					},
				},
				&ast.ReturnStmt{
					Results: []ast.Expr{
						&ast.BasicLit{
							Kind:  token.STRING,
							Value: def,
						},
					},
				},
			},
		},
	}
}

func typeDefault(t string) *ast.FuncDecl {
	return &ast.FuncDecl{
		Name: ast.NewIdent(fmt.Sprintf("Default%s", strings.ToCamel(t))),
		Doc: &ast.CommentGroup{
			List: []*ast.Comment{
				{
					Text: fmt.Sprintf(
						"// Default%s retrieves an argument of type %s from the list stored under the specified the index.",
						strings.ToCamel(t),
						t,
					),
				},
				{
					Text: "//",
				},
				{
					Text: fmt.Sprintf(
						"// If the index is present in the list and it is of type %s the value is returned.",
						t,
					),
				},
				{
					Text: "//",
				},
				{
					Text: "// Otherwise the specified default value is returned.",
				},
			},
		},
		Recv: &ast.FieldList{
			List: []*ast.Field{
				{
					Names: []*ast.Ident{
						ast.NewIdent("a"),
					},
					Type: ast.NewIdent("Arguments"),
				},
			},
		},
		Type: &ast.FuncType{
			Params: &ast.FieldList{
				List: []*ast.Field{
					{
						Names: []*ast.Ident{
							ast.NewIdent("index"),
						},
						Type: ast.NewIdent("int"),
					},
					{
						Names: []*ast.Ident{
							ast.NewIdent("def"),
						},
						Type: ast.NewIdent(t),
					},
				},
			},
			Results: &ast.FieldList{
				List: []*ast.Field{
					{
						Type: ast.NewIdent(t),
					},
				},
			},
		},
		Body: &ast.BlockStmt{
			List: []ast.Stmt{
				&ast.IfStmt{
					Init: &ast.AssignStmt{
						Tok: token.DEFINE,
						Lhs: []ast.Expr{
							ast.NewIdent("arg"),
							ast.NewIdent("ok"),
						},
						Rhs: []ast.Expr{
							&ast.CallExpr{
								Fun: ast.NewIdent(fmt.Sprintf("a.Lookup%s", strings.ToCamel(t))),
								Args: []ast.Expr{
									ast.NewIdent("index"),
								},
							},
						},
					},
					Cond: ast.NewIdent("ok"),
					Body: &ast.BlockStmt{
						List: []ast.Stmt{
							&ast.ReturnStmt{
								Results: []ast.Expr{
									ast.NewIdent("arg"),
								},
							},
						},
					},
				},
				&ast.ReturnStmt{
					Results: []ast.Expr{
						ast.NewIdent("def"),
					},
				},
			},
		},
	}
}
<commit_msg>Format generated source file<commit_after>package main

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/format"
	"go/printer"
	"go/token"
	"os"

	"github.com/goph/stdlib/strings"
)

var types = []struct {
	typ string
	def string
}{
	{"string", `""`},
	{"bool", "false"},
	{"int", "0"},
	{"int32", "0"},
	{"int64", "0"},
	{"float32", "0.0"},
	{"float64", "0.0"},
}

func main() {
	fset := token.NewFileSet()

	decl := []ast.Decl{}

	for _, t := range types {
		decl = append(
			decl,
			typeLookup(t.typ, t.def),
			typeGet(t.typ, t.def),
			typeDefault(t.typ),
		)
	}

	file := &ast.File{
		Name:  ast.NewIdent("ext"),
		Decls: decl,
	}

	f, err := os.OpenFile("args_gen.go", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
	if err != nil {
		fmt.Printf("%x", err)
		return
	}

	defer f.Close()

	var buf bytes.Buffer
	printer.Fprint(&buf, fset, file)

	formatted, err := format.Source(buf.Bytes())

	if err != nil {
		fmt.Printf("%x", err)
		return
	}

	f.WriteString("//+build experimental\n\n")
	f.Write(formatted)
}

func typeLookup(t string, def string) *ast.FuncDecl {
	return &ast.FuncDecl{
		Name: ast.NewIdent(fmt.Sprintf("Lookup%s", strings.ToCamel(t))),
		Doc: &ast.CommentGroup{
			List: []*ast.Comment{
				{
					Text: fmt.Sprintf(
						"// Lookup%s retrieves an argument of type %s from the list stored under the specified the index.",
						strings.ToCamel(t),
						t,
					),
				},
				{
					Text: "//",
				},
				{
					Text: fmt.Sprintf(
						"// If the index is present in the list and it is of type %s the value is returned and the boolean is true.",
						t,
					),
				},
				{
					Text: "//",
				},
				{
					Text: "// Otherwise the type's zero value and false are returned.",
				},
			},
		},
		Recv: &ast.FieldList{
			List: []*ast.Field{
				{
					Names: []*ast.Ident{
						ast.NewIdent("a"),
					},
					Type: ast.NewIdent("Arguments"),
				},
			},
		},
		Type: &ast.FuncType{
			Params: &ast.FieldList{
				List: []*ast.Field{
					{
						Names: []*ast.Ident{
							ast.NewIdent("index"),
						},
						Type: ast.NewIdent("int"),
					},
				},
			},
			Results: &ast.FieldList{
				List: []*ast.Field{
					{
						Type: ast.NewIdent(t),
					},
					{
						Type: ast.NewIdent("bool"),
					},
				},
			},
		},
		Body: &ast.BlockStmt{
			List: []ast.Stmt{
				&ast.AssignStmt{
					Tok: token.DEFINE,
					Lhs: []ast.Expr{
						ast.NewIdent("arg"),
						ast.NewIdent("ok"),
					},
					Rhs: []ast.Expr{
						&ast.CallExpr{
							Fun: ast.NewIdent("a.Lookup"),
							Args: []ast.Expr{
								ast.NewIdent("index"),
							},
						},
					},
				},
				&ast.IfStmt{
					Cond: &ast.UnaryExpr{
						X:  ast.NewIdent("ok"),
						Op: token.NOT,
					},
					Body: &ast.BlockStmt{
						List: []ast.Stmt{
							&ast.ReturnStmt{
								Results: []ast.Expr{
									&ast.BasicLit{
										Kind:  token.STRING,
										Value: def,
									},
									ast.NewIdent("false"),
								},
							},
						},
					},
				},
				&ast.IfStmt{
					Init: &ast.AssignStmt{
						Tok: token.DEFINE,
						Lhs: []ast.Expr{
							ast.NewIdent("v"),
							ast.NewIdent("ok"),
						},
						Rhs: []ast.Expr{
							&ast.TypeAssertExpr{
								X:    ast.NewIdent("arg"),
								Type: ast.NewIdent(t),
							},
						},
					},
					Cond: ast.NewIdent("ok"),
					Body: &ast.BlockStmt{
						List: []ast.Stmt{
							&ast.ReturnStmt{
								Results: []ast.Expr{
									ast.NewIdent("v"),
									ast.NewIdent("true"),
								},
							},
						},
					},
				},
				&ast.ReturnStmt{
					Results: []ast.Expr{
						&ast.BasicLit{
							Kind:  token.STRING,
							Value: def,
						},
						ast.NewIdent("false"),
					},
				},
			},
		},
	}
}

func typeGet(t string, def string) *ast.FuncDecl {
	return &ast.FuncDecl{
		Name: ast.NewIdent(fmt.Sprintf("%s", strings.ToCamel(t))),
		Doc: &ast.CommentGroup{
			List: []*ast.Comment{
				{
					Text: fmt.Sprintf(
						"// %s retrieves an argument of type %s from the list stored under the specified the index.",
						strings.ToCamel(t),
						t,
					),
				},
				{
					Text: "//",
				},
				{
					Text: fmt.Sprintf(
						"// If the index is present in the list and it is of type %s the value is returned.",
						t,
					),
				},
				{
					Text: "//",
				},
				{
					Text: fmt.Sprintf(
						"// Otherwise the type's zero value is returned. To distinguish between an empty value and an unset value, use Lookup%s.",
						strings.ToCamel(t),
					),
				},
			},
		},
		Recv: &ast.FieldList{
			List: []*ast.Field{
				{
					Names: []*ast.Ident{
						ast.NewIdent("a"),
					},
					Type: ast.NewIdent("Arguments"),
				},
			},
		},
		Type: &ast.FuncType{
			Params: &ast.FieldList{
				List: []*ast.Field{
					{
						Names: []*ast.Ident{
							ast.NewIdent("index"),
						},
						Type: ast.NewIdent("int"),
					},
				},
			},
			Results: &ast.FieldList{
				List: []*ast.Field{
					{
						Type: ast.NewIdent(t),
					},
				},
			},
		},
		Body: &ast.BlockStmt{
			List: []ast.Stmt{
				&ast.IfStmt{
					Init: &ast.AssignStmt{
						Tok: token.DEFINE,
						Lhs: []ast.Expr{
							ast.NewIdent("arg"),
							ast.NewIdent("ok"),
						},
						Rhs: []ast.Expr{
							&ast.CallExpr{
								Fun: ast.NewIdent(fmt.Sprintf("a.Lookup%s", strings.ToCamel(t))),
								Args: []ast.Expr{
									ast.NewIdent("index"),
								},
							},
						},
					},
					Cond: ast.NewIdent("ok"),
					Body: &ast.BlockStmt{
						List: []ast.Stmt{
							&ast.ReturnStmt{
								Results: []ast.Expr{
									ast.NewIdent("arg"),
								},
							},
						},
					},
				},
				&ast.ReturnStmt{
					Results: []ast.Expr{
						&ast.BasicLit{
							Kind:  token.STRING,
							Value: def,
						},
					},
				},
			},
		},
	}
}

func typeDefault(t string) *ast.FuncDecl {
	return &ast.FuncDecl{
		Name: ast.NewIdent(fmt.Sprintf("Default%s", strings.ToCamel(t))),
		Doc: &ast.CommentGroup{
			List: []*ast.Comment{
				{
					Text: fmt.Sprintf(
						"// Default%s retrieves an argument of type %s from the list stored under the specified the index.",
						strings.ToCamel(t),
						t,
					),
				},
				{
					Text: "//",
				},
				{
					Text: fmt.Sprintf(
						"// If the index is present in the list and it is of type %s the value is returned.",
						t,
					),
				},
				{
					Text: "//",
				},
				{
					Text: "// Otherwise the specified default value is returned.",
				},
			},
		},
		Recv: &ast.FieldList{
			List: []*ast.Field{
				{
					Names: []*ast.Ident{
						ast.NewIdent("a"),
					},
					Type: ast.NewIdent("Arguments"),
				},
			},
		},
		Type: &ast.FuncType{
			Params: &ast.FieldList{
				List: []*ast.Field{
					{
						Names: []*ast.Ident{
							ast.NewIdent("index"),
						},
						Type: ast.NewIdent("int"),
					},
					{
						Names: []*ast.Ident{
							ast.NewIdent("def"),
						},
						Type: ast.NewIdent(t),
					},
				},
			},
			Results: &ast.FieldList{
				List: []*ast.Field{
					{
						Type: ast.NewIdent(t),
					},
				},
			},
		},
		Body: &ast.BlockStmt{
			List: []ast.Stmt{
				&ast.IfStmt{
					Init: &ast.AssignStmt{
						Tok: token.DEFINE,
						Lhs: []ast.Expr{
							ast.NewIdent("arg"),
							ast.NewIdent("ok"),
						},
						Rhs: []ast.Expr{
							&ast.CallExpr{
								Fun: ast.NewIdent(fmt.Sprintf("a.Lookup%s", strings.ToCamel(t))),
								Args: []ast.Expr{
									ast.NewIdent("index"),
								},
							},
						},
					},
					Cond: ast.NewIdent("ok"),
					Body: &ast.BlockStmt{
						List: []ast.Stmt{
							&ast.ReturnStmt{
								Results: []ast.Expr{
									ast.NewIdent("arg"),
								},
							},
						},
					},
				},
				&ast.ReturnStmt{
					Results: []ast.Expr{
						ast.NewIdent("def"),
					},
				},
			},
		},
	}
}
<|endoftext|>