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

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

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

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

package api

import (
	"github.com/fsouza/go-dockerclient"
)

// Common string formats
// ---------------------
// Many fields in this API have formatting requirements.  The commonly used
// formats are defined here.
//
// C_IDENTIFIER:  This is a string that conforms the definition of an "identifier"
//     in the C language.  This is captured by the following regex:
//         [A-Za-z_][A-Za-z0-9_]*
//     This defines the format, but not the length restriction, which should be
//     specified at the definition of any field of this type.
//
// DNS_LABEL:  This is a string, no more than 63 characters long, that conforms
//     to the definition of a "label" in RFCs 1035 and 1123.  This is captured
//     by the following regex:
//         [a-z0-9]([-a-z0-9]*[a-z0-9])?
//
//  DNS_SUBDOMAIN:  This is a string, no more than 253 characters long, that conforms
//      to the definition of a "subdomain" in RFCs 1035 and 1123.  This is captured
//      by the following regex:
//         [a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*
//     or more simply:
//         DNS_LABEL(\.DNS_LABEL)*

// ContainerManifest corresponds to the Container Manifest format, documented at:
// https://developers.google.com/compute/docs/containers/container_vms#container_manifest
// This is used as the representation of Kubernetes workloads.
type ContainerManifest struct {
	// Required: This must be a supported version string, such as "v1beta1".
	Version string `yaml:"version" json:"version"`
	// Required: This must be a DNS_SUBDOMAIN.
	ID         string      `yaml:"id" json:"id"`
	Volumes    []Volume    `yaml:"volumes" json:"volumes"`
	Containers []Container `yaml:"containers" json:"containers"`
}

// Volume represents a named volume in a pod that may be accessed by any containers in the pod.
type Volume struct {
	// Required: This must be a DNS_LABEL.  Each volume in a pod must have
	// a unique name.
	Name string `yaml:"name" json:"name"`
}

// Port represents a network port in a single container
type Port struct {
	// Optional: If specified, this must be a DNS_LABEL.  Each named port
	// in a pod must have a unique name.
	Name string `yaml:"name,omitempty" json:"name,omitempty"`
	// Optional: Defaults to ContainerPort.  If specified, this must be a
	// valid port number, 0 < x < 65536.
	HostPort int `yaml:"hostPort,omitempty" json:"hostPort,omitempty"`
	// Required: This must be a valid port number, 0 < x < 65536.
	ContainerPort int `yaml:"containerPort" json:"containerPort"`
	// Optional: Defaults to "TCP".
	Protocol string `yaml:"protocol,omitempty" json:"protocol,omitempty"`
}

// VolumeMount describes a mounting of a Volume within a container
type VolumeMount struct {
	// Required: This must match the Name of a Volume [above].
	Name string `yaml:"name" json:"name"`
	// Optional: Defaults to false (read-write).
	ReadOnly bool `yaml:"readOnly,omitempty" json:"readOnly,omitempty"`
	// Required.
	// Exactly one of the following must be set.  If both are set, prefer MountPath.
	// DEPRECATED: Path will be removed in a future version of the API.
	MountPath string `yaml:"mountPath,omitempty" json:"mountPath,omitempty"`
	Path string `yaml:"path,omitempty" json:"path,omitempty"`
	// One of: "LOCAL" (local volume) or "HOST" (external mount from the host). Default: LOCAL.
	MountType string `yaml:"mountType,omitempty" json:"mountType,omitempty"`
}

// EnvVar represents an environment variable present in a Container
type EnvVar struct {
	// Required: This must be a C_IDENTIFIER.
	// Exactly one of the following must be set.  If both are set, prefer Name.
	// DEPRECATED: EnvVar.Key will be removed in a future version of the API.
	Name string `yaml:"name" json:"name"`
	Key  string `yaml:"key,omitempty" json:"key,omitempty"`
	// Optional: defaults to "".
	Value string `yaml:"value,omitempty" json:"value,omitempty"`
}

// Container represents a single container that is expected to be run on the host.
type Container struct {
	// Required: This must be a DNS_LABEL.  Each container in a pod must
	// have a unique name.
	Name string `yaml:"name" json:"name"`
	// Required.
	Image string `yaml:"image" json:"image"`
	// Optional: Defaults to whatever is defined in the image.
	Command []string `yaml:"command,omitempty" json:"command,omitempty"`
	// Optional: Defaults to Docker's default.
	WorkingDir string   `yaml:"workingDir,omitempty" json:"workingDir,omitempty"`
	Ports      []Port   `yaml:"ports,omitempty" json:"ports,omitempty"`
	Env        []EnvVar `yaml:"env,omitempty" json:"env,omitempty"`
	// Optional: Defaults to unlimited.
	Memory int `yaml:"memory,omitempty" json:"memory,omitempty"`
	// Optional: Defaults to unlimited.
	CPU          int           `yaml:"cpu,omitempty" json:"cpu,omitempty"`
	VolumeMounts []VolumeMount `yaml:"volumeMounts,omitempty" json:"volumeMounts,omitempty"`
}

// Percentile represents a pair which contains a percentage from 0 to 100 and
// its corresponding value.
type Percentile struct {
	Percentage int    `json:"percentage,omitempty"`
	Value      uint64 `json:"value,omitempty"`
}

// ContainerStats represents statistical information of a container
type ContainerStats struct {
	CpuUsagePercentiles    []Percentile `json:"cpu_usage_percentiles,omitempty"`
	MemoryUsagePercentiles []Percentile `json:"memory_usage_percentiles,omitempty"`
	MaxMemoryUsage         uint64       `json:"max_memory_usage,omitempty"`
}

// Event is the representation of an event logged to etcd backends
type Event struct {
	Event     string             `json:"event,omitempty"`
	Manifest  *ContainerManifest `json:"manifest,omitempty"`
	Container *Container         `json:"container,omitempty"`
	Timestamp int64              `json:"timestamp"`
}

// The below types are used by kube_client and api_server.

// JSONBase is shared by all objects sent to, or returned from the client
type JSONBase struct {
	Kind              string `json:"kind,omitempty" yaml:"kind,omitempty"`
	ID                string `json:"id,omitempty" yaml:"id,omitempty"`
	CreationTimestamp string `json:"creationTimestamp,omitempty" yaml:"creationTimestamp,omitempty"`
	SelfLink          string `json:"selfLink,omitempty" yaml:"selfLink,omitempty"`
	ResourceVersion   uint64 `json:"resourceVersion,omitempty" yaml:"resourceVersion,omitempty"`
}

// PodStatus represents a status of a pod.
type PodStatus string

// These are the valid statuses of pods.
const (
	PodRunning PodStatus = "Running"
	PodPending PodStatus = "Pending"
	PodStopped PodStatus = "Stopped"
)

// PodInfo contains one entry for every container with available info.
type PodInfo map[string]docker.Container

// PodState is the state of a pod, used as either input (desired state) or output (current state)
type PodState struct {
	Manifest ContainerManifest `json:"manifest,omitempty" yaml:"manifest,omitempty"`
	Status   PodStatus         `json:"status,omitempty" yaml:"status,omitempty"`
	Host     string            `json:"host,omitempty" yaml:"host,omitempty"`
	HostIP   string            `json:"hostIP,omitempty" yaml:"hostIP,omitempty"`

	// The key of this map is the *name* of the container within the manifest; it has one
	// entry per container in the manifest. The value of this map is currently the output
	// of `docker inspect`. This output format is *not* final and should not be relied
	// upon.
	// TODO: Make real decisions about what our info should look like.
	Info PodInfo `json:"info,omitempty" yaml:"info,omitempty"`
}

// PodList is a list of Pods.
type PodList struct {
	JSONBase `json:",inline" yaml:",inline"`
	Items    []Pod `json:"items" yaml:"items,omitempty"`
}

// Pod is a collection of containers, used as either input (create, update) or as output (list, get)
type Pod struct {
	JSONBase     `json:",inline" yaml:",inline"`
	Labels       map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`
	DesiredState PodState          `json:"desiredState,omitempty" yaml:"desiredState,omitempty"`
	CurrentState PodState          `json:"currentState,omitempty" yaml:"currentState,omitempty"`
}

// ReplicationControllerState is the state of a replication controller, either input (create, update) or as output (list, get)
type ReplicationControllerState struct {
	Replicas        int               `json:"replicas" yaml:"replicas"`
	ReplicaSelector map[string]string `json:"replicaSelector,omitempty" yaml:"replicaSelector,omitempty"`
	PodTemplate     PodTemplate       `json:"podTemplate,omitempty" yaml:"podTemplate,omitempty"`
}

// ReplicationControllerList is a collection of replication controllers.
type ReplicationControllerList struct {
	JSONBase `json:",inline" yaml:",inline"`
	Items    []ReplicationController `json:"items,omitempty" yaml:"items,omitempty"`
}

// ReplicationController represents the configuration of a replication controller
type ReplicationController struct {
	JSONBase     `json:",inline" yaml:",inline"`
	DesiredState ReplicationControllerState `json:"desiredState,omitempty" yaml:"desiredState,omitempty"`
	Labels       map[string]string          `json:"labels,omitempty" yaml:"labels,omitempty"`
}

// PodTemplate holds the information used for creating pods
type PodTemplate struct {
	DesiredState PodState          `json:"desiredState,omitempty" yaml:"desiredState,omitempty"`
	Labels       map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`
}

// ServiceList holds a list of services
type ServiceList struct {
	JSONBase `json:",inline" yaml:",inline"`
	Items    []Service `json:"items" yaml:"items"`
}

// Service is a named abstraction of software service (for example, mysql) consisting of local port
// (for example 3306) that the proxy listens on, and the selector that determines which pods
// will answer requests sent through the proxy.
type Service struct {
	JSONBase `json:",inline" yaml:",inline"`
	Port     int `json:"port,omitempty" yaml:"port,omitempty"`

	// This service's labels.
	Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`

	// This service will route traffic to pods having labels matching this selector.
	Selector                   map[string]string `json:"selector,omitempty" yaml:"selector,omitempty"`
	CreateExternalLoadBalancer bool              `json:"createExternalLoadBalancer,omitempty" yaml:"createExternalLoadBalancer,omitempty"`
}

// Endpoints is a collection of endpoints that implement the actual service, for example:
// Name: "mysql", Endpoints: ["10.10.1.1:1909", "10.10.2.2:8834"]
type Endpoints struct {
	Name      string
	Endpoints []string
}

// Minion is a worker node in Kubernetenes.
// The name of the minion according to etcd is in JSONBase.ID.
type Minion struct {
	JSONBase `json:",inline" yaml:",inline"`
	// Queried from cloud provider, if available.
	HostIP string `json:"hostIP,omitempty" yaml:"hostIP,omitempty"`
}

// MinionList is a list of minions.
type MinionList struct {
	JSONBase `json:",inline" yaml:",inline"`
	Items    []Minion `json:"minions,omitempty" yaml:"minions,omitempty"`
}

// Status is a return value for calls that don't return other objects.
// Arguably, this could go in apiserver, but I'm including it here so clients needn't
// import both.
type Status struct {
	JSONBase `json:",inline" yaml:",inline"`
	// One of: "success", "failure", "working" (for operations not yet completed)
	// TODO: if "working", include an operation identifier so final status can be
	// checked.
	Status string `json:"status,omitempty" yaml:"status,omitempty"`
	// Details about the status. May be an error description or an
	// operation number for later polling.
	Details string `json:"details,omitempty" yaml:"details,omitempty"`
	// Suggested HTTP return code for this status, 0 if not set.
	Code int `json:"code,omitempty" yaml:"code,omitempty"`
}

// Values of Status.Status
const (
	StatusSuccess = "success"
	StatusFailure = "failure"
	StatusWorking = "working"
)

// ServerOp is an operation delivered to API clients.
type ServerOp struct {
	JSONBase `yaml:",inline" json:",inline"`
}

// ServerOpList is a list of operations, as delivered to API clients.
type ServerOpList struct {
	JSONBase `yaml:",inline" json:",inline"`
	Items    []ServerOp `yaml:"items,omitempty" json:"items,omitempty"`
}
<commit_msg>Add support for host ip binding to the API (and kubelet)<commit_after>/*
Copyright 2014 Google Inc. All rights reserved.

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

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

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

package api

import (
	"github.com/fsouza/go-dockerclient"
)

// Common string formats
// ---------------------
// Many fields in this API have formatting requirements.  The commonly used
// formats are defined here.
//
// C_IDENTIFIER:  This is a string that conforms the definition of an "identifier"
//     in the C language.  This is captured by the following regex:
//         [A-Za-z_][A-Za-z0-9_]*
//     This defines the format, but not the length restriction, which should be
//     specified at the definition of any field of this type.
//
// DNS_LABEL:  This is a string, no more than 63 characters long, that conforms
//     to the definition of a "label" in RFCs 1035 and 1123.  This is captured
//     by the following regex:
//         [a-z0-9]([-a-z0-9]*[a-z0-9])?
//
//  DNS_SUBDOMAIN:  This is a string, no more than 253 characters long, that conforms
//      to the definition of a "subdomain" in RFCs 1035 and 1123.  This is captured
//      by the following regex:
//         [a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*
//     or more simply:
//         DNS_LABEL(\.DNS_LABEL)*

// ContainerManifest corresponds to the Container Manifest format, documented at:
// https://developers.google.com/compute/docs/containers/container_vms#container_manifest
// This is used as the representation of Kubernetes workloads.
type ContainerManifest struct {
	// Required: This must be a supported version string, such as "v1beta1".
	Version string `yaml:"version" json:"version"`
	// Required: This must be a DNS_SUBDOMAIN.
	ID         string      `yaml:"id" json:"id"`
	Volumes    []Volume    `yaml:"volumes" json:"volumes"`
	Containers []Container `yaml:"containers" json:"containers"`
}

// Volume represents a named volume in a pod that may be accessed by any containers in the pod.
type Volume struct {
	// Required: This must be a DNS_LABEL.  Each volume in a pod must have
	// a unique name.
	Name string `yaml:"name" json:"name"`
}

// Port represents a network port in a single container
type Port struct {
	// Optional: If specified, this must be a DNS_LABEL.  Each named port
	// in a pod must have a unique name.
	Name string `yaml:"name,omitempty" json:"name,omitempty"`
	// Optional: Defaults to ContainerPort.  If specified, this must be a
	// valid port number, 0 < x < 65536.
	HostPort int `yaml:"hostPort,omitempty" json:"hostPort,omitempty"`
	// Required: This must be a valid port number, 0 < x < 65536.
	ContainerPort int `yaml:"containerPort" json:"containerPort"`
	// Optional: Defaults to "TCP".
	Protocol string `yaml:"protocol,omitempty" json:"protocol,omitempty"`
	// Optional: What host IP to bind the external port to.
	HostIP string `yaml:"hostIP,omitempty" json:"hostIP,omitempty"`
}

// VolumeMount describes a mounting of a Volume within a container
type VolumeMount struct {
	// Required: This must match the Name of a Volume [above].
	Name string `yaml:"name" json:"name"`
	// Optional: Defaults to false (read-write).
	ReadOnly bool `yaml:"readOnly,omitempty" json:"readOnly,omitempty"`
	// Required.
	// Exactly one of the following must be set.  If both are set, prefer MountPath.
	// DEPRECATED: Path will be removed in a future version of the API.
	MountPath string `yaml:"mountPath,omitempty" json:"mountPath,omitempty"`
	Path      string `yaml:"path,omitempty" json:"path,omitempty"`
	// One of: "LOCAL" (local volume) or "HOST" (external mount from the host). Default: LOCAL.
	MountType string `yaml:"mountType,omitempty" json:"mountType,omitempty"`
}

// EnvVar represents an environment variable present in a Container
type EnvVar struct {
	// Required: This must be a C_IDENTIFIER.
	// Exactly one of the following must be set.  If both are set, prefer Name.
	// DEPRECATED: EnvVar.Key will be removed in a future version of the API.
	Name string `yaml:"name" json:"name"`
	Key  string `yaml:"key,omitempty" json:"key,omitempty"`
	// Optional: defaults to "".
	Value string `yaml:"value,omitempty" json:"value,omitempty"`
}

// Container represents a single container that is expected to be run on the host.
type Container struct {
	// Required: This must be a DNS_LABEL.  Each container in a pod must
	// have a unique name.
	Name string `yaml:"name" json:"name"`
	// Required.
	Image string `yaml:"image" json:"image"`
	// Optional: Defaults to whatever is defined in the image.
	Command []string `yaml:"command,omitempty" json:"command,omitempty"`
	// Optional: Defaults to Docker's default.
	WorkingDir string   `yaml:"workingDir,omitempty" json:"workingDir,omitempty"`
	Ports      []Port   `yaml:"ports,omitempty" json:"ports,omitempty"`
	Env        []EnvVar `yaml:"env,omitempty" json:"env,omitempty"`
	// Optional: Defaults to unlimited.
	Memory int `yaml:"memory,omitempty" json:"memory,omitempty"`
	// Optional: Defaults to unlimited.
	CPU          int           `yaml:"cpu,omitempty" json:"cpu,omitempty"`
	VolumeMounts []VolumeMount `yaml:"volumeMounts,omitempty" json:"volumeMounts,omitempty"`
}

// Percentile represents a pair which contains a percentage from 0 to 100 and
// its corresponding value.
type Percentile struct {
	Percentage int    `json:"percentage,omitempty"`
	Value      uint64 `json:"value,omitempty"`
}

// ContainerStats represents statistical information of a container
type ContainerStats struct {
	CpuUsagePercentiles    []Percentile `json:"cpu_usage_percentiles,omitempty"`
	MemoryUsagePercentiles []Percentile `json:"memory_usage_percentiles,omitempty"`
	MaxMemoryUsage         uint64       `json:"max_memory_usage,omitempty"`
}

// Event is the representation of an event logged to etcd backends
type Event struct {
	Event     string             `json:"event,omitempty"`
	Manifest  *ContainerManifest `json:"manifest,omitempty"`
	Container *Container         `json:"container,omitempty"`
	Timestamp int64              `json:"timestamp"`
}

// The below types are used by kube_client and api_server.

// JSONBase is shared by all objects sent to, or returned from the client
type JSONBase struct {
	Kind              string `json:"kind,omitempty" yaml:"kind,omitempty"`
	ID                string `json:"id,omitempty" yaml:"id,omitempty"`
	CreationTimestamp string `json:"creationTimestamp,omitempty" yaml:"creationTimestamp,omitempty"`
	SelfLink          string `json:"selfLink,omitempty" yaml:"selfLink,omitempty"`
	ResourceVersion   uint64 `json:"resourceVersion,omitempty" yaml:"resourceVersion,omitempty"`
}

// PodStatus represents a status of a pod.
type PodStatus string

// These are the valid statuses of pods.
const (
	PodRunning PodStatus = "Running"
	PodPending PodStatus = "Pending"
	PodStopped PodStatus = "Stopped"
)

// PodInfo contains one entry for every container with available info.
type PodInfo map[string]docker.Container

// PodState is the state of a pod, used as either input (desired state) or output (current state)
type PodState struct {
	Manifest ContainerManifest `json:"manifest,omitempty" yaml:"manifest,omitempty"`
	Status   PodStatus         `json:"status,omitempty" yaml:"status,omitempty"`
	Host     string            `json:"host,omitempty" yaml:"host,omitempty"`
	HostIP   string            `json:"hostIP,omitempty" yaml:"hostIP,omitempty"`

	// The key of this map is the *name* of the container within the manifest; it has one
	// entry per container in the manifest. The value of this map is currently the output
	// of `docker inspect`. This output format is *not* final and should not be relied
	// upon.
	// TODO: Make real decisions about what our info should look like.
	Info PodInfo `json:"info,omitempty" yaml:"info,omitempty"`
}

// PodList is a list of Pods.
type PodList struct {
	JSONBase `json:",inline" yaml:",inline"`
	Items    []Pod `json:"items" yaml:"items,omitempty"`
}

// Pod is a collection of containers, used as either input (create, update) or as output (list, get)
type Pod struct {
	JSONBase     `json:",inline" yaml:",inline"`
	Labels       map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`
	DesiredState PodState          `json:"desiredState,omitempty" yaml:"desiredState,omitempty"`
	CurrentState PodState          `json:"currentState,omitempty" yaml:"currentState,omitempty"`
}

// ReplicationControllerState is the state of a replication controller, either input (create, update) or as output (list, get)
type ReplicationControllerState struct {
	Replicas        int               `json:"replicas" yaml:"replicas"`
	ReplicaSelector map[string]string `json:"replicaSelector,omitempty" yaml:"replicaSelector,omitempty"`
	PodTemplate     PodTemplate       `json:"podTemplate,omitempty" yaml:"podTemplate,omitempty"`
}

// ReplicationControllerList is a collection of replication controllers.
type ReplicationControllerList struct {
	JSONBase `json:",inline" yaml:",inline"`
	Items    []ReplicationController `json:"items,omitempty" yaml:"items,omitempty"`
}

// ReplicationController represents the configuration of a replication controller
type ReplicationController struct {
	JSONBase     `json:",inline" yaml:",inline"`
	DesiredState ReplicationControllerState `json:"desiredState,omitempty" yaml:"desiredState,omitempty"`
	Labels       map[string]string          `json:"labels,omitempty" yaml:"labels,omitempty"`
}

// PodTemplate holds the information used for creating pods
type PodTemplate struct {
	DesiredState PodState          `json:"desiredState,omitempty" yaml:"desiredState,omitempty"`
	Labels       map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`
}

// ServiceList holds a list of services
type ServiceList struct {
	JSONBase `json:",inline" yaml:",inline"`
	Items    []Service `json:"items" yaml:"items"`
}

// Service is a named abstraction of software service (for example, mysql) consisting of local port
// (for example 3306) that the proxy listens on, and the selector that determines which pods
// will answer requests sent through the proxy.
type Service struct {
	JSONBase `json:",inline" yaml:",inline"`
	Port     int `json:"port,omitempty" yaml:"port,omitempty"`

	// This service's labels.
	Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`

	// This service will route traffic to pods having labels matching this selector.
	Selector                   map[string]string `json:"selector,omitempty" yaml:"selector,omitempty"`
	CreateExternalLoadBalancer bool              `json:"createExternalLoadBalancer,omitempty" yaml:"createExternalLoadBalancer,omitempty"`
}

// Endpoints is a collection of endpoints that implement the actual service, for example:
// Name: "mysql", Endpoints: ["10.10.1.1:1909", "10.10.2.2:8834"]
type Endpoints struct {
	Name      string
	Endpoints []string
}

// Minion is a worker node in Kubernetenes.
// The name of the minion according to etcd is in JSONBase.ID.
type Minion struct {
	JSONBase `json:",inline" yaml:",inline"`
	// Queried from cloud provider, if available.
	HostIP string `json:"hostIP,omitempty" yaml:"hostIP,omitempty"`
}

// MinionList is a list of minions.
type MinionList struct {
	JSONBase `json:",inline" yaml:",inline"`
	Items    []Minion `json:"minions,omitempty" yaml:"minions,omitempty"`
}

// Status is a return value for calls that don't return other objects.
// Arguably, this could go in apiserver, but I'm including it here so clients needn't
// import both.
type Status struct {
	JSONBase `json:",inline" yaml:",inline"`
	// One of: "success", "failure", "working" (for operations not yet completed)
	// TODO: if "working", include an operation identifier so final status can be
	// checked.
	Status string `json:"status,omitempty" yaml:"status,omitempty"`
	// Details about the status. May be an error description or an
	// operation number for later polling.
	Details string `json:"details,omitempty" yaml:"details,omitempty"`
	// Suggested HTTP return code for this status, 0 if not set.
	Code int `json:"code,omitempty" yaml:"code,omitempty"`
}

// Values of Status.Status
const (
	StatusSuccess = "success"
	StatusFailure = "failure"
	StatusWorking = "working"
)

// ServerOp is an operation delivered to API clients.
type ServerOp struct {
	JSONBase `yaml:",inline" json:",inline"`
}

// ServerOpList is a list of operations, as delivered to API clients.
type ServerOpList struct {
	JSONBase `yaml:",inline" json:",inline"`
	Items    []ServerOp `yaml:"items,omitempty" json:"items,omitempty"`
}
<|endoftext|>


<commit_before>package ipmi

import (
	"fmt"
	"os"
	"syscall"
	"unsafe"
)

const (
	_IOC_WRITE = 0x1
	_IOC_READ  = 0x2

	_IOC_NRBITS   = 8
	_IOC_TYPEBITS = 8
	_IOC_SIZEBITS = 14
	_IOC_NRSHIFT  = 0

	_IOC_TYPESHIFT = _IOC_NRSHIFT + _IOC_NRBITS
	_IOC_SIZESHIFT = _IOC_TYPESHIFT + _IOC_TYPEBITS
	_IOC_DIRSHIFT  = _IOC_SIZESHIFT + _IOC_SIZEBITS

	_IPMI_BMC_CHANNEL = 0xf
	_IPMI_BUF_SIZE = 1024
	_IPMI_IOC_MAGIC = 'i'
	_IPMI_NETFN_APP = 0x6
	_IPMI_OPENIPMI_READ_TIMEOUT = 15
	_IPMI_SYSTEM_INTERFACE_ADDR_TYPE = 0x0c

	_BMC_SET_WATCHDOG_TIMER = 0x24
	_BMC_GET_WATCHDOG_TIMER = 0x25

	_IPM_WATCHDOG_NO_ACTION = 0x00
	_IPM_WATCHDOG_SMS_OS = 0x04
	_IPM_WATCHDOG_CLEAR_SMS_OS = 0x10
)

var (
	_IPMICTL_RECEIVE_MSG  = iowr(_IPMI_IOC_MAGIC, 12, int(unsafe.Sizeof(recv{})))
	_IPMICTL_SEND_COMMAND = ior(_IPMI_IOC_MAGIC, 13, int(unsafe.Sizeof(req{})))
)

type Ipmi struct {
	fd int
}

type msg struct {
	netfn   byte
	cmd     byte
	dataLen uint16
	data    unsafe.Pointer
}

type req struct {
	addr    *systemInterfaceAddr
	addrLen uint32
	msgid   int64
	msg     msg
}

type recv struct {
	recvType int32
	addr     *systemInterfaceAddr
	addrLen  uint32
	msgid    int64
	msg      msg
}

type systemInterfaceAddr struct {
	addrType int32
	channel  int16
	lun      byte
}

func ioc(dir int, t int, nr int, size int) int {
	return (dir << _IOC_DIRSHIFT) | (t << _IOC_TYPESHIFT) |
		(nr << _IOC_NRSHIFT) | (size << _IOC_SIZESHIFT)
}

func ior(t int, nr int, size int) int {
	return ioc(_IOC_READ, t, nr, size)
}

func iowr(t int, nr int, size int) int {
	return ioc(_IOC_READ | _IOC_WRITE, t, nr, size)
}

func ioctl(fd int, name int, data unsafe.Pointer) syscall.Errno {
	_, _, err := syscall.RawSyscall(syscall.SYS_IOCTL, uintptr(fd), uintptr(name), uintptr(data))
	return err
}

func fd_set(fd int, p *syscall.FdSet) {
	p.Bits[fd/64] |= 1 << (uint(fd) % 64)
}

func Open(devnum int) (*Ipmi, error) {
	d := fmt.Sprintf("/dev/ipmi%d", devnum)

	f, err := os.OpenFile(d, os.O_RDWR, 0)
	if err != nil {
		return nil, err
	}

	fd := int(f.Fd())
	return &Ipmi{fd: fd}, nil
}

func (i *Ipmi) Close() error {
	return syscall.Close(i.fd)
}

func (i *Ipmi) sendrecv(req *req) (*recv, error) {
	addr := &systemInterfaceAddr{
		addrType: _IPMI_SYSTEM_INTERFACE_ADDR_TYPE,
		channel:  _IPMI_BMC_CHANNEL,
	}

	req.addr = addr
	req.addrLen = uint32(unsafe.Sizeof(addr))
	if err := ioctl(i.fd, _IPMICTL_SEND_COMMAND, unsafe.Pointer(req)); err != 0 {
		return nil, err
	}

	set := &syscall.FdSet{}
	fd_set(i.fd, set)
	time := syscall.Timeval{
		Sec:  _IPMI_OPENIPMI_READ_TIMEOUT,
		Usec: 0,
	}
	if _, err := syscall.Select(i.fd + 1, set, nil, nil, &time); err != nil {
		return nil, err
	}

	recv := &recv{}
	recv.addr = &systemInterfaceAddr{}
	recv.addrLen = uint32(unsafe.Sizeof(addr))
	recv.msg.data = unsafe.Pointer(new([_IPMI_BUF_SIZE]byte))
	recv.msg.dataLen = _IPMI_BUF_SIZE
	if err := ioctl(i.fd, _IPMICTL_RECEIVE_MSG, unsafe.Pointer(recv)); err != 0 {
		return nil, err
	}

	return recv, nil
}

func (i *Ipmi) WatchdogRunning() (bool, error) {
	req := &req{}
	req.msg.cmd   = _BMC_GET_WATCHDOG_TIMER
	req.msg.netfn = _IPMI_NETFN_APP

	recv, err := i.sendrecv(req)
	if err != nil {
		return false, err
	}

	use := (*[2]byte) (recv.msg.data)

	if (use[1] & 0x40) != 0 {
		return true, nil
	}

	return false, nil
}

func (i *Ipmi) ShutoffWatchdog() error {
	req := &req{}
	req.msg.cmd   = _BMC_SET_WATCHDOG_TIMER
	req.msg.netfn = _IPMI_NETFN_APP

	var data [6]byte
	data[0] = _IPM_WATCHDOG_SMS_OS
	data[1] = _IPM_WATCHDOG_NO_ACTION
	data[2] = 0x00;  // pretimeout interval
	data[3] = _IPM_WATCHDOG_CLEAR_SMS_OS
	data[4] = 0xb8;  // countdown lsb (100 ms/count)
	data[5] = 0x0b;  // countdown msb - 5 mins
	req.msg.data = unsafe.Pointer(&data)
	req.msg.dataLen = 6

	_, err := i.sendrecv(req)
	if err != nil {
		return err
	}

	return nil
}
<commit_msg>[pkg/ipmi] gofmt<commit_after>package ipmi

import (
	"fmt"
	"os"
	"syscall"
	"unsafe"
)

const (
	_IOC_WRITE = 0x1
	_IOC_READ  = 0x2

	_IOC_NRBITS   = 8
	_IOC_TYPEBITS = 8
	_IOC_SIZEBITS = 14
	_IOC_NRSHIFT  = 0

	_IOC_TYPESHIFT = _IOC_NRSHIFT + _IOC_NRBITS
	_IOC_SIZESHIFT = _IOC_TYPESHIFT + _IOC_TYPEBITS
	_IOC_DIRSHIFT  = _IOC_SIZESHIFT + _IOC_SIZEBITS

	_IPMI_BMC_CHANNEL                = 0xf
	_IPMI_BUF_SIZE                   = 1024
	_IPMI_IOC_MAGIC                  = 'i'
	_IPMI_NETFN_APP                  = 0x6
	_IPMI_OPENIPMI_READ_TIMEOUT      = 15
	_IPMI_SYSTEM_INTERFACE_ADDR_TYPE = 0x0c

	_BMC_SET_WATCHDOG_TIMER = 0x24
	_BMC_GET_WATCHDOG_TIMER = 0x25

	_IPM_WATCHDOG_NO_ACTION    = 0x00
	_IPM_WATCHDOG_SMS_OS       = 0x04
	_IPM_WATCHDOG_CLEAR_SMS_OS = 0x10
)

var (
	_IPMICTL_RECEIVE_MSG  = iowr(_IPMI_IOC_MAGIC, 12, int(unsafe.Sizeof(recv{})))
	_IPMICTL_SEND_COMMAND = ior(_IPMI_IOC_MAGIC, 13, int(unsafe.Sizeof(req{})))
)

type Ipmi struct {
	fd int
}

type msg struct {
	netfn   byte
	cmd     byte
	dataLen uint16
	data    unsafe.Pointer
}

type req struct {
	addr    *systemInterfaceAddr
	addrLen uint32
	msgid   int64
	msg     msg
}

type recv struct {
	recvType int32
	addr     *systemInterfaceAddr
	addrLen  uint32
	msgid    int64
	msg      msg
}

type systemInterfaceAddr struct {
	addrType int32
	channel  int16
	lun      byte
}

func ioc(dir int, t int, nr int, size int) int {
	return (dir << _IOC_DIRSHIFT) | (t << _IOC_TYPESHIFT) |
		(nr << _IOC_NRSHIFT) | (size << _IOC_SIZESHIFT)
}

func ior(t int, nr int, size int) int {
	return ioc(_IOC_READ, t, nr, size)
}

func iowr(t int, nr int, size int) int {
	return ioc(_IOC_READ|_IOC_WRITE, t, nr, size)
}

func ioctl(fd int, name int, data unsafe.Pointer) syscall.Errno {
	_, _, err := syscall.RawSyscall(syscall.SYS_IOCTL, uintptr(fd), uintptr(name), uintptr(data))
	return err
}

func fd_set(fd int, p *syscall.FdSet) {
	p.Bits[fd/64] |= 1 << (uint(fd) % 64)
}

func Open(devnum int) (*Ipmi, error) {
	d := fmt.Sprintf("/dev/ipmi%d", devnum)

	f, err := os.OpenFile(d, os.O_RDWR, 0)
	if err != nil {
		return nil, err
	}

	fd := int(f.Fd())
	return &Ipmi{fd: fd}, nil
}

func (i *Ipmi) Close() error {
	return syscall.Close(i.fd)
}

func (i *Ipmi) sendrecv(req *req) (*recv, error) {
	addr := &systemInterfaceAddr{
		addrType: _IPMI_SYSTEM_INTERFACE_ADDR_TYPE,
		channel:  _IPMI_BMC_CHANNEL,
	}

	req.addr = addr
	req.addrLen = uint32(unsafe.Sizeof(addr))
	if err := ioctl(i.fd, _IPMICTL_SEND_COMMAND, unsafe.Pointer(req)); err != 0 {
		return nil, err
	}

	set := &syscall.FdSet{}
	fd_set(i.fd, set)
	time := syscall.Timeval{
		Sec:  _IPMI_OPENIPMI_READ_TIMEOUT,
		Usec: 0,
	}
	if _, err := syscall.Select(i.fd+1, set, nil, nil, &time); err != nil {
		return nil, err
	}

	recv := &recv{}
	recv.addr = &systemInterfaceAddr{}
	recv.addrLen = uint32(unsafe.Sizeof(addr))
	recv.msg.data = unsafe.Pointer(new([_IPMI_BUF_SIZE]byte))
	recv.msg.dataLen = _IPMI_BUF_SIZE
	if err := ioctl(i.fd, _IPMICTL_RECEIVE_MSG, unsafe.Pointer(recv)); err != 0 {
		return nil, err
	}

	return recv, nil
}

func (i *Ipmi) WatchdogRunning() (bool, error) {
	req := &req{}
	req.msg.cmd = _BMC_GET_WATCHDOG_TIMER
	req.msg.netfn = _IPMI_NETFN_APP

	recv, err := i.sendrecv(req)
	if err != nil {
		return false, err
	}

	use := (*[2]byte)(recv.msg.data)

	if (use[1] & 0x40) != 0 {
		return true, nil
	}

	return false, nil
}

func (i *Ipmi) ShutoffWatchdog() error {
	req := &req{}
	req.msg.cmd = _BMC_SET_WATCHDOG_TIMER
	req.msg.netfn = _IPMI_NETFN_APP

	var data [6]byte
	data[0] = _IPM_WATCHDOG_SMS_OS
	data[1] = _IPM_WATCHDOG_NO_ACTION
	data[2] = 0x00 // pretimeout interval
	data[3] = _IPM_WATCHDOG_CLEAR_SMS_OS
	data[4] = 0xb8 // countdown lsb (100 ms/count)
	data[5] = 0x0b // countdown msb - 5 mins
	req.msg.data = unsafe.Pointer(&data)
	req.msg.dataLen = 6

	_, err := i.sendrecv(req)
	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package fish

import (
	"fmt"
	"math/rand"
	"os"
	"strings"
	"time"
)

type Direction byte

const (
	Right Direction = iota
	Down
	Left
	Up
)

var reader chan byte

// Stack is a type representing a stack in ><>. It holds the stack values in S, as well as a register. The
// register may contain data, but will only be considered filled if filledRegister is also true.
type Stack struct {
	S              []float64
	register       float64
	filledRegister bool
}

// NewStack returns a pointer to a Stack populated with s.
func NewStack(s []float64) *Stack {
	return &Stack{S: s}
}

// Register implements "&".
func (s *Stack) Register() {
	if s.filledRegister {
		s.Push(s.register)
		s.filledRegister = false
	} else {
		s.register = s.Pop()
		s.filledRegister = true
	}
}

// Extend implements ":".
func (s *Stack) Extend() {
	s.Push(s.S[len(s.S)-1])
}

// Reverse implements "r".
func (s *Stack) Reverse() {
	newS := make([]float64, len(s.S))
	for i, ii := 0, len(s.S)-1; ii >= 0; i, ii = i+1, ii-1 {
		newS[i] = s.S[ii]
	}
	s.S = newS
}

// SwapTwo implements "$".
func (s *Stack) SwapTwo() {
	x := s.S[len(s.S)-1]
	s.S[len(s.S)-1] = s.S[len(s.S)-2]
	s.S[len(s.S)-2] = x
}

// SwapThree implements "@": With 1,2,3,4, calling @ results in 1,4,2,3.
func (s *Stack) SwapThree() {
	x := s.S[len(s.S)-1]
	y := s.S[len(s.S)-2]
	s.S[len(s.S)-1] = y
	s.S[len(s.S)-2] = s.S[len(s.S)-3]
	s.S[len(s.S)-3] = x
}

// ShiftRight implements "}".
func (s *Stack) ShiftRight() {
	newS := make([]float64, 1, len(s.S))
	newS[0] = s.Pop()
	s.S = append(newS, s.S...)
}

// ShiftLeft implements "{".
func (s *Stack) ShiftLeft() {
	r := s.S[0]
	s.S = s.S[1:]
	s.Push(r)
}

// Push appends r to the end of the stack.
func (s *Stack) Push(r float64) {
	s.S = append(s.S, float64(r))
}

// Pop removes the value on the end of the stack and returns it.
func (s *Stack) Pop() (r float64) {
	if len(s.S) > 0 {
		r = s.S[len(s.S)-1]
		s.S = s.S[:len(s.S)-1]
	} else {
		panic("Stack is empty!")
	}
	return
}

func longestLineLength(lines []string) (l int) {
	for _, s := range lines {
		if len(s) > l {
			l = len(s)
		}
	}
	return
}

// CodeBox is an object usually created with NewCodeBox. It contains a ><> program complete with a stack,
// and is typically run in steps via CodeBox.Swim.
type CodeBox struct {
	Fx, Fy        int
	FDir          Direction
	Width, Height int
	Box           [][]byte
	stacks        []*Stack
	p             int // Used to keep track of the current stack
	StringMode    byte
	compMode      bool
}

// NewCodeBox returns a pointer to a new CodeBox. "script" should be a complete ><> script, "stack" should
// be the initial stack, and compatibilityMode should be set if fishinterpreter.com behaviour is needed.
func NewCodeBox(script string, stack []float64, compatibilityMode bool) *CodeBox {
	cB := new(CodeBox)

	script = strings.Replace(script, "\r", "", -1)
	if len(script) == 0 || script == "\n" {
		panic("Cannot accept script of length 0 (No room for the fish to survive).")
	}

	lines := strings.Split(script, "\n")
	cB.Width = longestLineLength(lines)
	cB.Height = len(lines)

	cB.Box = make([][]byte, cB.Height)
	for i, s := range lines {
		cB.Box[i] = make([]byte, cB.Width)
		for ii, r := 0, byte(0); ii < cB.Width; ii++ {
			if ii < len(s) {
				r = byte(s[ii])
			} else {
				r = ' '
			}
			cB.Box[i][ii] = byte(r)
		}
	}

	cB.stacks = []*Stack{NewStack(stack)}
	cB.compMode = compatibilityMode

	return cB
}

// Exe executes the instruction the ><> is currently on top of. It returns true when it executes ";".
func (cB *CodeBox) Exe(r byte) bool {
	switch r {
	default:
		panic(r)
	case ' ':
	case ';':
		return true
	case '>':
		cB.FDir = Right
	case 'v':
		cB.FDir = Down
	case '<':
		cB.FDir = Left
	case '^':
		cB.FDir = Up
	case '|':
		if cB.FDir == Right {
			cB.FDir = Left
		} else if cB.FDir == Left {
			cB.FDir = Right
		}
	case '_':
		if cB.FDir == Down {
			cB.FDir = Up
		} else if cB.FDir == Up {
			cB.FDir = Down
		}
	case '#':
		switch cB.FDir {
		case Right:
			cB.FDir = Left
		case Down:
			cB.FDir = Up
		case Left:
			cB.FDir = Right
		case Up:
			cB.FDir = Down
		}
	case '/':
		switch cB.FDir {
		case Right:
			cB.FDir = Up
		case Down:
			cB.FDir = Left
		case Left:
			cB.FDir = Down
		case Up:
			cB.FDir = Right
		}
	case '\\':
		switch cB.FDir {
		case Right:
			cB.FDir = Down
		case Down:
			cB.FDir = Right
		case Left:
			cB.FDir = Up
		case Up:
			cB.FDir = Left
		}
	case 'x':
		cB.FDir = Direction(rand.Int31n(4))
	case '"', '\'':
		if cB.StringMode == 0 {
			cB.StringMode = r
		} else if r == cB.StringMode {
			cB.StringMode = 0
		}
	case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
		cB.Push(float64(r - '0'))
	case 'a', 'b', 'c', 'd', 'e', 'f':
		cB.Push(float64(r - 'a' + 10))
	case '&':
		cB.Register()
	case 'o':
		print(string(byte(cB.Pop())))
	case 'n':
		fmt.Printf("%v", cB.Pop())
	case 'r':
		cB.ReverseStack()
	case '+':
		cB.Push(cB.Pop() + cB.Pop())
	case '-':
		x := cB.Pop()
		y := cB.Pop()
		cB.Push(y - x)
	case '*':
		cB.Push(cB.Pop() * cB.Pop())
	case ',':
		x := cB.Pop()
		y := cB.Pop()
		cB.Push(y / x)
	case '%':
		x := cB.Pop()
		y := cB.Pop()
		cB.Push(float64(int64(y) % int64(x)))
	case '=':
		if cB.Pop() == cB.Pop() {
			cB.Push(1)
		} else {
			cB.Push(0)
		}
	case ')':
		x := cB.Pop()
		y := cB.Pop()
		if y > x {
			cB.Push(1)
		} else {
			cB.Push(0)
		}
	case '(':
		x := cB.Pop()
		y := cB.Pop()
		if y < x {
			cB.Push(1)
		} else {
			cB.Push(0)
		}
	case '!':
		cB.Move()
	case '?':
		if cB.Pop() == 0 {
			cB.Move()
		}
	case '.':
		cB.Fy = int(cB.Pop())
		cB.Fx = int(cB.Pop())
	case ':':
		cB.ExtendStack()
	case '~':
		cB.Pop()
	case '$':
		cB.StackSwapTwo()
	case '@':
		cB.StackSwapThree()
	case '}':
		cB.StackShiftRight()
	case '{':
		cB.StackShiftLeft()
	case ']':
		cB.CloseStack()
	case '[':
		cB.NewStack(int(cB.Pop()))
	case 'l':
		cB.Push(cB.StackLength())
	case 'g':
		cB.Push(float64(cB.Box[int(cB.Pop())][int(cB.Pop())]))
	case 'p':
		cB.Box[int(cB.Pop())][int(cB.Pop())] = byte(cB.Pop())
	case 'i':
		r := float64(-1)
		b := byte(0)
		select {
		case b = <-reader:
			r = float64(b)
		default:
		}
		cB.Push(r)
	}
	return false
}

// Move changes the fish's x/y coordinates based on CodeBox.FDir.
func (cB *CodeBox) Move() {
	switch cB.FDir {
	case Right:
		cB.Fx++
		if cB.Fx >= cB.Width {
			cB.Fx = 0
		}
	case Down:
		cB.Fy++
		if cB.Fy >= cB.Height {
			cB.Fy = 0
		}
	case Left:
		cB.Fx--
		if cB.Fx < 0 {
			cB.Fx = cB.Width - 1
		}
	case Up:
		cB.Fy--
		if cB.Fy < 0 {
			cB.Fy = cB.Height - 1
		}
	}
}

// Swim causes the ><> to execute an instruction, then move. It returns true when it encounters ";".
func (cB *CodeBox) Swim() bool {
	defer func() {
		if r := recover(); r != nil {
			cB.PrintBox()
			println("something smells fishy...")
			os.Exit(1)
		}
	}()

	if r := cB.Box[cB.Fy][cB.Fx]; cB.StringMode != 0 && r != cB.StringMode {
		cB.Push(float64(r))
	} else if cB.Exe(r) {
		return true
	}
	cB.Move()
	return false
}

// Stack returns the underlying Stack slice.
func (cB *CodeBox) Stack() []float64 {
	return cB.stacks[cB.p].S
}

// Push appends r to the end of the current stack.
func (cB *CodeBox) Push(r float64) {
	cB.stacks[cB.p].Push(r)
}

// Pop removes the value on the end of the current stack and returns it.
func (cB *CodeBox) Pop() float64 {
	return cB.stacks[cB.p].Pop()
}

// StackLength implements "l" on the current stack.
func (cB *CodeBox) StackLength() float64 {
	return float64(len(cB.stacks[cB.p].S))
}

// Register implements "&" on the current stack.
func (cB *CodeBox) Register() {
	cB.stacks[cB.p].Register()
}

// ReverseStack implements "r" on the current stack.
func (cB *CodeBox) ReverseStack() {
	cB.stacks[cB.p].Reverse()
}

// ExtendStack implements ":" on the current stack.
func (cB *CodeBox) ExtendStack() {
	cB.stacks[cB.p].Extend()
}

// StackSwapTwo implements "$" on the current stack.
func (cB *CodeBox) StackSwapTwo() {
	cB.stacks[cB.p].SwapTwo()
}

// StackSwapThree implements "@" on the current stack.
func (cB *CodeBox) StackSwapThree() {
	cB.stacks[cB.p].SwapThree()
}

// StackShiftRight implements "}" on the current stack.
func (cB *CodeBox) StackShiftRight() {
	cB.stacks[cB.p].ShiftRight()
}

// StackShiftLeft implements "{" on the current stack.
func (cB *CodeBox) StackShiftLeft() {
	cB.stacks[cB.p].ShiftLeft()
}

// CloseStack implements "]".
func (cB *CodeBox) CloseStack() {
	cB.p--
	if cB.compMode {
		cB.stacks[cB.p+1].Reverse() // This is done to match the fishlanguage.com interpreter...
	}
	cB.stacks[cB.p].S = append(cB.stacks[cB.p].S, cB.stacks[cB.p+1].S...)
}

// NewStack implements "[".
func (cB *CodeBox) NewStack(n int) {
	cB.p++
	if cB.p == len(cB.stacks) {
		cB.stacks = append(cB.stacks, NewStack(cB.stacks[cB.p-1].S[len(cB.stacks[cB.p-1].S)-n:]))
		cB.stacks[cB.p-1].S = cB.stacks[cB.p-1].S[:len(cB.stacks[cB.p-1].S)-n]
	} else {
		cB.stacks[cB.p].S = cB.stacks[cB.p-1].S[len(cB.stacks[cB.p-1].S)-n:]
		cB.stacks[cB.p].filledRegister = false
	}
	if cB.compMode {
		cB.stacks[cB.p].Reverse() // This is done to match the fishlanguage.com interpreter...
	}
}

// PrintBox outputs the codebox to stdout.
func (cB *CodeBox) PrintBox() {
	println()
	for y, line := range cB.Box {
		for x, r := range line {
			if x != cB.Fx || y != cB.Fy {
				print(" " + string(rune(r)) + " ")
			} else {
				print("*" + string(rune(r)) + "*")
			}
		}
		println()
	}
}

func init() {
	rand.Seed(int64(time.Now().Nanosecond()))
	reader = make(chan byte, 1024)
	go func() {
		var err error
		b := make([]byte, 1)
		for err == nil {
			_, err = os.Stdin.Read(b)
			if err == nil {
				reader <- b[0]
			}
		}
	}()
}
<commit_msg>Minor documentation update to SwapThree<commit_after>package fish

import (
	"fmt"
	"math/rand"
	"os"
	"strings"
	"time"
)

type Direction byte

const (
	Right Direction = iota
	Down
	Left
	Up
)

var reader chan byte

// Stack is a type representing a stack in ><>. It holds the stack values in S, as well as a register. The
// register may contain data, but will only be considered filled if filledRegister is also true.
type Stack struct {
	S              []float64
	register       float64
	filledRegister bool
}

// NewStack returns a pointer to a Stack populated with s.
func NewStack(s []float64) *Stack {
	return &Stack{S: s}
}

// Register implements "&".
func (s *Stack) Register() {
	if s.filledRegister {
		s.Push(s.register)
		s.filledRegister = false
	} else {
		s.register = s.Pop()
		s.filledRegister = true
	}
}

// Extend implements ":".
func (s *Stack) Extend() {
	s.Push(s.S[len(s.S)-1])
}

// Reverse implements "r".
func (s *Stack) Reverse() {
	newS := make([]float64, len(s.S))
	for i, ii := 0, len(s.S)-1; ii >= 0; i, ii = i+1, ii-1 {
		newS[i] = s.S[ii]
	}
	s.S = newS
}

// SwapTwo implements "$".
func (s *Stack) SwapTwo() {
	x := s.S[len(s.S)-1]
	s.S[len(s.S)-1] = s.S[len(s.S)-2]
	s.S[len(s.S)-2] = x
}

// SwapThree implements "@": with [1,2,3,4], calling "@" results in [,4,2,3].
func (s *Stack) SwapThree() {
	x := s.S[len(s.S)-1]
	y := s.S[len(s.S)-2]
	s.S[len(s.S)-1] = y
	s.S[len(s.S)-2] = s.S[len(s.S)-3]
	s.S[len(s.S)-3] = x
}

// ShiftRight implements "}".
func (s *Stack) ShiftRight() {
	newS := make([]float64, 1, len(s.S))
	newS[0] = s.Pop()
	s.S = append(newS, s.S...)
}

// ShiftLeft implements "{".
func (s *Stack) ShiftLeft() {
	r := s.S[0]
	s.S = s.S[1:]
	s.Push(r)
}

// Push appends r to the end of the stack.
func (s *Stack) Push(r float64) {
	s.S = append(s.S, float64(r))
}

// Pop removes the value on the end of the stack and returns it.
func (s *Stack) Pop() (r float64) {
	if len(s.S) > 0 {
		r = s.S[len(s.S)-1]
		s.S = s.S[:len(s.S)-1]
	} else {
		panic("Stack is empty!")
	}
	return
}

func longestLineLength(lines []string) (l int) {
	for _, s := range lines {
		if len(s) > l {
			l = len(s)
		}
	}
	return
}

// CodeBox is an object usually created with NewCodeBox. It contains a ><> program complete with a stack,
// and is typically run in steps via CodeBox.Swim.
type CodeBox struct {
	Fx, Fy        int
	FDir          Direction
	Width, Height int
	Box           [][]byte
	stacks        []*Stack
	p             int // Used to keep track of the current stack
	StringMode    byte
	compMode      bool
}

// NewCodeBox returns a pointer to a new CodeBox. "script" should be a complete ><> script, "stack" should
// be the initial stack, and compatibilityMode should be set if fishinterpreter.com behaviour is needed.
func NewCodeBox(script string, stack []float64, compatibilityMode bool) *CodeBox {
	cB := new(CodeBox)

	script = strings.Replace(script, "\r", "", -1)
	if len(script) == 0 || script == "\n" {
		panic("Cannot accept script of length 0 (No room for the fish to survive).")
	}

	lines := strings.Split(script, "\n")
	cB.Width = longestLineLength(lines)
	cB.Height = len(lines)

	cB.Box = make([][]byte, cB.Height)
	for i, s := range lines {
		cB.Box[i] = make([]byte, cB.Width)
		for ii, r := 0, byte(0); ii < cB.Width; ii++ {
			if ii < len(s) {
				r = byte(s[ii])
			} else {
				r = ' '
			}
			cB.Box[i][ii] = byte(r)
		}
	}

	cB.stacks = []*Stack{NewStack(stack)}
	cB.compMode = compatibilityMode

	return cB
}

// Exe executes the instruction the ><> is currently on top of. It returns true when it executes ";".
func (cB *CodeBox) Exe(r byte) bool {
	switch r {
	default:
		panic(r)
	case ' ':
	case ';':
		return true
	case '>':
		cB.FDir = Right
	case 'v':
		cB.FDir = Down
	case '<':
		cB.FDir = Left
	case '^':
		cB.FDir = Up
	case '|':
		if cB.FDir == Right {
			cB.FDir = Left
		} else if cB.FDir == Left {
			cB.FDir = Right
		}
	case '_':
		if cB.FDir == Down {
			cB.FDir = Up
		} else if cB.FDir == Up {
			cB.FDir = Down
		}
	case '#':
		switch cB.FDir {
		case Right:
			cB.FDir = Left
		case Down:
			cB.FDir = Up
		case Left:
			cB.FDir = Right
		case Up:
			cB.FDir = Down
		}
	case '/':
		switch cB.FDir {
		case Right:
			cB.FDir = Up
		case Down:
			cB.FDir = Left
		case Left:
			cB.FDir = Down
		case Up:
			cB.FDir = Right
		}
	case '\\':
		switch cB.FDir {
		case Right:
			cB.FDir = Down
		case Down:
			cB.FDir = Right
		case Left:
			cB.FDir = Up
		case Up:
			cB.FDir = Left
		}
	case 'x':
		cB.FDir = Direction(rand.Int31n(4))
	case '"', '\'':
		if cB.StringMode == 0 {
			cB.StringMode = r
		} else if r == cB.StringMode {
			cB.StringMode = 0
		}
	case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
		cB.Push(float64(r - '0'))
	case 'a', 'b', 'c', 'd', 'e', 'f':
		cB.Push(float64(r - 'a' + 10))
	case '&':
		cB.Register()
	case 'o':
		print(string(byte(cB.Pop())))
	case 'n':
		fmt.Printf("%v", cB.Pop())
	case 'r':
		cB.ReverseStack()
	case '+':
		cB.Push(cB.Pop() + cB.Pop())
	case '-':
		x := cB.Pop()
		y := cB.Pop()
		cB.Push(y - x)
	case '*':
		cB.Push(cB.Pop() * cB.Pop())
	case ',':
		x := cB.Pop()
		y := cB.Pop()
		cB.Push(y / x)
	case '%':
		x := cB.Pop()
		y := cB.Pop()
		cB.Push(float64(int64(y) % int64(x)))
	case '=':
		if cB.Pop() == cB.Pop() {
			cB.Push(1)
		} else {
			cB.Push(0)
		}
	case ')':
		x := cB.Pop()
		y := cB.Pop()
		if y > x {
			cB.Push(1)
		} else {
			cB.Push(0)
		}
	case '(':
		x := cB.Pop()
		y := cB.Pop()
		if y < x {
			cB.Push(1)
		} else {
			cB.Push(0)
		}
	case '!':
		cB.Move()
	case '?':
		if cB.Pop() == 0 {
			cB.Move()
		}
	case '.':
		cB.Fy = int(cB.Pop())
		cB.Fx = int(cB.Pop())
	case ':':
		cB.ExtendStack()
	case '~':
		cB.Pop()
	case '$':
		cB.StackSwapTwo()
	case '@':
		cB.StackSwapThree()
	case '}':
		cB.StackShiftRight()
	case '{':
		cB.StackShiftLeft()
	case ']':
		cB.CloseStack()
	case '[':
		cB.NewStack(int(cB.Pop()))
	case 'l':
		cB.Push(cB.StackLength())
	case 'g':
		cB.Push(float64(cB.Box[int(cB.Pop())][int(cB.Pop())]))
	case 'p':
		cB.Box[int(cB.Pop())][int(cB.Pop())] = byte(cB.Pop())
	case 'i':
		r := float64(-1)
		b := byte(0)
		select {
		case b = <-reader:
			r = float64(b)
		default:
		}
		cB.Push(r)
	}
	return false
}

// Move changes the fish's x/y coordinates based on CodeBox.FDir.
func (cB *CodeBox) Move() {
	switch cB.FDir {
	case Right:
		cB.Fx++
		if cB.Fx >= cB.Width {
			cB.Fx = 0
		}
	case Down:
		cB.Fy++
		if cB.Fy >= cB.Height {
			cB.Fy = 0
		}
	case Left:
		cB.Fx--
		if cB.Fx < 0 {
			cB.Fx = cB.Width - 1
		}
	case Up:
		cB.Fy--
		if cB.Fy < 0 {
			cB.Fy = cB.Height - 1
		}
	}
}

// Swim causes the ><> to execute an instruction, then move. It returns true when it encounters ";".
func (cB *CodeBox) Swim() bool {
	defer func() {
		if r := recover(); r != nil {
			cB.PrintBox()
			println("something smells fishy...")
			os.Exit(1)
		}
	}()

	if r := cB.Box[cB.Fy][cB.Fx]; cB.StringMode != 0 && r != cB.StringMode {
		cB.Push(float64(r))
	} else if cB.Exe(r) {
		return true
	}
	cB.Move()
	return false
}

// Stack returns the underlying Stack slice.
func (cB *CodeBox) Stack() []float64 {
	return cB.stacks[cB.p].S
}

// Push appends r to the end of the current stack.
func (cB *CodeBox) Push(r float64) {
	cB.stacks[cB.p].Push(r)
}

// Pop removes the value on the end of the current stack and returns it.
func (cB *CodeBox) Pop() float64 {
	return cB.stacks[cB.p].Pop()
}

// StackLength implements "l" on the current stack.
func (cB *CodeBox) StackLength() float64 {
	return float64(len(cB.stacks[cB.p].S))
}

// Register implements "&" on the current stack.
func (cB *CodeBox) Register() {
	cB.stacks[cB.p].Register()
}

// ReverseStack implements "r" on the current stack.
func (cB *CodeBox) ReverseStack() {
	cB.stacks[cB.p].Reverse()
}

// ExtendStack implements ":" on the current stack.
func (cB *CodeBox) ExtendStack() {
	cB.stacks[cB.p].Extend()
}

// StackSwapTwo implements "$" on the current stack.
func (cB *CodeBox) StackSwapTwo() {
	cB.stacks[cB.p].SwapTwo()
}

// StackSwapThree implements "@" on the current stack.
func (cB *CodeBox) StackSwapThree() {
	cB.stacks[cB.p].SwapThree()
}

// StackShiftRight implements "}" on the current stack.
func (cB *CodeBox) StackShiftRight() {
	cB.stacks[cB.p].ShiftRight()
}

// StackShiftLeft implements "{" on the current stack.
func (cB *CodeBox) StackShiftLeft() {
	cB.stacks[cB.p].ShiftLeft()
}

// CloseStack implements "]".
func (cB *CodeBox) CloseStack() {
	cB.p--
	if cB.compMode {
		cB.stacks[cB.p+1].Reverse() // This is done to match the fishlanguage.com interpreter...
	}
	cB.stacks[cB.p].S = append(cB.stacks[cB.p].S, cB.stacks[cB.p+1].S...)
}

// NewStack implements "[".
func (cB *CodeBox) NewStack(n int) {
	cB.p++
	if cB.p == len(cB.stacks) {
		cB.stacks = append(cB.stacks, NewStack(cB.stacks[cB.p-1].S[len(cB.stacks[cB.p-1].S)-n:]))
		cB.stacks[cB.p-1].S = cB.stacks[cB.p-1].S[:len(cB.stacks[cB.p-1].S)-n]
	} else {
		cB.stacks[cB.p].S = cB.stacks[cB.p-1].S[len(cB.stacks[cB.p-1].S)-n:]
		cB.stacks[cB.p].filledRegister = false
	}
	if cB.compMode {
		cB.stacks[cB.p].Reverse() // This is done to match the fishlanguage.com interpreter...
	}
}

// PrintBox outputs the codebox to stdout.
func (cB *CodeBox) PrintBox() {
	println()
	for y, line := range cB.Box {
		for x, r := range line {
			if x != cB.Fx || y != cB.Fy {
				print(" " + string(rune(r)) + " ")
			} else {
				print("*" + string(rune(r)) + "*")
			}
		}
		println()
	}
}

func init() {
	rand.Seed(int64(time.Now().Nanosecond()))
	reader = make(chan byte, 1024)
	go func() {
		var err error
		b := make([]byte, 1)
		for err == nil {
			_, err = os.Stdin.Read(b)
			if err == nil {
				reader <- b[0]
			}
		}
	}()
}
<|endoftext|>


<commit_before>// Copyright 2016-2017 Authors of Cilium
//
// 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 policy

import (
	"bytes"
	"encoding/json"
	"fmt"
	"sort"
	"strconv"
	"strings"

	"github.com/cilium/cilium/api/v1/models"
	"github.com/cilium/cilium/pkg/identity"
	"github.com/cilium/cilium/pkg/labels"
	"github.com/cilium/cilium/pkg/policy/api"
	"github.com/cilium/cilium/pkg/u8proto"
)

var (
	// WildcardEndpointSelector is a selector that matches on all endpoints
	WildcardEndpointSelector = api.NewWildcardEndpointSelector()
)

// L7DataMap contains a map of L7 rules per endpoint where key is a hash of EndpointSelector
type L7DataMap map[api.EndpointSelector]api.L7Rules

func (l7 L7DataMap) MarshalJSON() ([]byte, error) {
	if len(l7) == 0 {
		return []byte("[]"), nil
	}

	/* First, create a sorted slice of the selectors so we can get
	 * consistent JSON output */
	selectors := make(api.EndpointSelectorSlice, 0, len(l7))
	for es := range l7 {
		selectors = append(selectors, es)
	}
	sort.Sort(selectors)

	/* Now we can iterate the slice and generate JSON entries. */
	var err error
	buffer := bytes.NewBufferString("[")
	for _, es := range selectors {
		buffer.WriteString("{\"")
		buffer.WriteString(es.LabelSelectorString())
		buffer.WriteString("\":")
		b, err := json.Marshal(l7[es])
		if err == nil {
			buffer.Write(b)
		} else {
			buffer.WriteString("\"L7DataMap error: ")
			buffer.WriteString(err.Error())
			buffer.WriteString("\"")
		}
		buffer.WriteString("},")
	}
	buffer.Truncate(buffer.Len() - 1) // Drop the final ","
	buffer.WriteString("]")

	return buffer.Bytes(), err
}

// L7ParserType is the type used to indicate what L7 parser to use and
// defines all supported types of L7 parsers
type L7ParserType string

const (
	// ParserTypeHTTP specifies a HTTP parser type
	ParserTypeHTTP L7ParserType = "http"
	// ParserTypeKafka specifies a Kafka parser type
	ParserTypeKafka L7ParserType = "kafka"
)

type L4Filter struct {
	// Port is the destination port to allow
	Port int `json:"port"`
	// Protocol is the L4 protocol to allow or NONE
	Protocol api.L4Proto `json:"protocol"`
	// U8Proto is the Protocol in numeric format, or 0 for NONE
	U8Proto u8proto.U8proto `json:"-"`
	// FromEndpoints limit the source labels for allowing traffic. If
	// FromEndpoints is empty, then it selects all endpoints.
	FromEndpoints []api.EndpointSelector `json:"-"`
	// L7Parser specifies the L7 protocol parser (optional)
	L7Parser L7ParserType `json:"-"`
	// L7RulesPerEp is a list of L7 rules per endpoint passed to the L7 proxy (optional)
	L7RulesPerEp L7DataMap `json:"l7-rules,omitempty"`
	// Ingress is true if filter applies at ingress
	Ingress bool `json:"-"`
	// The rule labels of this Filter
	DerivedFromRules labels.LabelArrayList `json:"-"`
}

// GetRelevantRules returns the relevant rules based on the source and
// destination addressing/identity information.
func (dm L7DataMap) GetRelevantRules(identity *identity.Identity) api.L7Rules {
	rules := api.L7Rules{}
	matched := 0

	if identity != nil {
		for selector, endpointRules := range dm {
			if selector.Matches(identity.Labels.LabelArray()) {
				matched++
				rules.HTTP = append(rules.HTTP, endpointRules.HTTP...)
				rules.Kafka = append(rules.Kafka, endpointRules.Kafka...)
			}
		}
	}

	if matched == 0 {
		// Fall back to wildcard selector
		if rules, ok := dm[WildcardEndpointSelector]; ok {
			return rules
		}
	}

	return rules
}

func (dm L7DataMap) addRulesForEndpoints(rules api.L7Rules, fromEndpoints []api.EndpointSelector) {
	if rules.Len() == 0 {
		return
	}

	if len(fromEndpoints) > 0 {
		for _, ep := range fromEndpoints {
			dm[ep] = api.L7Rules{
				HTTP:  append(dm[ep].HTTP, rules.HTTP...),
				Kafka: append(dm[ep].Kafka, rules.Kafka...),
			}
		}
	} else {
		// If there are no explicit fromEps, have a 'special' wildcard endpoint.
		dm[WildcardEndpointSelector] = api.L7Rules{
			HTTP:  append(dm[WildcardEndpointSelector].HTTP, rules.HTTP...),
			Kafka: append(dm[WildcardEndpointSelector].Kafka, rules.Kafka...),
		}
	}
}

// CreateL4Filter creates an L4Filter for the specified api.PortProtocol in
// the direction ("ingress"/"egress") for a particular protocol.
// This L4Filter will only apply to endpoints covered by `fromEndpoints`.
// `rule` allows a series of L7 rules to be associated with this L4Filter.
func CreateL4Filter(fromEndpoints []api.EndpointSelector, rule api.PortRule, port api.PortProtocol,
	direction string, protocol api.L4Proto, ruleLabels labels.LabelArray) L4Filter {

	// already validated via PortRule.Validate()
	p, _ := strconv.ParseUint(port.Port, 0, 16)
	// already validated via L4Proto.Validate()
	u8p, _ := u8proto.ParseProtocol(string(protocol))

	l4 := L4Filter{
		Port:             int(p),
		Protocol:         protocol,
		U8Proto:          u8p,
		L7RulesPerEp:     make(L7DataMap),
		FromEndpoints:    fromEndpoints,
		DerivedFromRules: labels.LabelArrayList{ruleLabels},
	}

	if strings.ToLower(direction) == "ingress" {
		l4.Ingress = true
	}

	if protocol == api.ProtoTCP && rule.Rules != nil {
		switch {
		case len(rule.Rules.HTTP) > 0:
			l4.L7Parser = ParserTypeHTTP
		case len(rule.Rules.Kafka) > 0:
			l4.L7Parser = ParserTypeKafka
		}

		l4.L7RulesPerEp.addRulesForEndpoints(*rule.Rules, fromEndpoints)
	}

	return l4
}

// IsRedirect returns true if the L4 filter contains a port redirection
func (l4 *L4Filter) IsRedirect() bool {
	return l4.L7Parser != ""
}

// MarshalIndent returns the `L4Filter` in indented JSON string.
func (l4 *L4Filter) MarshalIndent() string {
	b, err := json.MarshalIndent(l4, "", "  ")
	if err != nil {
		b = []byte("\"L4Filter error: " + err.Error() + "\"")
	}
	return string(b)
}

// String returns the `L4Filter` in a human-readable string.
func (l4 L4Filter) String() string {
	b, err := json.Marshal(l4)
	if err != nil {
		return err.Error()
	}
	return string(b)
}

func (l4 L4Filter) matchesLabels(labels labels.LabelArray) bool {
	if len(l4.FromEndpoints) == 0 {
		return true
	} else if len(labels) == 0 {
		return false
	}

	for _, sel := range l4.FromEndpoints {
		if sel.Matches(labels) {
			return true
		}
	}

	return false
}

// L4PolicyMap is a list of L4 filters indexable by protocol/port
// key format: "port/proto"
type L4PolicyMap map[string]L4Filter

// HasRedirect returns true if at least one L4 filter contains a port
// redirection
func (l4 L4PolicyMap) HasRedirect() bool {
	for _, f := range l4 {
		if f.IsRedirect() {
			return true
		}
	}

	return false
}

// containsAllL3L4 checks if the L4PolicyMap contains all L4 ports in `ports`.
// For L4Filters that specify FromEndpoints, uses `labels` to determine whether
// the policy allows L4 communication between the corresponding endpoints.
// Returns api.Denied in the following conditions:
// * If the `L4PolicyMap` has at least one rule and `ports` is empty.
// * If a single port is not present in the `L4PolicyMap`.
// * If a port is present in the `L4PolicyMap`, but it applies FromEndpoints
//   constraints that require labels not present in `labels`.
// Otherwise, returns api.Allowed.
func (l4 L4PolicyMap) containsAllL3L4(labels labels.LabelArray, ports []*models.Port) api.Decision {
	if len(l4) == 0 {
		return api.Allowed
	}

	if len(ports) == 0 {
		return api.Denied
	}

	for _, l4CtxIng := range ports {
		lwrProtocol := l4CtxIng.Protocol
		switch lwrProtocol {
		case "", models.PortProtocolANY:
			tcpPort := fmt.Sprintf("%d/TCP", l4CtxIng.Port)
			tcpFilter, tcpmatch := l4[tcpPort]
			if tcpmatch {
				tcpmatch = tcpFilter.matchesLabels(labels)
			}
			udpPort := fmt.Sprintf("%d/UDP", l4CtxIng.Port)
			udpFilter, udpmatch := l4[udpPort]
			if udpmatch {
				udpmatch = udpFilter.matchesLabels(labels)
			}
			if !tcpmatch && !udpmatch {
				return api.Denied
			}
		default:
			port := fmt.Sprintf("%d/%s", l4CtxIng.Port, lwrProtocol)
			filter, match := l4[port]
			if !match || !filter.matchesLabels(labels) {
				return api.Denied
			}
		}
	}
	return api.Allowed
}

type L4Policy struct {
	Ingress L4PolicyMap
	Egress  L4PolicyMap
}

func NewL4Policy() *L4Policy {
	return &L4Policy{
		Ingress: L4PolicyMap{},
		Egress:  L4PolicyMap{},
	}
}

// IngressCoversDPorts checks if the receiver's ingress `L4Policy` contains all
// `dPorts`.
func (l4 *L4Policy) IngressCoversDPorts(dPorts []*models.Port) api.Decision {
	return l4.Ingress.containsAllL3L4(labels.LabelArray{}, dPorts)
}

// IngressCoversContext checks if the receiver's ingress `L4Policy` contains
// all `dPorts` and `labels`.
func (l4 *L4Policy) IngressCoversContext(ctx *SearchContext) api.Decision {
	return l4.Ingress.containsAllL3L4(ctx.From, ctx.DPorts)
}

// EgressCoversDPorts checks if the receiver's egress `L4Policy` contains all
// `dPorts`.
func (l4 *L4Policy) EgressCoversDPorts(dPorts []*models.Port) api.Decision {
	return l4.Egress.containsAllL3L4(labels.LabelArray{}, dPorts)
}

// HasRedirect returns true if the L4 policy contains at least one port redirection
func (l4 *L4Policy) HasRedirect() bool {
	return l4 != nil && (l4.Ingress.HasRedirect() || l4.Egress.HasRedirect())
}

// RequiresConntrack returns true if if the L4 configuration requires
// connection tracking to be enabled.
func (l4 *L4Policy) RequiresConntrack() bool {
	return l4 != nil && (len(l4.Ingress) > 0 || len(l4.Egress) > 0)
}

func (l4 *L4Policy) GetModel() *models.L4Policy {
	if l4 == nil {
		return nil
	}

	ingress := []*models.PolicyRule{}
	for _, v := range l4.Ingress {
		ingress = append(ingress, &models.PolicyRule{
			Rule:             v.MarshalIndent(),
			DerivedFromRules: v.DerivedFromRules.GetModel(),
		})
	}

	egress := []*models.PolicyRule{}
	for _, v := range l4.Egress {
		egress = append(egress, &models.PolicyRule{
			Rule:             v.MarshalIndent(),
			DerivedFromRules: v.DerivedFromRules.GetModel(),
		})
	}

	return &models.L4Policy{
		Ingress: ingress,
		Egress:  egress,
	}
}
<commit_msg>policy: Simplify L7PolicyMap creation.<commit_after>// Copyright 2016-2017 Authors of Cilium
//
// 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 policy

import (
	"bytes"
	"encoding/json"
	"fmt"
	"sort"
	"strconv"
	"strings"

	"github.com/cilium/cilium/api/v1/models"
	"github.com/cilium/cilium/pkg/identity"
	"github.com/cilium/cilium/pkg/labels"
	"github.com/cilium/cilium/pkg/policy/api"
	"github.com/cilium/cilium/pkg/u8proto"
)

var (
	// WildcardEndpointSelector is a selector that matches on all endpoints
	WildcardEndpointSelector = api.NewWildcardEndpointSelector()
)

// L7DataMap contains a map of L7 rules per endpoint where key is a hash of EndpointSelector
type L7DataMap map[api.EndpointSelector]api.L7Rules

func (l7 L7DataMap) MarshalJSON() ([]byte, error) {
	if len(l7) == 0 {
		return []byte("[]"), nil
	}

	/* First, create a sorted slice of the selectors so we can get
	 * consistent JSON output */
	selectors := make(api.EndpointSelectorSlice, 0, len(l7))
	for es := range l7 {
		selectors = append(selectors, es)
	}
	sort.Sort(selectors)

	/* Now we can iterate the slice and generate JSON entries. */
	var err error
	buffer := bytes.NewBufferString("[")
	for _, es := range selectors {
		buffer.WriteString("{\"")
		buffer.WriteString(es.LabelSelectorString())
		buffer.WriteString("\":")
		b, err := json.Marshal(l7[es])
		if err == nil {
			buffer.Write(b)
		} else {
			buffer.WriteString("\"L7DataMap error: ")
			buffer.WriteString(err.Error())
			buffer.WriteString("\"")
		}
		buffer.WriteString("},")
	}
	buffer.Truncate(buffer.Len() - 1) // Drop the final ","
	buffer.WriteString("]")

	return buffer.Bytes(), err
}

// L7ParserType is the type used to indicate what L7 parser to use and
// defines all supported types of L7 parsers
type L7ParserType string

const (
	// ParserTypeHTTP specifies a HTTP parser type
	ParserTypeHTTP L7ParserType = "http"
	// ParserTypeKafka specifies a Kafka parser type
	ParserTypeKafka L7ParserType = "kafka"
)

type L4Filter struct {
	// Port is the destination port to allow
	Port int `json:"port"`
	// Protocol is the L4 protocol to allow or NONE
	Protocol api.L4Proto `json:"protocol"`
	// U8Proto is the Protocol in numeric format, or 0 for NONE
	U8Proto u8proto.U8proto `json:"-"`
	// FromEndpoints limit the source labels for allowing traffic. If
	// FromEndpoints is empty, then it selects all endpoints.
	FromEndpoints []api.EndpointSelector `json:"-"`
	// L7Parser specifies the L7 protocol parser (optional)
	L7Parser L7ParserType `json:"-"`
	// L7RulesPerEp is a list of L7 rules per endpoint passed to the L7 proxy (optional)
	L7RulesPerEp L7DataMap `json:"l7-rules,omitempty"`
	// Ingress is true if filter applies at ingress
	Ingress bool `json:"-"`
	// The rule labels of this Filter
	DerivedFromRules labels.LabelArrayList `json:"-"`
}

// GetRelevantRules returns the relevant rules based on the source and
// destination addressing/identity information.
func (dm L7DataMap) GetRelevantRules(identity *identity.Identity) api.L7Rules {
	rules := api.L7Rules{}
	matched := 0

	if identity != nil {
		for selector, endpointRules := range dm {
			if selector.Matches(identity.Labels.LabelArray()) {
				matched++
				rules.HTTP = append(rules.HTTP, endpointRules.HTTP...)
				rules.Kafka = append(rules.Kafka, endpointRules.Kafka...)
			}
		}
	}

	if matched == 0 {
		// Fall back to wildcard selector
		if rules, ok := dm[WildcardEndpointSelector]; ok {
			return rules
		}
	}

	return rules
}

func (dm L7DataMap) addRulesForEndpoints(rules api.L7Rules, fromEndpoints []api.EndpointSelector) {
	if rules.Len() == 0 {
		return
	}

	if len(fromEndpoints) > 0 {
		for _, epsel := range fromEndpoints {
			dm[epsel] = rules
		}
	} else {
		// If there are no explicit fromEps, have a 'special' wildcard endpoint.
		dm[WildcardEndpointSelector] = rules
	}
}

// CreateL4Filter creates an L4Filter for the specified api.PortProtocol in
// the direction ("ingress"/"egress") for a particular protocol.
// This L4Filter will only apply to endpoints covered by `fromEndpoints`.
// `rule` allows a series of L7 rules to be associated with this L4Filter.
func CreateL4Filter(fromEndpoints []api.EndpointSelector, rule api.PortRule, port api.PortProtocol,
	direction string, protocol api.L4Proto, ruleLabels labels.LabelArray) L4Filter {

	// already validated via PortRule.Validate()
	p, _ := strconv.ParseUint(port.Port, 0, 16)
	// already validated via L4Proto.Validate()
	u8p, _ := u8proto.ParseProtocol(string(protocol))

	l4 := L4Filter{
		Port:             int(p),
		Protocol:         protocol,
		U8Proto:          u8p,
		L7RulesPerEp:     make(L7DataMap),
		FromEndpoints:    fromEndpoints,
		DerivedFromRules: labels.LabelArrayList{ruleLabels},
	}

	if strings.ToLower(direction) == "ingress" {
		l4.Ingress = true
	}

	if protocol == api.ProtoTCP && rule.Rules != nil {
		switch {
		case len(rule.Rules.HTTP) > 0:
			l4.L7Parser = ParserTypeHTTP
		case len(rule.Rules.Kafka) > 0:
			l4.L7Parser = ParserTypeKafka
		}

		l4.L7RulesPerEp.addRulesForEndpoints(*rule.Rules, fromEndpoints)
	}

	return l4
}

// IsRedirect returns true if the L4 filter contains a port redirection
func (l4 *L4Filter) IsRedirect() bool {
	return l4.L7Parser != ""
}

// MarshalIndent returns the `L4Filter` in indented JSON string.
func (l4 *L4Filter) MarshalIndent() string {
	b, err := json.MarshalIndent(l4, "", "  ")
	if err != nil {
		b = []byte("\"L4Filter error: " + err.Error() + "\"")
	}
	return string(b)
}

// String returns the `L4Filter` in a human-readable string.
func (l4 L4Filter) String() string {
	b, err := json.Marshal(l4)
	if err != nil {
		return err.Error()
	}
	return string(b)
}

func (l4 L4Filter) matchesLabels(labels labels.LabelArray) bool {
	if len(l4.FromEndpoints) == 0 {
		return true
	} else if len(labels) == 0 {
		return false
	}

	for _, sel := range l4.FromEndpoints {
		if sel.Matches(labels) {
			return true
		}
	}

	return false
}

// L4PolicyMap is a list of L4 filters indexable by protocol/port
// key format: "port/proto"
type L4PolicyMap map[string]L4Filter

// HasRedirect returns true if at least one L4 filter contains a port
// redirection
func (l4 L4PolicyMap) HasRedirect() bool {
	for _, f := range l4 {
		if f.IsRedirect() {
			return true
		}
	}

	return false
}

// containsAllL3L4 checks if the L4PolicyMap contains all L4 ports in `ports`.
// For L4Filters that specify FromEndpoints, uses `labels` to determine whether
// the policy allows L4 communication between the corresponding endpoints.
// Returns api.Denied in the following conditions:
// * If the `L4PolicyMap` has at least one rule and `ports` is empty.
// * If a single port is not present in the `L4PolicyMap`.
// * If a port is present in the `L4PolicyMap`, but it applies FromEndpoints
//   constraints that require labels not present in `labels`.
// Otherwise, returns api.Allowed.
func (l4 L4PolicyMap) containsAllL3L4(labels labels.LabelArray, ports []*models.Port) api.Decision {
	if len(l4) == 0 {
		return api.Allowed
	}

	if len(ports) == 0 {
		return api.Denied
	}

	for _, l4CtxIng := range ports {
		lwrProtocol := l4CtxIng.Protocol
		switch lwrProtocol {
		case "", models.PortProtocolANY:
			tcpPort := fmt.Sprintf("%d/TCP", l4CtxIng.Port)
			tcpFilter, tcpmatch := l4[tcpPort]
			if tcpmatch {
				tcpmatch = tcpFilter.matchesLabels(labels)
			}
			udpPort := fmt.Sprintf("%d/UDP", l4CtxIng.Port)
			udpFilter, udpmatch := l4[udpPort]
			if udpmatch {
				udpmatch = udpFilter.matchesLabels(labels)
			}
			if !tcpmatch && !udpmatch {
				return api.Denied
			}
		default:
			port := fmt.Sprintf("%d/%s", l4CtxIng.Port, lwrProtocol)
			filter, match := l4[port]
			if !match || !filter.matchesLabels(labels) {
				return api.Denied
			}
		}
	}
	return api.Allowed
}

type L4Policy struct {
	Ingress L4PolicyMap
	Egress  L4PolicyMap
}

func NewL4Policy() *L4Policy {
	return &L4Policy{
		Ingress: L4PolicyMap{},
		Egress:  L4PolicyMap{},
	}
}

// IngressCoversDPorts checks if the receiver's ingress `L4Policy` contains all
// `dPorts`.
func (l4 *L4Policy) IngressCoversDPorts(dPorts []*models.Port) api.Decision {
	return l4.Ingress.containsAllL3L4(labels.LabelArray{}, dPorts)
}

// IngressCoversContext checks if the receiver's ingress `L4Policy` contains
// all `dPorts` and `labels`.
func (l4 *L4Policy) IngressCoversContext(ctx *SearchContext) api.Decision {
	return l4.Ingress.containsAllL3L4(ctx.From, ctx.DPorts)
}

// EgressCoversDPorts checks if the receiver's egress `L4Policy` contains all
// `dPorts`.
func (l4 *L4Policy) EgressCoversDPorts(dPorts []*models.Port) api.Decision {
	return l4.Egress.containsAllL3L4(labels.LabelArray{}, dPorts)
}

// HasRedirect returns true if the L4 policy contains at least one port redirection
func (l4 *L4Policy) HasRedirect() bool {
	return l4 != nil && (l4.Ingress.HasRedirect() || l4.Egress.HasRedirect())
}

// RequiresConntrack returns true if if the L4 configuration requires
// connection tracking to be enabled.
func (l4 *L4Policy) RequiresConntrack() bool {
	return l4 != nil && (len(l4.Ingress) > 0 || len(l4.Egress) > 0)
}

func (l4 *L4Policy) GetModel() *models.L4Policy {
	if l4 == nil {
		return nil
	}

	ingress := []*models.PolicyRule{}
	for _, v := range l4.Ingress {
		ingress = append(ingress, &models.PolicyRule{
			Rule:             v.MarshalIndent(),
			DerivedFromRules: v.DerivedFromRules.GetModel(),
		})
	}

	egress := []*models.PolicyRule{}
	for _, v := range l4.Egress {
		egress = append(egress, &models.PolicyRule{
			Rule:             v.MarshalIndent(),
			DerivedFromRules: v.DerivedFromRules.GetModel(),
		})
	}

	return &models.L4Policy{
		Ingress: ingress,
		Egress:  egress,
	}
}
<|endoftext|>


<commit_before>// The Ruby package is used to provision ruby on a host.
//
// Ruby will be downloaded, extracted, configured, built, and installed to `/opt/ruby-{{ .Version }}`. If the `Bundle`
// flag is set, bundler will be installed.
package ruby

import (
	"fmt"
	"github.com/dynport/urknall"
	. "github.com/dynport/urknall/cmd"
	"strings"
)

func New(version string) *Package {
	return &Package{
		Version: version,
	}
}

type Package struct {
	Version     string `urknall:"default=2.0.0-p247"`
	WithBundler bool
}

func (ruby *Package) Package(r *urknall.Runlist) {
	r.Add(
		InstallPackages("curl", "build-essential", "git-core",
			"libyaml-dev", "libxml2-dev", "libxslt1-dev",
			"libreadline-dev", "libssl-dev", "zlib1g-dev"))

	r.Add(
		DownloadAndExtract(ruby.downloadURL(), "/opt/src"))

	r.Add(
		And("cd {{ .SourcePath }}",
			"./configure --disable-install-doc --prefix={{ .InstallPath }}",
			"make",
			"make install"))

	if ruby.WithBundler {
		r.Add("{{ .InstallPath }}/bin/gem install bundler")
	}
}

func (ruby *Package) downloadURL() string {
	majorVersion := strings.Join(strings.Split(ruby.Version, ".")[0:2], ".")
	return fmt.Sprintf("http://ftp.ruby-lang.org/pub/ruby/%s/ruby-%s.tar.gz", majorVersion, ruby.Version)
}

func (ruby *Package) InstallPath() string {
	return fmt.Sprintf("/opt/ruby-%s", ruby.Version)
}

func (ruby *Package) SourcePath() string {
	return fmt.Sprintf("/opt/src/ruby-%s", ruby.Version)
}
<commit_msg>do nor install git-core in ruby package<commit_after>// The Ruby package is used to provision ruby on a host.
//
// Ruby will be downloaded, extracted, configured, built, and installed to `/opt/ruby-{{ .Version }}`. If the `Bundle`
// flag is set, bundler will be installed.
package ruby

import (
	"fmt"
	"github.com/dynport/urknall"
	. "github.com/dynport/urknall/cmd"
	"strings"
)

func New(version string) *Package {
	return &Package{
		Version: version,
	}
}

type Package struct {
	Version     string `urknall:"default=2.0.0-p247"`
	WithBundler bool
}

func (ruby *Package) Package(r *urknall.Runlist) {
	r.Add(
		InstallPackages("curl", "build-essential",
			"libyaml-dev", "libxml2-dev", "libxslt1-dev",
			"libreadline-dev", "libssl-dev", "zlib1g-dev"))

	r.Add(
		DownloadAndExtract(ruby.downloadURL(), "/opt/src"))

	r.Add(
		And("cd {{ .SourcePath }}",
			"./configure --disable-install-doc --prefix={{ .InstallPath }}",
			"make",
			"make install"))

	if ruby.WithBundler {
		r.Add("{{ .InstallPath }}/bin/gem install bundler")
	}
}

func (ruby *Package) downloadURL() string {
	majorVersion := strings.Join(strings.Split(ruby.Version, ".")[0:2], ".")
	return fmt.Sprintf("http://ftp.ruby-lang.org/pub/ruby/%s/ruby-%s.tar.gz", majorVersion, ruby.Version)
}

func (ruby *Package) InstallPath() string {
	return fmt.Sprintf("/opt/ruby-%s", ruby.Version)
}

func (ruby *Package) SourcePath() string {
	return fmt.Sprintf("/opt/src/ruby-%s", ruby.Version)
}
<|endoftext|>


<commit_before>package pkg

import (
	"archive/zip"
	"fmt"
	"regexp"
)

// zipWalker walks a .zip (or .pivotal) file implementing the Walker interface
type zipWalker struct {
	zipPath   string
	callbacks map[*regexp.Regexp]WalkFunc
}

// NewZipWalker creates a new Walker instance that can read a .zip stream
func NewZipWalker(zipFile string) Walker {
	return zipWalker{
		zipPath:   zipFile,
		callbacks: make(map[*regexp.Regexp]WalkFunc),
	}
}

func (z zipWalker) OnMatch(regexExpr string, fn WalkFunc) {
	regex, err := regexp.Compile(regexExpr)
	if err != nil {
		// this indicates a programming error, not something that should normally happen
		panic(err.Error())
	}
	z.callbacks[regex] = fn
}

func (z zipWalker) Walk() error {
	zr, err := zip.OpenReader(z.zipPath)
	if err != nil {
		return err
	}
	for _, zipFile := range zr.File {
		if !zipFile.FileInfo().IsDir() {
			fmt.Println(zipFile.Name)
			for regex, fn := range z.callbacks {
				if regex.MatchString(zipFile.Name) {
					r, err := zipFile.Open()
					if err != nil {
						return err
					}
					fn(FileEntry{
						FileName: zipFile.Name,
						Reader:   r,
					})
				}
			}
		}
	}
	return nil
}
<commit_msg>Remove debug print<commit_after>package pkg

import (
	"archive/zip"
	"regexp"
)

// zipWalker walks a .zip (or .pivotal) file implementing the Walker interface
type zipWalker struct {
	zipPath   string
	callbacks map[*regexp.Regexp]WalkFunc
}

// NewZipWalker creates a new Walker instance that can read a .zip stream
func NewZipWalker(zipFile string) Walker {
	return zipWalker{
		zipPath:   zipFile,
		callbacks: make(map[*regexp.Regexp]WalkFunc),
	}
}

func (z zipWalker) OnMatch(regexExpr string, fn WalkFunc) {
	regex, err := regexp.Compile(regexExpr)
	if err != nil {
		// this indicates a programming error, not something that should normally happen
		panic(err.Error())
	}
	z.callbacks[regex] = fn
}

func (z zipWalker) Walk() error {
	zr, err := zip.OpenReader(z.zipPath)
	if err != nil {
		return err
	}
	for _, zipFile := range zr.File {
		if !zipFile.FileInfo().IsDir() {
			for regex, fn := range z.callbacks {
				if regex.MatchString(zipFile.Name) {
					r, err := zipFile.Open()
					if err != nil {
						return err
					}
					fn(FileEntry{
						FileName: zipFile.Name,
						Reader:   r,
					})
				}
			}
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package players

import "strings"

func (r *Repo) Floor() []Player {
	floor := func(p1, p2 Player) bool {
		return p1.Floor > p2.Floor
	}
	return r.group(floor, 3)
}

func (r *Repo) FloorByPos(pos string) []Player {
    plyrs := filter(r.UnDrafted, func (p Player) bool {
        return strings.ToUpper(pos) == strings.ToUpper(p.Position)
    })
    floor := func(p1, p2 Player) bool {
        return p1.Floor > p2.Floor
    }
    By(floor).Sort(plyrs)
    return plyrs[:min(30, len(plyrs))]
}

func (r *Repo) Ceil() []Player {
	ceil := func(p1, p2 Player) bool {
		return p1.Ceil > p2.Ceil
	}
	return r.group(ceil, 3)
}

func (r *Repo) CeilByPos(pos string) []Player {
    plyrs := filter(r.UnDrafted, func (p Player) bool {
        return strings.ToUpper(pos) == strings.ToUpper(p.Position)
    })
    ceil := func(p1, p2 Player) bool {
        return p1.Ceil > p2.Ceil
    }
    By(ceil).Sort(plyrs)
    return plyrs[:min(30, len(plyrs))]
}

func (r *Repo) Team(name string) []Player {
	floor := func(p1, p2 Player) bool {
		return p1.Floor > p2.Floor
	}
	grouped := r.group(floor, 1000)
	return filter(grouped, func(p Player) bool {
		return strings.ToUpper(name) == strings.ToUpper(p.Team) || p.Team == ""
	})
}

func (r *Repo) group(sortFunc By, max int) []Player {
	results := []Player{}
	for _, pos := range OrderedPositions() {
		undrafted := filter(r.UnDrafted, func(p Player) bool {
			return p.Position == pos
		})
		By(sortFunc).Sort(undrafted)
		l := limit(undrafted, max)
		results = append(results, Player{})
		results = append(results, l...)
	}
	return results
}

func limit(plyrs []Player, max int) []Player {
	if len(plyrs) == 0 {
		return plyrs
	}
	index := min(max, len(plyrs))
	return plyrs[:index]
}

func min(i, j int) int {
	if i < j {
		return i
	} else {
		return j
	}
}
<commit_msg>make floor and ceil list top 5<commit_after>package players

import "strings"

func (r *Repo) Floor() []Player {
	floor := func(p1, p2 Player) bool {
		return p1.Floor > p2.Floor
	}
	return r.group(floor, 5)
}

func (r *Repo) FloorByPos(pos string) []Player {
    plyrs := filter(r.UnDrafted, func (p Player) bool {
        return strings.ToUpper(pos) == strings.ToUpper(p.Position)
    })
    floor := func(p1, p2 Player) bool {
        return p1.Floor > p2.Floor
    }
    By(floor).Sort(plyrs)
    return plyrs[:min(30, len(plyrs))]
}

func (r *Repo) Ceil() []Player {
	ceil := func(p1, p2 Player) bool {
		return p1.Ceil > p2.Ceil
	}
	return r.group(ceil, 5)
}

func (r *Repo) CeilByPos(pos string) []Player {
    plyrs := filter(r.UnDrafted, func (p Player) bool {
        return strings.ToUpper(pos) == strings.ToUpper(p.Position)
    })
    ceil := func(p1, p2 Player) bool {
        return p1.Ceil > p2.Ceil
    }
    By(ceil).Sort(plyrs)
    return plyrs[:min(30, len(plyrs))]
}

func (r *Repo) Team(name string) []Player {
	floor := func(p1, p2 Player) bool {
		return p1.Floor > p2.Floor
	}
	grouped := r.group(floor, 1000)
	return filter(grouped, func(p Player) bool {
		return strings.ToUpper(name) == strings.ToUpper(p.Team) || p.Team == ""
	})
}

func (r *Repo) group(sortFunc By, max int) []Player {
	results := []Player{}
	for _, pos := range OrderedPositions() {
		undrafted := filter(r.UnDrafted, func(p Player) bool {
			return p.Position == pos
		})
		By(sortFunc).Sort(undrafted)
		l := limit(undrafted, max)
		results = append(results, Player{})
		results = append(results, l...)
	}
	return results
}

func limit(plyrs []Player, max int) []Player {
	if len(plyrs) == 0 {
		return plyrs
	}
	index := min(max, len(plyrs))
	return plyrs[:index]
}

func min(i, j int) int {
	if i < j {
		return i
	} else {
		return j
	}
}
<|endoftext|>