<commit_before>package sqlstore

import (
	"errors"

	_ "github.com/go-sql-driver/mysql" // mysql driver
	"github.com/gobuffalo/packr"
	"github.com/jmoiron/sqlx"
	_ "github.com/lib/pq"           // postgresql driver
	_ "github.com/mattn/go-sqlite3" //sqlite3 driver
	migrate "github.com/rubenv/sql-migrate"
	log "github.com/sirupsen/logrus"
)

type sqlstore struct {
	*sqlx.DB

	Config *Config
}

// ErrNoResults is returned when a query yielded 0 results
var ErrNoResults = errors.New("datastore: query returned 0 results")

// New creates a new database pool
func New(c *Config) *sqlstore {
	dbx := sqlx.MustConnect(c.Driver, c.DSN())
	db := &sqlstore{dbx, c}

	// run migrations
	db.Migrate()

	return db
}

func (db *sqlstore) Migrate() {
	migrationSource := &migrate.PackrMigrationSource{
		Box: packr.NewBox("./migrations"),
		Dir: "./" + db.Config.Driver,
	}
	migrate.SetTable("migrations")

	migrations, err := migrationSource.FindMigrations()
	if err != nil {
		log.Errorf("Error loading database migrations: %s", err)
	}

	if len(migrations) == 0 {
		log.Fatalf("Missing database migrations")
	}

	n, err := migrate.Exec(db.DB.DB, db.Config.Driver, migrationSource, migrate.Up)
	if err != nil {
		log.Errorf("Error applying database migrations: %s", err)
	}

	if n > 0 {
		log.Infof("Applied %d database migrations!", n)
	}
}

// Closes the db pool
func (db *sqlstore) Close() {
	db.DB.Close()
}
<commit_msg>write info level after connecting to database<commit_after>package sqlstore

import (
	"errors"

	_ "github.com/go-sql-driver/mysql" // mysql driver
	"github.com/gobuffalo/packr"
	"github.com/jmoiron/sqlx"
	_ "github.com/lib/pq"           // postgresql driver
	_ "github.com/mattn/go-sqlite3" //sqlite3 driver
	migrate "github.com/rubenv/sql-migrate"
	log "github.com/sirupsen/logrus"
)

type sqlstore struct {
	*sqlx.DB

	Config *Config
}

// ErrNoResults is returned when a query yielded 0 results
var ErrNoResults = errors.New("datastore: query returned 0 results")

// New creates a new database pool
func New(c *Config) *sqlstore {
	dbx := sqlx.MustConnect(c.Driver, c.DSN())
	db := &sqlstore{dbx, c}

	// write log statement
	log.Infof("Connected to %s database: %s", c.Driver, c.Name)

	// run migrations
	db.Migrate()

	return db
}

func (db *sqlstore) Migrate() {
	migrationSource := &migrate.PackrMigrationSource{
		Box: packr.NewBox("./migrations"),
		Dir: "./" + db.Config.Driver,
	}
	migrate.SetTable("migrations")

	migrations, err := migrationSource.FindMigrations()
	if err != nil {
		log.Errorf("Error loading database migrations: %s", err)
	}

	if len(migrations) == 0 {
		log.Fatalf("Missing database migrations")
	}

	n, err := migrate.Exec(db.DB.DB, db.Config.Driver, migrationSource, migrate.Up)
	if err != nil {
		log.Errorf("Error applying database migrations: %s", err)
	}

	if n > 0 {
		log.Infof("Applied %d database migrations!", n)
	}
}

// Closes the db pool
func (db *sqlstore) Close() {
	db.DB.Close()
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

package container

import (
	"io"

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

type PodSandboxID string

// PodSandboxManager provides basic operations to create/delete and examine the
// PodSandboxes. These methods should either return an error or block until the
// operation succeeds.
type PodSandboxManager interface {
	// Create creates a sandbox based on the given config, and returns the
	// the new sandbox.
	Create(config *PodSandboxConfig) (PodSandboxID, error)
	// Stop stops the sandbox by its ID. If there are any running
	// containers in the sandbox, they will be terminated as a side-effect.
	Stop(id PodSandboxID) error
	// Delete deletes the sandbox by its ID. If there are any running
	// containers in the sandbox, they will be deleted as a side-effect.
	Delete(id PodSandboxID) error
	// List lists existing sandboxes, filtered by the given PodSandboxFilter.
	List(filter PodSandboxFilter) ([]PodSandboxListItem, error)
	// Status gets the status of the sandbox by ID.
	Status(id PodSandboxID) (PodSandboxStatus, error)
}

// PodSandboxConfig holds all the required and optional fields for creating a
// sandbox.
type PodSandboxConfig struct {
	// Name is the name of the sandbox. The string should conform to
	// [a-zA-Z0-9_-]+.
	Name string
	// Hostname is the hostname of the sandbox.
	Hostname string
	// DNSOptions sets the DNS options for the sandbox.
	DNSOptions DNSOptions
	// PortMappings lists the port mappings for the sandbox.
	PortMappings []PortMapping
	// Resources specifies the resource limits for the sandbox (i.e., the
	// aggregate cpu/memory resources limits of all containers).
	// Note: On a Linux host, kubelet will create a pod-level cgroup and pass
	// it as the cgroup parent for the PodSandbox. For some runtimes, this is
	// sufficient. For others, e.g., hypervisor-based runtimes, explicit
	// resource limits for the sandbox are needed at creation time.
	Resources PodSandboxResources
	// Path to the directory on the host in which container log files are
	// stored.
	// By default the Log of a container going into the LogDirectory will be
	// hooked up to STDOUT and STDERR. However, the LogDirectory may contain
	// binary log files with structured logging data from the individual
	// containers. For example, the files might be newline separated JSON
	// structured logs, systemd-journald journal files, gRPC trace files, etc.
	// E.g.,
	//     PodSandboxConfig.LogDirectory = `/var/log/pods/<podUID>/`
	//     ContainerConfig.LogPath = `containerName_Instance#.log`
	//
	// WARNING: Log management and how kubelet should interface with the
	// container logs are under active discussion in
	// https://issues.k8s.io/24677. There *may* be future change of direction
	// for logging as the discussion carries on.
	LogDirectory string
	// Labels are key value pairs that may be used to scope and select
	// individual resources.
	Labels Labels
	// Annotations is an unstructured key value map that may be set by external
	// tools to store and retrieve arbitrary metadata.
	Annotations map[string]string

	// Linux contains configurations specific to Linux hosts.
	Linux *LinuxPodSandboxConfig
}

// Labels are key value pairs that may be used to scope and select individual
// resources.
// Label keys are of the form:
//     label-key ::= prefixed-name | name
//     prefixed-name ::= prefix '/' name
//     prefix ::= DNS_SUBDOMAIN
//     name ::= DNS_LABEL
type Labels map[string]string

// LinuxPodSandboxConfig holds platform-specific configuraions for Linux
// host platforms and Linux-based containers.
type LinuxPodSandboxConfig struct {
	// CgroupParent is the parent cgroup of the sandbox. The cgroupfs style
	// syntax will be used, but the container runtime can convert it to systemd
	// semantices if needed.
	CgroupParent string
	// NamespaceOptions contains configurations for the sandbox's namespaces.
	// This will be used only if the PodSandbox uses namespace for isolation.
	NamespaceOptions NamespaceOptions
}

// NamespaceOptions provides options for Linux namespaces.
type NamespaceOptions struct {
	// HostNetwork uses the host's network namespace.
	HostNetwork bool
	// HostPID uses the host's pid namesapce.
	HostPID bool
	// HostIPC uses the host's ipc namespace.
	HostIPC bool
}

// DNSOptions specifies the DNS servers and search domains.
type DNSOptions struct {
	// Servers is a list of DNS servers of the cluster.
	Servers []string
	// Searches is a list of DNS search domains of the cluster.
	Searches []string
}

type PodSandboxState string

const (
	// PodSandboxReady means the sandbox is functioning properly.
	PodSandboxReady PodSandboxState = "Ready"
	// PodSandboxInNotReady means the sandbox is not functioning properly.
	PodSandboxNotReady PodSandboxState = "NotReady"
)

// PodSandboxFilter is used to filter a list of PodSandboxes.
type PodSandboxFilter struct {
	// Name of the sandbox.
	Name *string
	// ID of the sandbox.
	ID *PodSandboxID
	// State of the sandbox.
	State *PodSandboxState
	// LabelSelector to select matches.
	// Only api.MatchLabels is supported for now and the requirements
	// are ANDed. MatchExpressions is not supported yet.
	LabelSelector unversioned.LabelSelector
}

// PodSandboxListItem contains minimal information about a sandbox.
type PodSandboxListItem struct {
	ID    PodSandboxID
	State PodSandboxState
	// Labels are key value pairs that may be used to scope and select individual resources.
	Labels Labels
}

// PodSandboxStatus contains the status of the PodSandbox.
type PodSandboxStatus struct {
	// ID of the sandbox.
	ID PodSandboxID
	// State of the sandbox.
	State PodSandboxState
	// Network contains network status if network is handled by the runtime.
	Network *PodSandboxNetworkStatus
	// Status specific to a Linux sandbox.
	Linux *LinuxPodSandboxStatus
	// Labels are key value pairs that may be used to scope and select individual resources.
	Labels Labels
	// Annotations is an unstructured key value map.
	Annotations map[string]string
}

// PodSandboxNetworkStatus is the status of the network for a PodSandbox.
type PodSandboxNetworkStatus struct {
	IPs []string
}

// Namespaces contains paths to the namespaces.
type Namespaces struct {
	// Network is the path to the network namespace.
	Network string
}

// LinuxSandBoxStatus contains status specific to Linux sandboxes.
type LinuxPodSandboxStatus struct {
	// Namespaces contains paths to the sandbox's namespaces.
	Namespaces *Namespaces
}

// PodSandboxResources contains the CPU/memory resource requirements.
type PodSandboxResources struct {
	// CPU resource requirement.
	CPU resource.Quantity
	// Memory resource requirement.
	Memory resource.Quantity
}

// This is to distinguish with existing ContainerID type, which includes a
// runtime type prefix (e.g., docker://). We may rename this later.
type RawContainerID string

// ContainerRuntime provides methods for container lifecycle operations, as
// well as listing or inspecting existing containers. These methods should
// either return an error or block until the operation succeeds.
type ContainerRuntime interface {
	// Create creates a container in the sandbox, and returns the ID
	// of the created container.
	Create(config *ContainerConfig, sandboxConfig *PodSandboxConfig, sandboxID PodSandboxID) (RawContainerID, error)
	// Start starts a created container.
	Start(id RawContainerID) error
	// Stop stops a running container with a grace period (i.e., timeout).
	Stop(id RawContainerID, timeout int) error
	// Remove removes the container.
	Remove(id RawContainerID) error
	// List lists the existing containers that match the ContainerFilter.
	// The returned list should only include containers previously created
	// by this ContainerRuntime.
	List(filter ContainerFilter) ([]ContainerListItem, error)
	// Status returns the status of the container.
	Status(id RawContainerID) (RawContainerStatus, error)
	// Exec executes a command in the container.
	Exec(id RawContainerID, cmd []string, streamOpts StreamOptions) error
}

// ContainerListItem provides the runtime information for a container returned
// by List().
type ContainerListItem struct {
	// The ID of the container, used by the container runtime to identify
	// a container.
	ID ContainerID
	// The name of the container, which should be the same as specified by
	// api.Container.
	Name string
	// Reference to the image in use. For most runtimes, this should be an
	// image ID.
	ImageRef string
	// State is the state of the container.
	State ContainerState
	// Labels are key value pairs that may be used to scope and select individual resources.
	Labels Labels
}

type ContainerConfig struct {
	// Name of the container. The string should conform to [a-zA-Z0-9_-]+.
	Name string
	// Image to use.
	Image ImageSpec
	// Command to execute (i.e., entrypoint for docker)
	Command []string
	// Args for the Command (i.e., command for docker)
	Args []string
	// Current working directory of the command.
	WorkingDir string
	// List of environment variable to set in the container
	Env []KeyValue
	// Mounts specifies mounts for the container
	Mounts []Mount
	// Labels are key value pairs that may be used to scope and select individual resources.
	Labels Labels
	// Annotations is an unstructured key value map that may be set by external
	// tools to store and retrieve arbitrary metadata.
	Annotations map[string]string
	// Privileged runs the container in the privileged mode.
	Privileged bool
	// ReadOnlyRootFS sets the root filesystem of the container to be
	// read-only.
	ReadOnlyRootFS bool
	// Path relative to PodSandboxConfig.LogDirectory for container to store
	// the log (STDOUT and STDERR) on the host.
	// E.g.,
	//     PodSandboxConfig.LogDirectory = `/var/log/pods/<podUID>/`
	//     ContainerConfig.LogPath = `containerName_Instance#.log`
	//
	// WARNING: Log management and how kubelet should interface with the
	// container logs are under active discussion in
	// https://issues.k8s.io/24677. There *may* be future change of direction
	// for logging as the discussion carries on.
	LogPath string

	// Variables for interactive containers, these have very specialized
	// use-cases (e.g. debugging).
	// TODO: Determine if we need to continue supporting these fields that are
	// part of Kubernetes's Container Spec.
	STDIN     bool
	STDINONCE bool
	TTY       bool

	// Linux contains configuration specific to Linux containers.
	Linux *LinuxContainerConfig
}

// RawContainerStatus represents the status of a container.
type RawContainerStatus struct {
	// ID of the container.
	ID ContainerID
	// Name of the container.
	Name string
	// Status of the container.
	State ContainerState
	// Creation time of the container.
	CreatedAt unversioned.Time
	// Start time of the container.
	StartedAt unversioned.Time
	// Finish time of the container.
	FinishedAt unversioned.Time
	// Exit code of the container.
	ExitCode int
	// Reference to the image in use. For most runtimes, this should be an
	// image ID.
	ImageRef string
	// Labels are key value pairs that may be used to scope and select individual resources.
	Labels Labels
	// Annotations is an unstructured key value map.
	Annotations map[string]string
	// A brief CamelCase string explains why container is in such a status.
	Reason string
}

// LinuxContainerConfig contains platform-specific configuration for
// Linux-based containers.
type LinuxContainerConfig struct {
	// Resources specification for the container.
	Resources *LinuxContainerResources
	// Capabilities to add or drop.
	Capabilities *api.Capabilities
	// SELinux is the SELinux context to be applied.
	SELinux *api.SELinuxOptions
	// TODO: Add support for seccomp.
}

// LinuxContainerResources specifies Linux specific configuration for
// resources.
// TODO: Consider using Resources from opencontainers/runtime-spec/specs-go
// directly.
type LinuxContainerResources struct {
	// CPU CFS (Completely Fair Scheduler) period
	CPUPeriod *int64
	// CPU CFS (Completely Fair Scheduler) quota
	CPUQuota *int64
	// CPU shares (relative weight vs. other containers)
	CPUShares *int64
	// Memory limit in bytes
	MemoryLimitInBytes *int64
	// OOMScoreAdj adjusts the oom-killer score.
	OOMScoreAdj *int64
}

// ContainerFilter is used to filter containers.
type ContainerFilter struct {
	// Name of the container.
	Name *string
	// ID of the container.
	ID *RawContainerID
	// State of the contianer.
	State *ContainerState
	// ID of the PodSandbox.
	PodSandboxID *PodSandboxID
	// LabelSelector to select matches.
	// Only api.MatchLabels is supported for now and the requirements
	// are ANDed. MatchExpressions is not supported yet.
	LabelSelector unversioned.LabelSelector
}

type StreamOptions struct {
	TTY          bool
	InputStream  io.Reader
	OutputStream io.Writer
	ErrorStream  io.Writer
}

// KeyValue represents a key-value pair.
type KeyValue struct {
	Key   string
	Value string
}

// ImageService offers basic image operations.
type ImageService interface {
	// List lists the existing images.
	List() ([]Image, error)
	// Pull pulls an image with authentication config. The PodSandboxConfig is
	// passed so that the image service can charge the resources used for
	// pulling to a sepcific pod.
	Pull(image ImageSpec, auth AuthConfig, sandboxConfig *PodSandboxConfig) error
	// Remove removes an image.
	Remove(image ImageSpec) error
	// Status returns the status of an image.
	Status(image ImageSpec) (Image, error)
}

// AuthConfig contains authorization information for connecting to a registry.
// TODO: This is copied from docker's Authconfig. We should re-evaluate to
// support other registries.
type AuthConfig struct {
	Username      string
	Password      string
	Auth          string
	ServerAddress string
	// IdentityToken is used to authenticate the user and get
	// an access token for the registry.
	IdentityToken string
	// RegistryToken is a bearer token to be sent to a registry
	RegistryToken string
}

// TODO: Add ContainerMetricsGetter and ImageMetricsGetter.
<commit_msg>pkg/kubelet/container: amend cgroup type documentation<commit_after>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

package container

import (
	"io"

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

type PodSandboxID string

// PodSandboxManager provides basic operations to create/delete and examine the
// PodSandboxes. These methods should either return an error or block until the
// operation succeeds.
type PodSandboxManager interface {
	// Create creates a sandbox based on the given config, and returns the
	// the new sandbox.
	Create(config *PodSandboxConfig) (PodSandboxID, error)
	// Stop stops the sandbox by its ID. If there are any running
	// containers in the sandbox, they will be terminated as a side-effect.
	Stop(id PodSandboxID) error
	// Delete deletes the sandbox by its ID. If there are any running
	// containers in the sandbox, they will be deleted as a side-effect.
	Delete(id PodSandboxID) error
	// List lists existing sandboxes, filtered by the given PodSandboxFilter.
	List(filter PodSandboxFilter) ([]PodSandboxListItem, error)
	// Status gets the status of the sandbox by ID.
	Status(id PodSandboxID) (PodSandboxStatus, error)
}

// PodSandboxConfig holds all the required and optional fields for creating a
// sandbox.
type PodSandboxConfig struct {
	// Name is the name of the sandbox. The string should conform to
	// [a-zA-Z0-9_-]+.
	Name string
	// Hostname is the hostname of the sandbox.
	Hostname string
	// DNSOptions sets the DNS options for the sandbox.
	DNSOptions DNSOptions
	// PortMappings lists the port mappings for the sandbox.
	PortMappings []PortMapping
	// Resources specifies the resource limits for the sandbox (i.e., the
	// aggregate cpu/memory resources limits of all containers).
	// Note: On a Linux host, kubelet will create a pod-level cgroup and pass
	// it as the cgroup parent for the PodSandbox. For some runtimes, this is
	// sufficient. For others, e.g., hypervisor-based runtimes, explicit
	// resource limits for the sandbox are needed at creation time.
	Resources PodSandboxResources
	// Path to the directory on the host in which container log files are
	// stored.
	// By default the Log of a container going into the LogDirectory will be
	// hooked up to STDOUT and STDERR. However, the LogDirectory may contain
	// binary log files with structured logging data from the individual
	// containers. For example, the files might be newline separated JSON
	// structured logs, systemd-journald journal files, gRPC trace files, etc.
	// E.g.,
	//     PodSandboxConfig.LogDirectory = `/var/log/pods/<podUID>/`
	//     ContainerConfig.LogPath = `containerName_Instance#.log`
	//
	// WARNING: Log management and how kubelet should interface with the
	// container logs are under active discussion in
	// https://issues.k8s.io/24677. There *may* be future change of direction
	// for logging as the discussion carries on.
	LogDirectory string
	// Labels are key value pairs that may be used to scope and select
	// individual resources.
	Labels Labels
	// Annotations is an unstructured key value map that may be set by external
	// tools to store and retrieve arbitrary metadata.
	Annotations map[string]string

	// Linux contains configurations specific to Linux hosts.
	Linux *LinuxPodSandboxConfig
}

// Labels are key value pairs that may be used to scope and select individual
// resources.
// Label keys are of the form:
//     label-key ::= prefixed-name | name
//     prefixed-name ::= prefix '/' name
//     prefix ::= DNS_SUBDOMAIN
//     name ::= DNS_LABEL
type Labels map[string]string

// LinuxPodSandboxConfig holds platform-specific configuraions for Linux
// host platforms and Linux-based containers.
type LinuxPodSandboxConfig struct {
	// CgroupParent is the parent cgroup of the sandbox. The cgroupfs style
	// syntax will be used, but the container runtime can convert it to systemd
	// semantics if needed.
	CgroupParent string
	// NamespaceOptions contains configurations for the sandbox's namespaces.
	// This will be used only if the PodSandbox uses namespace for isolation.
	NamespaceOptions NamespaceOptions
}

// NamespaceOptions provides options for Linux namespaces.
type NamespaceOptions struct {
	// HostNetwork uses the host's network namespace.
	HostNetwork bool
	// HostPID uses the host's pid namesapce.
	HostPID bool
	// HostIPC uses the host's ipc namespace.
	HostIPC bool
}

// DNSOptions specifies the DNS servers and search domains.
type DNSOptions struct {
	// Servers is a list of DNS servers of the cluster.
	Servers []string
	// Searches is a list of DNS search domains of the cluster.
	Searches []string
}

type PodSandboxState string

const (
	// PodSandboxReady means the sandbox is functioning properly.
	PodSandboxReady PodSandboxState = "Ready"
	// PodSandboxInNotReady means the sandbox is not functioning properly.
	PodSandboxNotReady PodSandboxState = "NotReady"
)

// PodSandboxFilter is used to filter a list of PodSandboxes.
type PodSandboxFilter struct {
	// Name of the sandbox.
	Name *string
	// ID of the sandbox.
	ID *PodSandboxID
	// State of the sandbox.
	State *PodSandboxState
	// LabelSelector to select matches.
	// Only api.MatchLabels is supported for now and the requirements
	// are ANDed. MatchExpressions is not supported yet.
	LabelSelector unversioned.LabelSelector
}

// PodSandboxListItem contains minimal information about a sandbox.
type PodSandboxListItem struct {
	ID    PodSandboxID
	State PodSandboxState
	// Labels are key value pairs that may be used to scope and select individual resources.
	Labels Labels
}

// PodSandboxStatus contains the status of the PodSandbox.
type PodSandboxStatus struct {
	// ID of the sandbox.
	ID PodSandboxID
	// State of the sandbox.
	State PodSandboxState
	// Network contains network status if network is handled by the runtime.
	Network *PodSandboxNetworkStatus
	// Status specific to a Linux sandbox.
	Linux *LinuxPodSandboxStatus
	// Labels are key value pairs that may be used to scope and select individual resources.
	Labels Labels
	// Annotations is an unstructured key value map.
	Annotations map[string]string
}

// PodSandboxNetworkStatus is the status of the network for a PodSandbox.
type PodSandboxNetworkStatus struct {
	IPs []string
}

// Namespaces contains paths to the namespaces.
type Namespaces struct {
	// Network is the path to the network namespace.
	Network string
}

// LinuxSandBoxStatus contains status specific to Linux sandboxes.
type LinuxPodSandboxStatus struct {
	// Namespaces contains paths to the sandbox's namespaces.
	Namespaces *Namespaces
}

// PodSandboxResources contains the CPU/memory resource requirements.
type PodSandboxResources struct {
	// CPU resource requirement.
	CPU resource.Quantity
	// Memory resource requirement.
	Memory resource.Quantity
}

// This is to distinguish with existing ContainerID type, which includes a
// runtime type prefix (e.g., docker://). We may rename this later.
type RawContainerID string

// ContainerRuntime provides methods for container lifecycle operations, as
// well as listing or inspecting existing containers. These methods should
// either return an error or block until the operation succeeds.
type ContainerRuntime interface {
	// Create creates a container in the sandbox, and returns the ID
	// of the created container.
	Create(config *ContainerConfig, sandboxConfig *PodSandboxConfig, sandboxID PodSandboxID) (RawContainerID, error)
	// Start starts a created container.
	Start(id RawContainerID) error
	// Stop stops a running container with a grace period (i.e., timeout).
	Stop(id RawContainerID, timeout int) error
	// Remove removes the container.
	Remove(id RawContainerID) error
	// List lists the existing containers that match the ContainerFilter.
	// The returned list should only include containers previously created
	// by this ContainerRuntime.
	List(filter ContainerFilter) ([]ContainerListItem, error)
	// Status returns the status of the container.
	Status(id RawContainerID) (RawContainerStatus, error)
	// Exec executes a command in the container.
	Exec(id RawContainerID, cmd []string, streamOpts StreamOptions) error
}

// ContainerListItem provides the runtime information for a container returned
// by List().
type ContainerListItem struct {
	// The ID of the container, used by the container runtime to identify
	// a container.
	ID ContainerID
	// The name of the container, which should be the same as specified by
	// api.Container.
	Name string
	// Reference to the image in use. For most runtimes, this should be an
	// image ID.
	ImageRef string
	// State is the state of the container.
	State ContainerState
	// Labels are key value pairs that may be used to scope and select individual resources.
	Labels Labels
}

type ContainerConfig struct {
	// Name of the container. The string should conform to [a-zA-Z0-9_-]+.
	Name string
	// Image to use.
	Image ImageSpec
	// Command to execute (i.e., entrypoint for docker)
	Command []string
	// Args for the Command (i.e., command for docker)
	Args []string
	// Current working directory of the command.
	WorkingDir string
	// List of environment variable to set in the container
	Env []KeyValue
	// Mounts specifies mounts for the container
	Mounts []Mount
	// Labels are key value pairs that may be used to scope and select individual resources.
	Labels Labels
	// Annotations is an unstructured key value map that may be set by external
	// tools to store and retrieve arbitrary metadata.
	Annotations map[string]string
	// Privileged runs the container in the privileged mode.
	Privileged bool
	// ReadOnlyRootFS sets the root filesystem of the container to be
	// read-only.
	ReadOnlyRootFS bool
	// Path relative to PodSandboxConfig.LogDirectory for container to store
	// the log (STDOUT and STDERR) on the host.
	// E.g.,
	//     PodSandboxConfig.LogDirectory = `/var/log/pods/<podUID>/`
	//     ContainerConfig.LogPath = `containerName_Instance#.log`
	//
	// WARNING: Log management and how kubelet should interface with the
	// container logs are under active discussion in
	// https://issues.k8s.io/24677. There *may* be future change of direction
	// for logging as the discussion carries on.
	LogPath string

	// Variables for interactive containers, these have very specialized
	// use-cases (e.g. debugging).
	// TODO: Determine if we need to continue supporting these fields that are
	// part of Kubernetes's Container Spec.
	STDIN     bool
	STDINONCE bool
	TTY       bool

	// Linux contains configuration specific to Linux containers.
	Linux *LinuxContainerConfig
}

// RawContainerStatus represents the status of a container.
type RawContainerStatus struct {
	// ID of the container.
	ID ContainerID
	// Name of the container.
	Name string
	// Status of the container.
	State ContainerState
	// Creation time of the container.
	CreatedAt unversioned.Time
	// Start time of the container.
	StartedAt unversioned.Time
	// Finish time of the container.
	FinishedAt unversioned.Time
	// Exit code of the container.
	ExitCode int
	// Reference to the image in use. For most runtimes, this should be an
	// image ID.
	ImageRef string
	// Labels are key value pairs that may be used to scope and select individual resources.
	Labels Labels
	// Annotations is an unstructured key value map.
	Annotations map[string]string
	// A brief CamelCase string explains why container is in such a status.
	Reason string
}

// LinuxContainerConfig contains platform-specific configuration for
// Linux-based containers.
type LinuxContainerConfig struct {
	// Resources specification for the container.
	Resources *LinuxContainerResources
	// Capabilities to add or drop.
	Capabilities *api.Capabilities
	// SELinux is the SELinux context to be applied.
	SELinux *api.SELinuxOptions
	// TODO: Add support for seccomp.
}

// LinuxContainerResources specifies Linux specific configuration for
// resources.
// TODO: Consider using Resources from opencontainers/runtime-spec/specs-go
// directly.
type LinuxContainerResources struct {
	// CPU CFS (Completely Fair Scheduler) period
	CPUPeriod *int64
	// CPU CFS (Completely Fair Scheduler) quota
	CPUQuota *int64
	// CPU shares (relative weight vs. other containers)
	CPUShares *int64
	// Memory limit in bytes
	MemoryLimitInBytes *int64
	// OOMScoreAdj adjusts the oom-killer score.
	OOMScoreAdj *int64
}

// ContainerFilter is used to filter containers.
type ContainerFilter struct {
	// Name of the container.
	Name *string
	// ID of the container.
	ID *RawContainerID
	// State of the contianer.
	State *ContainerState
	// ID of the PodSandbox.
	PodSandboxID *PodSandboxID
	// LabelSelector to select matches.
	// Only api.MatchLabels is supported for now and the requirements
	// are ANDed. MatchExpressions is not supported yet.
	LabelSelector unversioned.LabelSelector
}

type StreamOptions struct {
	TTY          bool
	InputStream  io.Reader
	OutputStream io.Writer
	ErrorStream  io.Writer
}

// KeyValue represents a key-value pair.
type KeyValue struct {
	Key   string
	Value string
}

// ImageService offers basic image operations.
type ImageService interface {
	// List lists the existing images.
	List() ([]Image, error)
	// Pull pulls an image with authentication config. The PodSandboxConfig is
	// passed so that the image service can charge the resources used for
	// pulling to a sepcific pod.
	Pull(image ImageSpec, auth AuthConfig, sandboxConfig *PodSandboxConfig) error
	// Remove removes an image.
	Remove(image ImageSpec) error
	// Status returns the status of an image.
	Status(image ImageSpec) (Image, error)
}

// AuthConfig contains authorization information for connecting to a registry.
// TODO: This is copied from docker's Authconfig. We should re-evaluate to
// support other registries.
type AuthConfig struct {
	Username      string
	Password      string
	Auth          string
	ServerAddress string
	// IdentityToken is used to authenticate the user and get
	// an access token for the registry.
	IdentityToken string
	// RegistryToken is a bearer token to be sent to a registry
	RegistryToken string
}

// TODO: Add ContainerMetricsGetter and ImageMetricsGetter.
<|endoftext|>


<commit_before>package schema

import (
	"encoding/json"
	//"fmt"
)

// DefaultSchema returns an empty schema ready to be populated
func DefaultSchema() *Schema {
	tables := make(map[string]*Table)
	sch := &Schema{Tables: tables, TableAliases: nil}

	return sch
}

// ToJSON converts a schema into a JSON string.
func (s *Schema) ToJSON() (string, error) {
	buf, err := s.ToJSONBytes()
	if err != nil {
		return "", err
	}
	return string(buf), err
}

// ToJSONBytes converts a schema into a JSON byte array.
func (s *Schema) ToJSONBytes() ([]byte, error) {
	buf, err := json.Marshal(s)
	if err != nil {
		return nil, err
	}
	return buf, nil
}

// FromJSON unmarshals a JSON string into a Schema object.
func FromJSON(jsonStr string) (*Schema, error) {
	sch := DefaultSchema()
	err := json.Unmarshal([]byte(jsonStr), &sch)
	if err != nil {
		return nil, err
	}
	return sch, nil
}

// FromJSONBytes unmarshals a JSON byte array into a Schema object.
func FromJSONBytes(jsonBytes []byte) (*Schema, error) {
	sch := DefaultSchema()
	err := json.Unmarshal(jsonBytes, &sch)
	if err != nil {
		return nil, err
	}
	return sch, nil
}

// GetTableName returns the correct Table name in a potentially aliased environment.
func (s *Schema) GetTableName(n string) string {
	if s.TableAliases != nil {
		realName, ok := s.TableAliases[n]
		if !ok {
			// Perhaps it is not an alias
			return n
		}
		return realName
	}
	return n
}

// GetTable returns the correct Table type in a potentially aliased environment.
func (s *Schema) GetTable(n string) *Table {
	if s.TableAliases != nil {
		realName, ok := s.TableAliases[n]
		if !ok {
			// Perhaps it is not an alias
			return s.Tables[n]
		}
		return s.Tables[realName]
	}
	return s.Tables[n]
}

// GetColumnName returns the correct field name in a potentially aliased environment.
// This is useful in situations where you aren't sure what the 'real' key name
// may potentially be.
func (t *Table) GetColumnName(n string) string {
	if t.ColumnAliases != nil {
		realName, ok := t.ColumnAliases[n]
		if !ok {
			// Perhaps it is not an alias
			return n
		}
		return realName
	}
	return n
}

// GetColumn returns the correct field in a potentially aliased environment.
func (t *Table) GetColumn(n string) *Column {
	if t.ColumnAliases != nil {
		realName, ok := t.ColumnAliases[n]
		if !ok {
			// Perhaps it is not an alias
			return t.Columns[n]
		}
		return t.Columns[realName]
	}
	return t.Columns[n]
}

// DefaultTable returns an empty table ready to be populated
func DefaultTable() *Table {
	fieldsMap := make(map[string]*Column)
	childrenMap := make(map[string]*ChildTable)
	emptyAliasesMap := make(map[string]string)

	tbl := &Table{
		MultiKey:         false,
		Primary:          "",
		Columns:          fieldsMap,
		EssentialColumns: nil,
		Children:         childrenMap,
		ColumnAliases:    emptyAliasesMap,
	}
	return tbl
}

// DefaultTableWithName returns an empty table with a name set
func DefaultTableWithName(name string) *Table {
	tbl := DefaultTable()
	tbl.Name = name
	return tbl
}

// SetNewTableWithName
func (s *Schema) SetNewTableWithName(name string) {
	tbl := DefaultTableWithName(name)
	s.Tables[name] = tbl
}

// DefaultColumn returns an empty field struct ready to be populated
func DefaultColumn() *Column {
	fld := &Column{
		Name:         "",
		AllowNull:    false,
		DefaultValue: "",
		IsNumber:     false,
		DBType:       "",
		IsIdentity:   false,
	}
	return fld
}

// DefaultChildTable returns an empty child table ready to be populated
func DefaultChildTable() *ChildTable {
	chld := &ChildTable{
		ParentTable:   "",
		MultiKey:      false,
		LocalColumn:   "",
		ForeignColumn: "",

		LocalColumns:   nil,
		ForeignColumns: nil,
	}
	return chld
}
<commit_msg>no point in defaulting MultiKey to false<commit_after>package schema

import (
	"encoding/json"
	//"fmt"
)

// DefaultSchema returns an empty schema ready to be populated
func DefaultSchema() *Schema {
	tables := make(map[string]*Table)
	sch := &Schema{Tables: tables, TableAliases: nil}

	return sch
}

// ToJSON converts a schema into a JSON string.
func (s *Schema) ToJSON() (string, error) {
	buf, err := s.ToJSONBytes()
	if err != nil {
		return "", err
	}
	return string(buf), err
}

// ToJSONBytes converts a schema into a JSON byte array.
func (s *Schema) ToJSONBytes() ([]byte, error) {
	buf, err := json.Marshal(s)
	if err != nil {
		return nil, err
	}
	return buf, nil
}

// FromJSON unmarshals a JSON string into a Schema object.
func FromJSON(jsonStr string) (*Schema, error) {
	sch := DefaultSchema()
	err := json.Unmarshal([]byte(jsonStr), &sch)
	if err != nil {
		return nil, err
	}
	return sch, nil
}

// FromJSONBytes unmarshals a JSON byte array into a Schema object.
func FromJSONBytes(jsonBytes []byte) (*Schema, error) {
	sch := DefaultSchema()
	err := json.Unmarshal(jsonBytes, &sch)
	if err != nil {
		return nil, err
	}
	return sch, nil
}

// GetTableName returns the correct Table name in a potentially aliased environment.
func (s *Schema) GetTableName(n string) string {
	if s.TableAliases != nil {
		realName, ok := s.TableAliases[n]
		if !ok {
			// Perhaps it is not an alias
			return n
		}
		return realName
	}
	return n
}

// GetTable returns the correct Table type in a potentially aliased environment.
func (s *Schema) GetTable(n string) *Table {
	if s.TableAliases != nil {
		realName, ok := s.TableAliases[n]
		if !ok {
			// Perhaps it is not an alias
			return s.Tables[n]
		}
		return s.Tables[realName]
	}
	return s.Tables[n]
}

// GetColumnName returns the correct field name in a potentially aliased environment.
// This is useful in situations where you aren't sure what the 'real' key name
// may potentially be.
func (t *Table) GetColumnName(n string) string {
	if t.ColumnAliases != nil {
		realName, ok := t.ColumnAliases[n]
		if !ok {
			// Perhaps it is not an alias
			return n
		}
		return realName
	}
	return n
}

// GetColumn returns the correct field in a potentially aliased environment.
func (t *Table) GetColumn(n string) *Column {
	if t.ColumnAliases != nil {
		realName, ok := t.ColumnAliases[n]
		if !ok {
			// Perhaps it is not an alias
			return t.Columns[n]
		}
		return t.Columns[realName]
	}
	return t.Columns[n]
}

// DefaultTable returns an empty table ready to be populated
func DefaultTable() *Table {
	fieldsMap := make(map[string]*Column)
	childrenMap := make(map[string]*ChildTable)
	emptyAliasesMap := make(map[string]string)

	tbl := &Table{
		Primary:          "",
		Columns:          fieldsMap,
		EssentialColumns: nil,
		Children:         childrenMap,
		ColumnAliases:    emptyAliasesMap,
	}
	return tbl
}

// DefaultTableWithName returns an empty table with a name set
func DefaultTableWithName(name string) *Table {
	tbl := DefaultTable()
	tbl.Name = name
	return tbl
}

// SetNewTableWithName
func (s *Schema) SetNewTableWithName(name string) {
	tbl := DefaultTableWithName(name)
	s.Tables[name] = tbl
}

// DefaultColumn returns an empty field struct ready to be populated
func DefaultColumn() *Column {
	fld := &Column{
		Name:         "",
		AllowNull:    false,
		DefaultValue: "",
		IsNumber:     false,
		DBType:       "",
		IsIdentity:   false,
	}
	return fld
}

// DefaultChildTable returns an empty child table ready to be populated
func DefaultChildTable() *ChildTable {
	chld := &ChildTable{
		ParentTable:   "",
		LocalColumn:   "",
		ForeignColumn: "",

		LocalColumns:   nil,
		ForeignColumns: nil,
	}
	return chld
}
<|endoftext|>


<commit_before>//
// 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 editor

import (
	"strings"
	"unicode"

	"github.com/nsf/termbox-go"

	gott "github.com/timburks/gott/types"
)

// A Buffer represents a file being edited

type Buffer struct {
	rows     []Row
	FileName string
}

func NewBuffer() *Buffer {
	b := &Buffer{}
	b.rows = make([]Row, 0)
	return b
}

func (b *Buffer) GetFileName() string {
	return b.FileName
}

func (b *Buffer) ReadBytes(bytes []byte) {
	s := string(bytes)
	lines := strings.Split(s, "\n")
	b.rows = make([]Row, 0)
	for _, line := range lines {
		b.rows = append(b.rows, NewRow(line))
	}
}

func (b *Buffer) Bytes() []byte {
	var s string
	for i, row := range b.rows {
		if i > 0 {
			s += "\n"
		}
		s += string(row.Text)
	}
	return []byte(s)
}

func (b *Buffer) GetRowCount() int {
	return len(b.rows)
}

func (b *Buffer) GetRowLength(i int) int {
	if i < len(b.rows) {
		return b.rows[i].Length()
	} else {
		return 0
	}
}

func (b *Buffer) TextAfter(row, col int) string {
	if row < len(b.rows) {
		return b.rows[row].TextAfter(col)
	} else {
		return ""
	}
}

func (b *Buffer) InsertCharacter(row, col int, c rune) {
	if row < len(b.rows) {
		b.rows[row].InsertChar(col, c)
	}
}

func (b *Buffer) DeleteRow(row int) {
	if row < len(b.rows) {
		b.rows = append(b.rows[0:row], b.rows[row+1:]...)
	}
}

func (b *Buffer) DeleteCharacters(row int, col int, count int, joinLines bool) string {
	deletedText := ""
	if b.GetRowCount() == 0 {
		return deletedText
	}
	for i := 0; i < count; i++ {
		if col < b.rows[row].Length() {
			c := b.rows[row].DeleteChar(col)
			deletedText += string(c)
		} else if joinLines && row < b.GetRowCount()-1 {
			// join next row to current row
			nextRow := b.rows[row+1]
			b.rows[row].Join(nextRow)
			// remove next row
			b.DeleteRow(row + 1)
			deletedText += "\n"
		}
	}
	return deletedText
}

func checkalphanum(line string, start, end int) bool {
	if start > 0 {
		c := rune(line[start-1])
		if unicode.IsLetter(c) || unicode.IsDigit(c) {
			return true
		}
	}
	if end < len(line) {
		c := rune(line[end])
		if unicode.IsLetter(c) || unicode.IsDigit(c) {
			return true
		}
	}
	return false
}

// draw text in an area defined by origin and size with a specified offset into the buffer
func (b *Buffer) Render(origin gott.Point, size gott.Size, offset gott.Size) {
	for i := origin.Row; i < origin.Row+size.Rows; i++ {
		var line string
		var colors []termbox.Attribute
		if (i + offset.Rows) < len(b.rows) {
			b.rows[i+offset.Rows].Color()

			line = b.rows[i+offset.Rows].DisplayText()
			colors = b.rows[i+offset.Rows].Colors

			if offset.Cols < len(line) {
				line = line[offset.Cols:]
				colors = colors[offset.Cols:]
			} else {
				line = ""
			}
		} else {
			line = "~"
		}
		// truncate line to fit screen
		if len(line) > size.Cols {
			line = line[0:size.Cols]
			colors = colors[0:size.Cols]
		}

		for j, c := range line {
			termbox.SetCell(j+origin.Col, i, rune(c), colors[j], 0x01)
		}
	}
}
<commit_msg>fix coloring problem (crash) that occurred for files that didn't fill all screen rows.<commit_after>//
// 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 editor

import (
	"strings"
	"unicode"

	"github.com/nsf/termbox-go"

	gott "github.com/timburks/gott/types"
)

// A Buffer represents a file being edited

type Buffer struct {
	rows     []Row
	FileName string
}

func NewBuffer() *Buffer {
	b := &Buffer{}
	b.rows = make([]Row, 0)
	return b
}

func (b *Buffer) GetFileName() string {
	return b.FileName
}

func (b *Buffer) ReadBytes(bytes []byte) {
	s := string(bytes)
	lines := strings.Split(s, "\n")
	b.rows = make([]Row, 0)
	for _, line := range lines {
		b.rows = append(b.rows, NewRow(line))
	}
}

func (b *Buffer) Bytes() []byte {
	var s string
	for i, row := range b.rows {
		if i > 0 {
			s += "\n"
		}
		s += string(row.Text)
	}
	return []byte(s)
}

func (b *Buffer) GetRowCount() int {
	return len(b.rows)
}

func (b *Buffer) GetRowLength(i int) int {
	if i < len(b.rows) {
		return b.rows[i].Length()
	} else {
		return 0
	}
}

func (b *Buffer) TextAfter(row, col int) string {
	if row < len(b.rows) {
		return b.rows[row].TextAfter(col)
	} else {
		return ""
	}
}

func (b *Buffer) InsertCharacter(row, col int, c rune) {
	if row < len(b.rows) {
		b.rows[row].InsertChar(col, c)
	}
}

func (b *Buffer) DeleteRow(row int) {
	if row < len(b.rows) {
		b.rows = append(b.rows[0:row], b.rows[row+1:]...)
	}
}

func (b *Buffer) DeleteCharacters(row int, col int, count int, joinLines bool) string {
	deletedText := ""
	if b.GetRowCount() == 0 {
		return deletedText
	}
	for i := 0; i < count; i++ {
		if col < b.rows[row].Length() {
			c := b.rows[row].DeleteChar(col)
			deletedText += string(c)
		} else if joinLines && row < b.GetRowCount()-1 {
			// join next row to current row
			nextRow := b.rows[row+1]
			b.rows[row].Join(nextRow)
			// remove next row
			b.DeleteRow(row + 1)
			deletedText += "\n"
		}
	}
	return deletedText
}

func checkalphanum(line string, start, end int) bool {
	if start > 0 {
		c := rune(line[start-1])
		if unicode.IsLetter(c) || unicode.IsDigit(c) {
			return true
		}
	}
	if end < len(line) {
		c := rune(line[end])
		if unicode.IsLetter(c) || unicode.IsDigit(c) {
			return true
		}
	}
	return false
}

// draw text in an area defined by origin and size with a specified offset into the buffer
func (b *Buffer) Render(origin gott.Point, size gott.Size, offset gott.Size) {
	for i := origin.Row; i < origin.Row+size.Rows; i++ {
		var line string
		var colors []termbox.Attribute
		if (i + offset.Rows) < len(b.rows) {
			b.rows[i+offset.Rows].Color()

			line = b.rows[i+offset.Rows].DisplayText()
			colors = b.rows[i+offset.Rows].Colors

			if offset.Cols < len(line) {
				line = line[offset.Cols:]
				colors = colors[offset.Cols:]
			} else {
				line = ""
			}
		} else {
			line = "~"
			colors = make([]termbox.Attribute, 1, 1)
			colors[0] = termbox.ColorWhite
		}
		// truncate line to fit screen
		if len(line) > size.Cols {
			line = line[0:size.Cols]
			colors = colors[0:size.Cols]
		}

		for j, c := range line {
			var color = termbox.ColorRed // indicates a problem
			if j < len(colors) {
				color = colors[j]
			}
			termbox.SetCell(j+origin.Col, i, rune(c), color, 0x01)
		}
	}
}
<|endoftext|>


<commit_before>// Package editor provides a graphical, editable text area widget.
package editor // import "sigint.ca/graphics/editor"

import (
	"image"
	"time"

	"sigint.ca/clip"
	"sigint.ca/graphics/editor/internal/hist"
	"sigint.ca/graphics/editor/internal/text"

	"golang.org/x/image/font"
	"golang.org/x/mobile/event/key"
	"golang.org/x/mobile/event/mouse"
)

// An Editor is a graphical, editable text area widget, intended to be
// compatible with golang.org/x/exp/shiny, or any other graphical
// window package capable of drawing a widget via an image.RGBA and
// clipping rectangle. See sigint.ca/cmd/edit for an example program
// using this type.
type Editor struct {
	// textual state
	buf *text.Buffer
	dot text.Selection // the current selection

	// images and drawing data
	img      *image.RGBA
	scrollPt image.Point // the part of the image in view

	// configurable
	bgcol      *image.Uniform
	selcol     *image.Uniform
	cursor     image.Image // the cursor to draw when nothing is selected
	font       fontface
	lineHeight int
	margin     image.Point

	// history
	history     *hist.History        // represents the Editor's history
	savePoint   *hist.Transformation // records the last time the Editor was saved, for use by Saved and SetSaved
	uncommitted *hist.Transformation // recent input which hasn't yet been committed to history

	// mouse related state
	lastClickTime time.Time    // used to detect a double-click
	mPos          image.Point  // the position of the most recent mouse event
	mSweepOrigin  text.Address // keeps track of the origin of a sweep

	clipboard *clip.Clipboard // the clipboard to be used for copy or paste events
}

// NewEditor returns a new Editor with a clipping rectangle defined by size, a font face
// defined by face and height, and an OptionSet opt.
func NewEditor(size image.Point, face font.Face, height int, opt OptionSet) *Editor {
	ed := &Editor{
		buf: text.NewBuffer(),

		img: image.NewRGBA(image.Rectangle{Max: size}),

		bgcol:      image.NewUniform(opt.BGColor),
		selcol:     image.NewUniform(opt.SelColor),
		cursor:     opt.Cursor(height),
		font:       fontface{face: face, height: height - 3},
		lineHeight: height,
		margin:     opt.Margin,

		history:   new(hist.History),
		clipboard: new(clip.Clipboard),
	}
	return ed
}

func (ed *Editor) Release() {
}

func (ed *Editor) Bounds() image.Rectangle {
	return ed.img.Bounds()
}

func (ed *Editor) Size() image.Point {
	return ed.Bounds().Size()
}

// Resize resizes the Editor. Subsequent calls to RGBA will return an image of
// at least size, and a clipping rectangle of size.
func (ed *Editor) Resize(size image.Point) {
	r := image.Rectangle{Max: size}
	ed.img = image.NewRGBA(r)
}

// RGBA returns an image representing the current state of the Editor. The image
// may be larger than the rectangle returned by Bounds, which represents
// the portion of the image currently scrolled into view.
func (ed *Editor) RGBA() (img *image.RGBA) {
	ed.redraw()
	return ed.img
}

// Contents returns the contents of the Editor.
func (ed *Editor) Contents() []byte {
	return ed.buf.Contents()
}

// Load replaces the contents of the Editor with s, and
// resets the Editor's history.
func (ed *Editor) Load(s []byte) {
	ed.buf.ClearSel(ed.dot)
	ed.buf.InsertString(text.Address{0, 0}, string(s))
	ed.history = new(hist.History)
	ed.dot = text.Selection{}
}

// SetSaved instructs the Editor that the current contents should be
// considered saved. After calling SetSaved, the client can call
// Saved to see if the Editor has unsaved content.
func (ed *Editor) SetSaved() {
	// TODO: ensure ed.uncommitted is empty?
	if ed.uncommitted != nil {
		panic("TODO")
	}
	ed.savePoint = ed.history.Current()
}

// Saved reports whether the Editor has been modified since the last
// time SetSaved was called.
func (ed *Editor) Saved() bool {
	return ed.history.Current() == ed.savePoint && ed.uncommitted == nil
}

// SendKeyEvent sends a key event to be interpreted by the Editor.
func (ed *Editor) SendKeyEvent(e key.Event) {
	ed.handleKeyEvent(e)
}

// SendMouseEvent sends a mouse event to be interpreted by the Editor.
func (ed *Editor) SendMouseEvent(e mouse.Event) {
	ed.handleMouseEvent(e)
}

// SendScrollEvent sends a scroll event to be interpreted by the Editor.
func (ed *Editor) SendScrollEvent(e mouse.ScrollEvent) {
	var pt image.Point
	if e.Precise {
		pt.X = int(e.Dx)
		pt.Y = int(e.Dy)
	} else {
		pt.X = int(e.Dx * float32(ed.lineHeight))
		pt.Y = int(e.Dy * float32(ed.lineHeight))
	}
	ed.scroll(pt)
}
<commit_msg>editor: update type documentation<commit_after>// Package editor provides a graphical, editable text area widget.
package editor // import "sigint.ca/graphics/editor"

import (
	"image"
	"time"

	"sigint.ca/clip"
	"sigint.ca/graphics/editor/internal/hist"
	"sigint.ca/graphics/editor/internal/text"

	"golang.org/x/image/font"
	"golang.org/x/mobile/event/key"
	"golang.org/x/mobile/event/mouse"
)

// An Editor is a graphical, editable text area widget, intended to be
// compatible with golang.org/x/exp/shiny, or any other graphical
// window package capable of drawing a widget via an image.RGBA.
// See sigint.ca/cmd/edit for an example program using this type.
type Editor struct {
	// textual state
	buf *text.Buffer
	dot text.Selection // the current selection

	// images and drawing data
	img      *image.RGBA
	scrollPt image.Point // the part of the image in view

	// configurable
	bgcol      *image.Uniform
	selcol     *image.Uniform
	cursor     image.Image // the cursor to draw when nothing is selected
	font       fontface
	lineHeight int
	margin     image.Point

	// history
	history     *hist.History        // represents the Editor's history
	savePoint   *hist.Transformation // records the last time the Editor was saved, for use by Saved and SetSaved
	uncommitted *hist.Transformation // recent input which hasn't yet been committed to history

	// mouse related state
	lastClickTime time.Time    // used to detect a double-click
	mPos          image.Point  // the position of the most recent mouse event
	mSweepOrigin  text.Address // keeps track of the origin of a sweep

	clipboard *clip.Clipboard // the clipboard to be used for copy or paste events
}

// NewEditor returns a new Editor with a clipping rectangle defined by size, a font face
// defined by face and height, and an OptionSet opt.
func NewEditor(size image.Point, face font.Face, height int, opt OptionSet) *Editor {
	ed := &Editor{
		buf: text.NewBuffer(),

		img: image.NewRGBA(image.Rectangle{Max: size}),

		bgcol:      image.NewUniform(opt.BGColor),
		selcol:     image.NewUniform(opt.SelColor),
		cursor:     opt.Cursor(height),
		font:       fontface{face: face, height: height - 3},
		lineHeight: height,
		margin:     opt.Margin,

		history:   new(hist.History),
		clipboard: new(clip.Clipboard),
	}
	return ed
}

func (ed *Editor) Release() {
}

func (ed *Editor) Bounds() image.Rectangle {
	return ed.img.Bounds()
}

func (ed *Editor) Size() image.Point {
	return ed.Bounds().Size()
}

// Resize resizes the Editor. Subsequent calls to RGBA will return an image of
// at least size, and a clipping rectangle of size.
func (ed *Editor) Resize(size image.Point) {
	r := image.Rectangle{Max: size}
	ed.img = image.NewRGBA(r)
}

// RGBA returns an image representing the current state of the Editor. The image
// may be larger than the rectangle returned by Bounds, which represents
// the portion of the image currently scrolled into view.
func (ed *Editor) RGBA() (img *image.RGBA) {
	ed.redraw()
	return ed.img
}

// Contents returns the contents of the Editor.
func (ed *Editor) Contents() []byte {
	return ed.buf.Contents()
}

// Load replaces the contents of the Editor with s, and
// resets the Editor's history.
func (ed *Editor) Load(s []byte) {
	ed.buf.ClearSel(ed.dot)
	ed.buf.InsertString(text.Address{0, 0}, string(s))
	ed.history = new(hist.History)
	ed.dot = text.Selection{}
}

// SetSaved instructs the Editor that the current contents should be
// considered saved. After calling SetSaved, the client can call
// Saved to see if the Editor has unsaved content.
func (ed *Editor) SetSaved() {
	// TODO: ensure ed.uncommitted is empty?
	if ed.uncommitted != nil {
		panic("TODO")
	}
	ed.savePoint = ed.history.Current()
}

// Saved reports whether the Editor has been modified since the last
// time SetSaved was called.
func (ed *Editor) Saved() bool {
	return ed.history.Current() == ed.savePoint && ed.uncommitted == nil
}

// SendKeyEvent sends a key event to be interpreted by the Editor.
func (ed *Editor) SendKeyEvent(e key.Event) {
	ed.handleKeyEvent(e)
}

// SendMouseEvent sends a mouse event to be interpreted by the Editor.
func (ed *Editor) SendMouseEvent(e mouse.Event) {
	ed.handleMouseEvent(e)
}

// SendScrollEvent sends a scroll event to be interpreted by the Editor.
func (ed *Editor) SendScrollEvent(e mouse.ScrollEvent) {
	var pt image.Point
	if e.Precise {
		pt.X = int(e.Dx)
		pt.Y = int(e.Dy)
	} else {
		pt.X = int(e.Dx * float32(ed.lineHeight))
		pt.Y = int(e.Dy * float32(ed.lineHeight))
	}
	ed.scroll(pt)
}
<|endoftext|>


<commit_before>
package crypto
import (
	"testing"
	"fmt"
	"github.com/stretchr/testify/assert"
)

func TestEncrypt(t *testing.T) {
	authKey := []byte("545e0716f2fea0c7a9c46c74fec46c71")
	expected := map[string]interface{}{"entity": "something2"}
	res, _ := Encrypt(expected, authKey, authKey)
	fmt.Println(res)
	r, err := Decrypt(res, authKey, authKey)
	fmt.Println(r, err)
	assert.Equal(t, expected, r)
}

func TestDecrypt(t *testing.T) {
	authKey := []byte("545e0716f2fea0c7a9c46c74fec46c71")
	input := "WmtlMxl4d_VTfUYnl-A0Uycpr2e3VswKDwoPd03XtoY=.JZMk6FZloYh5BL0K7dHGSyTqB4lTgd9annrFEgLTELnxR3bHweL2"
	expected := map[string]interface{}{"entity": "something2"}
	r, _ := Decrypt(input, authKey, authKey)
	assert.Equal(t, expected, r)

}
<commit_msg>Remove Print statements<commit_after>
package crypto
import (
	"testing"
	"fmt"
	"github.com/stretchr/testify/assert"
)

func TestEncrypt(t *testing.T) {
	authKey := []byte("545e0716f2fea0c7a9c46c74fec46c71")
	expected := map[string]interface{}{"entity": "something2"}
	res, _ := Encrypt(expected, authKey, authKey)
	r, _ := Decrypt(res, authKey, authKey)
	assert.Equal(t, expected, r)
}

func TestDecrypt(t *testing.T) {
	authKey := []byte("545e0716f2fea0c7a9c46c74fec46c71")
	input := "WmtlMxl4d_VTfUYnl-A0Uycpr2e3VswKDwoPd03XtoY=.JZMk6FZloYh5BL0K7dHGSyTqB4lTgd9annrFEgLTELnxR3bHweL2"
	expected := map[string]interface{}{"entity": "something2"}
	r, _ := Decrypt(input, authKey, authKey)
	assert.Equal(t, expected, r)

}
<|endoftext|>


<commit_before>// +build !windows

/*
Copyright 2014 The Kubernetes Authors.

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

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

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

// Package app does all of the work necessary to configure and run a
// Kubernetes app process.
package app

import (
	"errors"
	"fmt"
	"net"

	"k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/types"
	utilnet "k8s.io/apimachinery/pkg/util/net"
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
	utilfeature "k8s.io/apiserver/pkg/util/feature"
	"k8s.io/client-go/tools/record"
	"k8s.io/kubernetes/pkg/apis/componentconfig"
	"k8s.io/kubernetes/pkg/features"
	"k8s.io/kubernetes/pkg/proxy"
	proxyconfig "k8s.io/kubernetes/pkg/proxy/config"
	"k8s.io/kubernetes/pkg/proxy/healthcheck"
	"k8s.io/kubernetes/pkg/proxy/iptables"
	"k8s.io/kubernetes/pkg/proxy/ipvs"
	"k8s.io/kubernetes/pkg/proxy/userspace"
	"k8s.io/kubernetes/pkg/util/configz"
	utildbus "k8s.io/kubernetes/pkg/util/dbus"
	utiliptables "k8s.io/kubernetes/pkg/util/iptables"
	utilipvs "k8s.io/kubernetes/pkg/util/ipvs"
	utilnode "k8s.io/kubernetes/pkg/util/node"
	utilsysctl "k8s.io/kubernetes/pkg/util/sysctl"
	"k8s.io/utils/exec"

	"github.com/golang/glog"
)

// NewProxyServer returns a new ProxyServer.
func NewProxyServer(config *componentconfig.KubeProxyConfiguration, cleanupAndExit bool, scheme *runtime.Scheme, master string) (*ProxyServer, error) {
	if config == nil {
		return nil, errors.New("config is required")
	}

	if c, err := configz.New("componentconfig"); err == nil {
		c.Set(config)
	} else {
		return nil, fmt.Errorf("unable to register configz: %s", err)
	}

	protocol := utiliptables.ProtocolIpv4
	if net.ParseIP(config.BindAddress).To4() == nil {
		protocol = utiliptables.ProtocolIpv6
	}

	var iptInterface utiliptables.Interface
	var ipvsInterface utilipvs.Interface
	var dbus utildbus.Interface

	// Create a iptables utils.
	execer := exec.New()

	dbus = utildbus.New()
	iptInterface = utiliptables.New(execer, dbus, protocol)
	ipvsInterface = utilipvs.New(execer)

	// We omit creation of pretty much everything if we run in cleanup mode
	if cleanupAndExit {
		return &ProxyServer{IptInterface: iptInterface, IpvsInterface: ipvsInterface, CleanupAndExit: cleanupAndExit}, nil
	}

	client, eventClient, err := createClients(config.ClientConnection, master)
	if err != nil {
		return nil, err
	}

	// Create event recorder
	hostname := utilnode.GetHostname(config.HostnameOverride)
	eventBroadcaster := record.NewBroadcaster()
	recorder := eventBroadcaster.NewRecorder(scheme, v1.EventSource{Component: "kube-proxy", Host: hostname})

	nodeRef := &v1.ObjectReference{
		Kind:      "Node",
		Name:      hostname,
		UID:       types.UID(hostname),
		Namespace: "",
	}

	var healthzServer *healthcheck.HealthzServer
	var healthzUpdater healthcheck.HealthzUpdater
	if len(config.HealthzBindAddress) > 0 {
		healthzServer = healthcheck.NewDefaultHealthzServer(config.HealthzBindAddress, 2*config.IPTables.SyncPeriod.Duration, recorder, nodeRef)
		healthzUpdater = healthzServer
	}

	var proxier proxy.ProxyProvider
	var serviceEventHandler proxyconfig.ServiceHandler
	var endpointsEventHandler proxyconfig.EndpointsHandler

	proxyMode := getProxyMode(string(config.Mode), iptInterface, iptables.LinuxKernelCompatTester{})
	if proxyMode == proxyModeIPTables {
		glog.V(0).Info("Using iptables Proxier.")
		var nodeIP net.IP
		if config.BindAddress != "0.0.0.0" {
			nodeIP = net.ParseIP(config.BindAddress)
		} else {
			nodeIP = getNodeIP(client, hostname)
		}
		if config.IPTables.MasqueradeBit == nil {
			// MasqueradeBit must be specified or defaulted.
			return nil, fmt.Errorf("unable to read IPTables MasqueradeBit from config")
		}

		// TODO this has side effects that should only happen when Run() is invoked.
		proxierIPTables, err := iptables.NewProxier(
			iptInterface,
			utilsysctl.New(),
			execer,
			config.IPTables.SyncPeriod.Duration,
			config.IPTables.MinSyncPeriod.Duration,
			config.IPTables.MasqueradeAll,
			int(*config.IPTables.MasqueradeBit),
			config.ClusterCIDR,
			hostname,
			nodeIP,
			recorder,
			healthzUpdater,
		)
		if err != nil {
			return nil, fmt.Errorf("unable to create proxier: %v", err)
		}
		iptables.RegisterMetrics()
		proxier = proxierIPTables
		serviceEventHandler = proxierIPTables
		endpointsEventHandler = proxierIPTables
		// No turning back. Remove artifacts that might still exist from the userspace Proxier.
		glog.V(0).Info("Tearing down inactive rules.")
		// TODO this has side effects that should only happen when Run() is invoked.
		userspace.CleanupLeftovers(iptInterface)
		// IPVS Proxier will generate some iptables rules,
		// need to clean them before switching to other proxy mode.
		ipvs.CleanupLeftovers(execer, ipvsInterface, iptInterface)
	} else if proxyMode == proxyModeIPVS {
		glog.V(0).Info("Using ipvs Proxier.")
		proxierIPVS, err := ipvs.NewProxier(
			iptInterface,
			ipvsInterface,
			utilsysctl.New(),
			execer,
			config.IPVS.SyncPeriod.Duration,
			config.IPVS.MinSyncPeriod.Duration,
			config.IPTables.MasqueradeAll,
			int(*config.IPTables.MasqueradeBit),
			config.ClusterCIDR,
			hostname,
			getNodeIP(client, hostname),
			recorder,
			healthzServer,
			config.IPVS.Scheduler,
		)
		if err != nil {
			return nil, fmt.Errorf("unable to create proxier: %v", err)
		}
		proxier = proxierIPVS
		serviceEventHandler = proxierIPVS
		endpointsEventHandler = proxierIPVS
		glog.V(0).Info("Tearing down inactive rules.")
		// TODO this has side effects that should only happen when Run() is invoked.
		userspace.CleanupLeftovers(iptInterface)
		iptables.CleanupLeftovers(iptInterface)
	} else {
		glog.V(0).Info("Using userspace Proxier.")
		// This is a proxy.LoadBalancer which NewProxier needs but has methods we don't need for
		// our config.EndpointsConfigHandler.
		loadBalancer := userspace.NewLoadBalancerRR()
		// set EndpointsConfigHandler to our loadBalancer
		endpointsEventHandler = loadBalancer

		// TODO this has side effects that should only happen when Run() is invoked.
		proxierUserspace, err := userspace.NewProxier(
			loadBalancer,
			net.ParseIP(config.BindAddress),
			iptInterface,
			execer,
			*utilnet.ParsePortRangeOrDie(config.PortRange),
			config.IPTables.SyncPeriod.Duration,
			config.IPTables.MinSyncPeriod.Duration,
			config.UDPIdleTimeout.Duration,
		)
		if err != nil {
			return nil, fmt.Errorf("unable to create proxier: %v", err)
		}
		serviceEventHandler = proxierUserspace
		proxier = proxierUserspace

		// Remove artifacts from the iptables and ipvs Proxier, if not on Windows.
		glog.V(0).Info("Tearing down inactive rules.")
		// TODO this has side effects that should only happen when Run() is invoked.
		iptables.CleanupLeftovers(iptInterface)
		// IPVS Proxier will generate some iptables rules,
		// need to clean them before switching to other proxy mode.
		ipvs.CleanupLeftovers(execer, ipvsInterface, iptInterface)
	}

	iptInterface.AddReloadFunc(proxier.Sync)

	return &ProxyServer{
		Client:                 client,
		EventClient:            eventClient,
		IptInterface:           iptInterface,
		IpvsInterface:          ipvsInterface,
		execer:                 execer,
		Proxier:                proxier,
		Broadcaster:            eventBroadcaster,
		Recorder:               recorder,
		ConntrackConfiguration: config.Conntrack,
		Conntracker:            &realConntracker{},
		ProxyMode:              proxyMode,
		NodeRef:                nodeRef,
		MetricsBindAddress:     config.MetricsBindAddress,
		EnableProfiling:        config.EnableProfiling,
		OOMScoreAdj:            config.OOMScoreAdj,
		ResourceContainer:      config.ResourceContainer,
		ConfigSyncPeriod:       config.ConfigSyncPeriod.Duration,
		ServiceEventHandler:    serviceEventHandler,
		EndpointsEventHandler:  endpointsEventHandler,
		HealthzServer:          healthzServer,
	}, nil
}

func getProxyMode(proxyMode string, iptver iptables.IPTablesVersioner, kcompat iptables.KernelCompatTester) string {
	if proxyMode == proxyModeUserspace {
		return proxyModeUserspace
	}

	if len(proxyMode) > 0 && proxyMode == proxyModeIPTables {
		return tryIPTablesProxy(iptver, kcompat)
	}

	if utilfeature.DefaultFeatureGate.Enabled(features.SupportIPVSProxyMode) {
		if proxyMode == proxyModeIPVS {
			return tryIPVSProxy(iptver, kcompat)
		} else {
			glog.Warningf("Can't use ipvs proxier, trying iptables proxier")
			return tryIPTablesProxy(iptver, kcompat)
		}
	}
	glog.Warningf("Flag proxy-mode=%q unknown, assuming iptables proxy", proxyMode)
	return tryIPTablesProxy(iptver, kcompat)
}

func tryIPVSProxy(iptver iptables.IPTablesVersioner, kcompat iptables.KernelCompatTester) string {
	// guaranteed false on error, error only necessary for debugging
	// IPVS Proxier relies on iptables
	useIPVSProxy, err := ipvs.CanUseIPVSProxier()
	if err != nil {
		utilruntime.HandleError(fmt.Errorf("can't determine whether to use ipvs proxy, using userspace proxier: %v", err))
		return proxyModeUserspace
	}
	if useIPVSProxy {
		return proxyModeIPVS
	}

	// TODO: Check ipvs version

	// Try to fallback to iptables before falling back to userspace
	glog.V(1).Infof("Can't use ipvs proxier, trying iptables proxier")
	return tryIPTablesProxy(iptver, kcompat)
}

func tryIPTablesProxy(iptver iptables.IPTablesVersioner, kcompat iptables.KernelCompatTester) string {
	// guaranteed false on error, error only necessary for debugging
	useIPTablesProxy, err := iptables.CanUseIPTablesProxier(iptver, kcompat)
	if err != nil {
		utilruntime.HandleError(fmt.Errorf("can't determine whether to use iptables proxy, using userspace proxier: %v", err))
		return proxyModeUserspace
	}
	if useIPTablesProxy {
		return proxyModeIPTables
	}
	// Fallback.
	glog.V(1).Infof("Can't use iptables proxy, using userspace proxier")
	return proxyModeUserspace
}
<commit_msg>apply kube-proxy patch<commit_after>// +build !windows

/*
Copyright 2014 The Kubernetes Authors.

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

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

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

// Package app does all of the work necessary to configure and run a
// Kubernetes app process.
package app

import (
	"errors"
	"fmt"
	"net"

	"k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/types"
	utilnet "k8s.io/apimachinery/pkg/util/net"
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
	utilfeature "k8s.io/apiserver/pkg/util/feature"
	"k8s.io/client-go/tools/record"
	"k8s.io/kubernetes/pkg/apis/componentconfig"
	"k8s.io/kubernetes/pkg/features"
	"k8s.io/kubernetes/pkg/proxy"
	proxyconfig "k8s.io/kubernetes/pkg/proxy/config"
	"k8s.io/kubernetes/pkg/proxy/healthcheck"
	"k8s.io/kubernetes/pkg/proxy/iptables"
	"k8s.io/kubernetes/pkg/proxy/ipvs"
	"k8s.io/kubernetes/pkg/proxy/userspace"
	"k8s.io/kubernetes/pkg/util/configz"
	utildbus "k8s.io/kubernetes/pkg/util/dbus"
	utiliptables "k8s.io/kubernetes/pkg/util/iptables"
	utilipvs "k8s.io/kubernetes/pkg/util/ipvs"
	utilnode "k8s.io/kubernetes/pkg/util/node"
	utilsysctl "k8s.io/kubernetes/pkg/util/sysctl"
	"k8s.io/utils/exec"

	"github.com/golang/glog"
)

// NewProxyServer returns a new ProxyServer.
func NewProxyServer(config *componentconfig.KubeProxyConfiguration, cleanupAndExit bool, scheme *runtime.Scheme, master string) (*ProxyServer, error) {
	if config == nil {
		return nil, errors.New("config is required")
	}

	if c, err := configz.New("componentconfig"); err == nil {
		c.Set(config)
	} else {
		glog.Warningf("unable to register configz: %s", err)
	}

	protocol := utiliptables.ProtocolIpv4
	if net.ParseIP(config.BindAddress).To4() == nil {
		protocol = utiliptables.ProtocolIpv6
	}

	var iptInterface utiliptables.Interface
	var ipvsInterface utilipvs.Interface
	var dbus utildbus.Interface

	// Create a iptables utils.
	execer := exec.New()

	dbus = utildbus.New()
	iptInterface = utiliptables.New(execer, dbus, protocol)
	ipvsInterface = utilipvs.New(execer)

	// We omit creation of pretty much everything if we run in cleanup mode
	if cleanupAndExit {
		return &ProxyServer{IptInterface: iptInterface, IpvsInterface: ipvsInterface, CleanupAndExit: cleanupAndExit}, nil
	}

	client, eventClient, err := createClients(config.ClientConnection, master)
	if err != nil {
		return nil, err
	}

	// Create event recorder
	hostname := utilnode.GetHostname(config.HostnameOverride)
	eventBroadcaster := record.NewBroadcaster()
	recorder := eventBroadcaster.NewRecorder(scheme, v1.EventSource{Component: "kube-proxy", Host: hostname})

	nodeRef := &v1.ObjectReference{
		Kind:      "Node",
		Name:      hostname,
		UID:       types.UID(hostname),
		Namespace: "",
	}

	var healthzServer *healthcheck.HealthzServer
	var healthzUpdater healthcheck.HealthzUpdater
	if len(config.HealthzBindAddress) > 0 {
		healthzServer = healthcheck.NewDefaultHealthzServer(config.HealthzBindAddress, 2*config.IPTables.SyncPeriod.Duration, recorder, nodeRef)
		healthzUpdater = healthzServer
	}

	var proxier proxy.ProxyProvider
	var serviceEventHandler proxyconfig.ServiceHandler
	var endpointsEventHandler proxyconfig.EndpointsHandler

	proxyMode := getProxyMode(string(config.Mode), iptInterface, iptables.LinuxKernelCompatTester{})
	if proxyMode == proxyModeIPTables {
		glog.V(0).Info("Using iptables Proxier.")
		var nodeIP net.IP
		if config.BindAddress != "0.0.0.0" {
			nodeIP = net.ParseIP(config.BindAddress)
		} else {
			nodeIP = getNodeIP(client, hostname)
		}
		if config.IPTables.MasqueradeBit == nil {
			// MasqueradeBit must be specified or defaulted.
			return nil, fmt.Errorf("unable to read IPTables MasqueradeBit from config")
		}

		// TODO this has side effects that should only happen when Run() is invoked.
		proxierIPTables, err := iptables.NewProxier(
			iptInterface,
			utilsysctl.New(),
			execer,
			config.IPTables.SyncPeriod.Duration,
			config.IPTables.MinSyncPeriod.Duration,
			config.IPTables.MasqueradeAll,
			int(*config.IPTables.MasqueradeBit),
			config.ClusterCIDR,
			hostname,
			nodeIP,
			recorder,
			healthzUpdater,
		)
		if err != nil {
			return nil, fmt.Errorf("unable to create proxier: %v", err)
		}
		iptables.RegisterMetrics()
		proxier = proxierIPTables
		serviceEventHandler = proxierIPTables
		endpointsEventHandler = proxierIPTables
		// No turning back. Remove artifacts that might still exist from the userspace Proxier.
		glog.V(0).Info("Tearing down inactive rules.")
		// TODO this has side effects that should only happen when Run() is invoked.
		userspace.CleanupLeftovers(iptInterface)
		// IPVS Proxier will generate some iptables rules,
		// need to clean them before switching to other proxy mode.
		ipvs.CleanupLeftovers(execer, ipvsInterface, iptInterface)
	} else if proxyMode == proxyModeIPVS {
		glog.V(0).Info("Using ipvs Proxier.")
		proxierIPVS, err := ipvs.NewProxier(
			iptInterface,
			ipvsInterface,
			utilsysctl.New(),
			execer,
			config.IPVS.SyncPeriod.Duration,
			config.IPVS.MinSyncPeriod.Duration,
			config.IPTables.MasqueradeAll,
			int(*config.IPTables.MasqueradeBit),
			config.ClusterCIDR,
			hostname,
			getNodeIP(client, hostname),
			recorder,
			healthzServer,
			config.IPVS.Scheduler,
		)
		if err != nil {
			return nil, fmt.Errorf("unable to create proxier: %v", err)
		}
		proxier = proxierIPVS
		serviceEventHandler = proxierIPVS
		endpointsEventHandler = proxierIPVS
		glog.V(0).Info("Tearing down inactive rules.")
		// TODO this has side effects that should only happen when Run() is invoked.
		userspace.CleanupLeftovers(iptInterface)
		iptables.CleanupLeftovers(iptInterface)
	} else {
		glog.V(0).Info("Using userspace Proxier.")
		// This is a proxy.LoadBalancer which NewProxier needs but has methods we don't need for
		// our config.EndpointsConfigHandler.
		loadBalancer := userspace.NewLoadBalancerRR()
		// set EndpointsConfigHandler to our loadBalancer
		endpointsEventHandler = loadBalancer

		// TODO this has side effects that should only happen when Run() is invoked.
		proxierUserspace, err := userspace.NewProxier(
			loadBalancer,
			net.ParseIP(config.BindAddress),
			iptInterface,
			execer,
			*utilnet.ParsePortRangeOrDie(config.PortRange),
			config.IPTables.SyncPeriod.Duration,
			config.IPTables.MinSyncPeriod.Duration,
			config.UDPIdleTimeout.Duration,
		)
		if err != nil {
			return nil, fmt.Errorf("unable to create proxier: %v", err)
		}
		serviceEventHandler = proxierUserspace
		proxier = proxierUserspace

		// Remove artifacts from the iptables and ipvs Proxier, if not on Windows.
		glog.V(0).Info("Tearing down inactive rules.")
		// TODO this has side effects that should only happen when Run() is invoked.
		iptables.CleanupLeftovers(iptInterface)
		// IPVS Proxier will generate some iptables rules,
		// need to clean them before switching to other proxy mode.
		ipvs.CleanupLeftovers(execer, ipvsInterface, iptInterface)
	}

	iptInterface.AddReloadFunc(proxier.Sync)

	return &ProxyServer{
		Client:                 client,
		EventClient:            eventClient,
		IptInterface:           iptInterface,
		IpvsInterface:          ipvsInterface,
		execer:                 execer,
		Proxier:                proxier,
		Broadcaster:            eventBroadcaster,
		Recorder:               recorder,
		ConntrackConfiguration: config.Conntrack,
		Conntracker:            &realConntracker{},
		ProxyMode:              proxyMode,
		NodeRef:                nodeRef,
		MetricsBindAddress:     config.MetricsBindAddress,
		EnableProfiling:        config.EnableProfiling,
		OOMScoreAdj:            config.OOMScoreAdj,
		ResourceContainer:      config.ResourceContainer,
		ConfigSyncPeriod:       config.ConfigSyncPeriod.Duration,
		ServiceEventHandler:    serviceEventHandler,
		EndpointsEventHandler:  endpointsEventHandler,
		HealthzServer:          healthzServer,
	}, nil
}

func getProxyMode(proxyMode string, iptver iptables.IPTablesVersioner, kcompat iptables.KernelCompatTester) string {
	if proxyMode == proxyModeUserspace {
		return proxyModeUserspace
	}

	if len(proxyMode) > 0 && proxyMode == proxyModeIPTables {
		return tryIPTablesProxy(iptver, kcompat)
	}

	if utilfeature.DefaultFeatureGate.Enabled(features.SupportIPVSProxyMode) {
		if proxyMode == proxyModeIPVS {
			return tryIPVSProxy(iptver, kcompat)
		} else {
			glog.Warningf("Can't use ipvs proxier, trying iptables proxier")
			return tryIPTablesProxy(iptver, kcompat)
		}
	}
	glog.Warningf("Flag proxy-mode=%q unknown, assuming iptables proxy", proxyMode)
	return tryIPTablesProxy(iptver, kcompat)
}

func tryIPVSProxy(iptver iptables.IPTablesVersioner, kcompat iptables.KernelCompatTester) string {
	// guaranteed false on error, error only necessary for debugging
	// IPVS Proxier relies on iptables
	useIPVSProxy, err := ipvs.CanUseIPVSProxier()
	if err != nil {
		utilruntime.HandleError(fmt.Errorf("can't determine whether to use ipvs proxy, using userspace proxier: %v", err))
		return proxyModeUserspace
	}
	if useIPVSProxy {
		return proxyModeIPVS
	}

	// TODO: Check ipvs version

	// Try to fallback to iptables before falling back to userspace
	glog.V(1).Infof("Can't use ipvs proxier, trying iptables proxier")
	return tryIPTablesProxy(iptver, kcompat)
}

func tryIPTablesProxy(iptver iptables.IPTablesVersioner, kcompat iptables.KernelCompatTester) string {
	// guaranteed false on error, error only necessary for debugging
	useIPTablesProxy, err := iptables.CanUseIPTablesProxier(iptver, kcompat)
	if err != nil {
		utilruntime.HandleError(fmt.Errorf("can't determine whether to use iptables proxy, using userspace proxier: %v", err))
		return proxyModeUserspace
	}
	if useIPTablesProxy {
		return proxyModeIPTables
	}
	// Fallback.
	glog.V(1).Infof("Can't use iptables proxy, using userspace proxier")
	return proxyModeUserspace
}
<|endoftext|>


<commit_before>/*
Copyright 2015 Christian Grabowski 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 image

import (
	"bytes"
	"fmt"
	"log"
	"os"
	"os/exec"
	"regexp"
	"strings"
	"sync"
)

var waitgroup sync.WaitGroup

// ImageManager is a struct with data for OS images for instances
type ImageManager struct {
	Platform   string
	OS         string
	SSHCommand *exec.Cmd
}

func getLocalOS() string {
	goos := os.Getenv("GOOS")
	osNameCMD := exec.Command("cat", "/etc/*-release", "|", "grep", "PRETTY_NAME")
	var osNameOut bytes.Buffer
	osNameCMD.Stdout = &osNameOut
	err := osNameCMD.Run()
	if err != nil && goos != "darwin" { // uses GOOS in the event it is OSX
		log.Fatal(err)
	} else if goos != "darwin" {
		return osNameOut.String()
	} else {
		return goos
	}
	return ""
}

func formatPrettyName(prettyName string) string {
	var distro, majorVer, minorVer string
	if strings.Contains(prettyName, "Ubuntu") {
		distro = "ubuntu"
	} else if strings.Contains(prettyName, "Debian") {
		distro = "debian"
	} else if strings.Contains(prettyName, "CentOs") {
		distro = "centos"
	} else if strings.Contains(prettyName, "CoreOs") {
		distro = "coreos"
	} else {
		distro = prettyName //log.Fatal("Your OS is not currently supported, to change this, please create an issue @ https://github.com/cpg1111/kubongo/issues")
	}
	rx := regexp.MustCompile("([0-9]+)")
	matches := rx.FindStringSubmatch(prettyName)
	matchesLen := len(matches)
	if matchesLen > 0 {
		majorVer = matches[0]
	}
	if matchesLen > 1 {
		minorVer = matches[1]
	}
	return fmt.Sprintf("%s-%s-%s", distro, majorVer, minorVer)
}

// NewImageManager returns a new ImageManager struct
func NewImageManager(platform string) *ImageManager {
	var (
		sshCommand *exec.Cmd
		imageOS    string
	)
	switch platform {
	case "GCE":
		sshCommand = exec.Command("gcloud", "compute", "ssh")
		imageOS = os.Getenv("MONGO_INSTANCE_OS")
		break
	case "local":
		sshCommand = exec.Command("sh")
		imageOS = formatPrettyName(getLocalOS())
	}
	if imageOS == "" {
		imageOS = "ubuntu-14-04"
	}
	return &ImageManager{
		Platform:   platform,
		OS:         imageOS,
		SSHCommand: sshCommand,
	}
}

func (i *ImageManager) run(finish chan error) {
	log.Println("Running exec")
	finish <- i.SSHCommand.Run()
	//log.Println(i.SSHCommand.Output())
}

// RunCMD runs a Bash command on targeted image
func (i *ImageManager) RunCMD(command string) {
	waitgroup.Wait()
	waitgroup.Add(1)
	defer waitgroup.Done()
	if strings.Contains(i.Platform, "GCE") {
		i.SSHCommand.Args = append(i.SSHCommand.Args, "--command", fmt.Sprintf("\"%s\"", command))
	} else if strings.Contains(i.Platform, "local") {
		i.SSHCommand.Args = append(i.SSHCommand.Args, "-C", fmt.Sprintf("\"%s\"", command))
	}
	finish := make(chan error)
	go i.run(finish)
	select {
	case m1 := <-finish:
		log.Println(command, "pid:", i.SSHCommand.Process.Pid, "is about to close")
		if m1 != nil && !strings.Contains(fmt.Sprintf("%v", m1), "127") {
			log.Fatal("res", m1)
		} else {
			log.Println("res", m1)
			i.SSHCommand = exec.Command(i.SSHCommand.Path)
			return
		}
	}
}

// InstallMongo installs mongo on target image
func (i *ImageManager) InstallMongo() {
	var installCMD string
	switch i.OS {
	case "ubuntu-14-04", "ubuntu-12-04", "debian-7", "debian-8":
		installCMD = "apt-get update && apt-get install mongodb"
	case "darwin--": // TODO clean up "darwin" OS name
		log.Println("is darwin OS")
		installCMD = "/usr/local/bin/brew update && /usr/local/bin/brew install mongodb"
	}
	i.RunCMD(installCMD)
}
<commit_msg>remove TODO comment on darwin tagging<commit_after>/*
Copyright 2015 Christian Grabowski 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 image

import (
	"bytes"
	"fmt"
	"log"
	"os"
	"os/exec"
	"regexp"
	"strings"
	"sync"
)

var waitgroup sync.WaitGroup

// ImageManager is a struct with data for OS images for instances
type ImageManager struct {
	Platform   string
	OS         string
	SSHCommand *exec.Cmd
}

func getLocalOS() string {
	goos := os.Getenv("GOOS")
	osNameCMD := exec.Command("cat", "/etc/*-release", "|", "grep", "PRETTY_NAME")
	var osNameOut bytes.Buffer
	osNameCMD.Stdout = &osNameOut
	err := osNameCMD.Run()
	if err != nil && goos != "darwin" { // uses GOOS in the event it is OSX
		log.Fatal(err)
	} else if goos != "darwin" {
		return osNameOut.String()
	} else {
		return goos
	}
	return ""
}

func formatPrettyName(prettyName string) string {
	var distro, majorVer, minorVer string
	if strings.Contains(prettyName, "Ubuntu") {
		distro = "ubuntu"
	} else if strings.Contains(prettyName, "Debian") {
		distro = "debian"
	} else if strings.Contains(prettyName, "CentOs") {
		distro = "centos"
	} else if strings.Contains(prettyName, "CoreOs") {
		distro = "coreos"
	} else {
		distro = prettyName //log.Fatal("Your OS is not currently supported, to change this, please create an issue @ https://github.com/cpg1111/kubongo/issues")
	}
	rx := regexp.MustCompile("([0-9]+)")
	matches := rx.FindStringSubmatch(prettyName)
	matchesLen := len(matches)
	if matchesLen > 0 {
		majorVer = matches[0]
	}
	if matchesLen > 1 {
		minorVer = matches[1]
	}
	return fmt.Sprintf("%s-%s-%s", distro, majorVer, minorVer)
}

// NewImageManager returns a new ImageManager struct
func NewImageManager(platform string) *ImageManager {
	var (
		sshCommand *exec.Cmd
		imageOS    string
	)
	switch platform {
	case "GCE":
		sshCommand = exec.Command("gcloud", "compute", "ssh")
		imageOS = os.Getenv("MONGO_INSTANCE_OS")
		break
	case "local":
		sshCommand = exec.Command("sh")
		imageOS = formatPrettyName(getLocalOS())
	}
	if imageOS == "" {
		imageOS = "ubuntu-14-04"
	}
	return &ImageManager{
		Platform:   platform,
		OS:         imageOS,
		SSHCommand: sshCommand,
	}
}

func (i *ImageManager) run(finish chan error) {
	log.Println("Running exec")
	finish <- i.SSHCommand.Run()
	//log.Println(i.SSHCommand.Output())
}

// RunCMD runs a Bash command on targeted image
func (i *ImageManager) RunCMD(command string) {
	waitgroup.Wait()
	waitgroup.Add(1)
	defer waitgroup.Done()
	if strings.Contains(i.Platform, "GCE") {
		i.SSHCommand.Args = append(i.SSHCommand.Args, "--command", fmt.Sprintf("\"%s\"", command))
	} else if strings.Contains(i.Platform, "local") {
		i.SSHCommand.Args = append(i.SSHCommand.Args, "-C", fmt.Sprintf("\"%s\"", command))
	}
	finish := make(chan error)
	go i.run(finish)
	select {
	case m1 := <-finish:
		log.Println(command, "pid:", i.SSHCommand.Process.Pid, "is about to close")
		if m1 != nil && !strings.Contains(fmt.Sprintf("%v", m1), "127") {
			log.Fatal("res", m1)
		} else {
			log.Println("res", m1)
			i.SSHCommand = exec.Command(i.SSHCommand.Path)
			return
		}
	}
}

// InstallMongo installs mongo on target image
func (i *ImageManager) InstallMongo() {
	var installCMD string
	switch i.OS {
	case "ubuntu-14-04", "ubuntu-12-04", "debian-7", "debian-8":
		installCMD = "apt-get update && apt-get install mongodb"
	case "darwin--": // clean up "darwin" OS name
		log.Println("is darwin OS")
		installCMD = "/usr/local/bin/brew update && /usr/local/bin/brew install mongodb"
	}
	i.RunCMD(installCMD)
}
<|endoftext|>


<commit_before>package image

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"strconv"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/docker/docker/pkg/archive"
	"github.com/docker/docker/runconfig"
	"github.com/docker/docker/utils"
)

// Set the max depth to the aufs default that most
// kernels are compiled with
// For more information see: http://sourceforge.net/p/aufs/aufs3-standalone/ci/aufs3.12/tree/config.mk
const MaxImageDepth = 127

type Image struct {
	ID              string            `json:"id"`
	Parent          string            `json:"parent,omitempty"`
	Comment         string            `json:"comment,omitempty"`
	Created         time.Time         `json:"created"`
	Container       string            `json:"container,omitempty"`
	ContainerConfig runconfig.Config  `json:"container_config,omitempty"`
	DockerVersion   string            `json:"docker_version,omitempty"`
	Author          string            `json:"author,omitempty"`
	Config          *runconfig.Config `json:"config,omitempty"`
	Architecture    string            `json:"architecture,omitempty"`
	OS              string            `json:"os,omitempty"`
	Size            int64

	graph Graph
}

func LoadImage(root string) (*Image, error) {
	// Load the json data
	jsonData, err := ioutil.ReadFile(jsonPath(root))
	if err != nil {
		return nil, err
	}
	img := &Image{}

	if err := json.Unmarshal(jsonData, img); err != nil {
		return nil, err
	}
	if err := utils.ValidateID(img.ID); err != nil {
		return nil, err
	}

	if buf, err := ioutil.ReadFile(path.Join(root, "layersize")); err != nil {
		if !os.IsNotExist(err) {
			return nil, err
		}
		// If the layersize file does not exist then set the size to a negative number
		// because a layer size of 0 (zero) is valid
		img.Size = -1
	} else {
		size, err := strconv.Atoi(string(buf))
		if err != nil {
			return nil, err
		}
		img.Size = int64(size)
	}

	return img, nil
}

func StoreImage(img *Image, layerData archive.ArchiveReader, root string) error {
	// Store the layer
	var (
		size   int64
		err    error
		driver = img.graph.Driver()
	)

	// If layerData is not nil, unpack it into the new layer
	if layerData != nil {
		if size, err = driver.ApplyDiff(img.ID, img.Parent, layerData); err != nil {
			return err
		}
	}

	img.Size = size
	if err := img.SaveSize(root); err != nil {
		return err
	}

	f, err := os.OpenFile(jsonPath(root), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0600))
	if err != nil {
		return err
	}

	defer f.Close()

	return json.NewEncoder(f).Encode(img)
}

func (img *Image) SetGraph(graph Graph) {
	img.graph = graph
}

// SaveSize stores the current `size` value of `img` in the directory `root`.
func (img *Image) SaveSize(root string) error {
	if err := ioutil.WriteFile(path.Join(root, "layersize"), []byte(strconv.Itoa(int(img.Size))), 0600); err != nil {
		return fmt.Errorf("Error storing image size in %s/layersize: %s", root, err)
	}
	return nil
}

func jsonPath(root string) string {
	return path.Join(root, "json")
}

func (img *Image) RawJson() ([]byte, error) {
	root, err := img.root()
	if err != nil {
		return nil, fmt.Errorf("Failed to get root for image %s: %s", img.ID, err)
	}
	fh, err := os.Open(jsonPath(root))
	if err != nil {
		return nil, fmt.Errorf("Failed to open json for image %s: %s", img.ID, err)
	}
	buf, err := ioutil.ReadAll(fh)
	if err != nil {
		return nil, fmt.Errorf("Failed to read json for image %s: %s", img.ID, err)
	}
	return buf, nil
}

// TarLayer returns a tar archive of the image's filesystem layer.
func (img *Image) TarLayer() (arch archive.Archive, err error) {
	if img.graph == nil {
		return nil, fmt.Errorf("Can't load storage driver for unregistered image %s", img.ID)
	}

	driver := img.graph.Driver()

	return driver.Diff(img.ID, img.Parent)
}

// Image includes convenience proxy functions to its graph
// These functions will return an error if the image is not registered
// (ie. if image.graph == nil)
func (img *Image) History() ([]*Image, error) {
	var parents []*Image
	if err := img.WalkHistory(
		func(img *Image) error {
			parents = append(parents, img)
			return nil
		},
	); err != nil {
		return nil, err
	}
	return parents, nil
}

func (img *Image) WalkHistory(handler func(*Image) error) (err error) {
	currentImg := img
	for currentImg != nil {
		if handler != nil {
			if err := handler(currentImg); err != nil {
				return err
			}
		}
		currentImg, err = currentImg.GetParent()
		if err != nil {
			return fmt.Errorf("Error while getting parent image: %v", err)
		}
	}
	return nil
}

func (img *Image) GetParent() (*Image, error) {
	if img.Parent == "" {
		return nil, nil
	}
	if img.graph == nil {
		return nil, fmt.Errorf("Can't lookup parent of unregistered image")
	}
	return img.graph.Get(img.Parent)
}

func (img *Image) root() (string, error) {
	if img.graph == nil {
		return "", fmt.Errorf("Can't lookup root of unregistered image")
	}
	return img.graph.ImageRoot(img.ID), nil
}

func (img *Image) GetParentsSize(size int64) int64 {
	parentImage, err := img.GetParent()
	if err != nil || parentImage == nil {
		return size
	}
	size += parentImage.Size
	return parentImage.GetParentsSize(size)
}

// Depth returns the number of parents for a
// current image
func (img *Image) Depth() (int, error) {
	var (
		count  = 0
		parent = img
		err    error
	)

	for parent != nil {
		count++
		parent, err = parent.GetParent()
		if err != nil {
			return -1, err
		}
	}
	return count, nil
}

// CheckDepth returns an error if the depth of an image, as returned
// by ImageDepth, is too large to support creating a container from it
// on this daemon.
func (img *Image) CheckDepth() error {
	// We add 2 layers to the depth because the container's rw and
	// init layer add to the restriction
	depth, err := img.Depth()
	if err != nil {
		return err
	}
	if depth+2 >= MaxImageDepth {
		return fmt.Errorf("Cannot create container with more than %d parents", MaxImageDepth)
	}
	return nil
}

// Build an Image object from raw json data
func NewImgJSON(src []byte) (*Image, error) {
	ret := &Image{}

	log.Debugf("Json string: {%s}", src)
	// FIXME: Is there a cleaner way to "purify" the input json?
	if err := json.Unmarshal(src, ret); err != nil {
		return nil, err
	}
	return ret, nil
}
<commit_msg>image: stream img JSON & Decode in LoadImage<commit_after>package image

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"strconv"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/docker/docker/pkg/archive"
	"github.com/docker/docker/runconfig"
	"github.com/docker/docker/utils"
)

// Set the max depth to the aufs default that most
// kernels are compiled with
// For more information see: http://sourceforge.net/p/aufs/aufs3-standalone/ci/aufs3.12/tree/config.mk
const MaxImageDepth = 127

type Image struct {
	ID              string            `json:"id"`
	Parent          string            `json:"parent,omitempty"`
	Comment         string            `json:"comment,omitempty"`
	Created         time.Time         `json:"created"`
	Container       string            `json:"container,omitempty"`
	ContainerConfig runconfig.Config  `json:"container_config,omitempty"`
	DockerVersion   string            `json:"docker_version,omitempty"`
	Author          string            `json:"author,omitempty"`
	Config          *runconfig.Config `json:"config,omitempty"`
	Architecture    string            `json:"architecture,omitempty"`
	OS              string            `json:"os,omitempty"`
	Size            int64

	graph Graph
}

func LoadImage(root string) (*Image, error) {
	// Open the JSON file to decode by streaming
	jsonSource, err := os.Open(jsonPath(root))
	if err != nil {
		return nil, err
	}
	defer jsonSource.Close()

	img := &Image{}
	dec := json.NewDecoder(jsonSource)

	// Decode the JSON data
	if err := dec.Decode(img); err != nil {
		return nil, err
	}
	if err := utils.ValidateID(img.ID); err != nil {
		return nil, err
	}

	if buf, err := ioutil.ReadFile(path.Join(root, "layersize")); err != nil {
		if !os.IsNotExist(err) {
			return nil, err
		}
		// If the layersize file does not exist then set the size to a negative number
		// because a layer size of 0 (zero) is valid
		img.Size = -1
	} else {
		size, err := strconv.Atoi(string(buf))
		if err != nil {
			return nil, err
		}
		img.Size = int64(size)
	}

	return img, nil
}

func StoreImage(img *Image, layerData archive.ArchiveReader, root string) error {
	// Store the layer
	var (
		size   int64
		err    error
		driver = img.graph.Driver()
	)

	// If layerData is not nil, unpack it into the new layer
	if layerData != nil {
		if size, err = driver.ApplyDiff(img.ID, img.Parent, layerData); err != nil {
			return err
		}
	}

	img.Size = size
	if err := img.SaveSize(root); err != nil {
		return err
	}

	f, err := os.OpenFile(jsonPath(root), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0600))
	if err != nil {
		return err
	}

	defer f.Close()

	return json.NewEncoder(f).Encode(img)
}

func (img *Image) SetGraph(graph Graph) {
	img.graph = graph
}

// SaveSize stores the current `size` value of `img` in the directory `root`.
func (img *Image) SaveSize(root string) error {
	if err := ioutil.WriteFile(path.Join(root, "layersize"), []byte(strconv.Itoa(int(img.Size))), 0600); err != nil {
		return fmt.Errorf("Error storing image size in %s/layersize: %s", root, err)
	}
	return nil
}

func jsonPath(root string) string {
	return path.Join(root, "json")
}

func (img *Image) RawJson() ([]byte, error) {
	root, err := img.root()
	if err != nil {
		return nil, fmt.Errorf("Failed to get root for image %s: %s", img.ID, err)
	}
	fh, err := os.Open(jsonPath(root))
	if err != nil {
		return nil, fmt.Errorf("Failed to open json for image %s: %s", img.ID, err)
	}
	buf, err := ioutil.ReadAll(fh)
	if err != nil {
		return nil, fmt.Errorf("Failed to read json for image %s: %s", img.ID, err)
	}
	return buf, nil
}

// TarLayer returns a tar archive of the image's filesystem layer.
func (img *Image) TarLayer() (arch archive.Archive, err error) {
	if img.graph == nil {
		return nil, fmt.Errorf("Can't load storage driver for unregistered image %s", img.ID)
	}

	driver := img.graph.Driver()

	return driver.Diff(img.ID, img.Parent)
}

// Image includes convenience proxy functions to its graph
// These functions will return an error if the image is not registered
// (ie. if image.graph == nil)
func (img *Image) History() ([]*Image, error) {
	var parents []*Image
	if err := img.WalkHistory(
		func(img *Image) error {
			parents = append(parents, img)
			return nil
		},
	); err != nil {
		return nil, err
	}
	return parents, nil
}

func (img *Image) WalkHistory(handler func(*Image) error) (err error) {
	currentImg := img
	for currentImg != nil {
		if handler != nil {
			if err := handler(currentImg); err != nil {
				return err
			}
		}
		currentImg, err = currentImg.GetParent()
		if err != nil {
			return fmt.Errorf("Error while getting parent image: %v", err)
		}
	}
	return nil
}

func (img *Image) GetParent() (*Image, error) {
	if img.Parent == "" {
		return nil, nil
	}
	if img.graph == nil {
		return nil, fmt.Errorf("Can't lookup parent of unregistered image")
	}
	return img.graph.Get(img.Parent)
}

func (img *Image) root() (string, error) {
	if img.graph == nil {
		return "", fmt.Errorf("Can't lookup root of unregistered image")
	}
	return img.graph.ImageRoot(img.ID), nil
}

func (img *Image) GetParentsSize(size int64) int64 {
	parentImage, err := img.GetParent()
	if err != nil || parentImage == nil {
		return size
	}
	size += parentImage.Size
	return parentImage.GetParentsSize(size)
}

// Depth returns the number of parents for a
// current image
func (img *Image) Depth() (int, error) {
	var (
		count  = 0
		parent = img
		err    error
	)

	for parent != nil {
		count++
		parent, err = parent.GetParent()
		if err != nil {
			return -1, err
		}
	}
	return count, nil
}

// CheckDepth returns an error if the depth of an image, as returned
// by ImageDepth, is too large to support creating a container from it
// on this daemon.
func (img *Image) CheckDepth() error {
	// We add 2 layers to the depth because the container's rw and
	// init layer add to the restriction
	depth, err := img.Depth()
	if err != nil {
		return err
	}
	if depth+2 >= MaxImageDepth {
		return fmt.Errorf("Cannot create container with more than %d parents", MaxImageDepth)
	}
	return nil
}

// Build an Image object from raw json data
func NewImgJSON(src []byte) (*Image, error) {
	ret := &Image{}

	log.Debugf("Json string: {%s}", src)
	// FIXME: Is there a cleaner way to "purify" the input json?
	if err := json.Unmarshal(src, ret); err != nil {
		return nil, err
	}
	return ret, nil
}
<|endoftext|>