<commit_before>// Copyright 2015-2016, Cyrill @ Schumacher.fm and the CoreStore contributors
//
// 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 config

import "github.com/corestoreio/csfw/store/scope"

type (

	// deprecated

	// ModelConstructor implements different fields/functions which can be differently used
	// by the FieldSourceModeller or FieldBackendModeller types.
	// Nearly all functions will return not nil. The Construct() function takes what it needs.
	ModelConstructor struct {
		// WebsiteID contains a website/store ID or nil (=default scope) both can be nil or just one
		ScopeWebsite scope.WebsiteIDer
		ScopeStore   scope.StoreIDer
		// Config returns the configuration Getter and never nil
		Config Getter
		// @todo more fields to be added, depends on the overall requirements of all Magento models.
	}

	// BackendModeller defines how to save and load the data @todo rethink AddData
	// In Magento slang: beforeSave() and afterLoad().
	// The Construct() must be used because NOT all fields of ModelConstructor are available during
	// init process and can of course change during the running app. Also to prevent circular dependencies.
	BackendModeller interface {
		// not sure Construct(ModelConstructor) error
		AddData(interface{})
		Save() error
	}
)
<commit_msg>config: Delete growing OOP pattern before it more evolves.<commit_after><|endoftext|>


<commit_before>package specs

import "os"

// LinuxStateDirectory holds the container's state information
const LinuxStateDirectory = "/run/opencontainer/containers"

// LinuxSpec is the full specification for linux containers.
type LinuxSpec struct {
	Spec
	// Linux is platform specific configuration for linux based containers.
	Linux Linux `json:"linux"`
}

// Linux contains platform specific configuration for linux based containers.
type Linux struct {
	// UIDMapping specifies user mappings for supporting user namespaces on linux.
	UIDMappings []IDMapping `json:"uidMappings,omitempty"`
	// GIDMapping specifies group mappings for supporting user namespaces on linux.
	GIDMappings []IDMapping `json:"gidMappings,omitempty"`
	// Rlimits specifies rlimit options to apply to the container's process.
	Rlimits []Rlimit `json:"rlimits,omitempty"`
	// Sysctl are a set of key value pairs that are set for the container on start
	Sysctl map[string]string `json:"sysctl,omitempty"`
	// Resources contain cgroup information for handling resource constraints
	// for the container
	Resources *Resources `json:"resources,omitempty"`
	// CgroupsPath specifies the path to cgroups that are created and/or joined by the container.
	// The path is expected to be relative to the cgroups mountpoint.
	// If resources are specified, the cgroups at CgroupsPath will be updated based on resources.
	CgroupsPath *string `json:"cgroupsPath,omitempty"`
	// Namespaces contains the namespaces that are created and/or joined by the container
	Namespaces []Namespace `json:"namespaces"`
	// Devices are a list of device nodes that are created for the container
	Devices []Device `json:"devices"`
	// Seccomp specifies the seccomp security settings for the container.
	Seccomp Seccomp `json:"seccomp"`
	// RootfsPropagation is the rootfs mount propagation mode for the container.
	RootfsPropagation string `json:"rootfsPropagation,omitempty"`
}

// User specifies linux specific user and group information for the container's
// main process.
type User struct {
	// UID is the user id.
	UID uint32 `json:"uid"`
	// GID is the group id.
	GID uint32 `json:"gid"`
	// AdditionalGids are additional group ids set for the container's process.
	AdditionalGids []uint32 `json:"additionalGids,omitempty"`
}

// Namespace is the configuration for a linux namespace
type Namespace struct {
	// Type is the type of Linux namespace
	Type NamespaceType `json:"type"`
	// Path is a path to an existing namespace persisted on disk that can be joined
	// and is of the same type
	Path string `json:"path,omitempty"`
}

// NamespaceType is one of the linux namespaces
type NamespaceType string

const (
	// PIDNamespace for isolating process IDs
	PIDNamespace NamespaceType = "pid"
	// NetworkNamespace for isolating network devices, stacks, ports, etc
	NetworkNamespace = "network"
	// MountNamespace for isolating mount points
	MountNamespace = "mount"
	// IPCNamespace for isolating System V IPC, POSIX message queues
	IPCNamespace = "ipc"
	// UTSNamespace for isolating hostname and NIS domain name
	UTSNamespace = "uts"
	// UserNamespace for isolating user and group IDs
	UserNamespace = "user"
)

// IDMapping specifies UID/GID mappings
type IDMapping struct {
	// HostID is the UID/GID of the host user or group
	HostID uint32 `json:"hostID"`
	// ContainerID is the UID/GID of the container's user or group
	ContainerID uint32 `json:"containerID"`
	// Size is the length of the range of IDs mapped between the two namespaces
	Size uint32 `json:"size"`
}

// Rlimit type and restrictions
type Rlimit struct {
	// Type of the rlimit to set
	Type string `json:"type"`
	// Hard is the hard limit for the specified type
	Hard uint64 `json:"hard"`
	// Soft is the soft limit for the specified type
	Soft uint64 `json:"soft"`
}

// HugepageLimit structure corresponds to limiting kernel hugepages
type HugepageLimit struct {
	// Pagesize is the hugepage size
	Pagesize *string `json:"pageSize,omitempty"`
	// Limit is the limit of "hugepagesize" hugetlb usage
	Limit *uint64 `json:"limit,omitempty"`
}

// InterfacePriority for network interfaces
type InterfacePriority struct {
	// Name is the name of the network interface
	Name string `json:"name"`
	// Priority for the interface
	Priority uint32 `json:"priority"`
}

// blockIODevice holds major:minor format supported in blkio cgroup
type blockIODevice struct {
	// Major is the device's major number.
	Major int64 `json:"major"`
	// Minor is the device's minor number.
	Minor int64 `json:"minor"`
}

// WeightDevice struct holds a `major:minor weight` pair for blkioWeightDevice
type WeightDevice struct {
	blockIODevice
	// Weight is the bandwidth rate for the device, range is from 10 to 1000
	Weight *uint16 `json:"weight,omitempty"`
	// LeafWeight is the bandwidth rate for the device while competing with the cgroup's child cgroups, range is from 10 to 1000, CFQ scheduler only
	LeafWeight *uint16 `json:"leafWeight,omitempty"`
}

// ThrottleDevice struct holds a `major:minor rate_per_second` pair
type ThrottleDevice struct {
	blockIODevice
	// Rate is the IO rate limit per cgroup per device
	Rate *uint64 `json:"rate,omitempty"`
}

// BlockIO for Linux cgroup 'blkio' resource management
type BlockIO struct {
	// Specifies per cgroup weight, range is from 10 to 1000
	Weight *uint16 `json:"blkioWeight,omitempty"`
	// Specifies tasks' weight in the given cgroup while competing with the cgroup's child cgroups, range is from 10 to 1000, CFQ scheduler only
	LeafWeight *uint16 `json:"blkioLeafWeight,omitempty"`
	// Weight per cgroup per device, can override BlkioWeight
	WeightDevice []WeightDevice `json:"blkioWeightDevice,omitempty"`
	// IO read rate limit per cgroup per device, bytes per second
	ThrottleReadBpsDevice []ThrottleDevice `json:"blkioThrottleReadBpsDevice,omitempty"`
	// IO write rate limit per cgroup per device, bytes per second
	ThrottleWriteBpsDevice []ThrottleDevice `json:"blkioThrottleWriteBpsDevice,omitempty"`
	// IO read rate limit per cgroup per device, IO per second
	ThrottleReadIOPSDevice []ThrottleDevice `json:"blkioThrottleReadIOPSDevice,omitempty"`
	// IO write rate limit per cgroup per device, IO per second
	ThrottleWriteIOPSDevice []ThrottleDevice `json:"blkioThrottleWriteIOPSDevice,omitempty"`
}

// Memory for Linux cgroup 'memory' resource management
type Memory struct {
	// Memory limit (in bytes).
	Limit *uint64 `json:"limit,omitempty"`
	// Memory reservation or soft_limit (in bytes).
	Reservation *uint64 `json:"reservation,omitempty"`
	// Total memory limit (memory + swap).
	Swap *uint64 `json:"swap,omitempty"`
	// Kernel memory limit (in bytes).
	Kernel *uint64 `json:"kernel,omitempty"`
	// Kernel memory limit for tcp (in bytes)
	KernelTCP *uint64 `json:"kernelTCP"`
	// How aggressive the kernel will swap memory pages. Range from 0 to 100.
	Swappiness *uint64 `json:"swappiness,omitempty"`
}

// CPU for Linux cgroup 'cpu' resource management
type CPU struct {
	// CPU shares (relative weight (ratio) vs. other cgroups with cpu shares).
	Shares *uint64 `json:"shares,omitempty"`
	// CPU hardcap limit (in usecs). Allowed cpu time in a given period.
	Quota *uint64 `json:"quota,omitempty"`
	// CPU period to be used for hardcapping (in usecs).
	Period *uint64 `json:"period,omitempty"`
	// How much time realtime scheduling may use (in usecs).
	RealtimeRuntime *uint64 `json:"realtimeRuntime,omitempty"`
	// CPU period to be used for realtime scheduling (in usecs).
	RealtimePeriod *uint64 `json:"realtimePeriod,omitempty"`
	// CPUs to use within the cpuset. Default is to use any CPU available.
	Cpus *string `json:"cpus,omitempty"`
	// List of memory nodes in the cpuset. Default is to use any available memory node.
	Mems *string `json:"mems,omitempty"`
}

// Pids for Linux cgroup 'pids' resource management (Linux 4.3)
type Pids struct {
	// Maximum number of PIDs. Default is "no limit".
	Limit *int64 `json:"limit,omitempty"`
}

// Network identification and priority configuration
type Network struct {
	// Set class identifier for container's network packets
	ClassID *uint32 `json:"classID"`
	// Set priority of network traffic for container
	Priorities []InterfacePriority `json:"priorities,omitempty"`
}

// Resources has container runtime resource constraints
type Resources struct {
	// Devices are a list of device rules for the whitelist controller
	Devices []DeviceCgroup `json:"devices"`
	// DisableOOMKiller disables the OOM killer for out of memory conditions
	DisableOOMKiller *bool `json:"disableOOMKiller,omitempty"`
	// Specify an oom_score_adj for the container.
	OOMScoreAdj *int `json:"oomScoreAdj,omitempty"`
	// Memory restriction configuration
	Memory *Memory `json:"memory,omitempty"`
	// CPU resource restriction configuration
	CPU *CPU `json:"cpu,omitempty"`
	// Task resource restriction configuration.
	Pids *Pids `json:"pids,omitempty"`
	// BlockIO restriction configuration
	BlockIO *BlockIO `json:"blockIO,omitempty"`
	// Hugetlb limit (in bytes)
	HugepageLimits []HugepageLimit `json:"hugepageLimits,omitempty"`
	// Network restriction configuration
	Network *Network `json:"network,omitempty"`
}

// Device represents the mknod information for a Linux special device file
type Device struct {
	// Path to the device.
	Path string `json:"path"`
	// Device type, block, char, etc.
	Type string `json:"type"`
	// Major is the device's major number.
	Major int64 `json:"major"`
	// Minor is the device's minor number.
	Minor int64 `json:"minor"`
	// FileMode permission bits for the device.
	FileMode *os.FileMode `json:"fileMode,omitempty"`
	// UID of the device.
	UID *uint32 `json:"uid,omitempty"`
	// Gid of the device.
	GID *uint32 `json:"gid,omitempty"`
}

// DeviceCgroup represents a device rule for the whitelist controller
type DeviceCgroup struct {
	// Allow or deny
	Allow bool `json:"allow"`
	// Device type, block, char, etc.
	Type *string `json:"type,omitempty"`
	// Major is the device's major number.
	Major *int64 `json:"major,omitempty"`
	// Minor is the device's minor number.
	Minor *int64 `json:"minor,omitempty"`
	// Cgroup access permissions format, rwm.
	Access *string `json:"access,omitempty"`
}

// Seccomp represents syscall restrictions
type Seccomp struct {
	DefaultAction Action    `json:"defaultAction"`
	Architectures []Arch    `json:"architectures"`
	Syscalls      []Syscall `json:"syscalls,omitempty"`
}

// Arch used for additional architectures
type Arch string

// Additional architectures permitted to be used for system calls
// By default only the native architecture of the kernel is permitted
const (
	ArchX86         Arch = "SCMP_ARCH_X86"
	ArchX86_64      Arch = "SCMP_ARCH_X86_64"
	ArchX32         Arch = "SCMP_ARCH_X32"
	ArchARM         Arch = "SCMP_ARCH_ARM"
	ArchAARCH64     Arch = "SCMP_ARCH_AARCH64"
	ArchMIPS        Arch = "SCMP_ARCH_MIPS"
	ArchMIPS64      Arch = "SCMP_ARCH_MIPS64"
	ArchMIPS64N32   Arch = "SCMP_ARCH_MIPS64N32"
	ArchMIPSEL      Arch = "SCMP_ARCH_MIPSEL"
	ArchMIPSEL64    Arch = "SCMP_ARCH_MIPSEL64"
	ArchMIPSEL64N32 Arch = "SCMP_ARCH_MIPSEL64N32"
)

// Action taken upon Seccomp rule match
type Action string

// Define actions for Seccomp rules
const (
	ActKill  Action = "SCMP_ACT_KILL"
	ActTrap  Action = "SCMP_ACT_TRAP"
	ActErrno Action = "SCMP_ACT_ERRNO"
	ActTrace Action = "SCMP_ACT_TRACE"
	ActAllow Action = "SCMP_ACT_ALLOW"
)

// Operator used to match syscall arguments in Seccomp
type Operator string

// Define operators for syscall arguments in Seccomp
const (
	OpNotEqual     Operator = "SCMP_CMP_NE"
	OpLessThan     Operator = "SCMP_CMP_LT"
	OpLessEqual    Operator = "SCMP_CMP_LE"
	OpEqualTo      Operator = "SCMP_CMP_EQ"
	OpGreaterEqual Operator = "SCMP_CMP_GE"
	OpGreaterThan  Operator = "SCMP_CMP_GT"
	OpMaskedEqual  Operator = "SCMP_CMP_MASKED_EQ"
)

// Arg used for matching specific syscall arguments in Seccomp
type Arg struct {
	Index    uint     `json:"index"`
	Value    uint64   `json:"value"`
	ValueTwo uint64   `json:"valueTwo"`
	Op       Operator `json:"op"`
}

// Syscall is used to match a syscall in Seccomp
type Syscall struct {
	Name   string `json:"name"`
	Action Action `json:"action"`
	Args   []Arg  `json:"args,omitempty"`
}
<commit_msg>Seccomp should be optional<commit_after>package specs

import "os"

// LinuxStateDirectory holds the container's state information
const LinuxStateDirectory = "/run/opencontainer/containers"

// LinuxSpec is the full specification for linux containers.
type LinuxSpec struct {
	Spec
	// Linux is platform specific configuration for linux based containers.
	Linux Linux `json:"linux"`
}

// Linux contains platform specific configuration for linux based containers.
type Linux struct {
	// UIDMapping specifies user mappings for supporting user namespaces on linux.
	UIDMappings []IDMapping `json:"uidMappings,omitempty"`
	// GIDMapping specifies group mappings for supporting user namespaces on linux.
	GIDMappings []IDMapping `json:"gidMappings,omitempty"`
	// Rlimits specifies rlimit options to apply to the container's process.
	Rlimits []Rlimit `json:"rlimits,omitempty"`
	// Sysctl are a set of key value pairs that are set for the container on start
	Sysctl map[string]string `json:"sysctl,omitempty"`
	// Resources contain cgroup information for handling resource constraints
	// for the container
	Resources *Resources `json:"resources,omitempty"`
	// CgroupsPath specifies the path to cgroups that are created and/or joined by the container.
	// The path is expected to be relative to the cgroups mountpoint.
	// If resources are specified, the cgroups at CgroupsPath will be updated based on resources.
	CgroupsPath *string `json:"cgroupsPath,omitempty"`
	// Namespaces contains the namespaces that are created and/or joined by the container
	Namespaces []Namespace `json:"namespaces"`
	// Devices are a list of device nodes that are created for the container
	Devices []Device `json:"devices"`
	// Seccomp specifies the seccomp security settings for the container.
	Seccomp *Seccomp `json:"seccomp,omitempty"`
	// RootfsPropagation is the rootfs mount propagation mode for the container.
	RootfsPropagation string `json:"rootfsPropagation,omitempty"`
}

// User specifies linux specific user and group information for the container's
// main process.
type User struct {
	// UID is the user id.
	UID uint32 `json:"uid"`
	// GID is the group id.
	GID uint32 `json:"gid"`
	// AdditionalGids are additional group ids set for the container's process.
	AdditionalGids []uint32 `json:"additionalGids,omitempty"`
}

// Namespace is the configuration for a linux namespace
type Namespace struct {
	// Type is the type of Linux namespace
	Type NamespaceType `json:"type"`
	// Path is a path to an existing namespace persisted on disk that can be joined
	// and is of the same type
	Path string `json:"path,omitempty"`
}

// NamespaceType is one of the linux namespaces
type NamespaceType string

const (
	// PIDNamespace for isolating process IDs
	PIDNamespace NamespaceType = "pid"
	// NetworkNamespace for isolating network devices, stacks, ports, etc
	NetworkNamespace = "network"
	// MountNamespace for isolating mount points
	MountNamespace = "mount"
	// IPCNamespace for isolating System V IPC, POSIX message queues
	IPCNamespace = "ipc"
	// UTSNamespace for isolating hostname and NIS domain name
	UTSNamespace = "uts"
	// UserNamespace for isolating user and group IDs
	UserNamespace = "user"
)

// IDMapping specifies UID/GID mappings
type IDMapping struct {
	// HostID is the UID/GID of the host user or group
	HostID uint32 `json:"hostID"`
	// ContainerID is the UID/GID of the container's user or group
	ContainerID uint32 `json:"containerID"`
	// Size is the length of the range of IDs mapped between the two namespaces
	Size uint32 `json:"size"`
}

// Rlimit type and restrictions
type Rlimit struct {
	// Type of the rlimit to set
	Type string `json:"type"`
	// Hard is the hard limit for the specified type
	Hard uint64 `json:"hard"`
	// Soft is the soft limit for the specified type
	Soft uint64 `json:"soft"`
}

// HugepageLimit structure corresponds to limiting kernel hugepages
type HugepageLimit struct {
	// Pagesize is the hugepage size
	Pagesize *string `json:"pageSize,omitempty"`
	// Limit is the limit of "hugepagesize" hugetlb usage
	Limit *uint64 `json:"limit,omitempty"`
}

// InterfacePriority for network interfaces
type InterfacePriority struct {
	// Name is the name of the network interface
	Name string `json:"name"`
	// Priority for the interface
	Priority uint32 `json:"priority"`
}

// blockIODevice holds major:minor format supported in blkio cgroup
type blockIODevice struct {
	// Major is the device's major number.
	Major int64 `json:"major"`
	// Minor is the device's minor number.
	Minor int64 `json:"minor"`
}

// WeightDevice struct holds a `major:minor weight` pair for blkioWeightDevice
type WeightDevice struct {
	blockIODevice
	// Weight is the bandwidth rate for the device, range is from 10 to 1000
	Weight *uint16 `json:"weight,omitempty"`
	// LeafWeight is the bandwidth rate for the device while competing with the cgroup's child cgroups, range is from 10 to 1000, CFQ scheduler only
	LeafWeight *uint16 `json:"leafWeight,omitempty"`
}

// ThrottleDevice struct holds a `major:minor rate_per_second` pair
type ThrottleDevice struct {
	blockIODevice
	// Rate is the IO rate limit per cgroup per device
	Rate *uint64 `json:"rate,omitempty"`
}

// BlockIO for Linux cgroup 'blkio' resource management
type BlockIO struct {
	// Specifies per cgroup weight, range is from 10 to 1000
	Weight *uint16 `json:"blkioWeight,omitempty"`
	// Specifies tasks' weight in the given cgroup while competing with the cgroup's child cgroups, range is from 10 to 1000, CFQ scheduler only
	LeafWeight *uint16 `json:"blkioLeafWeight,omitempty"`
	// Weight per cgroup per device, can override BlkioWeight
	WeightDevice []WeightDevice `json:"blkioWeightDevice,omitempty"`
	// IO read rate limit per cgroup per device, bytes per second
	ThrottleReadBpsDevice []ThrottleDevice `json:"blkioThrottleReadBpsDevice,omitempty"`
	// IO write rate limit per cgroup per device, bytes per second
	ThrottleWriteBpsDevice []ThrottleDevice `json:"blkioThrottleWriteBpsDevice,omitempty"`
	// IO read rate limit per cgroup per device, IO per second
	ThrottleReadIOPSDevice []ThrottleDevice `json:"blkioThrottleReadIOPSDevice,omitempty"`
	// IO write rate limit per cgroup per device, IO per second
	ThrottleWriteIOPSDevice []ThrottleDevice `json:"blkioThrottleWriteIOPSDevice,omitempty"`
}

// Memory for Linux cgroup 'memory' resource management
type Memory struct {
	// Memory limit (in bytes).
	Limit *uint64 `json:"limit,omitempty"`
	// Memory reservation or soft_limit (in bytes).
	Reservation *uint64 `json:"reservation,omitempty"`
	// Total memory limit (memory + swap).
	Swap *uint64 `json:"swap,omitempty"`
	// Kernel memory limit (in bytes).
	Kernel *uint64 `json:"kernel,omitempty"`
	// Kernel memory limit for tcp (in bytes)
	KernelTCP *uint64 `json:"kernelTCP"`
	// How aggressive the kernel will swap memory pages. Range from 0 to 100.
	Swappiness *uint64 `json:"swappiness,omitempty"`
}

// CPU for Linux cgroup 'cpu' resource management
type CPU struct {
	// CPU shares (relative weight (ratio) vs. other cgroups with cpu shares).
	Shares *uint64 `json:"shares,omitempty"`
	// CPU hardcap limit (in usecs). Allowed cpu time in a given period.
	Quota *uint64 `json:"quota,omitempty"`
	// CPU period to be used for hardcapping (in usecs).
	Period *uint64 `json:"period,omitempty"`
	// How much time realtime scheduling may use (in usecs).
	RealtimeRuntime *uint64 `json:"realtimeRuntime,omitempty"`
	// CPU period to be used for realtime scheduling (in usecs).
	RealtimePeriod *uint64 `json:"realtimePeriod,omitempty"`
	// CPUs to use within the cpuset. Default is to use any CPU available.
	Cpus *string `json:"cpus,omitempty"`
	// List of memory nodes in the cpuset. Default is to use any available memory node.
	Mems *string `json:"mems,omitempty"`
}

// Pids for Linux cgroup 'pids' resource management (Linux 4.3)
type Pids struct {
	// Maximum number of PIDs. Default is "no limit".
	Limit *int64 `json:"limit,omitempty"`
}

// Network identification and priority configuration
type Network struct {
	// Set class identifier for container's network packets
	ClassID *uint32 `json:"classID"`
	// Set priority of network traffic for container
	Priorities []InterfacePriority `json:"priorities,omitempty"`
}

// Resources has container runtime resource constraints
type Resources struct {
	// Devices are a list of device rules for the whitelist controller
	Devices []DeviceCgroup `json:"devices"`
	// DisableOOMKiller disables the OOM killer for out of memory conditions
	DisableOOMKiller *bool `json:"disableOOMKiller,omitempty"`
	// Specify an oom_score_adj for the container.
	OOMScoreAdj *int `json:"oomScoreAdj,omitempty"`
	// Memory restriction configuration
	Memory *Memory `json:"memory,omitempty"`
	// CPU resource restriction configuration
	CPU *CPU `json:"cpu,omitempty"`
	// Task resource restriction configuration.
	Pids *Pids `json:"pids,omitempty"`
	// BlockIO restriction configuration
	BlockIO *BlockIO `json:"blockIO,omitempty"`
	// Hugetlb limit (in bytes)
	HugepageLimits []HugepageLimit `json:"hugepageLimits,omitempty"`
	// Network restriction configuration
	Network *Network `json:"network,omitempty"`
}

// Device represents the mknod information for a Linux special device file
type Device struct {
	// Path to the device.
	Path string `json:"path"`
	// Device type, block, char, etc.
	Type string `json:"type"`
	// Major is the device's major number.
	Major int64 `json:"major"`
	// Minor is the device's minor number.
	Minor int64 `json:"minor"`
	// FileMode permission bits for the device.
	FileMode *os.FileMode `json:"fileMode,omitempty"`
	// UID of the device.
	UID *uint32 `json:"uid,omitempty"`
	// Gid of the device.
	GID *uint32 `json:"gid,omitempty"`
}

// DeviceCgroup represents a device rule for the whitelist controller
type DeviceCgroup struct {
	// Allow or deny
	Allow bool `json:"allow"`
	// Device type, block, char, etc.
	Type *string `json:"type,omitempty"`
	// Major is the device's major number.
	Major *int64 `json:"major,omitempty"`
	// Minor is the device's minor number.
	Minor *int64 `json:"minor,omitempty"`
	// Cgroup access permissions format, rwm.
	Access *string `json:"access,omitempty"`
}

// Seccomp represents syscall restrictions
type Seccomp struct {
	DefaultAction Action    `json:"defaultAction"`
	Architectures []Arch    `json:"architectures"`
	Syscalls      []Syscall `json:"syscalls,omitempty"`
}

// Arch used for additional architectures
type Arch string

// Additional architectures permitted to be used for system calls
// By default only the native architecture of the kernel is permitted
const (
	ArchX86         Arch = "SCMP_ARCH_X86"
	ArchX86_64      Arch = "SCMP_ARCH_X86_64"
	ArchX32         Arch = "SCMP_ARCH_X32"
	ArchARM         Arch = "SCMP_ARCH_ARM"
	ArchAARCH64     Arch = "SCMP_ARCH_AARCH64"
	ArchMIPS        Arch = "SCMP_ARCH_MIPS"
	ArchMIPS64      Arch = "SCMP_ARCH_MIPS64"
	ArchMIPS64N32   Arch = "SCMP_ARCH_MIPS64N32"
	ArchMIPSEL      Arch = "SCMP_ARCH_MIPSEL"
	ArchMIPSEL64    Arch = "SCMP_ARCH_MIPSEL64"
	ArchMIPSEL64N32 Arch = "SCMP_ARCH_MIPSEL64N32"
)

// Action taken upon Seccomp rule match
type Action string

// Define actions for Seccomp rules
const (
	ActKill  Action = "SCMP_ACT_KILL"
	ActTrap  Action = "SCMP_ACT_TRAP"
	ActErrno Action = "SCMP_ACT_ERRNO"
	ActTrace Action = "SCMP_ACT_TRACE"
	ActAllow Action = "SCMP_ACT_ALLOW"
)

// Operator used to match syscall arguments in Seccomp
type Operator string

// Define operators for syscall arguments in Seccomp
const (
	OpNotEqual     Operator = "SCMP_CMP_NE"
	OpLessThan     Operator = "SCMP_CMP_LT"
	OpLessEqual    Operator = "SCMP_CMP_LE"
	OpEqualTo      Operator = "SCMP_CMP_EQ"
	OpGreaterEqual Operator = "SCMP_CMP_GE"
	OpGreaterThan  Operator = "SCMP_CMP_GT"
	OpMaskedEqual  Operator = "SCMP_CMP_MASKED_EQ"
)

// Arg used for matching specific syscall arguments in Seccomp
type Arg struct {
	Index    uint     `json:"index"`
	Value    uint64   `json:"value"`
	ValueTwo uint64   `json:"valueTwo"`
	Op       Operator `json:"op"`
}

// Syscall is used to match a syscall in Seccomp
type Syscall struct {
	Name   string `json:"name"`
	Action Action `json:"action"`
	Args   []Arg  `json:"args,omitempty"`
}
<|endoftext|>


<commit_before>package fh

import (
	"context"
	"sync"
	"sync/atomic"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/firehose"
	"github.com/gallir/bytebufferpool"
	"github.com/gallir/smart-relayer/lib"
)

const (
	recordsTimeout = 15 * time.Second
	maxRecordSize  = 1000000 // The maximum size of a record sent to Kinesis Firehose, before base64-encoding, is 1000 KB
)

var (
	clientCount int64 = 0
	buffPool          = &bytebufferpool.Pool{}
)

// Client is the thread that connect to the remote redis server
type Client struct {
	sync.Mutex
	srv         *Server
	mode        int
	records     []*record
	status      int
	finish      chan bool
	done        chan bool
	ID          int
	tick        *time.Ticker
	lastFlushed time.Time
}

// NewClient creates a new client that connect to a Redis server
func NewClient(srv *Server) *Client {
	n := atomic.AddInt64(&clientCount, 1)

	clt := &Client{
		done:   make(chan bool),
		finish: make(chan bool),
		status: 0,
		srv:    srv,
		ID:     int(n),
		tick:   time.NewTicker(recordsTimeout),
	}

	if err := clt.Reload(); err != nil {
		lib.Debugf("Firehose client %d ERROR: reload %s", clt.ID, err)
		return nil
	}

	lib.Debugf("Firehose client %d ready", clt.ID)

	return clt
}

// Reload finish the listener and run it again
func (clt *Client) Reload() error {
	clt.Lock()
	defer clt.Unlock()

	if clt.status > 0 {
		clt.Exit()
	}

	go clt.listen()

	return nil
}

func (clt *Client) listen() {
	defer lib.Debugf("Firehose client %d: Closed listener", clt.ID)
	clt.status = 1

	for {
		select {
		case r := <-clt.srv.recordsCh:
			// ignore empty messages
			if r.len() <= 0 {
				continue
			}

			clt.records = append(clt.records, r)
			if len(clt.records) >= clt.srv.config.MaxRecords {
				clt.flush()
			}
		case <-clt.tick.C:
			if time.Since(clt.lastFlushed) >= recordsTimeout {
				clt.flush()
			}
		case <-clt.done:
			lib.Debugf("Firehose client %d: closing..", clt.ID)
			clt.finish <- true
			return
		}
	}

}

func (clt *Client) flush() {
	clt.lastFlushed = time.Now()

	if len(clt.records) <= 0 {
		return
	}

	records := make([]*firehose.Record, 0)

	b := buffPool.Get()
	defer buffPool.Put(b)

	for _, r := range clt.records {
		if r.len()+b.Len()+1 >= maxRecordSize {
			records = append(records, &firehose.Record{Data: b.Bytes()})
			b.Reset()
		}

		b.Write(r.bytes())
		b.Write([]byte("\n"))
	}

	if b.Len() > 0 {
		records = append(records, &firehose.Record{Data: b.Bytes()})
		b.Reset()
	}

	req, _ := clt.srv.awsSvc.PutRecordBatchRequest(&firehose.PutRecordBatchInput{
		DeliveryStreamName: aws.String(clt.srv.config.StreamName),
		Records:            records,
	})

	ctx, cancel := context.WithTimeout(context.Background(), connectTimeout)
	defer cancel()

	req.SetContext(ctx)

	err := req.Send()
	if err != nil {
		if req.IsErrorThrottle() {
			lib.Debugf("Firehose client %d: ERROR IsErrorThrottle: %s", clt.ID, err)
		} else {
			lib.Debugf("Firehose client %d: ERROR PutRecordBatch->Send: %s", clt.ID, err)
		}
		clt.srv.failure()
		return
	}

	lib.Debugf("Firehose: sent %d", len(records))

	for _, r := range clt.records {
		putPool(r)
	}
	clt.records = nil
}

// Exit finish the go routine of the client
func (clt *Client) Exit() {
	defer lib.Debugf("Firehose client %d: Exit, %d records lost", clt.ID, len(clt.records))

	clt.done <- true
	<-clt.finish

	clt.flush()
}
<commit_msg>Change the way to use the bytesbuffer<commit_after>package fh

import (
	"context"
	"sync"
	"sync/atomic"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/firehose"
	"github.com/gallir/bytebufferpool"
	"github.com/gallir/smart-relayer/lib"
)

const (
	recordsTimeout = 15 * time.Second
	maxRecordSize  = 1000000 // The maximum size of a record sent to Kinesis Firehose, before base64-encoding, is 1000 KB
)

var (
	clientCount int64 = 0
	buffPool          = &bytebufferpool.Pool{}
)

// Client is the thread that connect to the remote redis server
type Client struct {
	sync.Mutex
	srv         *Server
	mode        int
	records     []*record
	status      int
	finish      chan bool
	done        chan bool
	ID          int
	tick        *time.Ticker
	lastFlushed time.Time
}

// NewClient creates a new client that connect to a Redis server
func NewClient(srv *Server) *Client {
	n := atomic.AddInt64(&clientCount, 1)

	clt := &Client{
		done:   make(chan bool),
		finish: make(chan bool),
		status: 0,
		srv:    srv,
		ID:     int(n),
		tick:   time.NewTicker(recordsTimeout),
	}

	if err := clt.Reload(); err != nil {
		lib.Debugf("Firehose client %d ERROR: reload %s", clt.ID, err)
		return nil
	}

	lib.Debugf("Firehose client %d ready", clt.ID)

	return clt
}

// Reload finish the listener and run it again
func (clt *Client) Reload() error {
	clt.Lock()
	defer clt.Unlock()

	if clt.status > 0 {
		clt.Exit()
	}

	go clt.listen()

	return nil
}

func (clt *Client) listen() {
	defer lib.Debugf("Firehose client %d: Closed listener", clt.ID)
	clt.status = 1

	for {
		select {
		case r := <-clt.srv.recordsCh:
			// ignore empty messages
			if r.len() <= 0 {
				continue
			}

			clt.records = append(clt.records, r)
			if len(clt.records) >= clt.srv.config.MaxRecords {
				clt.flush()
			}
		case <-clt.tick.C:
			if time.Since(clt.lastFlushed) >= recordsTimeout {
				clt.flush()
			}
		case <-clt.done:
			lib.Debugf("Firehose client %d: closing..", clt.ID)
			clt.finish <- true
			return
		}
	}

}

func (clt *Client) flush() {
	clt.lastFlushed = time.Now()

	if len(clt.records) <= 0 {
		return
	}

	records := make([]*firehose.Record, 0)

	b := buffPool.Get()
	b.Reset()

	for _, r := range clt.records {
		if r.len()+b.Len()+1 >= maxRecordSize {
			records = append(records, &firehose.Record{Data: b.Bytes()})
			b.Reset()
		}

		b.Write(r.bytes())
		b.Write([]byte("\n"))
	}

	if b.Len() > 0 {
		records = append(records, &firehose.Record{Data: b.Bytes()})
	}

	defer buffPool.Put(b)

	req, _ := clt.srv.awsSvc.PutRecordBatchRequest(&firehose.PutRecordBatchInput{
		DeliveryStreamName: aws.String(clt.srv.config.StreamName),
		Records:            records,
	})

	ctx, cancel := context.WithTimeout(context.Background(), connectTimeout)
	defer cancel()

	req.SetContext(ctx)

	err := req.Send()
	if err != nil {
		if req.IsErrorThrottle() {
			lib.Debugf("Firehose client %d: ERROR IsErrorThrottle: %s", clt.ID, err)
		} else {
			lib.Debugf("Firehose client %d: ERROR PutRecordBatch->Send: %s", clt.ID, err)
		}
		clt.srv.failure()
		return
	}

	lib.Debugf("Firehose: sent %d", len(records))

	for _, r := range clt.records {
		putPool(r)
	}
	clt.records = nil
}

// Exit finish the go routine of the client
func (clt *Client) Exit() {
	defer lib.Debugf("Firehose client %d: Exit, %d records lost", clt.ID, len(clt.records))

	clt.done <- true
	<-clt.finish

	clt.flush()
}
<|endoftext|>


<commit_before>package reflect

import (
	"fmt"

	. "github.com/anaminus/rbxmk"
	"github.com/yuin/gopher-lua"
)

func ReflectVariantTo(s State, v Value) (lv lua.LValue, t Type, err error) {
	switch v := v.(type) {
	case nil:
		return lua.LNil, s.Type("nil"), nil
	case bool:
		return lua.LBool(v), s.Type("bool"), nil
	case uint8:
		return lua.LNumber(v), s.Type("number"), nil
	case uint16:
		return lua.LNumber(v), s.Type("number"), nil
	case uint32:
		return lua.LNumber(v), s.Type("number"), nil
	case uint64:
		return lua.LNumber(v), s.Type("number"), nil
	case uint:
		return lua.LNumber(v), s.Type("number"), nil
	case int8:
		return lua.LNumber(v), s.Type("number"), nil
	case int16:
		return lua.LNumber(v), s.Type("number"), nil
	case int32:
		return lua.LNumber(v), s.Type("number"), nil
	case int64:
		return lua.LNumber(v), s.Type("number"), nil
	case int:
		return lua.LNumber(v), s.Type("number"), nil
	case float32:
		return lua.LNumber(v), s.Type("number"), nil
	case float64:
		return lua.LNumber(v), s.Type("number"), nil
	case string:
		return lua.LString(v), s.Type("string"), nil
	case []byte:
		return lua.LString(v), s.Type("string"), nil
	case []rune:
		return lua.LString(v), s.Type("string"), nil
	case []Value:
		typ := s.Type("Array")
		values, err := typ.ReflectTo(s, typ, v)
		if err != nil {
			return nil, typ, err
		}
		return values[0], typ, nil
	case map[string]Value:
		typ := s.Type("Dictionary")
		values, err := typ.ReflectTo(s, typ, v)
		if err != nil {
			return nil, typ, err
		}
		return values[0], typ, nil
	case TValue:
		typ := s.Type(v.Type)
		if typ.ReflectTo == nil {
			return nil, typ, fmt.Errorf("unknown type %q", v.Type)
		}
		values, err := typ.ReflectTo(s, typ, v.Value)
		if err != nil {
			return nil, typ, err
		}
		if len(values) > 0 {
			return values[0], typ, nil
		}
	}
	return nil, s.Type("Variant"), fmt.Errorf("unable to cast value to Variant")
}

func ReflectVariantFrom(s State, lv lua.LValue) (v Value, t Type, err error) {
	switch lv := lv.(type) {
	case *lua.LNilType:
		return nil, s.Type("nil"), nil
	case lua.LBool:
		return bool(lv), s.Type("bool"), nil
	case lua.LNumber:
		return float64(lv), s.Type("number"), nil
	case lua.LString:
		return string(lv), s.Type("string"), nil
	case *lua.LTable:
		if lv.Len() > 0 {
			arrayType := s.Type("Array")
			if v, err = arrayType.ReflectFrom(s, arrayType, lv); err == nil {
				return v, arrayType, nil
			}
		}
		dictType := s.Type("Dictionary")
		v, err := dictType.ReflectFrom(s, dictType, lv)
		return v, dictType, err
	case *lua.LUserData:
		name, ok := s.L.GetMetaField(lv, "__type").(lua.LString)
		if !ok {
			return nil, s.Type("Variant"), fmt.Errorf("unable to cast %s to Variant", lv.Type().String())
		}
		typ := s.Type(string(name))
		if typ.Name == "" {
			return nil, s.Type("Variant"), fmt.Errorf("unknown type %q", string(name))
		}
		if typ.ReflectFrom == nil {
			return nil, typ, fmt.Errorf("unable to cast %s to Variant", typ.Name)
		}
		v, err := typ.ReflectFrom(s, typ, lv)
		return v, typ, err
	}
	return nil, s.Type("Variant"), fmt.Errorf("unable to cast %s to Variant", lv.Type().String())
}

// PullVariant gets from the Lua state the value at n, and reflects a value from
// it according to the Variant type.
func PullVariant(s State, n int) (v Value, t Type) {
	v, t, err := ReflectVariantFrom(s, s.L.CheckAny(n))
	if err != nil {
		s.L.ArgError(n, err.Error())
		return nil, t
	}
	return v, t
}

func Variant() Type {
	return Type{
		Name: "Variant",
		ReflectTo: func(s State, t Type, v Value) (lvs []lua.LValue, err error) {
			lv, _, err := ReflectVariantTo(s, v)
			if err != nil {
				return nil, err
			}
			return []lua.LValue{lv}, nil
		},
		ReflectFrom: func(s State, t Type, lvs ...lua.LValue) (v Value, err error) {
			v, _, err = ReflectVariantFrom(s, lvs[0])
			return v, err
		},
	}
}
<commit_msg>Allow Variant to receive Stringlike and numberlike types.<commit_after>package reflect

import (
	"fmt"

	. "github.com/anaminus/rbxmk"
	"github.com/anaminus/rbxmk/types"
	"github.com/yuin/gopher-lua"
)

func ReflectVariantTo(s State, v Value) (lv lua.LValue, t Type, err error) {
	switch v := v.(type) {
	case nil:
		return lua.LNil, s.Type("nil"), nil
	case bool:
		return lua.LBool(v), s.Type("bool"), nil
	case uint8:
		return lua.LNumber(v), s.Type("number"), nil
	case uint16:
		return lua.LNumber(v), s.Type("number"), nil
	case uint32:
		return lua.LNumber(v), s.Type("number"), nil
	case uint64:
		return lua.LNumber(v), s.Type("number"), nil
	case uint:
		return lua.LNumber(v), s.Type("number"), nil
	case int8:
		return lua.LNumber(v), s.Type("number"), nil
	case int16:
		return lua.LNumber(v), s.Type("number"), nil
	case int32:
		return lua.LNumber(v), s.Type("number"), nil
	case int64:
		return lua.LNumber(v), s.Type("number"), nil
	case int:
		return lua.LNumber(v), s.Type("number"), nil
	case float32:
		return lua.LNumber(v), s.Type("number"), nil
	case float64:
		return lua.LNumber(v), s.Type("number"), nil
	case string:
		return lua.LString(v), s.Type("string"), nil
	case []byte:
		return lua.LString(v), s.Type("string"), nil
	case []rune:
		return lua.LString(v), s.Type("string"), nil
	case []Value:
		typ := s.Type("Array")
		values, err := typ.ReflectTo(s, typ, v)
		if err != nil {
			return nil, typ, err
		}
		return values[0], typ, nil
	case map[string]Value:
		typ := s.Type("Dictionary")
		values, err := typ.ReflectTo(s, typ, v)
		if err != nil {
			return nil, typ, err
		}
		return values[0], typ, nil
	case types.Stringlike:
		if v, ok := v.Stringlike(); ok {
			return lua.LString(v), s.Type("string"), nil
		}
	case types.Floatlike:
		if v, ok := v.Floatlike(); ok {
			return lua.LNumber(v), s.Type("number"), nil
		}
	case types.Intlike:
		if v, ok := v.Intlike(); ok {
			return lua.LNumber(v), s.Type("int"), nil
		}
	case TValue:
		typ := s.Type(v.Type)
		if typ.ReflectTo == nil {
			return nil, typ, fmt.Errorf("unknown type %q", v.Type)
		}
		values, err := typ.ReflectTo(s, typ, v.Value)
		if err != nil {
			return nil, typ, err
		}
		if len(values) > 0 {
			return values[0], typ, nil
		}
	}
	return nil, s.Type("Variant"), fmt.Errorf("unable to cast value to Variant")
}

func ReflectVariantFrom(s State, lv lua.LValue) (v Value, t Type, err error) {
	switch lv := lv.(type) {
	case *lua.LNilType:
		return nil, s.Type("nil"), nil
	case lua.LBool:
		return bool(lv), s.Type("bool"), nil
	case lua.LNumber:
		return float64(lv), s.Type("number"), nil
	case lua.LString:
		return string(lv), s.Type("string"), nil
	case *lua.LTable:
		if lv.Len() > 0 {
			arrayType := s.Type("Array")
			if v, err = arrayType.ReflectFrom(s, arrayType, lv); err == nil {
				return v, arrayType, nil
			}
		}
		dictType := s.Type("Dictionary")
		v, err := dictType.ReflectFrom(s, dictType, lv)
		return v, dictType, err
	case *lua.LUserData:
		name, ok := s.L.GetMetaField(lv, "__type").(lua.LString)
		if !ok {
			return nil, s.Type("Variant"), fmt.Errorf("unable to cast %s to Variant", lv.Type().String())
		}
		typ := s.Type(string(name))
		if typ.Name == "" {
			return nil, s.Type("Variant"), fmt.Errorf("unknown type %q", string(name))
		}
		if typ.ReflectFrom == nil {
			return nil, typ, fmt.Errorf("unable to cast %s to Variant", typ.Name)
		}
		v, err := typ.ReflectFrom(s, typ, lv)
		return v, typ, err
	}
	return nil, s.Type("Variant"), fmt.Errorf("unable to cast %s to Variant", lv.Type().String())
}

// PullVariant gets from the Lua state the value at n, and reflects a value from
// it according to the Variant type.
func PullVariant(s State, n int) (v Value, t Type) {
	v, t, err := ReflectVariantFrom(s, s.L.CheckAny(n))
	if err != nil {
		s.L.ArgError(n, err.Error())
		return nil, t
	}
	return v, t
}

func Variant() Type {
	return Type{
		Name: "Variant",
		ReflectTo: func(s State, t Type, v Value) (lvs []lua.LValue, err error) {
			lv, _, err := ReflectVariantTo(s, v)
			if err != nil {
				return nil, err
			}
			return []lua.LValue{lv}, nil
		},
		ReflectFrom: func(s State, t Type, lvs ...lua.LValue) (v Value, err error) {
			v, _, err = ReflectVariantFrom(s, lvs[0])
			return v, err
		},
	}
}
<|endoftext|>


<commit_before>package bleve

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"reflect"
	"testing"

	"github.com/blevesearch/bleve"
	_ "github.com/blevesearch/bleve/analysis/analyzer/keyword"
	"github.com/ironman-project/ironman/template/model"
	"github.com/ironman-project/ironman/template/repository"
	uuid "github.com/satori/go.uuid"
)

func tempIndexPath(t *testing.T) string {
	dir, err := ioutil.TempDir("", "ironman-bleve-test")
	if err != nil {
		t.Fatal("Failed to create test bleve index directory", err)
	}

	indexPath := filepath.Join(dir, "index")
	return indexPath
}

func newTestRepository(t *testing.T) (repository.Repository, bleve.Index, func()) {
	path := tempIndexPath(t)

	index, err := BuildIndex(path)

	if err != nil {
		t.Fatalf("Failed to open test index %s", err)
	}

	r := New(SetIndex(index))

	return r, index, func() {
		err := index.Close()

		if err != nil {
			t.Fatal("Failed to close bleve index", err)
		}
		err = os.RemoveAll(path)
		if err != nil {
			t.Fatal("Failed to clean bleve index", err)
		}
	}
}

func Test_bleeveRepository_Index(t *testing.T) {

	type args struct {
		template *model.Template
	}
	tests := []struct {
		name    string
		args    args
		wantErr bool
	}{
		{
			"Index a template",
			args{
				&model.Template{
					ID:          "test-template",
					Name:        "Test template",
					Description: "This is a test template",
					Generators: []*model.Generator{
						&model.Generator{
							ID:          "test-generator",
							Name:        "Test generator",
							Description: "This is a test generator",
						},
					},
				},
			},
			false,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			r, index, clean := newTestRepository(t)
			defer clean()
			var id string
			var err error
			if id, err = r.Index(tt.args.template); (err != nil) != tt.wantErr {
				t.Errorf("bleeveRepository.Index() error = %v, wantErr %v", err, tt.wantErr)
				return
			}
			doc, err := index.Document(id)

			if err != nil {
				t.Errorf("bleeveRepository.Index() error = %v, wantErr %v", err, tt.wantErr)
			}

			if doc == nil {
				t.Errorf("bleeveRepository.Index() nil , want %v", tt.args.template)
			}

			got, err := deserialize(doc)

			if err != nil {
				t.Errorf("bleeveRepository.Index()  error = %v", err)
			}

			if got != nil && !reflect.DeepEqual(got, tt.args.template) {
				t.Errorf("bleeveRepository.FindTemplateByID() = %v, want %v", got, tt.args.template)
			}

		})
	}
}

func Test_bleeveRepository_Update(t *testing.T) {

	type args struct {
		template *model.Template
	}
	tests := []struct {
		name     string
		args     args
		template *model.Template
		wantErr  bool
	}{
		{
			"Update template index",
			args{
				&model.Template{
					ID:          "template-id",
					Name:        "Updated name",
					Description: "Updated description",
					Generators: []*model.Generator{
						&model.Generator{
							ID:          "test-generator",
							Name:        "Test generator",
							Description: "This is a test generator",
						},
						&model.Generator{
							ID:          "test-generator2",
							Name:        "Test generator2",
							Description: "This is a test generator 2",
						},
					},
				},
			},
			&model.Template{
				ID: "template-id",
			},
			false,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			r, index, clean := newTestRepository(t)
			defer clean()
			id := uuid.NewV4().String()
			tt.template.IID = id
			err := index.Index(id, tt.template)

			if err != nil {
				t.Error("Failed to index template to update", err)
			}

			if err := r.Update(tt.args.template); (err != nil) != tt.wantErr {
				t.Errorf("bleeveRepository.Update() error = %v, wantErr %v", err, tt.wantErr)
			}

			doc, err := index.Document(id)

			if doc == nil {
				t.Error("failed to retreive indexed document with ID", id)
			}

			if err != nil {
				t.Error("failed to retreive indexed document", tt.template, err)
			}

			for _, field := range doc.Fields {

				value := string(field.Value())
				switch field.Name() {
				case "IID":
					if string(value) == "" || (value != id) {
						t.Errorf("bleveRepository.Update() IID = %v want %v", value, id)
					}
				case "ID":
					if string(value) == "" || (value != tt.args.template.ID) {
						t.Errorf("bleveRepository.Update() templateID = %v want %v", value, tt.args.template.ID)
					}
				case "Name":
					if string(value) == "" || (value != tt.args.template.Name) {
						t.Errorf("bleveRepository.Update() templateName = %v want %v", value, tt.args.template.Name)
					}
				case "Description":
					if string(value) == "" || (value != tt.args.template.Description) {
						t.Errorf("bleveRepository.Update() templateDescription = %v want %v", value, tt.args.template.Description)
					}
				case "Generators.ID":
					pos := field.ArrayPositions()[0]
					expectedID := tt.args.template.Generators[pos].ID
					if value != expectedID {
						t.Errorf("bleveRepository.Update() template.Generators[%d].ID = %v want %v", pos, value, expectedID)
					}
				case "Generators.Name":
					pos := field.ArrayPositions()[0]
					expectedName := tt.args.template.Generators[pos].Name
					if value != expectedName {
						t.Errorf("bleveRepository.Update() template.Generators[%d].Name = %v want %v", pos, value, expectedName)
					}
				case "Generators.Description":
					pos := field.ArrayPositions()[0]
					expectedDescription := tt.args.template.Generators[pos].Description
					if value != expectedDescription {
						t.Errorf("bleveRepository.Update() template.Generators[%d].Description = %v want %v", pos, value, expectedDescription)
					}
				default:
					t.Error("doc.Fields should assert field", field.Name(), string(field.Value()))
				}
			}

		})
	}
}

func Test_bleeveRepository_FindTemplateByID(t *testing.T) {

	type args struct {
		ID string
	}
	tests := []struct {
		name    string
		args    args
		want    *model.Template
		wantErr bool
	}{
		{
			"Find by id",
			args{
				"test-template-id",
			},
			&model.Template{
				ID:          "test-template-id",
				Description: "Some description",
			},
			false,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			r, index, clean := newTestRepository(t)
			defer clean()
			err := index.Index(uuid.NewV4().String(), tt.want)

			if err != nil {
				t.Errorf("Failed to index template model")
			}

			got, err := r.FindTemplateByID(tt.args.ID)

			if (err != nil) != tt.wantErr {
				t.Errorf("bleeveRepository.FindTemplateByID() error = %v, wantErr %v", err, tt.wantErr)
				return
			}

			if got != nil && !reflect.DeepEqual(got, tt.want) {
				t.Errorf("bleeveRepository.FindTemplateByID() = %v, want %v", got, tt.want)
			}
		})
	}
}
<commit_msg>add unit test for bleve repository Delete method<commit_after>package bleve

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"reflect"
	"testing"

	"github.com/blevesearch/bleve"
	_ "github.com/blevesearch/bleve/analysis/analyzer/keyword"
	"github.com/ironman-project/ironman/template/model"
	"github.com/ironman-project/ironman/template/repository"
	uuid "github.com/satori/go.uuid"
)

func tempIndexPath(t *testing.T) string {
	dir, err := ioutil.TempDir("", "ironman-bleve-test")
	if err != nil {
		t.Fatal("Failed to create test bleve index directory", err)
	}

	indexPath := filepath.Join(dir, "index")
	return indexPath
}

func newTestRepository(t *testing.T) (repository.Repository, bleve.Index, func()) {
	path := tempIndexPath(t)

	index, err := BuildIndex(path)

	if err != nil {
		t.Fatalf("Failed to open test index %s", err)
	}

	r := New(SetIndex(index))

	return r, index, func() {
		err := index.Close()

		if err != nil {
			t.Fatal("Failed to close bleve index", err)
		}
		err = os.RemoveAll(path)
		if err != nil {
			t.Fatal("Failed to clean bleve index", err)
		}
	}
}

func Test_bleeveRepository_Index(t *testing.T) {

	type args struct {
		template *model.Template
	}
	tests := []struct {
		name    string
		args    args
		wantErr bool
	}{
		{
			"Index a template",
			args{
				&model.Template{
					ID:          "test-template",
					Name:        "Test template",
					Description: "This is a test template",
					Generators: []*model.Generator{
						&model.Generator{
							ID:          "test-generator",
							Name:        "Test generator",
							Description: "This is a test generator",
						},
					},
				},
			},
			false,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			r, index, clean := newTestRepository(t)
			defer clean()
			var id string
			var err error
			if id, err = r.Index(tt.args.template); (err != nil) != tt.wantErr {
				t.Errorf("bleeveRepository.Index() error = %v, wantErr %v", err, tt.wantErr)
				return
			}
			doc, err := index.Document(id)

			if err != nil {
				t.Errorf("bleeveRepository.Index() error = %v, wantErr %v", err, tt.wantErr)
			}

			if doc == nil {
				t.Errorf("bleeveRepository.Index() nil , want %v", tt.args.template)
			}

			got, err := deserialize(doc)

			if err != nil {
				t.Errorf("bleeveRepository.Index()  error = %v", err)
			}

			if got != nil && !reflect.DeepEqual(got, tt.args.template) {
				t.Errorf("bleeveRepository.FindTemplateByID() = %v, want %v", got, tt.args.template)
			}

		})
	}
}

func Test_bleeveRepository_Update(t *testing.T) {

	type args struct {
		template *model.Template
	}
	tests := []struct {
		name     string
		args     args
		template *model.Template
		wantErr  bool
	}{
		{
			"Update template index",
			args{
				&model.Template{
					ID:          "template-id",
					Name:        "Updated name",
					Description: "Updated description",
					Generators: []*model.Generator{
						&model.Generator{
							ID:          "test-generator",
							Name:        "Test generator",
							Description: "This is a test generator",
						},
						&model.Generator{
							ID:          "test-generator2",
							Name:        "Test generator2",
							Description: "This is a test generator 2",
						},
					},
				},
			},
			&model.Template{
				ID: "template-id",
			},
			false,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			r, index, clean := newTestRepository(t)
			defer clean()
			id := uuid.NewV4().String()
			tt.template.IID = id
			err := index.Index(id, tt.template)

			if err != nil {
				t.Error("Failed to index template to update", err)
			}

			if err := r.Update(tt.args.template); (err != nil) != tt.wantErr {
				t.Errorf("bleeveRepository.Update() error = %v, wantErr %v", err, tt.wantErr)
			}

			doc, err := index.Document(id)

			if doc == nil {
				t.Error("failed to retreive indexed document with ID", id)
			}

			if err != nil {
				t.Error("failed to retreive indexed document", tt.template, err)
			}

			for _, field := range doc.Fields {

				value := string(field.Value())
				switch field.Name() {
				case "IID":
					if string(value) == "" || (value != id) {
						t.Errorf("bleveRepository.Update() IID = %v want %v", value, id)
					}
				case "ID":
					if string(value) == "" || (value != tt.args.template.ID) {
						t.Errorf("bleveRepository.Update() templateID = %v want %v", value, tt.args.template.ID)
					}
				case "Name":
					if string(value) == "" || (value != tt.args.template.Name) {
						t.Errorf("bleveRepository.Update() templateName = %v want %v", value, tt.args.template.Name)
					}
				case "Description":
					if string(value) == "" || (value != tt.args.template.Description) {
						t.Errorf("bleveRepository.Update() templateDescription = %v want %v", value, tt.args.template.Description)
					}
				case "Generators.ID":
					pos := field.ArrayPositions()[0]
					expectedID := tt.args.template.Generators[pos].ID
					if value != expectedID {
						t.Errorf("bleveRepository.Update() template.Generators[%d].ID = %v want %v", pos, value, expectedID)
					}
				case "Generators.Name":
					pos := field.ArrayPositions()[0]
					expectedName := tt.args.template.Generators[pos].Name
					if value != expectedName {
						t.Errorf("bleveRepository.Update() template.Generators[%d].Name = %v want %v", pos, value, expectedName)
					}
				case "Generators.Description":
					pos := field.ArrayPositions()[0]
					expectedDescription := tt.args.template.Generators[pos].Description
					if value != expectedDescription {
						t.Errorf("bleveRepository.Update() template.Generators[%d].Description = %v want %v", pos, value, expectedDescription)
					}
				default:
					t.Error("doc.Fields should assert field", field.Name(), string(field.Value()))
				}
			}

		})
	}
}

func Test_bleeveRepository_FindTemplateByID(t *testing.T) {

	type args struct {
		ID string
	}
	tests := []struct {
		name    string
		args    args
		want    *model.Template
		wantErr bool
	}{
		{
			"Find by id",
			args{
				"test-template-id",
			},
			&model.Template{
				ID:          "test-template-id",
				Description: "Some description",
			},
			false,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			r, index, clean := newTestRepository(t)
			defer clean()
			err := index.Index(uuid.NewV4().String(), tt.want)

			if err != nil {
				t.Errorf("Failed to index template model")
			}

			got, err := r.FindTemplateByID(tt.args.ID)

			if (err != nil) != tt.wantErr {
				t.Errorf("bleeveRepository.FindTemplateByID() error = %v, wantErr %v", err, tt.wantErr)
				return
			}

			if got != nil && !reflect.DeepEqual(got, tt.want) {
				t.Errorf("bleeveRepository.FindTemplateByID() = %v, want %v", got, tt.want)
			}
		})
	}
}

func Test_bleeveRepository_Delete(t *testing.T) {

	type args struct {
		ID string
	}
	tests := []struct {
		name    string
		args    args
		want    bool
		wantErr bool
	}{
		{
			"Delete template from index",
			args{
				"template-id",
			},
			true,
			false,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			r, index, clean := newTestRepository(t)
			defer clean()
			id := uuid.NewV4().String()
			templ := &model.Template{
				IID: id,
				ID:  "template-id",
			}
			err := index.Index(id, templ)

			if err != nil {
				t.Error("Failed to index template to update", err)
			}
			got, err := r.Delete(tt.args.ID)
			if (err != nil) != tt.wantErr {
				t.Errorf("bleeveRepository.Delete() error = %v, wantErr %v", err, tt.wantErr)
				return
			}
			if got != tt.want {
				t.Errorf("bleeveRepository.Delete() = %v, want %v", got, tt.want)
			}
		})
	}
}
<|endoftext|>


<commit_before>package vault

import (
	"errors"
	"os"
	"os/user"
	"strings"

	"github.com/99designs/aws-vault/Godeps/_workspace/src/github.com/vaughan0/go-ini"
)

var AWSConfigFile string

func init() {
	AWSConfigFile = os.Getenv("AWS_CONFIG_FILE")
	if AWSConfigFile == "" {
		usr, err := user.Current()
		if err != nil {
			panic(err)
		}
		AWSConfigFile = usr.HomeDir + "/.aws/config"
	}
}

type AWSProfile struct {
	Name          string
	Region        string
	MFASerial     string
	RoleARN       string
	SourceProfile string
}

func LoadAWSProfile(name string) (AWSProfile, error) {
	f, err := ini.LoadFile(AWSConfigFile)
	if err != nil {
		return AWSProfile{}, err
	}
	for sectionName, section := range f {
		if strings.TrimPrefix(sectionName, "profile ") == name {
			return AWSProfile{
				Region:        section["region"],
				MFASerial:     section["mfa_serial"],
				RoleARN:       section["role_arn"],
				SourceProfile: section["source_profile"],
			}, nil
		}
	}
	return AWSProfile{}, ErrProfileNotFound
}

var ErrProfileNotFound = errors.New("Profile not found")
<commit_msg>Error for missing profile reports profile name and config file.<commit_after>package vault

import (
	"fmt"
	"os"
	"os/user"
	"strings"

	"github.com/99designs/aws-vault/Godeps/_workspace/src/github.com/vaughan0/go-ini"
)

var AWSConfigFile string

func init() {
	AWSConfigFile = os.Getenv("AWS_CONFIG_FILE")
	if AWSConfigFile == "" {
		usr, err := user.Current()
		if err != nil {
			panic(err)
		}
		AWSConfigFile = usr.HomeDir + "/.aws/config"
	}
}

type AWSProfile struct {
	Name          string
	Region        string
	MFASerial     string
	RoleARN       string
	SourceProfile string
}

func LoadAWSProfile(name string) (AWSProfile, error) {
	f, err := ini.LoadFile(AWSConfigFile)
	if err != nil {
		return AWSProfile{}, err
	}
	for sectionName, section := range f {
		if strings.TrimPrefix(sectionName, "profile ") == name {
			return AWSProfile{
				Region:        section["region"],
				MFASerial:     section["mfa_serial"],
				RoleARN:       section["role_arn"],
				SourceProfile: section["source_profile"],
			}, nil
		}
	}
	err = fmt.Errorf(
		"Profile '%s' not found in %s",
		name,
		AWSConfigFile,
	)
	return AWSProfile{}, err
}
<|endoftext|>


<commit_before>// Package logger provides collection of loggin functions with colored output and stack frames
package logger

import (
	"encoding/json"
	"fmt"
	"io"
	"os"
	"runtime"
	"time"

	"github.com/fatih/color"
	"github.com/shiena/ansicolor"
)

const (
	// FileNameNo indicates to no print filename
	FileNameNo int = iota
	// FileNameShort indicates to print short filename
	FileNameShort
	// FileNameLong indicates to print full filename
	FileNameLong
)

var (
	colored = false
	btrace  = true
	pdebug  = true
	fname   = FileNameNo

	output     = ansicolor.NewAnsiColorWriter(os.Stdout)
	timeFormat = "2006-Jan-2 15:04:05.0000"

	// InfoPrefix is text prefix for info log
	InfoPrefix = "INFO"
	// WarnPrefix is text prefix for warning log
	WarnPrefix = "WARN"
	// ErrPrefix is text prefix for error log
	ErrPrefix = " ERR"
	// DebugPrefix is text prefix for debug log
	DebugPrefix = " DEB"
)

// EnableColored enables colored output
func EnableColored() {
	colored = true
}

// DisableColored disables colored output
func DisableColored() {
	colored = false
}

// EnableBTrace enables backtrace for warnings and errors
func EnableBTrace() {
	btrace = true
}

// DisableBTrace disables backtrace
func DisableBTrace() {
	btrace = false
}

// EnableDebug enables debug logs
func EnableDebug() {
	pdebug = true
}

// DisableDebug disables debug logs
func DisableDebug() {
	pdebug = false
}

// SetFileName sets flag for print ceurrent file name in log
func SetFileName(fn int) {
	switch fn {
	case FileNameLong, FileNameNo, FileNameShort:
		fname = fn
	}
}

// SetOut set writer fo print logs. Default writer is os.Stdout
func SetOut(out io.Writer) {
	output = ansicolor.NewAnsiColorWriter(out)
}

func makeStack() (ret string) {
	st := make([]uintptr, 50)
	cnt := runtime.Callers(4, st)
	st = st[0:cnt]
	for _, r := range st {
		fnc := runtime.FuncForPC(r)
		file, line := fnc.FileLine(r - 1)

		stack_line := fmt.Sprintf("\t%s:%d\n", file, line)
		stack_func := fmt.Sprintf("\t\t%s\n", fnc.Name())
		if colored {
			stack_line = color.MagentaString(stack_line)
			stack_func = color.MagentaString(stack_func)
		}

		ret += stack_line + stack_func
	}
	return
}

func printLog(colora color.Attribute, prefix string, printTrace bool, message string, v ...interface{}) {
	var f func(format string, a ...interface{}) string
	if colored {
		f = color.New(colora).SprintfFunc()
	} else {
		f = fmt.Sprintf
	}

	var fileName string
	if fname != FileNameNo {
		_, file, line, ok := runtime.Caller(2)
		if !ok {
			file = "???"
			line = 0
		}
		if fname == FileNameShort {
			short := file
			for i := len(file) - 1; i > 0; i-- {
				if file[i] == '/' {
					short = file[i+1:]
					break
				}
			}
			file = short
		}
		fileName = fmt.Sprintf(" %s:%d", file, line)
	}

	var stack string
	if printTrace && btrace {
		stack = makeStack()
	}
	fmt.Fprint(output, f("%s %s %s\n", time.Now().Format(timeFormat), prefix+fileName, fmt.Sprintf(message, v...)), stack)
}

// Info prints info log (green if colored)
func Info(message string, v ...interface{}) {
	printLog(color.FgGreen, InfoPrefix, false, message, v...)
}

// Warning prints warning log (yellow if colored)
func Warning(message string, v ...interface{}) {
	printLog(color.FgYellow, WarnPrefix, true, message, v...)
}

// Error prints error log (red if colored)
func Error(message string, v ...interface{}) {
	printLog(color.FgRed, ErrPrefix, true, message, v...)
}

// Debug prints debug log (blue if colored)
func Debug(message string, v ...interface{}) {
	if pdebug {
		printLog(color.FgBlue, DebugPrefix, false, message, v...)
	}
}

// Fatal prints error log and finish proccess by os.Exit(1)
func Fatal(message string, v ...interface{}) {
	printLog(color.FgRed, ErrPrefix, true, message, v...)
	os.Exit(1)
}

// Panic prints error log and call panic
func Panic(message string, v ...interface{}) {
	DisableBTrace()
	printLog(color.FgRed, ErrPrefix, true, message, v...)
	panic(fmt.Sprintf(message, v...))
}

// PanicRecover recovers panic an print error message
func PanicRecover() {
	if err := recover(); err != nil {
		Error("PANIC: %s", err)
	}
}

// ErrorErr prints err as error log and returns true if err!=nil
func ErrorErr(err error) bool {
	if err != nil {
		printLog(color.FgRed, ErrPrefix, true, "%v", err)
		return true
	}
	return false
}

// WarningErr prints err as warning log and returns true if err!=nil
func WarningErr(err error) bool {
	if err != nil {
		printLog(color.FgYellow, WarnPrefix, true, "%v", err)
		return true
	}
	return false
}

// FatalErr prints err as fatal log
func FatalErr(err error) {
	if err != nil {
		printLog(color.FgRed, ErrPrefix, true, "%v", err)
	}
}

func JsonDebug(a interface{}) {
	buf, err := json.MarshalIndent(a, "", "  ")
	if !WarningErr(err) {
		Debug("%s", buf)
	}
}
<commit_msg>lint fixes<commit_after>// Package logger provides collection of loggin functions with colored output and stack frames
package logger

import (
	"encoding/json"
	"fmt"
	"io"
	"os"
	"runtime"
	"time"

	"github.com/fatih/color"
	"github.com/shiena/ansicolor"
)

const (
	// FileNameNo indicates to no print filename
	FileNameNo int = iota
	// FileNameShort indicates to print short filename
	FileNameShort
	// FileNameLong indicates to print full filename
	FileNameLong
)

var (
	colored = false
	btrace  = true
	pdebug  = true
	fname   = FileNameNo

	output     = ansicolor.NewAnsiColorWriter(os.Stdout)
	timeFormat = "2006-Jan-2 15:04:05.0000"

	// InfoPrefix is text prefix for info log
	InfoPrefix = "INFO"
	// WarnPrefix is text prefix for warning log
	WarnPrefix = "WARN"
	// ErrPrefix is text prefix for error log
	ErrPrefix = " ERR"
	// DebugPrefix is text prefix for debug log
	DebugPrefix = " DEB"
)

// EnableColored enables colored output
func EnableColored() {
	colored = true
}

// DisableColored disables colored output
func DisableColored() {
	colored = false
}

// EnableBTrace enables backtrace for warnings and errors
func EnableBTrace() {
	btrace = true
}

// DisableBTrace disables backtrace
func DisableBTrace() {
	btrace = false
}

// EnableDebug enables debug logs
func EnableDebug() {
	pdebug = true
}

// DisableDebug disables debug logs
func DisableDebug() {
	pdebug = false
}

// SetFileName sets flag for print ceurrent file name in log
func SetFileName(fn int) {
	switch fn {
	case FileNameLong, FileNameNo, FileNameShort:
		fname = fn
	}
}

// SetOut set writer fo print logs. Default writer is os.Stdout
func SetOut(out io.Writer) {
	output = ansicolor.NewAnsiColorWriter(out)
}

func makeStack() (ret string) {
	st := make([]uintptr, 50)
	cnt := runtime.Callers(4, st)
	st = st[0:cnt]
	for _, r := range st {
		fnc := runtime.FuncForPC(r)
		file, line := fnc.FileLine(r - 1)

		stackLine := fmt.Sprintf("\t%s:%d\n", file, line)
		stackFunc := fmt.Sprintf("\t\t%s\n", fnc.Name())
		if colored {
			stackLine = color.MagentaString(stackLine)
			stackFunc = color.MagentaString(stackFunc)
		}

		ret += stackLine + stackFunc
	}
	return
}

func printLog(colora color.Attribute, prefix string, printTrace bool, message string, v ...interface{}) {
	var f func(format string, a ...interface{}) string
	if colored {
		f = color.New(colora).SprintfFunc()
	} else {
		f = fmt.Sprintf
	}

	var fileName string
	if fname != FileNameNo {
		_, file, line, ok := runtime.Caller(2)
		if !ok {
			file = "???"
			line = 0
		}
		if fname == FileNameShort {
			short := file
			for i := len(file) - 1; i > 0; i-- {
				if file[i] == '/' {
					short = file[i+1:]
					break
				}
			}
			file = short
		}
		fileName = fmt.Sprintf(" %s:%d", file, line)
	}

	var stack string
	if printTrace && btrace {
		stack = makeStack()
	}
	fmt.Fprint(output, f("%s %s %s\n", time.Now().Format(timeFormat), prefix+fileName, fmt.Sprintf(message, v...)), stack)
}

// Info prints info log (green if colored)
func Info(message string, v ...interface{}) {
	printLog(color.FgGreen, InfoPrefix, false, message, v...)
}

// Warning prints warning log (yellow if colored)
func Warning(message string, v ...interface{}) {
	printLog(color.FgYellow, WarnPrefix, true, message, v...)
}

// Error prints error log (red if colored)
func Error(message string, v ...interface{}) {
	printLog(color.FgRed, ErrPrefix, true, message, v...)
}

// Debug prints debug log (blue if colored)
func Debug(message string, v ...interface{}) {
	if pdebug {
		printLog(color.FgBlue, DebugPrefix, false, message, v...)
	}
}

// Fatal prints error log and finish proccess by os.Exit(1)
func Fatal(message string, v ...interface{}) {
	printLog(color.FgRed, ErrPrefix, true, message, v...)
	os.Exit(1)
}

// Panic prints error log and call panic
func Panic(message string, v ...interface{}) {
	DisableBTrace()
	printLog(color.FgRed, ErrPrefix, true, message, v...)
	panic(fmt.Sprintf(message, v...))
}

// PanicRecover recovers panic an print error message
func PanicRecover() {
	if err := recover(); err != nil {
		Error("PANIC: %s", err)
	}
}

// ErrorErr prints err as error log and returns true if err!=nil
func ErrorErr(err error) bool {
	if err != nil {
		printLog(color.FgRed, ErrPrefix, true, "%v", err)
		return true
	}
	return false
}

// WarningErr prints err as warning log and returns true if err!=nil
func WarningErr(err error) bool {
	if err != nil {
		printLog(color.FgYellow, WarnPrefix, true, "%v", err)
		return true
	}
	return false
}

// FatalErr prints err as fatal log
func FatalErr(err error) {
	if err != nil {
		printLog(color.FgRed, ErrPrefix, true, "%v", err)
	}
}

// JSONDebug prints object in json format
func JSONDebug(a interface{}) {
	buf, err := json.MarshalIndent(a, "", "  ")
	if !WarningErr(err) {
		Debug("%s", buf)
	}
}
<|endoftext|>


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

// Package logger offers simple cross platform logging for Windows and Linux.
// Available logging endpoints are event log (Windows), syslog (Linux), and
// an io.Writer.
package logger

import (
	"fmt"
	"io"
	"log"
	"os"
	"sync"
)

var (
	defaultLogger *Logger
	logLock       sync.Mutex
)

const (
	flags    = log.Ldate | log.Lmicroseconds | log.Lshortfile
	initText = "ERROR: Logging before logger.Init.\n"
)

func initialize() {
	defaultLogger = &Logger{
		infoLog:  log.New(os.Stderr, initText+"INFO: ", flags),
		errorLog: log.New(os.Stderr, initText+"ERROR: ", flags),
		fatalLog: log.New(os.Stderr, initText+"FATAL: ", flags),
	}
}

func init() {
	initialize()
}

// Init sets up logging and should be called before log functions, usually in
// the caller's main(). Default log functions can be called before Init(), but log
// output will only go to stderr (along with a warning).
// The first call to Init populates the default logger and returns the
// generated logger, subsequent calls to Init will only return the generated
// logger.
func Init(name string, verbose, systemLog bool, logFile io.Writer) *Logger {
	var il, el io.Writer
	if systemLog {
		var err error
		il, el, err = setup(name)
		if err != nil {
			log.Fatal(err)
		}
	}

	iLogs := []io.Writer{logFile}
	eLogs := []io.Writer{logFile, os.Stderr}
	if verbose {
		iLogs = append(iLogs, os.Stdout)
	}
	if il != nil {
		iLogs = append(iLogs, il)
	}
	if el != nil {
		eLogs = append(eLogs, el)
	}

	var l Logger
	l.infoLog = log.New(io.MultiWriter(iLogs...), "INFO: ", flags)
	l.errorLog = log.New(io.MultiWriter(eLogs...), "ERROR: ", flags)
	l.fatalLog = log.New(io.MultiWriter(eLogs...), "FATAL: ", flags)
	l.initialized = true

	logLock.Lock()
	defer logLock.Unlock()
	if !defaultLogger.initialized {
		defaultLogger = &l
	}

	return &l
}

type severity int

const (
	sInfo = iota
	sError
	sFatal
)

// A Logger represents an active logging object. Multiple loggers can be used
// simultaneously even if they are using the same same writers.
type Logger struct {
	infoLog     *log.Logger
	errorLog    *log.Logger
	fatalLog    *log.Logger
	initialized bool
}

func (l *Logger) output(s severity, txt string) {
	logLock.Lock()
	defer logLock.Unlock()
	switch s {
	case sInfo:
		l.infoLog.Output(3, txt)
	case sError:
		l.errorLog.Output(3, txt)
	case sFatal:
		l.fatalLog.Output(3, txt)
	default:
		panic(fmt.Sprintln("unrecognized severity:", s))
	}
}

// Info logs with the INFO severity.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) Info(v ...interface{}) {
	l.output(sInfo, fmt.Sprint(v...))
}

// Infoln logs with the INFO severity.
// Arguments are handled in the manner of fmt.Println.
func (l *Logger) Infoln(v ...interface{}) {
	l.output(sInfo, fmt.Sprintln(v...))
}

// Infof logs with the INFO severity.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Infof(format string, v ...interface{}) {
	l.output(sInfo, fmt.Sprintf(format, v...))
}

// Error logs with the ERROR severity.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) Error(v ...interface{}) {
	l.output(sError, fmt.Sprint(v...))
}

// Errorln logs with the ERROR severity.
// Arguments are handled in the manner of fmt.Println.
func (l *Logger) Errorln(v ...interface{}) {
	l.output(sError, fmt.Sprintln(v...))
}

// Errorf logs with the Error severity.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Errorf(format string, v ...interface{}) {
	l.output(sError, fmt.Sprintf(format, v...))
}

// Fatal logs with the Fatal severity, and ends with os.Exit(1).
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) Fatal(v ...interface{}) {
	l.output(sFatal, fmt.Sprint(v...))
	os.Exit(1)
}

// Fatalln logs with the Fatal severity, and ends with os.Exit(1).
// Arguments are handled in the manner of fmt.Println.
func (l *Logger) Fatalln(v ...interface{}) {
	l.output(sFatal, fmt.Sprintln(v...))
	os.Exit(1)
}

// Fatalf logs with the Fatal severity, and ends with os.Exit(1).
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Fatalf(format string, v ...interface{}) {
	l.output(sFatal, fmt.Sprintf(format, v...))
	os.Exit(1)
}

// Info calls the default logger's Info.
func Info(v ...interface{}) {
	defaultLogger.Info(v...)
}

// Infoln calls the default logger's Infoln.
func Infoln(v ...interface{}) {
	defaultLogger.Infoln(v...)
}

// Infof calls the default logger's Infof.
func Infof(format string, v ...interface{}) {
	defaultLogger.Infof(format, v...)
}

// Error calls the default logger's Error.
func Error(v ...interface{}) {
	defaultLogger.Error(v...)
}

// Errorln calls the default logger's Errorln.
func Errorln(v ...interface{}) {
	defaultLogger.Errorln(v...)
}

// Errorf calls the default logger's Errorf.
func Errorf(format string, v ...interface{}) {
	defaultLogger.Errorf(format, v...)
}

// Fatal calls the default logger's Fatal.
func Fatal(v ...interface{}) {
	defaultLogger.Fatal(v...)
}

// Fatalln calls the default logger's Fatalln.
func Fatalln(v ...interface{}) {
	defaultLogger.Fatalln(v...)
}

// Fatalf calls the default logger's Fatalln.
func Fatalf(format string, v ...interface{}) {
	defaultLogger.Fatalf(format, v...)
}
<commit_msg>Fix logging depth for default logger (#6)<commit_after>/*
Copyright 2016 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Package logger offers simple cross platform logging for Windows and Linux.
// Available logging endpoints are event log (Windows), syslog (Linux), and
// an io.Writer.
package logger

import (
	"fmt"
	"io"
	"log"
	"os"
	"sync"
)

var (
	defaultLogger *Logger
	logLock       sync.Mutex
)

const (
	flags    = log.Ldate | log.Lmicroseconds | log.Lshortfile
	initText = "ERROR: Logging before logger.Init.\n"
)

func initialize() {
	defaultLogger = &Logger{
		infoLog:  log.New(os.Stderr, initText+"INFO: ", flags),
		errorLog: log.New(os.Stderr, initText+"ERROR: ", flags),
		fatalLog: log.New(os.Stderr, initText+"FATAL: ", flags),
	}
}

func init() {
	initialize()
}

// Init sets up logging and should be called before log functions, usually in
// the caller's main(). Default log functions can be called before Init(), but log
// output will only go to stderr (along with a warning).
// The first call to Init populates the default logger and returns the
// generated logger, subsequent calls to Init will only return the generated
// logger.
func Init(name string, verbose, systemLog bool, logFile io.Writer) *Logger {
	var il, el io.Writer
	if systemLog {
		var err error
		il, el, err = setup(name)
		if err != nil {
			log.Fatal(err)
		}
	}

	iLogs := []io.Writer{logFile}
	eLogs := []io.Writer{logFile, os.Stderr}
	if verbose {
		iLogs = append(iLogs, os.Stdout)
	}
	if il != nil {
		iLogs = append(iLogs, il)
	}
	if el != nil {
		eLogs = append(eLogs, el)
	}

	var l Logger
	l.infoLog = log.New(io.MultiWriter(iLogs...), "INFO: ", flags)
	l.errorLog = log.New(io.MultiWriter(eLogs...), "ERROR: ", flags)
	l.fatalLog = log.New(io.MultiWriter(eLogs...), "FATAL: ", flags)
	l.initialized = true

	logLock.Lock()
	defer logLock.Unlock()
	if !defaultLogger.initialized {
		defaultLogger = &l
	}

	return &l
}

type severity int

const (
	sInfo = iota
	sError
	sFatal
)

// A Logger represents an active logging object. Multiple loggers can be used
// simultaneously even if they are using the same same writers.
type Logger struct {
	infoLog     *log.Logger
	errorLog    *log.Logger
	fatalLog    *log.Logger
	initialized bool
}

func (l *Logger) output(s severity, txt string) {
	logLock.Lock()
	defer logLock.Unlock()
	switch s {
	case sInfo:
		l.infoLog.Output(3, txt)
	case sError:
		l.errorLog.Output(3, txt)
	case sFatal:
		l.fatalLog.Output(3, txt)
	default:
		panic(fmt.Sprintln("unrecognized severity:", s))
	}
}

// Info logs with the INFO severity.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) Info(v ...interface{}) {
	l.output(sInfo, fmt.Sprint(v...))
}

// Infoln logs with the INFO severity.
// Arguments are handled in the manner of fmt.Println.
func (l *Logger) Infoln(v ...interface{}) {
	l.output(sInfo, fmt.Sprintln(v...))
}

// Infof logs with the INFO severity.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Infof(format string, v ...interface{}) {
	l.output(sInfo, fmt.Sprintf(format, v...))
}

// Error logs with the ERROR severity.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) Error(v ...interface{}) {
	l.output(sError, fmt.Sprint(v...))
}

// Errorln logs with the ERROR severity.
// Arguments are handled in the manner of fmt.Println.
func (l *Logger) Errorln(v ...interface{}) {
	l.output(sError, fmt.Sprintln(v...))
}

// Errorf logs with the Error severity.
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Errorf(format string, v ...interface{}) {
	l.output(sError, fmt.Sprintf(format, v...))
}

// Fatal logs with the Fatal severity, and ends with os.Exit(1).
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) Fatal(v ...interface{}) {
	l.output(sFatal, fmt.Sprint(v...))
	os.Exit(1)
}

// Fatalln logs with the Fatal severity, and ends with os.Exit(1).
// Arguments are handled in the manner of fmt.Println.
func (l *Logger) Fatalln(v ...interface{}) {
	l.output(sFatal, fmt.Sprintln(v...))
	os.Exit(1)
}

// Fatalf logs with the Fatal severity, and ends with os.Exit(1).
// Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Fatalf(format string, v ...interface{}) {
	l.output(sFatal, fmt.Sprintf(format, v...))
	os.Exit(1)
}

// Info uses the default logger and logs with the Info severity.
// Arguments are handled in the manner of fmt.Print.
func Info(v ...interface{}) {
	defaultLogger.output(sInfo, fmt.Sprint(v...))
}

// Infoln uses the default logger and logs with the Info severity.
// Arguments are handled in the manner of fmt.Println.
func Infoln(v ...interface{}) {
	defaultLogger.output(sInfo, fmt.Sprintln(v...))
}

// Infof uses the default logger and logs with the Info severity.
// Arguments are handled in the manner of fmt.Printf.
func Infof(format string, v ...interface{}) {
	defaultLogger.output(sInfo, fmt.Sprintf(format, v...))
}

// Error uses the default logger and logs with the Error severity.
// Arguments are handled in the manner of fmt.Print.
func Error(v ...interface{}) {
	defaultLogger.output(sError, fmt.Sprint(v...))
}

// Errorln uses the default logger and logs with the Error severity.
// Arguments are handled in the manner of fmt.Println.
func Errorln(v ...interface{}) {
	defaultLogger.output(sError, fmt.Sprintln(v...))
}

// Errorf uses the default logger and logs with the Error severity.
// Arguments are handled in the manner of fmt.Printf.
func Errorf(format string, v ...interface{}) {
	defaultLogger.output(sError, fmt.Sprintf(format, v...))
}

// Fatalln uses the default logger, logs with the Fatal severity,
// and ends with os.Exit(1).
// Arguments are handled in the manner of fmt.Print.
func Fatal(v ...interface{}) {
	defaultLogger.output(sFatal, fmt.Sprint(v...))
	os.Exit(1)
}

// Fatalln uses the default logger, logs with the Fatal severity,
// and ends with os.Exit(1).
// Arguments are handled in the manner of fmt.Println.
func Fatalln(v ...interface{}) {
	defaultLogger.output(sFatal, fmt.Sprintln(v...))
	os.Exit(1)
}

// Fatalf uses the default logger, logs with the Fatal severity,
// and ends with os.Exit(1).
// Arguments are handled in the manner of fmt.Printf.
func Fatalf(format string, v ...interface{}) {
	defaultLogger.output(sFatal, fmt.Sprintf(format, v...))
	os.Exit(1)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"os"

	"github.com/op/go-logging"
)

// LoggerInit Initializes the logger
func LoggerInit(logFile string) (*os.File, error) {
	error_level := map[int]logging.Level{
		0: logging.WARNING,
		1: logging.INFO,
		2: logging.DEBUG,
	}
	const module_name = "grimd"
	logger = logging.MustGetLogger(module_name)
	var format = logging.MustStringFormatter(
		`%{color}%{time:15:04:05.000} %{level:.4s} %{shortfile} ▶ %{id:03x}%{color:reset} %{message}`)
	stderr_backend := logging.NewLogBackend(os.Stderr, "", 0)
	stderr_formatter := logging.NewBackendFormatter(stderr_backend, format)
	stderr_leveled := logging.AddModuleLevel(stderr_formatter)

	stderr_leveled.SetLevel(error_level[Config.LogLevel], module_name)

	if _, err := os.Stat(logFile); os.IsNotExist(err) {
		if _, err := os.Create(logFile); err != nil {
			return nil, fmt.Errorf("error creating log file: %s", err)
		}
	}

	file, err := os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
	if err != nil {
		return nil, fmt.Errorf("error opening log file: %s", err)
	}

	format = logging.MustStringFormatter(
		`%{time:15:04:05.000} %{level:.4s} %{shortfile} ▶ %{id:03x} %{message}`)
	file_writer := io.Writer(file)
	file_backend := logging.NewLogBackend(file_writer, "", 0)
	file_formatter := logging.NewBackendFormatter(file_backend, format)
	file_leveled := logging.AddModuleLevel(file_formatter)

	file_leveled.SetLevel(error_level[Config.LogLevel], module_name)

	logging.SetBackend(stderr_leveled, file_leveled)

	return file, nil
}

var (
	logger *logging.Logger = nil
)
<commit_msg>Added a default logger so that tested code has an available logger<commit_after>package main

import (
	"fmt"
	"io"
	"os"

	"github.com/op/go-logging"
)

// LoggerInit Initializes the logger
func LoggerInit(logFile string) (*os.File, error) {
	error_level := map[int]logging.Level{
		0: logging.WARNING,
		1: logging.INFO,
		2: logging.DEBUG,
	}
	const module_name = "grimd"
	logger = logging.MustGetLogger(module_name)
	var format = logging.MustStringFormatter(
		`%{color}%{time:15:04:05.000} %{level:.4s} %{shortfile} ▶ %{id:03x}%{color:reset} %{message}`)
	stderr_backend := logging.NewLogBackend(os.Stderr, "", 0)
	stderr_formatter := logging.NewBackendFormatter(stderr_backend, format)
	stderr_leveled := logging.AddModuleLevel(stderr_formatter)

	stderr_leveled.SetLevel(error_level[Config.LogLevel], module_name)

	if _, err := os.Stat(logFile); os.IsNotExist(err) {
		if _, err := os.Create(logFile); err != nil {
			return nil, fmt.Errorf("error creating log file: %s", err)
		}
	}

	file, err := os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
	if err != nil {
		return nil, fmt.Errorf("error opening log file: %s", err)
	}

	format = logging.MustStringFormatter(
		`%{time:15:04:05.000} %{level:.4s} %{shortfile} ▶ %{id:03x} %{message}`)
	file_writer := io.Writer(file)
	file_backend := logging.NewLogBackend(file_writer, "", 0)
	file_formatter := logging.NewBackendFormatter(file_backend, format)
	file_leveled := logging.AddModuleLevel(file_formatter)

	file_leveled.SetLevel(error_level[Config.LogLevel], module_name)

	logging.SetBackend(stderr_leveled, file_leveled)

	return file, nil
}

var (
	// Initialize to a dummy but functional logger so that tested code has something to write to
	logger *logging.Logger = logging.MustGetLogger("test")
)
<|endoftext|>