<commit_before>package main

import (
	"crypto/sha256"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"strings"

	"github.com/lxc/lxd/shared"

	log "gopkg.in/inconshreveable/log15.v2"
)

const (
	APPARMOR_CMD_LOAD   = "r"
	APPARMOR_CMD_UNLOAD = "R"
	APPARMOR_CMD_PARSE  = "Q"
)

var aaPath = shared.VarPath("security", "apparmor")

const NESTING_AA_PROFILE = `
  pivot_root,
  mount /var/lib/lxd/shmounts/ -> /var/lib/lxd/shmounts/,
  mount none -> /var/lib/lxd/shmounts/,
  mount fstype=proc -> /usr/lib/x86_64-linux-gnu/lxc/**,
  mount fstype=sysfs -> /usr/lib/x86_64-linux-gnu/lxc/**,
  mount options=(rw,bind),
  mount options=(rw,rbind),
  deny /dev/.lxd/proc/** rw,
  deny /dev/.lxd/sys/** rw,
  mount options=(rw,make-rshared),

  # there doesn't seem to be a way to ask for:
  # mount options=(ro,nosuid,nodev,noexec,remount,bind),
  # as we always get mount to $cdir/proc/sys with those flags denied
  # So allow all mounts until that is straightened out:
  mount,
  mount options=bind /var/lib/lxd/shmounts/** -> /var/lib/lxd/**,
  # lxc-container-default-with-nesting also inherited these
  # from start-container, and seems to need them.
  ptrace,
  signal,
`

const DEFAULT_AA_PROFILE = `
#include <tunables/global>
profile "%s" flags=(attach_disconnected,mediate_deleted) {
    #include <abstractions/lxc/container-base>

    # user input raw.apparmor below here
    %s

    # nesting support goes here if needed
    %s
    change_profile -> "%s",
}`

func AAProfileFull(c container) string {
	lxddir := shared.VarPath("")
	if len(c.Name())+len(lxddir)+7 >= 253 {
		hash := sha256.New()
		io.WriteString(hash, lxddir)
		lxddir = fmt.Sprintf("%x", hash.Sum(nil))
	}

	return fmt.Sprintf("lxd-%s_<%s>", c.Name(), lxddir)
}

func AAProfileShort(c container) string {
	return fmt.Sprintf("lxd-%s", c.Name())
}

// getProfileContent generates the apparmor profile template from the given
// container. This includes the stock lxc includes as well as stuff from
// raw.apparmor.
func getAAProfileContent(c container) string {
	rawApparmor, ok := c.ExpandedConfig()["raw.apparmor"]
	if !ok {
		rawApparmor = ""
	}

	nesting := ""
	if c.IsNesting() {
		nesting = NESTING_AA_PROFILE
	}

	return fmt.Sprintf(DEFAULT_AA_PROFILE, AAProfileFull(c), rawApparmor, nesting, AAProfileFull(c))
}

func runApparmor(command string, c container) error {
	if !aaAvailable {
		return nil
	}

	cmd := exec.Command("apparmor_parser", []string{
		fmt.Sprintf("-%sWL", command),
		path.Join(aaPath, "cache"),
		path.Join(aaPath, "profiles", AAProfileShort(c)),
	}...)

	output, err := cmd.CombinedOutput()
	if err != nil {
		shared.Log.Error("Running apparmor",
			log.Ctx{"action": command, "output": string(output), "err": err})
	}

	return err
}

// Ensure that the container's policy is loaded into the kernel so the
// container can boot.
func AALoadProfile(c container) error {
	if !aaAdmin {
		return nil
	}

	/* In order to avoid forcing a profile parse (potentially slow) on
	 * every container start, let's use apparmor's binary policy cache,
	 * which checks mtime of the files to figure out if the policy needs to
	 * be regenerated.
	 *
	 * Since it uses mtimes, we shouldn't just always write out our local
	 * apparmor template; instead we should check to see whether the
	 * template is the same as ours. If it isn't we should write our
	 * version out so that the new changes are reflected and we definitely
	 * force a recompile.
	 */
	profile := path.Join(aaPath, "profiles", AAProfileShort(c))
	content, err := ioutil.ReadFile(profile)
	if err != nil && !os.IsNotExist(err) {
		return err
	}

	updated := getAAProfileContent(c)

	if string(content) != string(updated) {
		if err := os.MkdirAll(path.Join(aaPath, "cache"), 0700); err != nil {
			return err
		}

		if err := os.MkdirAll(path.Join(aaPath, "profiles"), 0700); err != nil {
			return err
		}

		if err := ioutil.WriteFile(profile, []byte(updated), 0600); err != nil {
			return err
		}
	}

	return runApparmor(APPARMOR_CMD_LOAD, c)
}

// Ensure that the container's policy is unloaded to free kernel memory. This
// does not delete the policy from disk or cache.
func AAUnloadProfile(c container) error {
	if !aaAdmin {
		return nil
	}

	return runApparmor(APPARMOR_CMD_UNLOAD, c)
}

// Parse the profile without loading it into the kernel.
func AAParseProfile(c container) error {
	if !aaAvailable {
	}

	return runApparmor(APPARMOR_CMD_PARSE, c)
}

// Delete the policy from cache/disk.
func AADeleteProfile(c container) {
	if !aaAdmin {
		return
	}

	/* It's ok if these deletes fail: if the container was never started,
	 * we'll have never written a profile or cached it.
	 */
	os.Remove(path.Join(aaPath, "cache", AAProfileShort(c)))
	os.Remove(path.Join(aaPath, "profiles", AAProfileShort(c)))
}

// What's current apparmor profile
func aaProfile() string {
	contents, err := ioutil.ReadFile("/proc/self/attr/current")
	if err == nil {
		return strings.TrimSpace(string(contents))
	}
	return ""
}
<commit_msg>allow cgroupfs mounting on cgns kernels<commit_after>package main

import (
	"crypto/sha256"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"strings"

	"github.com/lxc/lxd/shared"

	log "gopkg.in/inconshreveable/log15.v2"
)

const (
	APPARMOR_CMD_LOAD   = "r"
	APPARMOR_CMD_UNLOAD = "R"
	APPARMOR_CMD_PARSE  = "Q"
)

var aaPath = shared.VarPath("security", "apparmor")

const NESTING_AA_PROFILE = `
  pivot_root,
  mount /var/lib/lxd/shmounts/ -> /var/lib/lxd/shmounts/,
  mount none -> /var/lib/lxd/shmounts/,
  mount fstype=proc -> /usr/lib/x86_64-linux-gnu/lxc/**,
  mount fstype=sysfs -> /usr/lib/x86_64-linux-gnu/lxc/**,
  mount options=(rw,bind),
  mount options=(rw,rbind),
  deny /dev/.lxd/proc/** rw,
  deny /dev/.lxd/sys/** rw,
  mount options=(rw,make-rshared),

  # there doesn't seem to be a way to ask for:
  # mount options=(ro,nosuid,nodev,noexec,remount,bind),
  # as we always get mount to $cdir/proc/sys with those flags denied
  # So allow all mounts until that is straightened out:
  mount,
  mount options=bind /var/lib/lxd/shmounts/** -> /var/lib/lxd/**,
  # lxc-container-default-with-nesting also inherited these
  # from start-container, and seems to need them.
  ptrace,
  signal,
`

const DEFAULT_AA_PROFILE = `
#include <tunables/global>
profile "%s" flags=(attach_disconnected,mediate_deleted) {
    #include <abstractions/lxc/container-base>

    # Special exception for cgroup namespaces
    %s

    # user input raw.apparmor below here
    %s

    # nesting support goes here if needed
    %s
    change_profile -> "%s",
}`

func AAProfileFull(c container) string {
	lxddir := shared.VarPath("")
	if len(c.Name())+len(lxddir)+7 >= 253 {
		hash := sha256.New()
		io.WriteString(hash, lxddir)
		lxddir = fmt.Sprintf("%x", hash.Sum(nil))
	}

	return fmt.Sprintf("lxd-%s_<%s>", c.Name(), lxddir)
}

func AAProfileShort(c container) string {
	return fmt.Sprintf("lxd-%s", c.Name())
}

func AAProfileCgns() string {
	if shared.PathExists("/proc/self/ns/cgroup") {
		return "  mount fstype=cgroup -> /sys/fs/cgroup/**,"
	}
	return ""
}

// getProfileContent generates the apparmor profile template from the given
// container. This includes the stock lxc includes as well as stuff from
// raw.apparmor.
func getAAProfileContent(c container) string {
	rawApparmor, ok := c.ExpandedConfig()["raw.apparmor"]
	if !ok {
		rawApparmor = ""
	}

	nesting := ""
	if c.IsNesting() {
		nesting = NESTING_AA_PROFILE
	}

	return fmt.Sprintf(DEFAULT_AA_PROFILE, AAProfileFull(c), AAProfileCgns(), rawApparmor, nesting, AAProfileFull(c))
}

func runApparmor(command string, c container) error {
	if !aaAvailable {
		return nil
	}

	cmd := exec.Command("apparmor_parser", []string{
		fmt.Sprintf("-%sWL", command),
		path.Join(aaPath, "cache"),
		path.Join(aaPath, "profiles", AAProfileShort(c)),
	}...)

	output, err := cmd.CombinedOutput()
	if err != nil {
		shared.Log.Error("Running apparmor",
			log.Ctx{"action": command, "output": string(output), "err": err})
	}

	return err
}

// Ensure that the container's policy is loaded into the kernel so the
// container can boot.
func AALoadProfile(c container) error {
	if !aaAdmin {
		return nil
	}

	/* In order to avoid forcing a profile parse (potentially slow) on
	 * every container start, let's use apparmor's binary policy cache,
	 * which checks mtime of the files to figure out if the policy needs to
	 * be regenerated.
	 *
	 * Since it uses mtimes, we shouldn't just always write out our local
	 * apparmor template; instead we should check to see whether the
	 * template is the same as ours. If it isn't we should write our
	 * version out so that the new changes are reflected and we definitely
	 * force a recompile.
	 */
	profile := path.Join(aaPath, "profiles", AAProfileShort(c))
	content, err := ioutil.ReadFile(profile)
	if err != nil && !os.IsNotExist(err) {
		return err
	}

	updated := getAAProfileContent(c)

	if string(content) != string(updated) {
		if err := os.MkdirAll(path.Join(aaPath, "cache"), 0700); err != nil {
			return err
		}

		if err := os.MkdirAll(path.Join(aaPath, "profiles"), 0700); err != nil {
			return err
		}

		if err := ioutil.WriteFile(profile, []byte(updated), 0600); err != nil {
			return err
		}
	}

	return runApparmor(APPARMOR_CMD_LOAD, c)
}

// Ensure that the container's policy is unloaded to free kernel memory. This
// does not delete the policy from disk or cache.
func AAUnloadProfile(c container) error {
	if !aaAdmin {
		return nil
	}

	return runApparmor(APPARMOR_CMD_UNLOAD, c)
}

// Parse the profile without loading it into the kernel.
func AAParseProfile(c container) error {
	if !aaAvailable {
	}

	return runApparmor(APPARMOR_CMD_PARSE, c)
}

// Delete the policy from cache/disk.
func AADeleteProfile(c container) {
	if !aaAdmin {
		return
	}

	/* It's ok if these deletes fail: if the container was never started,
	 * we'll have never written a profile or cached it.
	 */
	os.Remove(path.Join(aaPath, "cache", AAProfileShort(c)))
	os.Remove(path.Join(aaPath, "profiles", AAProfileShort(c)))
}

// What's current apparmor profile
func aaProfile() string {
	contents, err := ioutil.ReadFile("/proc/self/attr/current")
	if err == nil {
		return strings.TrimSpace(string(contents))
	}
	return ""
}
<|endoftext|>


<commit_before>package version

const (
	Version = "0.1.0"
)
<commit_msg>feat(version): bump to 0.1.0+git<commit_after>package version

const (
	Version = "0.1.0+git"
)
<|endoftext|>


<commit_before>// Package version returns the version of the application
package version

// Version returns the current application version
const Version = "1.0.12"
<commit_msg>bump to v1.0.13<commit_after>// Package version returns the version of the application
package version

// Version returns the current application version
const Version = "1.0.13"
<|endoftext|>


<commit_before>package version

import (
	"fmt"
)

var Version VersionNumber = NewVersionNumber(0, 0, 6)

type VersionNumber struct {
	major int
	minor int
	patch int
}

func (v *VersionNumber) String() string {
	return fmt.Sprintf("%d.%d.%d", v.major, v.minor, v.patch)
}

func NewVersionNumber(major int, minor int, patch int) VersionNumber {
	return VersionNumber{major: major, minor: minor, patch: patch}
}
<commit_msg>Update version to 0.0.7<commit_after>package version

import (
	"fmt"
)

var Version VersionNumber = NewVersionNumber(0, 0, 7)

type VersionNumber struct {
	major int
	minor int
	patch int
}

func (v *VersionNumber) String() string {
	return fmt.Sprintf("%d.%d.%d", v.major, v.minor, v.patch)
}

func NewVersionNumber(major int, minor int, patch int) VersionNumber {
	return VersionNumber{major: major, minor: minor, patch: patch}
}
<|endoftext|>


<commit_before>// Copyright 2017 Istio 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 version for fortio holds version information and build information.
package version // import "fortio.org/fortio/version"
import (
	"fmt"
	"runtime"

	"fortio.org/fortio/log"
)

const (
	major = 1
	minor = 6
	patch = 6

	debug = false // turn on to debug init()
)

// nolint:gochecknoglobals // we do need these
var (
	// The following are set by Dockerfile during link time:
	tag       = "n/a"
	buildInfo = "unknown"
	// Number of lines in git status --porcelain; 0 means clean
	gitstatus = "0" // buildInfo default is unknown so no need to add -dirty
	// computed in init()
	version     = ""
	longVersion = ""
)

// Major returns the numerical major version number (first digit of version.Short()).
func Major() int {
	return major
}

// Minor returns the numerical minor version number (second digit of version.Short()).
func Minor() int {
	return minor
}

// Patch returns the numerical patch level (third digit of version.Short()).
func Patch() int {
	return patch
}

// Short returns the 3 digit short version string Major.Minor.Patch[-pre]
// version.Short() is the overall project version (used to version json
// output too). "-pre" is added when the version doesn't match exactly
// a git tag or the build isn't from a clean source tree. (only standard
// dockerfile based build of a clean, tagged source tree should print "X.Y.Z"
// as short version).
func Short() string {
	return version
}

// Long returns the full version and build information.
// Format is "X.Y.X[-pre] YYYY-MM-DD HH:MM SHA[-dirty]" date and time is
// the build date (UTC), sha is the git sha of the source tree.
func Long() string {
	return longVersion
}

// Carefully manually tested all the combinations in pair with Dockerfile.

func init() { // nolint:gochecknoinits //we do need an init for this
	if debug {
		log.SetLogLevel(log.Debug)
	}
	version = fmt.Sprintf("%d.%d.%d", major, minor, patch)
	clean := (gitstatus == "0")
	// The docker build will pass the git tag to the build, if it is clean
	// from a tag it will look like v0.7.0
	if tag != "v"+version || !clean {
		log.Debugf("tag is %v, clean is %v marking as pre release", tag, clean)
		version += "-pre"
	}
	if !clean {
		buildInfo += "-dirty"
		log.Debugf("gitstatus is %q, marking buildinfo as dirty: %v", gitstatus, buildInfo)
	}
	longVersion = version + " " + buildInfo + " " + runtime.Version()
}
<commit_msg>1.6.7 prep<commit_after>// Copyright 2017 Istio 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 version for fortio holds version information and build information.
package version // import "fortio.org/fortio/version"
import (
	"fmt"
	"runtime"

	"fortio.org/fortio/log"
)

const (
	major = 1
	minor = 6
	patch = 7

	debug = false // turn on to debug init()
)

// nolint:gochecknoglobals // we do need these
var (
	// The following are set by Dockerfile during link time:
	tag       = "n/a"
	buildInfo = "unknown"
	// Number of lines in git status --porcelain; 0 means clean
	gitstatus = "0" // buildInfo default is unknown so no need to add -dirty
	// computed in init()
	version     = ""
	longVersion = ""
)

// Major returns the numerical major version number (first digit of version.Short()).
func Major() int {
	return major
}

// Minor returns the numerical minor version number (second digit of version.Short()).
func Minor() int {
	return minor
}

// Patch returns the numerical patch level (third digit of version.Short()).
func Patch() int {
	return patch
}

// Short returns the 3 digit short version string Major.Minor.Patch[-pre]
// version.Short() is the overall project version (used to version json
// output too). "-pre" is added when the version doesn't match exactly
// a git tag or the build isn't from a clean source tree. (only standard
// dockerfile based build of a clean, tagged source tree should print "X.Y.Z"
// as short version).
func Short() string {
	return version
}

// Long returns the full version and build information.
// Format is "X.Y.X[-pre] YYYY-MM-DD HH:MM SHA[-dirty]" date and time is
// the build date (UTC), sha is the git sha of the source tree.
func Long() string {
	return longVersion
}

// Carefully manually tested all the combinations in pair with Dockerfile.

func init() { // nolint:gochecknoinits //we do need an init for this
	if debug {
		log.SetLogLevel(log.Debug)
	}
	version = fmt.Sprintf("%d.%d.%d", major, minor, patch)
	clean := (gitstatus == "0")
	// The docker build will pass the git tag to the build, if it is clean
	// from a tag it will look like v0.7.0
	if tag != "v"+version || !clean {
		log.Debugf("tag is %v, clean is %v marking as pre release", tag, clean)
		version += "-pre"
	}
	if !clean {
		buildInfo += "-dirty"
		log.Debugf("gitstatus is %q, marking buildinfo as dirty: %v", gitstatus, buildInfo)
	}
	longVersion = version + " " + buildInfo + " " + runtime.Version()
}
<|endoftext|>


<commit_before>package version

const Version = "0.1.3"
<commit_msg>Revert "Revert "chore(release): bump version to 0.1.3+git""<commit_after>package version

const Version = "0.1.3+git"
<|endoftext|>


<commit_before>// The version package implements version parsing.
// It also acts as guardian of the current client Juju version number.
package version

import (
	"fmt"
	"io/ioutil"
	"labix.org/v2/mgo/bson"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"strconv"
	"strings"
)

// The presence and format of this constant is very important.
// The debian/rules build recipe uses this value for the version
// number of the release package.
const version = "1.9.10"

// Current gives the current version of the system.  If the file
// "FORCE-VERSION" is present in the same directory as the running
// binary, it will override this.
var Current = Binary{
	Number: MustParse(version),
	Series: readSeries("/etc/lsb-release"), // current Ubuntu release name.
	Arch:   ubuntuArch(runtime.GOARCH),
}

func init() {
	toolsDir := filepath.Dir(os.Args[0])
	v, err := ioutil.ReadFile(filepath.Join(toolsDir, "FORCE-VERSION"))
	if err != nil {
		if os.IsNotExist(err) {
			return
		}
		panic(fmt.Errorf("version: cannot read forced version: %v", err))
	}
	Current.Number = MustParse(strings.TrimSpace(string(v)))
}

// Number represents a juju version.  When bugs are fixed the patch
// number is incremented; when new features are added the minor number
// is incremented and patch is reset; and when compatibility is broken
// the major version is incremented and minor and patch are reset.  The
// build number is automatically assigned and has no well defined
// sequence.  If the build number is greater than zero or any of the
// other numbers are odd, it indicates that the release is still in
// development.
type Number struct {
	Major int
	Minor int
	Patch int
	Build int
}

// Binary specifies a binary version of juju.
type Binary struct {
	Number
	Series string
	Arch   string
}

func (v Binary) String() string {
	return fmt.Sprintf("%v-%s-%s", v.Number, v.Series, v.Arch)
}

// GetBSON turns v into a bson.Getter so it can be saved directly
// on a MongoDB database with mgo.
func (v Binary) GetBSON() (interface{}, error) {
	return v.String(), nil
}

// SetBSON turns v into a bson.Setter so it can be loaded directly
// from a MongoDB database with mgo.
func (vp *Binary) SetBSON(raw bson.Raw) error {
	var s string
	err := raw.Unmarshal(&s)
	if err != nil {
		return err
	}
	v, err := ParseBinary(s)
	if err != nil {
		return err
	}
	*vp = v
	return nil
}

var (
	binaryPat = regexp.MustCompile(`^(\d{1,9})\.(\d{1,9})\.(\d{1,9})(\.\d{1,9})?-([^-]+)-([^-]+)$`)
	numberPat = regexp.MustCompile(`^(\d{1,9})\.(\d{1,9})\.(\d{1,9})(\.\d{1,9})?$`)
)

// MustParse parses a version and panics if it does
// not parse correctly.
func MustParse(s string) Number {
	v, err := Parse(s)
	if err != nil {
		panic(err)
	}
	return v
}

// MustParseBinary parses a binary version and panics if it does
// not parse correctly.
func MustParseBinary(s string) Binary {
	v, err := ParseBinary(s)
	if err != nil {
		panic(err)
	}
	return v
}

// ParseBinary parses a binary version of the form "1.2.3-series-arch".
func ParseBinary(s string) (Binary, error) {
	m := binaryPat.FindStringSubmatch(s)
	if m == nil {
		return Binary{}, fmt.Errorf("invalid binary version %q", s)
	}
	var v Binary
	v.Major = atoi(m[1])
	v.Minor = atoi(m[2])
	v.Patch = atoi(m[3])
	if m[4] != "" {
		v.Build = atoi(m[4][1:])
	}
	v.Series = m[5]
	v.Arch = m[6]
	return v, nil
}

// Parse parses the version, which is of the form 1.2.3
// giving the major, minor and release versions
// respectively.
func Parse(s string) (Number, error) {
	m := numberPat.FindStringSubmatch(s)
	if m == nil {
		return Number{}, fmt.Errorf("invalid version %q", s)
	}
	var v Number
	v.Major = atoi(m[1])
	v.Minor = atoi(m[2])
	v.Patch = atoi(m[3])
	if m[4] != "" {
		v.Build = atoi(m[4][1:])
	}
	return v, nil
}

// atoi is the same as strconv.Atoi but assumes that
// the string has been verified to be a valid integer.
func atoi(s string) int {
	n, err := strconv.Atoi(s)
	if err != nil {
		panic(err)
	}
	return n
}

func (v Number) String() string {
	s := fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch)
	if v.Build > 0 {
		s += fmt.Sprintf(".%d", v.Build)
	}
	return s
}

// Less returns whether v is semantically earlier in the
// version sequence than w.
func (v Number) Less(w Number) bool {
	switch {
	case v.Major != w.Major:
		return v.Major < w.Major
	case v.Minor != w.Minor:
		return v.Minor < w.Minor
	case v.Patch != w.Patch:
		return v.Patch < w.Patch
	case v.Build != w.Build:
		return v.Build < w.Build
	}
	return false
}

// GetBSON turns v into a bson.Getter so it can be saved directly
// on a MongoDB database with mgo.
func (v Number) GetBSON() (interface{}, error) {
	return v.String(), nil
}

// SetBSON turns v into a bson.Setter so it can be loaded directly
// from a MongoDB database with mgo.
func (vp *Number) SetBSON(raw bson.Raw) error {
	var s string
	err := raw.Unmarshal(&s)
	if err != nil {
		return err
	}
	v, err := Parse(s)
	if err != nil {
		return err
	}
	*vp = v
	return nil
}

func isOdd(x int) bool {
	return x%2 != 0
}

// IsDev returns whether the version represents a development
// version. A version with an odd-numbered major, minor
// or patch version is considered to be a development version.
func (v Number) IsDev() bool {
	return isOdd(v.Major) || isOdd(v.Minor) || isOdd(v.Patch) || v.Build > 0
}

func readSeries(releaseFile string) string {
	data, err := ioutil.ReadFile(releaseFile)
	if err != nil {
		return "unknown"
	}
	for _, line := range strings.Split(string(data), "\n") {
		const p = "DISTRIB_CODENAME="
		if strings.HasPrefix(line, p) {
			return strings.Trim(line[len(p):], "\t '\"")
		}
	}
	return "unknown"
}

func ubuntuArch(arch string) string {
	if arch == "386" {
		arch = "i386"
	}
	return arch
}
<commit_msg>set development version to 1.9.11<commit_after>// The version package implements version parsing.
// It also acts as guardian of the current client Juju version number.
package version

import (
	"fmt"
	"io/ioutil"
	"labix.org/v2/mgo/bson"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"strconv"
	"strings"
)

// The presence and format of this constant is very important.
// The debian/rules build recipe uses this value for the version
// number of the release package.
const version = "1.9.11"

// Current gives the current version of the system.  If the file
// "FORCE-VERSION" is present in the same directory as the running
// binary, it will override this.
var Current = Binary{
	Number: MustParse(version),
	Series: readSeries("/etc/lsb-release"), // current Ubuntu release name.
	Arch:   ubuntuArch(runtime.GOARCH),
}

func init() {
	toolsDir := filepath.Dir(os.Args[0])
	v, err := ioutil.ReadFile(filepath.Join(toolsDir, "FORCE-VERSION"))
	if err != nil {
		if os.IsNotExist(err) {
			return
		}
		panic(fmt.Errorf("version: cannot read forced version: %v", err))
	}
	Current.Number = MustParse(strings.TrimSpace(string(v)))
}

// Number represents a juju version.  When bugs are fixed the patch
// number is incremented; when new features are added the minor number
// is incremented and patch is reset; and when compatibility is broken
// the major version is incremented and minor and patch are reset.  The
// build number is automatically assigned and has no well defined
// sequence.  If the build number is greater than zero or any of the
// other numbers are odd, it indicates that the release is still in
// development.
type Number struct {
	Major int
	Minor int
	Patch int
	Build int
}

// Binary specifies a binary version of juju.
type Binary struct {
	Number
	Series string
	Arch   string
}

func (v Binary) String() string {
	return fmt.Sprintf("%v-%s-%s", v.Number, v.Series, v.Arch)
}

// GetBSON turns v into a bson.Getter so it can be saved directly
// on a MongoDB database with mgo.
func (v Binary) GetBSON() (interface{}, error) {
	return v.String(), nil
}

// SetBSON turns v into a bson.Setter so it can be loaded directly
// from a MongoDB database with mgo.
func (vp *Binary) SetBSON(raw bson.Raw) error {
	var s string
	err := raw.Unmarshal(&s)
	if err != nil {
		return err
	}
	v, err := ParseBinary(s)
	if err != nil {
		return err
	}
	*vp = v
	return nil
}

var (
	binaryPat = regexp.MustCompile(`^(\d{1,9})\.(\d{1,9})\.(\d{1,9})(\.\d{1,9})?-([^-]+)-([^-]+)$`)
	numberPat = regexp.MustCompile(`^(\d{1,9})\.(\d{1,9})\.(\d{1,9})(\.\d{1,9})?$`)
)

// MustParse parses a version and panics if it does
// not parse correctly.
func MustParse(s string) Number {
	v, err := Parse(s)
	if err != nil {
		panic(err)
	}
	return v
}

// MustParseBinary parses a binary version and panics if it does
// not parse correctly.
func MustParseBinary(s string) Binary {
	v, err := ParseBinary(s)
	if err != nil {
		panic(err)
	}
	return v
}

// ParseBinary parses a binary version of the form "1.2.3-series-arch".
func ParseBinary(s string) (Binary, error) {
	m := binaryPat.FindStringSubmatch(s)
	if m == nil {
		return Binary{}, fmt.Errorf("invalid binary version %q", s)
	}
	var v Binary
	v.Major = atoi(m[1])
	v.Minor = atoi(m[2])
	v.Patch = atoi(m[3])
	if m[4] != "" {
		v.Build = atoi(m[4][1:])
	}
	v.Series = m[5]
	v.Arch = m[6]
	return v, nil
}

// Parse parses the version, which is of the form 1.2.3
// giving the major, minor and release versions
// respectively.
func Parse(s string) (Number, error) {
	m := numberPat.FindStringSubmatch(s)
	if m == nil {
		return Number{}, fmt.Errorf("invalid version %q", s)
	}
	var v Number
	v.Major = atoi(m[1])
	v.Minor = atoi(m[2])
	v.Patch = atoi(m[3])
	if m[4] != "" {
		v.Build = atoi(m[4][1:])
	}
	return v, nil
}

// atoi is the same as strconv.Atoi but assumes that
// the string has been verified to be a valid integer.
func atoi(s string) int {
	n, err := strconv.Atoi(s)
	if err != nil {
		panic(err)
	}
	return n
}

func (v Number) String() string {
	s := fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch)
	if v.Build > 0 {
		s += fmt.Sprintf(".%d", v.Build)
	}
	return s
}

// Less returns whether v is semantically earlier in the
// version sequence than w.
func (v Number) Less(w Number) bool {
	switch {
	case v.Major != w.Major:
		return v.Major < w.Major
	case v.Minor != w.Minor:
		return v.Minor < w.Minor
	case v.Patch != w.Patch:
		return v.Patch < w.Patch
	case v.Build != w.Build:
		return v.Build < w.Build
	}
	return false
}

// GetBSON turns v into a bson.Getter so it can be saved directly
// on a MongoDB database with mgo.
func (v Number) GetBSON() (interface{}, error) {
	return v.String(), nil
}

// SetBSON turns v into a bson.Setter so it can be loaded directly
// from a MongoDB database with mgo.
func (vp *Number) SetBSON(raw bson.Raw) error {
	var s string
	err := raw.Unmarshal(&s)
	if err != nil {
		return err
	}
	v, err := Parse(s)
	if err != nil {
		return err
	}
	*vp = v
	return nil
}

func isOdd(x int) bool {
	return x%2 != 0
}

// IsDev returns whether the version represents a development
// version. A version with an odd-numbered major, minor
// or patch version is considered to be a development version.
func (v Number) IsDev() bool {
	return isOdd(v.Major) || isOdd(v.Minor) || isOdd(v.Patch) || v.Build > 0
}

func readSeries(releaseFile string) string {
	data, err := ioutil.ReadFile(releaseFile)
	if err != nil {
		return "unknown"
	}
	for _, line := range strings.Split(string(data), "\n") {
		const p = "DISTRIB_CODENAME="
		if strings.HasPrefix(line, p) {
			return strings.Trim(line[len(p):], "\t '\"")
		}
	}
	return "unknown"
}

func ubuntuArch(arch string) string {
	if arch == "386" {
		arch = "i386"
	}
	return arch
}
<|endoftext|>


<commit_before>package version
var(
Id = 17101435
TagName = "1-0-9"
)
<commit_msg>version<commit_after>package version
var(
Id = 17127440
TagName = "1-0-9a"
)
<|endoftext|>


<commit_before>package version

import (
	"bytes"
	"fmt"
)

// The git commit that was compiled. This will be filled in by the compiler.
var GitCommit string

// The main version number that is being run at the moment.
const Version = "0.12.0"

// A pre-release marker for the version. If this is "" (empty string)
// then it means that it is a final release. Otherwise, this is a pre-release
// such as "dev" (in development), "beta", "rc1", etc.
const VersionPrerelease = ""

func FormattedVersion() string {
	var versionString bytes.Buffer
	fmt.Fprintf(&versionString, "%s", Version)
	if VersionPrerelease != "" {
		fmt.Fprintf(&versionString, ".%s", VersionPrerelease)

		if GitCommit != "" {
			fmt.Fprintf(&versionString, " (%s)", GitCommit)
		}
	}

	return versionString.String()
}
<commit_msg>0.12.1 will be next version<commit_after>package version

import (
	"bytes"
	"fmt"
)

// The git commit that was compiled. This will be filled in by the compiler.
var GitCommit string

// The main version number that is being run at the moment.
const Version = "0.12.1"

// A pre-release marker for the version. If this is "" (empty string)
// then it means that it is a final release. Otherwise, this is a pre-release
// such as "dev" (in development), "beta", "rc1", etc.
const VersionPrerelease = "dev"

func FormattedVersion() string {
	var versionString bytes.Buffer
	fmt.Fprintf(&versionString, "%s", Version)
	if VersionPrerelease != "" {
		fmt.Fprintf(&versionString, ".%s", VersionPrerelease)

		if GitCommit != "" {
			fmt.Fprintf(&versionString, " (%s)", GitCommit)
		}
	}

	return versionString.String()
}
<|endoftext|>


<commit_before>// Copyright 2016 The etcd-operator 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 version

var (
	Version = "0.2.5"
	GitSHA  = "Not provided (use ./build instead of go build)"
)
<commit_msg>version: bump to 0.2.5+git<commit_after>// Copyright 2016 The etcd-operator 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 version

var (
	Version = "0.2.5+git"
	GitSHA  = "Not provided (use ./build instead of go build)"
)
<|endoftext|>


<commit_before>// Copyright 2017 The TensorFlow Authors. 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 main contains the ctpu main program.
package main

import (
	"context"
	"fmt"
	"os"

	"flag"
	// context is used to cancel outstanding requests
	"github.com/google/subcommands"
	"github.com/tensorflow/tpu/tools/ctpu/commands"
	"github.com/tensorflow/tpu/tools/ctpu/config"
	"github.com/tensorflow/tpu/tools/ctpu/ctrl"
)

const version = "1.13"

var logRequests bool

func check(context string, err error) {
	if err != nil {
		fmt.Printf("Error encountered while %s: %s\n", context, err)
		os.Exit(1)
	}
}

func init() {
	flag.BoolVar(&logRequests, "log-http", false,
		`When debugging the ctpu tool, it can be helpful to see the full content of
        all HTTP request-response pairs. Set this flag to true in order to print out
        the requests.`)
}

func main() {
	cfg, err := config.FromEnv()
	check("creating configuration", err)
	cfg.SetFlags(flag.CommandLine)
	flag.Parse()

	ctx := context.Background()
	ctrls, err := ctrl.New(ctx, cfg, version, logRequests)
	check("creating API clients", err)

	subcommands.ImportantFlag("name")
	subcommands.ImportantFlag("project")
	subcommands.ImportantFlag("zone")

	subcommands.Register(commands.UpCommand(cfg, ctrls.TPU, ctrls.GCE, ctrls.ResourceManagement, ctrls.CLI), "")
	subcommands.Register(commands.PauseCommand(cfg, ctrls.TPU, ctrls.GCE), "")
	subcommands.Register(commands.DeleteCommand(cfg, ctrls.TPU, ctrls.GCE), "")
	subcommands.Register(commands.StatusCommand(cfg, ctrls.TPU, ctrls.GCE), "")
	subcommands.Register(commands.RestartCommand(cfg, ctrls.TPU), "")

	subcommands.Register(commands.AuthCommand(cfg, ctrls.ResourceManagement), "configuration")
	subcommands.Register(commands.ConfigCommand(cfg, ctrls.CLI), "configuration")
	subcommands.Register(commands.VersionCommand(version), "configuration")
	subcommands.Register(commands.ListCommand(cfg, ctrls.TPU, ctrls.GCE), "configuration")
	subcommands.Register(commands.TFVersionsCommand(cfg, ctrls.TPU), "configuration")
	subcommands.Register(commands.TPULocationsCommand(cfg, ctrls.TPU), "configuration")
	subcommands.Register(commands.QuotaCommand(cfg), "configuration")
	subcommands.Register(commands.TPUSizeCommand(cfg, ctrls.TPU), "configuration")

	subcommands.Register(commands.PauseCommandAlias(cfg, ctrls.TPU, ctrls.GCE), "aliases for other commands")
	subcommands.Register(commands.DeleteCommandAlias(cfg, ctrls.TPU, ctrls.GCE), "aliases for other commands")
	subcommands.Register(commands.StatusCommandAlias(cfg, ctrls.TPU, ctrls.GCE), "aliases for other commands")
	subcommands.Register(commands.ListCommandAlias(cfg, ctrls.TPU, ctrls.GCE), "aliases for other commands")
	subcommands.Register(commands.ConfigCommandAlias(cfg, ctrls.CLI), "aliases for other commands")

	subcommands.Register(subcommands.HelpCommand(), "usage")
	subcommands.Register(subcommands.FlagsCommand(), "usage")
	subcommands.Register(subcommands.CommandsCommand(), "usage")

	os.Exit(int(subcommands.Execute(ctx)))
}
<commit_msg>Version bump to add tf-nightly-2.x support in ctpu.<commit_after>// Copyright 2017 The TensorFlow Authors. 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 main contains the ctpu main program.
package main

import (
	"context"
	"fmt"
	"os"

	"flag"
	// context is used to cancel outstanding requests
	"github.com/google/subcommands"
	"github.com/tensorflow/tpu/tools/ctpu/commands"
	"github.com/tensorflow/tpu/tools/ctpu/config"
	"github.com/tensorflow/tpu/tools/ctpu/ctrl"
)

const version = "1.14"

var logRequests bool

func check(context string, err error) {
	if err != nil {
		fmt.Printf("Error encountered while %s: %s\n", context, err)
		os.Exit(1)
	}
}

func init() {
	flag.BoolVar(&logRequests, "log-http", false,
		`When debugging the ctpu tool, it can be helpful to see the full content of
        all HTTP request-response pairs. Set this flag to true in order to print out
        the requests.`)
}

func main() {
	cfg, err := config.FromEnv()
	check("creating configuration", err)
	cfg.SetFlags(flag.CommandLine)
	flag.Parse()

	ctx := context.Background()
	ctrls, err := ctrl.New(ctx, cfg, version, logRequests)
	check("creating API clients", err)

	subcommands.ImportantFlag("name")
	subcommands.ImportantFlag("project")
	subcommands.ImportantFlag("zone")

	subcommands.Register(commands.UpCommand(cfg, ctrls.TPU, ctrls.GCE, ctrls.ResourceManagement, ctrls.CLI), "")
	subcommands.Register(commands.PauseCommand(cfg, ctrls.TPU, ctrls.GCE), "")
	subcommands.Register(commands.DeleteCommand(cfg, ctrls.TPU, ctrls.GCE), "")
	subcommands.Register(commands.StatusCommand(cfg, ctrls.TPU, ctrls.GCE), "")
	subcommands.Register(commands.RestartCommand(cfg, ctrls.TPU), "")

	subcommands.Register(commands.AuthCommand(cfg, ctrls.ResourceManagement), "configuration")
	subcommands.Register(commands.ConfigCommand(cfg, ctrls.CLI), "configuration")
	subcommands.Register(commands.VersionCommand(version), "configuration")
	subcommands.Register(commands.ListCommand(cfg, ctrls.TPU, ctrls.GCE), "configuration")
	subcommands.Register(commands.TFVersionsCommand(cfg, ctrls.TPU), "configuration")
	subcommands.Register(commands.TPULocationsCommand(cfg, ctrls.TPU), "configuration")
	subcommands.Register(commands.QuotaCommand(cfg), "configuration")
	subcommands.Register(commands.TPUSizeCommand(cfg, ctrls.TPU), "configuration")

	subcommands.Register(commands.PauseCommandAlias(cfg, ctrls.TPU, ctrls.GCE), "aliases for other commands")
	subcommands.Register(commands.DeleteCommandAlias(cfg, ctrls.TPU, ctrls.GCE), "aliases for other commands")
	subcommands.Register(commands.StatusCommandAlias(cfg, ctrls.TPU, ctrls.GCE), "aliases for other commands")
	subcommands.Register(commands.ListCommandAlias(cfg, ctrls.TPU, ctrls.GCE), "aliases for other commands")
	subcommands.Register(commands.ConfigCommandAlias(cfg, ctrls.CLI), "aliases for other commands")

	subcommands.Register(subcommands.HelpCommand(), "usage")
	subcommands.Register(subcommands.FlagsCommand(), "usage")
	subcommands.Register(subcommands.CommandsCommand(), "usage")

	os.Exit(int(subcommands.Execute(ctx)))
}
<|endoftext|>


<commit_before>// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you 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 ucfg

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

type myIntInitializer int
type myMapInitializer map[string]string

func (i *myIntInitializer) InitDefaults() {
	*i = myIntInitializer(3)
}

func (m *myMapInitializer) InitDefaults() {
	(*m)["init"] = "defaults"
}

type structInitializer struct {
	I int
	J int
}

func (s *structInitializer) InitDefaults() {
	s.J = 10
}

type structNoInitalizer struct {
	I myIntInitializer
}

type nestedStructInitializer struct {
	M myMapInitializer
	N structInitializer
	O int
	P structNoInitalizer
}

func (n *nestedStructInitializer) InitDefaults() {
	n.O = 20

	// overridden by InitDefaults from structInitializer
	n.N.J = 15
}

type ptrNestedStructInitializer struct {
	M *myMapInitializer
	N *structInitializer
	O int
	P *structNoInitalizer
}

func (n *ptrNestedStructInitializer) InitDefaults() {
	n.O = 20
}

func TestInitDefaultsPrimitive(t *testing.T) {
	c, _ := NewFrom(map[string]interface{}{})

	// unpack S
	r := &struct {
		I myIntInitializer
	}{}

	err := c.Unpack(r)
	assert.NoError(t, err)
	assert.Equal(t, myIntInitializer(3), r.I)
}

func TestInitDefaultsPrimitiveSet(t *testing.T) {
	c, _ := NewFrom(map[string]interface{}{
		"i": 25,
	})

	// unpack S
	r := &struct {
		I myIntInitializer
	}{}

	err := c.Unpack(r)
	assert.NoError(t, err)
	assert.Equal(t, myIntInitializer(25), r.I)
}

func TestInitDefaultsMap(t *testing.T) {
	c, _ := NewFrom(map[string]interface{}{})

	// unpack S
	r := &struct {
		M myMapInitializer
	}{}

	err := c.Unpack(r)
	assert.NoError(t, err)
	assert.Equal(t, myMapInitializer{
		"init": "defaults",
	}, r.M)
}

func TestInitDefaultsMapUpdate(t *testing.T) {
	c, _ := NewFrom(map[string]interface{}{
		"m": map[string]interface{}{
			"other": "config",
		},
	})

	// unpack S
	r := &struct {
		M myMapInitializer
	}{}

	err := c.Unpack(r)
	assert.NoError(t, err)
	assert.Equal(t, myMapInitializer{
		"init":  "defaults",
		"other": "config",
	}, r.M)
}

func TestInitDefaultsMapReplace(t *testing.T) {
	c, _ := NewFrom(map[string]interface{}{
		"m": map[string]interface{}{
			"init":  "replace",
			"other": "config",
		},
	})

	// unpack S
	r := &struct {
		M myMapInitializer
	}{}

	err := c.Unpack(r)
	assert.NoError(t, err)
	assert.Equal(t, myMapInitializer{
		"init":  "replace",
		"other": "config",
	}, r.M)
}

func TestInitDefaultsSingle(t *testing.T) {
	c, _ := NewFrom(map[string]interface{}{
		"s": map[string]interface{}{
			"i": 5,
		},
	})

	// unpack S
	r := &struct {
		S structInitializer
	}{}

	err := c.Unpack(r)
	assert.NoError(t, err)
	assert.Equal(t, 5, r.S.I)
	assert.Equal(t, 10, r.S.J)
}

func TestInitDefaultsNested(t *testing.T) {
	c, _ := NewFrom(map[string]interface{}{
		"s": map[string]interface{}{
			"n": map[string]interface{}{
				"i": 5,
			},
		},
	})

	// unpack S
	r := &struct {
		S nestedStructInitializer
	}{}

	err := c.Unpack(r)
	assert.NoError(t, err)
	assert.Equal(t, myMapInitializer{
		"init": "defaults",
	}, r.S.M)
	assert.Equal(t, 5, r.S.N.I)
	assert.Equal(t, 10, r.S.N.J)
	assert.Equal(t, 20, r.S.O)
	assert.Equal(t, myIntInitializer(3), r.S.P.I)
}

func TestInitDefaultsNestedEmpty(t *testing.T) {
	c, _ := NewFrom(map[string]interface{}{})

	// unpack S
	r := &struct {
		S nestedStructInitializer
	}{}

	err := c.Unpack(r)
	assert.NoError(t, err)
	assert.Equal(t, myMapInitializer{
		"init": "defaults",
	}, r.S.M)
	assert.Equal(t, 0, r.S.N.I)
	assert.Equal(t, 10, r.S.N.J)
	assert.Equal(t, 20, r.S.O)
	assert.Equal(t, myIntInitializer(3), r.S.P.I)
}

func TestInitDefaultsPtrNestedEmpty(t *testing.T) {
	c, _ := NewFrom(map[string]interface{}{})

	// unpack S
	r := &struct {
		S ptrNestedStructInitializer
	}{}

	err := c.Unpack(r)
	assert.NoError(t, err)
	assert.Nil(t, r.S.M)
	assert.Nil(t, r.S.N)
	assert.Nil(t, r.S.P)
	assert.Equal(t, 20, r.S.O)
}
<commit_msg>Add test for struct with array initializer (#164)<commit_after>// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you 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 ucfg

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

type myIntInitializer int
type myMapInitializer map[string]string

func (i *myIntInitializer) InitDefaults() {
	*i = myIntInitializer(3)
}

func (m *myMapInitializer) InitDefaults() {
	(*m)["init"] = "defaults"
}

type structInitializer struct {
	I int
	J int
}

func (s *structInitializer) InitDefaults() {
	s.J = 10
}

type structNoInitalizer struct {
	I myIntInitializer
}

type nestedStructInitializer struct {
	M myMapInitializer
	N structInitializer
	O int
	P structNoInitalizer
}

func (n *nestedStructInitializer) InitDefaults() {
	n.O = 20

	// overridden by InitDefaults from structInitializer
	n.N.J = 15
}

type ptrNestedStructInitializer struct {
	M *myMapInitializer
	N *structInitializer
	O int
	P *structNoInitalizer
}

func (n *ptrNestedStructInitializer) InitDefaults() {
	n.O = 20
}

type structWithArrayInitializer struct {
	O int
	A []structInitializer
}

func (s *structWithArrayInitializer) InitDefaults() {
	s.O = 10
}

func TestInitDefaultsPrimitive(t *testing.T) {
	c, _ := NewFrom(map[string]interface{}{})

	// unpack S
	r := &struct {
		I myIntInitializer
	}{}

	err := c.Unpack(r)
	assert.NoError(t, err)
	assert.Equal(t, myIntInitializer(3), r.I)
}

func TestInitDefaultsPrimitiveSet(t *testing.T) {
	c, _ := NewFrom(map[string]interface{}{
		"i": 25,
	})

	// unpack S
	r := &struct {
		I myIntInitializer
	}{}

	err := c.Unpack(r)
	assert.NoError(t, err)
	assert.Equal(t, myIntInitializer(25), r.I)
}

func TestInitDefaultsMap(t *testing.T) {
	c, _ := NewFrom(map[string]interface{}{})

	// unpack S
	r := &struct {
		M myMapInitializer
	}{}

	err := c.Unpack(r)
	assert.NoError(t, err)
	assert.Equal(t, myMapInitializer{
		"init": "defaults",
	}, r.M)
}

func TestInitDefaultsMapUpdate(t *testing.T) {
	c, _ := NewFrom(map[string]interface{}{
		"m": map[string]interface{}{
			"other": "config",
		},
	})

	// unpack S
	r := &struct {
		M myMapInitializer
	}{}

	err := c.Unpack(r)
	assert.NoError(t, err)
	assert.Equal(t, myMapInitializer{
		"init":  "defaults",
		"other": "config",
	}, r.M)
}

func TestInitDefaultsMapReplace(t *testing.T) {
	c, _ := NewFrom(map[string]interface{}{
		"m": map[string]interface{}{
			"init":  "replace",
			"other": "config",
		},
	})

	// unpack S
	r := &struct {
		M myMapInitializer
	}{}

	err := c.Unpack(r)
	assert.NoError(t, err)
	assert.Equal(t, myMapInitializer{
		"init":  "replace",
		"other": "config",
	}, r.M)
}

func TestInitDefaultsSingle(t *testing.T) {
	c, _ := NewFrom(map[string]interface{}{
		"s": map[string]interface{}{
			"i": 5,
		},
	})

	// unpack S
	r := &struct {
		S structInitializer
	}{}

	err := c.Unpack(r)
	assert.NoError(t, err)
	assert.Equal(t, 5, r.S.I)
	assert.Equal(t, 10, r.S.J)
}

func TestInitDefaultsNested(t *testing.T) {
	c, _ := NewFrom(map[string]interface{}{
		"s": map[string]interface{}{
			"n": map[string]interface{}{
				"i": 5,
			},
		},
	})

	// unpack S
	r := &struct {
		S nestedStructInitializer
	}{}

	err := c.Unpack(r)
	assert.NoError(t, err)
	assert.Equal(t, myMapInitializer{
		"init": "defaults",
	}, r.S.M)
	assert.Equal(t, 5, r.S.N.I)
	assert.Equal(t, 10, r.S.N.J)
	assert.Equal(t, 20, r.S.O)
	assert.Equal(t, myIntInitializer(3), r.S.P.I)
}

func TestInitDefaultsNestedEmpty(t *testing.T) {
	c, _ := NewFrom(map[string]interface{}{})

	// unpack S
	r := &struct {
		S nestedStructInitializer
	}{}

	err := c.Unpack(r)
	assert.NoError(t, err)
	assert.Equal(t, myMapInitializer{
		"init": "defaults",
	}, r.S.M)
	assert.Equal(t, 0, r.S.N.I)
	assert.Equal(t, 10, r.S.N.J)
	assert.Equal(t, 20, r.S.O)
	assert.Equal(t, myIntInitializer(3), r.S.P.I)
}

func TestInitDefaultsPtrNestedEmpty(t *testing.T) {
	c, _ := NewFrom(map[string]interface{}{})

	// unpack S
	r := &struct {
		S ptrNestedStructInitializer
	}{}

	err := c.Unpack(r)
	assert.NoError(t, err)
	assert.Nil(t, r.S.M)
	assert.Nil(t, r.S.N)
	assert.Nil(t, r.S.P)
	assert.Equal(t, 20, r.S.O)
}

func TestInitDefaultsStructWithArray(t *testing.T) {
	c, _ := NewFrom(map[string]interface{}{
		"a": []map[string]interface{}{
			{
				"i": 5,
			},
		},
	})

	r := structWithArrayInitializer{}
	err := c.Unpack(&r)
	assert.NoError(t, err)
	assert.Equal(t, 10, r.O)
	assert.Len(t, r.A, 1)
	for _, e := range r.A {
		assert.Equal(t, 5, e.I)
		assert.Equal(t, 10, e.J)
	}
}
<|endoftext|>


<commit_before>// Copyright 2011 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 ogletest_test

import (
	"errors"
	"fmt"
	"io/ioutil"
	"path"
	"os"
	"os/exec"
	"strings"
	"testing"
)

////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////

// getCaseNames looks for integration test cases as files in the
// integration_test_cases directory.
func getCaseNames() ([]string, error) {
	// Open the test cases directory.
	dir, err := os.Open("integration_test_cases")
	if err != nil {
		return nil, errors.New(fmt.Sprintf("Opening dir: %v", err))
	}

	// Get a list of the names in the directory.
	names, err := dir.Readdirnames(0)
	if err != nil {
		return nil, errors.New(fmt.Sprintf("Readdirnames: %v", err))
	}

	// Filter the names.
	result := make([]string, len(names))
	resultLen := 0
	for _, name := range names {
		// Skip golden files.
		if strings.HasPrefix(name, "golden.") {
			continue
		}

		// Check for the right format.
		if !strings.HasSuffix(name, "_test.go") {
			return nil, errors.New(fmt.Sprintf("Unexpected file: %s", name))
		}

		// Store the name minus the extension.
		result[resultLen] = name[len(name) - 2:]
	}

	return result, nil
}

func writeStringToFileOrDie(contents []byte, path string) {
	if err := ioutil.WriteFile(path, contents, 0600); err != nil {
		panic("iotuil.WriteFile: " + err.Error())
	}
}

func readFileOrDie(path string) []byte {
	contents, err := ioutil.ReadFile(path)
	if err != nil {
		panic("iotuil.ReadFile: " + err.Error())
	}

	return contents
}

// runTestCase runs the case with the supplied name (e.g. "passing_test"), and
// returns its output and exit code.
func runTestCase(name string) ([]byte, int, error) {
	// Create a temporary directory for the test files.
	tempDir, err := ioutil.TempDir("", "ogletest_integration_test")
	if err != nil {
		return nil, 0, errors.New("ioutil.TempDir: " + err.Error())
	}

	// Create a makefile within the directory.
	makefileContents := "include $(GOROOT)/src/Make.inc\n" +
		"TARG = github.com/jacobsa/ogletest/foobar\n" +
		"GOFILES = " + name + ".go\n" +
		"include $(GOROOT)/src/Make.pkg\n"

	writeStringToFileOrDie([]byte(makefileContents), path.Join(tempDir, "Makefile"))

	// Create the test source file.
	sourceFile := name + ".go"
	testContents := readFileOrDie(path.Join("integration_test_cases", sourceFile))
	writeStringToFileOrDie(testContents, path.Join(tempDir, sourceFile))

	// Invoke gotest.
	cmd := exec.Command("gotest")
	cmd.Dir = tempDir
	output, err := cmd.Output()

	// Did the process exist with zero code?
	if err == nil {
		return output, 0, nil
	}

	// Make sure the process actually exited.
	exitError, ok := err.(*exec.ExitError)
	if !ok || !exitError.Exited() {
		return nil, 0, errors.New("exec.Command.Output: " + err.Error())
	}

	return output, exitError.ExitStatus(), nil
}

////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////

func TestGoldenFiles(t *testing.T) {
	// We expect there to be at least one case.
	caseNames, err := getCaseNames()
	if err != nil || len(caseNames) == 0 {
		t.Fatalf("Error getting cases: %v", err)
	}

	// Run each test case.
	for _, caseName := range caseNames {
		t.Logf("Running test case: %s", caseName)

		// Run the test case.
		_, exitCode, err := runTestCase(caseName)
		if err != nil {
			t.Fatalf("Running test case %s: %v", caseName, err)
		}

		// Check the status code. We assume all test cases fail except for passing_test.
		shouldPass := caseName == "passint_test"
		didPass := exitCode == 0
		if shouldPass != didPass {
			t.Errorf("Bad exit code for test case %s: %d", caseName, exitCode)
		}
	}
}
<commit_msg>Fixed a test bug.<commit_after>// Copyright 2011 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 ogletest_test

import (
	"errors"
	"fmt"
	"io/ioutil"
	"path"
	"os"
	"os/exec"
	"strings"
	"testing"
)

////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////

// getCaseNames looks for integration test cases as files in the
// integration_test_cases directory.
func getCaseNames() ([]string, error) {
	// Open the test cases directory.
	dir, err := os.Open("integration_test_cases")
	if err != nil {
		return nil, errors.New(fmt.Sprintf("Opening dir: %v", err))
	}

	// Get a list of the names in the directory.
	names, err := dir.Readdirnames(0)
	if err != nil {
		return nil, errors.New(fmt.Sprintf("Readdirnames: %v", err))
	}

	// Filter the names.
	result := make([]string, len(names))
	resultLen := 0
	for _, name := range names {
		// Skip golden files.
		if strings.HasPrefix(name, "golden.") {
			continue
		}

		// Check for the right format.
		if !strings.HasSuffix(name, "_test.go") {
			return nil, errors.New(fmt.Sprintf("Unexpected file: %s", name))
		}

		// Store the name minus the extension.
		result[resultLen] = name[:len(name) - 3]
	}

	return result, nil
}

func writeStringToFileOrDie(contents []byte, path string) {
	if err := ioutil.WriteFile(path, contents, 0600); err != nil {
		panic("iotuil.WriteFile: " + err.Error())
	}
}

func readFileOrDie(path string) []byte {
	contents, err := ioutil.ReadFile(path)
	if err != nil {
		panic("iotuil.ReadFile: " + err.Error())
	}

	return contents
}

// runTestCase runs the case with the supplied name (e.g. "passing_test"), and
// returns its output and exit code.
func runTestCase(name string) ([]byte, int, error) {
	// Create a temporary directory for the test files.
	tempDir, err := ioutil.TempDir("", "ogletest_integration_test")
	if err != nil {
		return nil, 0, errors.New("ioutil.TempDir: " + err.Error())
	}

	// Create a makefile within the directory.
	makefileContents := "include $(GOROOT)/src/Make.inc\n" +
		"TARG = github.com/jacobsa/ogletest/foobar\n" +
		"GOFILES = " + name + ".go\n" +
		"include $(GOROOT)/src/Make.pkg\n"

	writeStringToFileOrDie([]byte(makefileContents), path.Join(tempDir, "Makefile"))

	// Create the test source file.
	sourceFile := name + ".go"
	testContents := readFileOrDie(path.Join("integration_test_cases", sourceFile))
	writeStringToFileOrDie(testContents, path.Join(tempDir, sourceFile))

	// Invoke gotest.
	cmd := exec.Command("gotest")
	cmd.Dir = tempDir
	output, err := cmd.Output()

	// Did the process exist with zero code?
	if err == nil {
		return output, 0, nil
	}

	// Make sure the process actually exited.
	exitError, ok := err.(*exec.ExitError)
	if !ok || !exitError.Exited() {
		return nil, 0, errors.New("exec.Command.Output: " + err.Error())
	}

	return output, exitError.ExitStatus(), nil
}

////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////

func TestGoldenFiles(t *testing.T) {
	// We expect there to be at least one case.
	caseNames, err := getCaseNames()
	if err != nil || len(caseNames) == 0 {
		t.Fatalf("Error getting cases: %v", err)
	}

	// Run each test case.
	for _, caseName := range caseNames {
		t.Logf("Running test case: %s", caseName)

		// Run the test case.
		_, exitCode, err := runTestCase(caseName)
		if err != nil {
			t.Fatalf("Running test case %s: %v", caseName, err)
		}

		// Check the status code. We assume all test cases fail except for passing_test.
		shouldPass := caseName == "passint_test"
		didPass := exitCode == 0
		if shouldPass != didPass {
			t.Errorf("Bad exit code for test case %s: %d", caseName, exitCode)
		}
	}
}
<|endoftext|>


<commit_before>package oci

import (
	"bytes"
	"fmt"
	"io"
	"sync"
	"syscall"
	"time"

	"github.com/cri-o/cri-o/pkg/config"
	rspec "github.com/opencontainers/runtime-spec/specs-go"
	"golang.org/x/net/context"
	"k8s.io/client-go/tools/remotecommand"
)

const (
	// ContainerStateCreated represents the created state of a container
	ContainerStateCreated = "created"
	// ContainerStatePaused represents the paused state of a container
	ContainerStatePaused = "paused"
	// ContainerStateRunning represents the running state of a container
	ContainerStateRunning = "running"
	// ContainerStateStopped represents the stopped state of a container
	ContainerStateStopped = "stopped"
	// ContainerCreateTimeout represents the value of container creating timeout
	ContainerCreateTimeout = 240 * time.Second

	// CgroupfsCgroupsManager represents cgroupfs native cgroup manager
	CgroupfsCgroupsManager = "cgroupfs"
	// SystemdCgroupsManager represents systemd native cgroup manager
	SystemdCgroupsManager = "systemd"

	// killContainerTimeout is the timeout that we wait for the container to
	// be SIGKILLed.
	killContainerTimeout = 2 * time.Minute
)

// Runtime is the generic structure holding both global and specific
// information about the runtime.
type Runtime struct {
	config              *config.Config
	runtimeImplMap      map[string]RuntimeImpl
	runtimeImplMapMutex sync.RWMutex
}

// RuntimeImpl is an interface used by the caller to interact with the
// container runtime. The purpose of this interface being to abstract
// implementations and their associated assumptions regarding the way to
// interact with containers. This will allow for new implementations of
// this interface, especially useful for the case of VM based container
// runtimes. Assumptions based on the fact that a container process runs
// on the host will be limited to the RuntimeOCI implementation.
type RuntimeImpl interface {
	CreateContainer(*Container, string) error
	StartContainer(*Container) error
	ExecContainer(*Container, []string, io.Reader, io.WriteCloser, io.WriteCloser,
		bool, <-chan remotecommand.TerminalSize) error
	ExecSyncContainer(*Container, []string, int64) (*ExecSyncResponse, error)
	UpdateContainer(*Container, *rspec.LinuxResources) error
	StopContainer(context.Context, *Container, int64) error
	DeleteContainer(*Container) error
	UpdateContainerStatus(*Container) error
	PauseContainer(*Container) error
	UnpauseContainer(*Container) error
	ContainerStats(*Container, string) (*ContainerStats, error)
	SignalContainer(*Container, syscall.Signal) error
	AttachContainer(*Container, io.Reader, io.WriteCloser, io.WriteCloser,
		bool, <-chan remotecommand.TerminalSize) error
	PortForwardContainer(*Container, int32, io.ReadWriter) error
	ReopenContainerLog(*Container) error
	WaitContainerStateStopped(context.Context, *Container) error
}

// New creates a new Runtime with options provided
func New(c *config.Config) *Runtime {
	return &Runtime{
		config:         c,
		runtimeImplMap: make(map[string]RuntimeImpl),
	}
}

// Runtimes returns the map of OCI runtimes.
func (r *Runtime) Runtimes() config.Runtimes {
	return r.config.Runtimes
}

// ValidateRuntimeHandler returns an error if the runtime handler string
// provided does not match any valid use case.
func (r *Runtime) ValidateRuntimeHandler(handler string) (*config.RuntimeHandler, error) {
	if handler == "" {
		return nil, fmt.Errorf("empty runtime handler")
	}

	runtimeHandler, ok := r.config.Runtimes[handler]
	if !ok {
		return nil, fmt.Errorf("failed to find runtime handler %s from runtime list %v",
			handler, r.config.Runtimes)
	}
	if runtimeHandler.RuntimePath == "" {
		return nil, fmt.Errorf("empty runtime path for runtime handler %s", handler)
	}

	return runtimeHandler, nil
}

// WaitContainerStateStopped runs a loop polling UpdateStatus(), seeking for
// the container status to be updated to 'stopped'. Either it gets the expected
// status and returns nil, or it reaches the timeout and returns an error.
func (r *Runtime) WaitContainerStateStopped(ctx context.Context, c *Container) (err error) {
	impl, err := r.RuntimeImpl(c)
	if err != nil {
		return err
	}

	// No need to go further and spawn the go routine if the container
	// is already in the expected status.
	if c.State().Status == ContainerStateStopped {
		return nil
	}

	done := make(chan error)
	chControl := make(chan struct{})
	go func() {
		for {
			select {
			case <-chControl:
				return
			default:
				// Check if the container is stopped
				if err := impl.UpdateContainerStatus(c); err != nil {
					done <- err
					close(done)
					return
				}
				if c.State().Status == ContainerStateStopped {
					close(done)
					return
				}
				time.Sleep(100 * time.Millisecond)
			}
		}
	}()
	select {
	case err = <-done:
		break
	case <-ctx.Done():
		close(chControl)
		return ctx.Err()
	case <-time.After(time.Duration(r.config.CtrStopTimeout) * time.Second):
		close(chControl)
		return fmt.Errorf(
			"failed to get container stopped status: %ds timeout reached",
			r.config.CtrStopTimeout,
		)
	}

	if err != nil {
		return fmt.Errorf("failed to get container stopped status: %v", err)
	}

	return nil
}

func (r *Runtime) getRuntimeHandler(handler string) (*config.RuntimeHandler, error) {
	// Define the current runtime handler as the default runtime handler.
	rh := r.config.Runtimes[r.config.DefaultRuntime]

	// Override the current runtime handler with the runtime handler
	// corresponding to the runtime handler key provided with this
	// specific container.
	if handler != "" {
		runtimeHandler, err := r.ValidateRuntimeHandler(handler)
		if err != nil {
			return nil, err
		}

		rh = runtimeHandler
	}

	return rh, nil
}

// PrivelegedRuntimeHandler returns a boolean value configured for the
// runtimeHandler indicating if devices on the host are passed/not passed
// to a container running as privileged.
func (r *Runtime) PrivilegedWithoutHostDevices(handler string) (bool, error) {
	rh, err := r.getRuntimeHandler(handler)
	if err != nil {
		return false, err
	}

	return rh.PrivilegedWithoutHostDevices, nil
}

// ContainerRuntimeType returns the type of runtime configured.
// This is needed when callers need to do specific work for oci vs vm
// containers, like monitor an oci container's conmon.
func (r *Runtime) ContainerRuntimeType(c *Container) (string, error) {
	rh, err := r.getRuntimeHandler(c.runtimeHandler)
	if err != nil {
		return "", err
	}

	return rh.RuntimeType, nil
}

func (r *Runtime) newRuntimeImpl(c *Container) (RuntimeImpl, error) {
	rh, err := r.getRuntimeHandler(c.runtimeHandler)
	if err != nil {
		return nil, err
	}

	if rh.RuntimeType == config.RuntimeTypeVM {
		return newRuntimeVM(rh.RuntimePath), nil
	}

	// If the runtime type is different from "vm", then let's fallback
	// onto the OCI implementation by default.
	return newRuntimeOCI(r, rh), nil
}

// RuntimeImpl returns the runtime implementation for a given container
func (r *Runtime) RuntimeImpl(c *Container) (RuntimeImpl, error) {
	r.runtimeImplMapMutex.RLock()
	impl, ok := r.runtimeImplMap[c.ID()]
	r.runtimeImplMapMutex.RUnlock()
	if !ok {
		return r.newRuntimeImpl(c)
	}

	return impl, nil
}

// CreateContainer creates a container.
func (r *Runtime) CreateContainer(c *Container, cgroupParent string) error {
	// Instantiate a new runtime implementation for this new container
	impl, err := r.newRuntimeImpl(c)
	if err != nil {
		return err
	}

	// Assign this runtime implementation to the current container
	r.runtimeImplMapMutex.Lock()
	r.runtimeImplMap[c.ID()] = impl
	r.runtimeImplMapMutex.Unlock()

	return impl.CreateContainer(c, cgroupParent)
}

// StartContainer starts a container.
func (r *Runtime) StartContainer(c *Container) error {
	impl, err := r.RuntimeImpl(c)
	if err != nil {
		return err
	}

	return impl.StartContainer(c)
}

// ExecContainer prepares a streaming endpoint to execute a command in the container.
func (r *Runtime) ExecContainer(c *Container, cmd []string, stdin io.Reader, stdout, stderr io.WriteCloser, tty bool, resize <-chan remotecommand.TerminalSize) error {
	impl, err := r.RuntimeImpl(c)
	if err != nil {
		return err
	}

	return impl.ExecContainer(c, cmd, stdin, stdout, stderr, tty, resize)
}

// ExecSyncContainer execs a command in a container and returns it's stdout, stderr and return code.
func (r *Runtime) ExecSyncContainer(c *Container, command []string, timeout int64) (*ExecSyncResponse, error) {
	impl, err := r.RuntimeImpl(c)
	if err != nil {
		return nil, err
	}

	return impl.ExecSyncContainer(c, command, timeout)
}

// UpdateContainer updates container resources
func (r *Runtime) UpdateContainer(c *Container, res *rspec.LinuxResources) error {
	impl, err := r.RuntimeImpl(c)
	if err != nil {
		return err
	}

	return impl.UpdateContainer(c, res)
}

// StopContainer stops a container. Timeout is given in seconds.
func (r *Runtime) StopContainer(ctx context.Context, c *Container, timeout int64) error {
	impl, err := r.RuntimeImpl(c)
	if err != nil {
		return err
	}

	return impl.StopContainer(ctx, c, timeout)
}

// DeleteContainer deletes a container.
func (r *Runtime) DeleteContainer(c *Container) error {
	impl, err := r.RuntimeImpl(c)
	if err != nil {
		return err
	}

	defer func() {
		r.runtimeImplMapMutex.Lock()
		delete(r.runtimeImplMap, c.ID())
		r.runtimeImplMapMutex.Unlock()
	}()

	return impl.DeleteContainer(c)
}

// UpdateContainerStatus refreshes the status of the container.
func (r *Runtime) UpdateContainerStatus(c *Container) error {
	impl, err := r.RuntimeImpl(c)
	if err != nil {
		return err
	}

	return impl.UpdateContainerStatus(c)
}

// PauseContainer pauses a container.
func (r *Runtime) PauseContainer(c *Container) error {
	impl, err := r.RuntimeImpl(c)
	if err != nil {
		return err
	}

	return impl.PauseContainer(c)
}

// UnpauseContainer unpauses a container.
func (r *Runtime) UnpauseContainer(c *Container) error {
	impl, err := r.RuntimeImpl(c)
	if err != nil {
		return err
	}

	return impl.UnpauseContainer(c)
}

// ContainerStats provides statistics of a container.
func (r *Runtime) ContainerStats(c *Container, cgroup string) (*ContainerStats, error) {
	impl, err := r.RuntimeImpl(c)
	if err != nil {
		return nil, err
	}

	return impl.ContainerStats(c, cgroup)
}

// SignalContainer sends a signal to a container process.
func (r *Runtime) SignalContainer(c *Container, sig syscall.Signal) error {
	impl, err := r.RuntimeImpl(c)
	if err != nil {
		return err
	}

	return impl.SignalContainer(c, sig)
}

// AttachContainer attaches IO to a running container.
func (r *Runtime) AttachContainer(c *Container, inputStream io.Reader, outputStream, errorStream io.WriteCloser, tty bool, resize <-chan remotecommand.TerminalSize) error {
	impl, err := r.RuntimeImpl(c)
	if err != nil {
		return err
	}

	return impl.AttachContainer(c, inputStream, outputStream, errorStream, tty, resize)
}

// PortForwardContainer forwards the specified port provides statistics of a container.
func (r *Runtime) PortForwardContainer(c *Container, port int32, stream io.ReadWriter) error {
	impl, err := r.RuntimeImpl(c)
	if err != nil {
		return err
	}

	return impl.PortForwardContainer(c, port, stream)
}

// ReopenContainerLog reopens the log file of a container.
func (r *Runtime) ReopenContainerLog(c *Container) error {
	impl, err := r.RuntimeImpl(c)
	if err != nil {
		return err
	}

	return impl.ReopenContainerLog(c)
}

// ExecSyncResponse is returned from ExecSync.
type ExecSyncResponse struct {
	Stdout   []byte
	Stderr   []byte
	ExitCode int32
}

// ExecSyncError wraps command's streams, exit code and error on ExecSync error.
type ExecSyncError struct {
	Stdout   bytes.Buffer
	Stderr   bytes.Buffer
	ExitCode int32
	Err      error
}

func (e *ExecSyncError) Error() string {
	return fmt.Sprintf("command error: %+v, stdout: %s, stderr: %s, exit code %d", e.Err, e.Stdout.Bytes(), e.Stderr.Bytes(), e.ExitCode)
}
<commit_msg>Close done channel if the wait for ContainerStateStopped times out<commit_after>package oci

import (
	"bytes"
	"fmt"
	"io"
	"sync"
	"syscall"
	"time"

	"github.com/cri-o/cri-o/pkg/config"
	rspec "github.com/opencontainers/runtime-spec/specs-go"
	"golang.org/x/net/context"
	"k8s.io/client-go/tools/remotecommand"
)

const (
	// ContainerStateCreated represents the created state of a container
	ContainerStateCreated = "created"
	// ContainerStatePaused represents the paused state of a container
	ContainerStatePaused = "paused"
	// ContainerStateRunning represents the running state of a container
	ContainerStateRunning = "running"
	// ContainerStateStopped represents the stopped state of a container
	ContainerStateStopped = "stopped"
	// ContainerCreateTimeout represents the value of container creating timeout
	ContainerCreateTimeout = 240 * time.Second

	// CgroupfsCgroupsManager represents cgroupfs native cgroup manager
	CgroupfsCgroupsManager = "cgroupfs"
	// SystemdCgroupsManager represents systemd native cgroup manager
	SystemdCgroupsManager = "systemd"

	// killContainerTimeout is the timeout that we wait for the container to
	// be SIGKILLed.
	killContainerTimeout = 2 * time.Minute
)

// Runtime is the generic structure holding both global and specific
// information about the runtime.
type Runtime struct {
	config              *config.Config
	runtimeImplMap      map[string]RuntimeImpl
	runtimeImplMapMutex sync.RWMutex
}

// RuntimeImpl is an interface used by the caller to interact with the
// container runtime. The purpose of this interface being to abstract
// implementations and their associated assumptions regarding the way to
// interact with containers. This will allow for new implementations of
// this interface, especially useful for the case of VM based container
// runtimes. Assumptions based on the fact that a container process runs
// on the host will be limited to the RuntimeOCI implementation.
type RuntimeImpl interface {
	CreateContainer(*Container, string) error
	StartContainer(*Container) error
	ExecContainer(*Container, []string, io.Reader, io.WriteCloser, io.WriteCloser,
		bool, <-chan remotecommand.TerminalSize) error
	ExecSyncContainer(*Container, []string, int64) (*ExecSyncResponse, error)
	UpdateContainer(*Container, *rspec.LinuxResources) error
	StopContainer(context.Context, *Container, int64) error
	DeleteContainer(*Container) error
	UpdateContainerStatus(*Container) error
	PauseContainer(*Container) error
	UnpauseContainer(*Container) error
	ContainerStats(*Container, string) (*ContainerStats, error)
	SignalContainer(*Container, syscall.Signal) error
	AttachContainer(*Container, io.Reader, io.WriteCloser, io.WriteCloser,
		bool, <-chan remotecommand.TerminalSize) error
	PortForwardContainer(*Container, int32, io.ReadWriter) error
	ReopenContainerLog(*Container) error
	WaitContainerStateStopped(context.Context, *Container) error
}

// New creates a new Runtime with options provided
func New(c *config.Config) *Runtime {
	return &Runtime{
		config:         c,
		runtimeImplMap: make(map[string]RuntimeImpl),
	}
}

// Runtimes returns the map of OCI runtimes.
func (r *Runtime) Runtimes() config.Runtimes {
	return r.config.Runtimes
}

// ValidateRuntimeHandler returns an error if the runtime handler string
// provided does not match any valid use case.
func (r *Runtime) ValidateRuntimeHandler(handler string) (*config.RuntimeHandler, error) {
	if handler == "" {
		return nil, fmt.Errorf("empty runtime handler")
	}

	runtimeHandler, ok := r.config.Runtimes[handler]
	if !ok {
		return nil, fmt.Errorf("failed to find runtime handler %s from runtime list %v",
			handler, r.config.Runtimes)
	}
	if runtimeHandler.RuntimePath == "" {
		return nil, fmt.Errorf("empty runtime path for runtime handler %s", handler)
	}

	return runtimeHandler, nil
}

// WaitContainerStateStopped runs a loop polling UpdateStatus(), seeking for
// the container status to be updated to 'stopped'. Either it gets the expected
// status and returns nil, or it reaches the timeout and returns an error.
func (r *Runtime) WaitContainerStateStopped(ctx context.Context, c *Container) (err error) {
	impl, err := r.RuntimeImpl(c)
	if err != nil {
		return err
	}

	// No need to go further and spawn the go routine if the container
	// is already in the expected status.
	if c.State().Status == ContainerStateStopped {
		return nil
	}

	done := make(chan error)
	chControl := make(chan struct{})
	go func() {
		for {
			select {
			case <-chControl:
				return
			default:
				// Check if the container is stopped
				if err := impl.UpdateContainerStatus(c); err != nil {
					done <- err
					close(done)
					return
				}
				if c.State().Status == ContainerStateStopped {
					close(done)
					return
				}
				time.Sleep(100 * time.Millisecond)
			}
		}
	}()
	select {
	case err = <-done:
		break
	case <-ctx.Done():
		close(chControl)
		close(done)
		return ctx.Err()
	case <-time.After(time.Duration(r.config.CtrStopTimeout) * time.Second):
		close(chControl)
		close(done)
		return fmt.Errorf(
			"failed to get container stopped status: %ds timeout reached",
			r.config.CtrStopTimeout,
		)
	}

	if err != nil {
		return fmt.Errorf("failed to get container stopped status: %v", err)
	}

	return nil
}

func (r *Runtime) getRuntimeHandler(handler string) (*config.RuntimeHandler, error) {
	// Define the current runtime handler as the default runtime handler.
	rh := r.config.Runtimes[r.config.DefaultRuntime]

	// Override the current runtime handler with the runtime handler
	// corresponding to the runtime handler key provided with this
	// specific container.
	if handler != "" {
		runtimeHandler, err := r.ValidateRuntimeHandler(handler)
		if err != nil {
			return nil, err
		}

		rh = runtimeHandler
	}

	return rh, nil
}

// PrivelegedRuntimeHandler returns a boolean value configured for the
// runtimeHandler indicating if devices on the host are passed/not passed
// to a container running as privileged.
func (r *Runtime) PrivilegedWithoutHostDevices(handler string) (bool, error) {
	rh, err := r.getRuntimeHandler(handler)
	if err != nil {
		return false, err
	}

	return rh.PrivilegedWithoutHostDevices, nil
}

// ContainerRuntimeType returns the type of runtime configured.
// This is needed when callers need to do specific work for oci vs vm
// containers, like monitor an oci container's conmon.
func (r *Runtime) ContainerRuntimeType(c *Container) (string, error) {
	rh, err := r.getRuntimeHandler(c.runtimeHandler)
	if err != nil {
		return "", err
	}

	return rh.RuntimeType, nil
}

func (r *Runtime) newRuntimeImpl(c *Container) (RuntimeImpl, error) {
	rh, err := r.getRuntimeHandler(c.runtimeHandler)
	if err != nil {
		return nil, err
	}

	if rh.RuntimeType == config.RuntimeTypeVM {
		return newRuntimeVM(rh.RuntimePath), nil
	}

	// If the runtime type is different from "vm", then let's fallback
	// onto the OCI implementation by default.
	return newRuntimeOCI(r, rh), nil
}

// RuntimeImpl returns the runtime implementation for a given container
func (r *Runtime) RuntimeImpl(c *Container) (RuntimeImpl, error) {
	r.runtimeImplMapMutex.RLock()
	impl, ok := r.runtimeImplMap[c.ID()]
	r.runtimeImplMapMutex.RUnlock()
	if !ok {
		return r.newRuntimeImpl(c)
	}

	return impl, nil
}

// CreateContainer creates a container.
func (r *Runtime) CreateContainer(c *Container, cgroupParent string) error {
	// Instantiate a new runtime implementation for this new container
	impl, err := r.newRuntimeImpl(c)
	if err != nil {
		return err
	}

	// Assign this runtime implementation to the current container
	r.runtimeImplMapMutex.Lock()
	r.runtimeImplMap[c.ID()] = impl
	r.runtimeImplMapMutex.Unlock()

	return impl.CreateContainer(c, cgroupParent)
}

// StartContainer starts a container.
func (r *Runtime) StartContainer(c *Container) error {
	impl, err := r.RuntimeImpl(c)
	if err != nil {
		return err
	}

	return impl.StartContainer(c)
}

// ExecContainer prepares a streaming endpoint to execute a command in the container.
func (r *Runtime) ExecContainer(c *Container, cmd []string, stdin io.Reader, stdout, stderr io.WriteCloser, tty bool, resize <-chan remotecommand.TerminalSize) error {
	impl, err := r.RuntimeImpl(c)
	if err != nil {
		return err
	}

	return impl.ExecContainer(c, cmd, stdin, stdout, stderr, tty, resize)
}

// ExecSyncContainer execs a command in a container and returns it's stdout, stderr and return code.
func (r *Runtime) ExecSyncContainer(c *Container, command []string, timeout int64) (*ExecSyncResponse, error) {
	impl, err := r.RuntimeImpl(c)
	if err != nil {
		return nil, err
	}

	return impl.ExecSyncContainer(c, command, timeout)
}

// UpdateContainer updates container resources
func (r *Runtime) UpdateContainer(c *Container, res *rspec.LinuxResources) error {
	impl, err := r.RuntimeImpl(c)
	if err != nil {
		return err
	}

	return impl.UpdateContainer(c, res)
}

// StopContainer stops a container. Timeout is given in seconds.
func (r *Runtime) StopContainer(ctx context.Context, c *Container, timeout int64) error {
	impl, err := r.RuntimeImpl(c)
	if err != nil {
		return err
	}

	return impl.StopContainer(ctx, c, timeout)
}

// DeleteContainer deletes a container.
func (r *Runtime) DeleteContainer(c *Container) error {
	impl, err := r.RuntimeImpl(c)
	if err != nil {
		return err
	}

	defer func() {
		r.runtimeImplMapMutex.Lock()
		delete(r.runtimeImplMap, c.ID())
		r.runtimeImplMapMutex.Unlock()
	}()

	return impl.DeleteContainer(c)
}

// UpdateContainerStatus refreshes the status of the container.
func (r *Runtime) UpdateContainerStatus(c *Container) error {
	impl, err := r.RuntimeImpl(c)
	if err != nil {
		return err
	}

	return impl.UpdateContainerStatus(c)
}

// PauseContainer pauses a container.
func (r *Runtime) PauseContainer(c *Container) error {
	impl, err := r.RuntimeImpl(c)
	if err != nil {
		return err
	}

	return impl.PauseContainer(c)
}

// UnpauseContainer unpauses a container.
func (r *Runtime) UnpauseContainer(c *Container) error {
	impl, err := r.RuntimeImpl(c)
	if err != nil {
		return err
	}

	return impl.UnpauseContainer(c)
}

// ContainerStats provides statistics of a container.
func (r *Runtime) ContainerStats(c *Container, cgroup string) (*ContainerStats, error) {
	impl, err := r.RuntimeImpl(c)
	if err != nil {
		return nil, err
	}

	return impl.ContainerStats(c, cgroup)
}

// SignalContainer sends a signal to a container process.
func (r *Runtime) SignalContainer(c *Container, sig syscall.Signal) error {
	impl, err := r.RuntimeImpl(c)
	if err != nil {
		return err
	}

	return impl.SignalContainer(c, sig)
}

// AttachContainer attaches IO to a running container.
func (r *Runtime) AttachContainer(c *Container, inputStream io.Reader, outputStream, errorStream io.WriteCloser, tty bool, resize <-chan remotecommand.TerminalSize) error {
	impl, err := r.RuntimeImpl(c)
	if err != nil {
		return err
	}

	return impl.AttachContainer(c, inputStream, outputStream, errorStream, tty, resize)
}

// PortForwardContainer forwards the specified port provides statistics of a container.
func (r *Runtime) PortForwardContainer(c *Container, port int32, stream io.ReadWriter) error {
	impl, err := r.RuntimeImpl(c)
	if err != nil {
		return err
	}

	return impl.PortForwardContainer(c, port, stream)
}

// ReopenContainerLog reopens the log file of a container.
func (r *Runtime) ReopenContainerLog(c *Container) error {
	impl, err := r.RuntimeImpl(c)
	if err != nil {
		return err
	}

	return impl.ReopenContainerLog(c)
}

// ExecSyncResponse is returned from ExecSync.
type ExecSyncResponse struct {
	Stdout   []byte
	Stderr   []byte
	ExitCode int32
}

// ExecSyncError wraps command's streams, exit code and error on ExecSync error.
type ExecSyncError struct {
	Stdout   bytes.Buffer
	Stderr   bytes.Buffer
	ExitCode int32
	Err      error
}

func (e *ExecSyncError) Error() string {
	return fmt.Sprintf("command error: %+v, stdout: %s, stderr: %s, exit code %d", e.Err, e.Stdout.Bytes(), e.Stderr.Bytes(), e.ExitCode)
}
<|endoftext|>


<commit_before>// Copyright 2015 CoreOS, Inc.
//
// 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 oem

import (
	"fmt"

	"github.com/coreos/ignition/internal/log"
	"github.com/coreos/ignition/internal/providers"
	"github.com/coreos/ignition/internal/providers/azure"
	"github.com/coreos/ignition/internal/providers/cloudstack"
	"github.com/coreos/ignition/internal/providers/digitalocean"
	"github.com/coreos/ignition/internal/providers/ec2"
	"github.com/coreos/ignition/internal/providers/file"
	"github.com/coreos/ignition/internal/providers/gce"
	"github.com/coreos/ignition/internal/providers/noop"
	"github.com/coreos/ignition/internal/providers/openstack"
	"github.com/coreos/ignition/internal/providers/packet"
	"github.com/coreos/ignition/internal/providers/qemu"
	"github.com/coreos/ignition/internal/providers/virtualbox"
	"github.com/coreos/ignition/internal/providers/vmware"
	"github.com/coreos/ignition/internal/registry"
	"github.com/coreos/ignition/internal/resource"
)

// Config represents a set of options that map to a particular OEM.
type Config struct {
	name       string
	fetch      providers.FuncFetchConfig
	newFetcher providers.FuncNewFetcher
	status     providers.FuncPostStatus
}

func (c Config) Name() string {
	return c.name
}

func (c Config) FetchFunc() providers.FuncFetchConfig {
	return c.fetch
}

func (c Config) NewFetcherFunc() providers.FuncNewFetcher {
	if c.newFetcher != nil {
		return c.newFetcher
	}
	return func(l *log.Logger) (resource.Fetcher, error) {
		return resource.Fetcher{
			Logger: l,
		}, nil
	}
}

// Status takes a Fetcher and the error from Run (from engine)
func (c Config) Status(stageName string, f resource.Fetcher, statusErr error) error {
	if c.status != nil {
		return c.status(stageName, f, statusErr)
	}
	return nil
}

var configs = registry.Create("oem configs")

func init() {
	configs.Register(Config{
		name:  "azure",
		fetch: azure.FetchConfig,
	})
	configs.Register(Config{
		name:  "cloudsigma",
		fetch: noop.FetchConfig,
	})
	configs.Register(Config{
		name:  "cloudstack",
		fetch: cloudstack.FetchConfig,
	})
	configs.Register(Config{
		name:  "digitalocean",
		fetch: digitalocean.FetchConfig,
	})
	configs.Register(Config{
		name:  "brightbox",
		fetch: openstack.FetchConfig,
	})
	configs.Register(Config{
		name:  "openstack",
		fetch: openstack.FetchConfig,
	})
	configs.Register(Config{
		name:       "ec2",
		fetch:      ec2.FetchConfig,
		newFetcher: ec2.NewFetcher,
	})
	configs.Register(Config{
		name:  "exoscale",
		fetch: noop.FetchConfig,
	})
	configs.Register(Config{
		name:  "gce",
		fetch: gce.FetchConfig,
	})
	configs.Register(Config{
		name:  "hyperv",
		fetch: noop.FetchConfig,
	})
	configs.Register(Config{
		name:  "niftycloud",
		fetch: noop.FetchConfig,
	})
	configs.Register(Config{
		name:   "packet",
		fetch:  packet.FetchConfig,
		status: packet.PostStatus,
	})
	configs.Register(Config{
		name:  "pxe",
		fetch: noop.FetchConfig,
	})
	configs.Register(Config{
		name:  "rackspace",
		fetch: noop.FetchConfig,
	})
	configs.Register(Config{
		name:  "rackspace-onmetal",
		fetch: noop.FetchConfig,
	})
	configs.Register(Config{
		name:  "vagrant",
		fetch: noop.FetchConfig,
	})
	configs.Register(Config{
		name:  "vagrant-virtualbox",
		fetch: virtualbox.FetchConfig,
	})
	configs.Register(Config{
		name:  "virtualbox",
		fetch: virtualbox.FetchConfig,
	})
	configs.Register(Config{
		name:  "vmware",
		fetch: vmware.FetchConfig,
	})
	configs.Register(Config{
		name:  "interoute",
		fetch: noop.FetchConfig,
	})
	configs.Register(Config{
		name:  "qemu",
		fetch: qemu.FetchConfig,
	})
	configs.Register(Config{
		name:  "file",
		fetch: file.FetchConfig,
	})
}

func Get(name string) (config Config, ok bool) {
	config, ok = configs.Get(name).(Config)
	return
}

func MustGet(name string) Config {
	if config, ok := Get(name); ok {
		return config
	} else {
		panic(fmt.Sprintf("invalid OEM name %q provided", name))
	}
}

func Names() (names []string) {
	return configs.Names()
}
<commit_msg>internal/oem: drop noop OEMs<commit_after>// Copyright 2015 CoreOS, Inc.
//
// 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 oem

import (
	"fmt"

	"github.com/coreos/ignition/internal/log"
	"github.com/coreos/ignition/internal/providers"
	"github.com/coreos/ignition/internal/providers/azure"
	"github.com/coreos/ignition/internal/providers/cloudstack"
	"github.com/coreos/ignition/internal/providers/digitalocean"
	"github.com/coreos/ignition/internal/providers/ec2"
	"github.com/coreos/ignition/internal/providers/file"
	"github.com/coreos/ignition/internal/providers/gce"
	"github.com/coreos/ignition/internal/providers/noop"
	"github.com/coreos/ignition/internal/providers/openstack"
	"github.com/coreos/ignition/internal/providers/packet"
	"github.com/coreos/ignition/internal/providers/qemu"
	"github.com/coreos/ignition/internal/providers/virtualbox"
	"github.com/coreos/ignition/internal/providers/vmware"
	"github.com/coreos/ignition/internal/registry"
	"github.com/coreos/ignition/internal/resource"
)

// Config represents a set of options that map to a particular OEM.
type Config struct {
	name       string
	fetch      providers.FuncFetchConfig
	newFetcher providers.FuncNewFetcher
	status     providers.FuncPostStatus
}

func (c Config) Name() string {
	return c.name
}

func (c Config) FetchFunc() providers.FuncFetchConfig {
	return c.fetch
}

func (c Config) NewFetcherFunc() providers.FuncNewFetcher {
	if c.newFetcher != nil {
		return c.newFetcher
	}
	return func(l *log.Logger) (resource.Fetcher, error) {
		return resource.Fetcher{
			Logger: l,
		}, nil
	}
}

// Status takes a Fetcher and the error from Run (from engine)
func (c Config) Status(stageName string, f resource.Fetcher, statusErr error) error {
	if c.status != nil {
		return c.status(stageName, f, statusErr)
	}
	return nil
}

var configs = registry.Create("oem configs")

func init() {
	configs.Register(Config{
		name:  "azure",
		fetch: azure.FetchConfig,
	})
	configs.Register(Config{
		name:  "cloudstack",
		fetch: cloudstack.FetchConfig,
	})
	configs.Register(Config{
		name:  "digitalocean",
		fetch: digitalocean.FetchConfig,
	})
	configs.Register(Config{
		name:  "brightbox",
		fetch: openstack.FetchConfig,
	})
	configs.Register(Config{
		name:  "openstack",
		fetch: openstack.FetchConfig,
	})
	configs.Register(Config{
		name:       "ec2",
		fetch:      ec2.FetchConfig,
		newFetcher: ec2.NewFetcher,
	})
	configs.Register(Config{
		name:  "gce",
		fetch: gce.FetchConfig,
	})
	configs.Register(Config{
		name:   "packet",
		fetch:  packet.FetchConfig,
		status: packet.PostStatus,
	})
	configs.Register(Config{
		name:  "pxe",
		fetch: noop.FetchConfig,
	})
	configs.Register(Config{
		name:  "vagrant-virtualbox",
		fetch: virtualbox.FetchConfig,
	})
	configs.Register(Config{
		name:  "virtualbox",
		fetch: virtualbox.FetchConfig,
	})
	configs.Register(Config{
		name:  "vmware",
		fetch: vmware.FetchConfig,
	})
	configs.Register(Config{
		name:  "qemu",
		fetch: qemu.FetchConfig,
	})
	configs.Register(Config{
		name:  "file",
		fetch: file.FetchConfig,
	})
}

func Get(name string) (config Config, ok bool) {
	config, ok = configs.Get(name).(Config)
	return
}

func MustGet(name string) Config {
	if config, ok := Get(name); ok {
		return config
	} else {
		panic(fmt.Sprintf("invalid OEM name %q provided", name))
	}
}

func Names() (names []string) {
	return configs.Names()
}
<|endoftext|>


<commit_before>package internal

import "unsafe"

// JoinStrings join slice strings with ""
func JoinStrings(strs ...string) string {
	ln := 0
	for i := 0; i < len(strs); i++ {
		ln += len(strs[i])
	}
	bts := make([]byte, ln)
	ln = 0
	for _, str := range strs {
		ln += copy(bts[ln:], str)
	}

	return Bytes2str(bts)
}

// Str2bytes trans string to bytes
func Str2bytes(s string) []byte {
	x := (*[2]uintptr)(unsafe.Pointer(&s))
	h := [3]uintptr{x[0], x[1], x[1]}
	return *(*[]byte)(unsafe.Pointer(&h))
}

// Bytes2str trans bytes to string
func Bytes2str(b []byte) string {
	return *(*string)(unsafe.Pointer(&b))
}
<commit_msg>add join bytes<commit_after>package internal

import "unsafe"

// JoinStrings concatenate slice strings with ""
func JoinStrings(strs ...string) string {
	ln := 0
	for i := 0; i < len(strs); i++ {
		ln += len(strs[i])
	}
	bts := make([]byte, ln)
	ln = 0
	for _, str := range strs {
		ln += copy(bts[ln:], str)
	}

	return Bytes2str(bts)
}

// Str2bytes trans string to bytes
func Str2bytes(s string) []byte {
	x := (*[2]uintptr)(unsafe.Pointer(&s))
	h := [3]uintptr{x[0], x[1], x[1]}
	return *(*[]byte)(unsafe.Pointer(&h))
}

// Bytes2str trans bytes to string
func Bytes2str(b []byte) string {
	return *(*string)(unsafe.Pointer(&b))
}

// JoinBytes concatenate all bytes
func JoinBytes(bts ...[]byte) []byte {
	ln := 0
	for i := 0; i < len(bts); i++ {
		ln += len(bts[i])
	}
	ret := make([]byte, ln)
	ln = 0
	for _, b := range bts {
		ln += copy(ret[ln:], b)
	}

	return ret
}
<|endoftext|>


<commit_before>package webhook

type IntegrationContainer struct {
	Integration         *Integration                  `json:"integration"`
	ChannelIntegrations []ChannelIntegrationContainer `json:"channelIntegrations"`
}

func NewIntegrationContainer() *IntegrationContainer {
	return &IntegrationContainer{
		ChannelIntegrations: make([]ChannelIntegrationContainer, 0),
	}
}

func (ic *IntegrationContainer) Push(ci ChannelIntegrationContainer) {
	ic.ChannelIntegrations = append(ic.ChannelIntegrations, ci)
}

type IntegrationContainers []IntegrationContainer

func NewIntegrationContainers() *IntegrationContainers {
	return &IntegrationContainers{}
}

func (ics *IntegrationContainers) Push(i IntegrationContainer) {
	*ics = append(*ics, i)
}

func (ics *IntegrationContainers) Populate(groupName string) error {
	// fetch channel containers with given group name
	ci := NewChannelIntegration()
	channelIntegrations, err := ci.ByGroupName(groupName)
	if err != nil {
		return err
	}

	// group channel integrations by integration id
	containers := make(map[int64]*IntegrationContainer)
	for _, channelIntegration := range channelIntegrations {
		integration, ok := containers[channelIntegration.IntegrationId]
		if !ok {
			integration = NewIntegrationContainer()
			containers[channelIntegration.IntegrationId] = integration
		}
		cic := NewChannelIntegrationContainer(&channelIntegration)
		if err := cic.Populate(); err != nil {
			return err
		}

		integration.Push(*cic)
	}

	// fetch related integrations
	integrationIds := make([]int64, 0)
	for k, _ := range containers {
		integrationIds = append(integrationIds, k)
	}

	ints, err := NewIntegration().FetchByIds(integrationIds)
	if err != nil {
		return err
	}

	for _, integration := range ints {
		ic := containers[integration.Id]
		ic.Integration = &integration
		ics.Push(*ic)
	}

	return nil
}
<commit_msg>integration: fix configured integrations are wrongly listed bug<commit_after>package webhook

type IntegrationContainer struct {
	Integration         *Integration                  `json:"integration"`
	ChannelIntegrations []ChannelIntegrationContainer `json:"channelIntegrations"`
}

func NewIntegrationContainer() *IntegrationContainer {
	return &IntegrationContainer{
		ChannelIntegrations: make([]ChannelIntegrationContainer, 0),
	}
}

func (ic *IntegrationContainer) Push(ci ChannelIntegrationContainer) {
	ic.ChannelIntegrations = append(ic.ChannelIntegrations, ci)
}

type IntegrationContainers []IntegrationContainer

func NewIntegrationContainers() *IntegrationContainers {
	return &IntegrationContainers{}
}

func (ics *IntegrationContainers) Push(i IntegrationContainer) {
	*ics = append(*ics, i)
}

func (ics *IntegrationContainers) Populate(groupName string) error {
	// fetch channel containers with given group name
	ci := NewChannelIntegration()
	channelIntegrations, err := ci.ByGroupName(groupName)
	if err != nil {
		return err
	}

	// group channel integrations by integration id
	containers := make(map[int64]*IntegrationContainer)
	for k := range channelIntegrations {
		channelIntegration := channelIntegrations[k]
		cic := NewChannelIntegrationContainer(&channelIntegration)
		if err := cic.Populate(); err != nil {
			return err
		}

		integration, ok := containers[channelIntegration.IntegrationId]
		if !ok {
			integration = NewIntegrationContainer()
			containers[channelIntegration.IntegrationId] = integration
		}
		integration.Push(*cic)
	}

	// fetch related integrations
	integrationIds := make([]int64, 0)
	for k, _ := range containers {
		integrationIds = append(integrationIds, k)
	}

	ints, err := NewIntegration().FetchByIds(integrationIds)
	if err != nil {
		return err
	}

	for k := range ints {
		integration := ints[k]
		ic := containers[integration.Id]
		ic.Integration = &integration
		ics.Push(*ic)
	}

	return nil
}
<|endoftext|>