<commit_before>// +build linux,cgo

package native

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"

	"github.com/docker/docker/daemon/execdriver"
	"github.com/docker/docker/daemon/execdriver/native/configuration"
	"github.com/docker/docker/daemon/execdriver/native/template"
	"github.com/docker/libcontainer"
	"github.com/docker/libcontainer/apparmor"
	"github.com/docker/libcontainer/devices"
	"github.com/docker/libcontainer/mount"
	"github.com/docker/libcontainer/security/capabilities"
)

// createContainer populates and configures the container type with the
// data provided by the execdriver.Command
func (d *driver) createContainer(c *execdriver.Command) (*libcontainer.Config, error) {
	container := template.New()

	container.Hostname = getEnv("HOSTNAME", c.ProcessConfig.Env)
	container.Tty = c.ProcessConfig.Tty
	container.User = c.ProcessConfig.User
	container.WorkingDir = c.WorkingDir
	container.Env = c.ProcessConfig.Env
	container.Cgroups.Name = c.ID
	container.Cgroups.AllowedDevices = c.AllowedDevices
	container.MountConfig.DeviceNodes = c.AutoCreatedDevices

	// check to see if we are running in ramdisk to disable pivot root
	container.MountConfig.NoPivotRoot = os.Getenv("DOCKER_RAMDISK") != ""
	container.RestrictSys = true

	if err := d.createNetwork(container, c); err != nil {
		return nil, err
	}

	if c.ProcessConfig.Privileged {
		if err := d.setPrivileged(container); err != nil {
			return nil, err
		}
	} else {
		if err := d.setCapabilities(container, c); err != nil {
			return nil, err
		}
	}

	if err := d.setupCgroups(container, c); err != nil {
		return nil, err
	}

	if err := d.setupMounts(container, c); err != nil {
		return nil, err
	}

	if err := d.setupLabels(container, c); err != nil {
		return nil, err
	}

	cmds := make(map[string]*exec.Cmd)
	d.Lock()
	for k, v := range d.activeContainers {
		cmds[k] = v.cmd
	}
	d.Unlock()

	if err := configuration.ParseConfiguration(container, cmds, c.Config["native"]); err != nil {
		return nil, err
	}

	return container, nil
}

func (d *driver) createNetwork(container *libcontainer.Config, c *execdriver.Command) error {
	if c.Network.HostNetworking {
		container.Namespaces["NEWNET"] = false
		return nil
	}

	container.Networks = []*libcontainer.Network{
		{
			Mtu:     c.Network.Mtu,
			Address: fmt.Sprintf("%s/%d", "127.0.0.1", 0),
			Gateway: "localhost",
			Type:    "loopback",
		},
	}

	if c.Network.Interface != nil {
		vethNetwork := libcontainer.Network{
			Mtu:        c.Network.Mtu,
			Address:    fmt.Sprintf("%s/%d", c.Network.Interface.IPAddress, c.Network.Interface.IPPrefixLen),
			Gateway:    c.Network.Interface.Gateway,
			Type:       "veth",
			Bridge:     c.Network.Interface.Bridge,
			VethPrefix: "veth",
		}
		container.Networks = append(container.Networks, &vethNetwork)
	}

	if c.Network.ContainerID != "" {
		d.Lock()
		active := d.activeContainers[c.Network.ContainerID]
		d.Unlock()

		if active == nil || active.cmd.Process == nil {
			return fmt.Errorf("%s is not a valid running container to join", c.Network.ContainerID)
		}
		cmd := active.cmd

		nspath := filepath.Join("/proc", fmt.Sprint(cmd.Process.Pid), "ns", "net")
		container.Networks = append(container.Networks, &libcontainer.Network{
			Type:   "netns",
			NsPath: nspath,
		})
	}

	return nil
}

func (d *driver) setPrivileged(container *libcontainer.Config) (err error) {
	container.Capabilities = capabilities.GetAllCapabilities()
	container.Cgroups.AllowAllDevices = true

	hostDeviceNodes, err := devices.GetHostDeviceNodes()
	if err != nil {
		return err
	}
	container.MountConfig.DeviceNodes = hostDeviceNodes

	container.RestrictSys = false

	if apparmor.IsEnabled() {
		container.AppArmorProfile = "unconfined"
	}

	return nil
}

func (d *driver) setCapabilities(container *libcontainer.Config, c *execdriver.Command) (err error) {
	container.Capabilities, err = execdriver.TweakCapabilities(container.Capabilities, c.CapAdd, c.CapDrop)
	return err
}

func (d *driver) setupCgroups(container *libcontainer.Config, c *execdriver.Command) error {
	if c.Resources != nil {
		container.Cgroups.CpuShares = c.Resources.CpuShares
		container.Cgroups.Memory = c.Resources.Memory
		container.Cgroups.MemoryReservation = c.Resources.Memory
		container.Cgroups.MemorySwap = c.Resources.MemorySwap
		container.Cgroups.CpusetCpus = c.Resources.Cpuset
	}

	return nil
}

func (d *driver) setupMounts(container *libcontainer.Config, c *execdriver.Command) error {
	for _, m := range c.Mounts {
		container.MountConfig.Mounts = append(container.MountConfig.Mounts, mount.Mount{
			Type:        "bind",
			Source:      m.Source,
			Destination: m.Destination,
			Writable:    m.Writable,
			Private:     m.Private,
		})
	}

	return nil
}

func (d *driver) setupLabels(container *libcontainer.Config, c *execdriver.Command) error {
	container.ProcessLabel = c.Config["process_label"][0]
	container.MountConfig.MountLabel = c.Config["mount_label"][0]

	return nil
}
<commit_msg>Update mount struct with reference<commit_after>// +build linux,cgo

package native

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"

	"github.com/docker/docker/daemon/execdriver"
	"github.com/docker/docker/daemon/execdriver/native/configuration"
	"github.com/docker/docker/daemon/execdriver/native/template"
	"github.com/docker/libcontainer"
	"github.com/docker/libcontainer/apparmor"
	"github.com/docker/libcontainer/devices"
	"github.com/docker/libcontainer/mount"
	"github.com/docker/libcontainer/security/capabilities"
)

// createContainer populates and configures the container type with the
// data provided by the execdriver.Command
func (d *driver) createContainer(c *execdriver.Command) (*libcontainer.Config, error) {
	container := template.New()

	container.Hostname = getEnv("HOSTNAME", c.ProcessConfig.Env)
	container.Tty = c.ProcessConfig.Tty
	container.User = c.ProcessConfig.User
	container.WorkingDir = c.WorkingDir
	container.Env = c.ProcessConfig.Env
	container.Cgroups.Name = c.ID
	container.Cgroups.AllowedDevices = c.AllowedDevices
	container.MountConfig.DeviceNodes = c.AutoCreatedDevices

	// check to see if we are running in ramdisk to disable pivot root
	container.MountConfig.NoPivotRoot = os.Getenv("DOCKER_RAMDISK") != ""
	container.RestrictSys = true

	if err := d.createNetwork(container, c); err != nil {
		return nil, err
	}

	if c.ProcessConfig.Privileged {
		if err := d.setPrivileged(container); err != nil {
			return nil, err
		}
	} else {
		if err := d.setCapabilities(container, c); err != nil {
			return nil, err
		}
	}

	if err := d.setupCgroups(container, c); err != nil {
		return nil, err
	}

	if err := d.setupMounts(container, c); err != nil {
		return nil, err
	}

	if err := d.setupLabels(container, c); err != nil {
		return nil, err
	}

	cmds := make(map[string]*exec.Cmd)
	d.Lock()
	for k, v := range d.activeContainers {
		cmds[k] = v.cmd
	}
	d.Unlock()

	if err := configuration.ParseConfiguration(container, cmds, c.Config["native"]); err != nil {
		return nil, err
	}

	return container, nil
}

func (d *driver) createNetwork(container *libcontainer.Config, c *execdriver.Command) error {
	if c.Network.HostNetworking {
		container.Namespaces["NEWNET"] = false
		return nil
	}

	container.Networks = []*libcontainer.Network{
		{
			Mtu:     c.Network.Mtu,
			Address: fmt.Sprintf("%s/%d", "127.0.0.1", 0),
			Gateway: "localhost",
			Type:    "loopback",
		},
	}

	if c.Network.Interface != nil {
		vethNetwork := libcontainer.Network{
			Mtu:        c.Network.Mtu,
			Address:    fmt.Sprintf("%s/%d", c.Network.Interface.IPAddress, c.Network.Interface.IPPrefixLen),
			Gateway:    c.Network.Interface.Gateway,
			Type:       "veth",
			Bridge:     c.Network.Interface.Bridge,
			VethPrefix: "veth",
		}
		container.Networks = append(container.Networks, &vethNetwork)
	}

	if c.Network.ContainerID != "" {
		d.Lock()
		active := d.activeContainers[c.Network.ContainerID]
		d.Unlock()

		if active == nil || active.cmd.Process == nil {
			return fmt.Errorf("%s is not a valid running container to join", c.Network.ContainerID)
		}
		cmd := active.cmd

		nspath := filepath.Join("/proc", fmt.Sprint(cmd.Process.Pid), "ns", "net")
		container.Networks = append(container.Networks, &libcontainer.Network{
			Type:   "netns",
			NsPath: nspath,
		})
	}

	return nil
}

func (d *driver) setPrivileged(container *libcontainer.Config) (err error) {
	container.Capabilities = capabilities.GetAllCapabilities()
	container.Cgroups.AllowAllDevices = true

	hostDeviceNodes, err := devices.GetHostDeviceNodes()
	if err != nil {
		return err
	}
	container.MountConfig.DeviceNodes = hostDeviceNodes

	container.RestrictSys = false

	if apparmor.IsEnabled() {
		container.AppArmorProfile = "unconfined"
	}

	return nil
}

func (d *driver) setCapabilities(container *libcontainer.Config, c *execdriver.Command) (err error) {
	container.Capabilities, err = execdriver.TweakCapabilities(container.Capabilities, c.CapAdd, c.CapDrop)
	return err
}

func (d *driver) setupCgroups(container *libcontainer.Config, c *execdriver.Command) error {
	if c.Resources != nil {
		container.Cgroups.CpuShares = c.Resources.CpuShares
		container.Cgroups.Memory = c.Resources.Memory
		container.Cgroups.MemoryReservation = c.Resources.Memory
		container.Cgroups.MemorySwap = c.Resources.MemorySwap
		container.Cgroups.CpusetCpus = c.Resources.Cpuset
	}

	return nil
}

func (d *driver) setupMounts(container *libcontainer.Config, c *execdriver.Command) error {
	for _, m := range c.Mounts {
		container.MountConfig.Mounts = append(container.MountConfig.Mounts, &mount.Mount{
			Type:        "bind",
			Source:      m.Source,
			Destination: m.Destination,
			Writable:    m.Writable,
			Private:     m.Private,
		})
	}

	return nil
}

func (d *driver) setupLabels(container *libcontainer.Config, c *execdriver.Command) error {
	container.ProcessLabel = c.Config["process_label"][0]
	container.MountConfig.MountLabel = c.Config["mount_label"][0]

	return nil
}
<|endoftext|>


<commit_before>package action

import (
	"bytes"
	"crypto/sha1"
	"encoding/base64"
	"encoding/hex"
	"errors"
	"github.com/cloudfoundry/bosh-utils/blobstore"
)

type UploadBlobAction struct {
	blobManager blobstore.BlobManagerInterface
}

func NewUploadBlobAction(blobManager blobstore.BlobManagerInterface) UploadBlobAction {
	return UploadBlobAction{blobManager: blobManager}
}

func (a UploadBlobAction) IsAsynchronous() bool {
	return true
}

func (a UploadBlobAction) IsPersistent() bool {
	return false
}

func (a UploadBlobAction) IsLoggable() bool {
	return false
}

func (a UploadBlobAction) Run(base64Payload, payloadSha1, blobID string) (string, error) {

	decodedPayload, err := base64.StdEncoding.DecodeString(base64Payload)
	if err != nil {
		return blobID, err
	}

	if err = a.validatePayload(decodedPayload, payloadSha1); err != nil {
		return blobID, err
	}

	reader := bytes.NewReader(decodedPayload)

	err = a.blobManager.Write(blobID, reader)

	return blobID, err
}

func (a UploadBlobAction) validatePayload(payload []byte, payloadSha1 string) error {

	h := sha1.New()
	h.Write(payload)
	computedShaHex := h.Sum(nil)

	computedHash := hex.EncodeToString(computedShaHex)

	if computedHash != payloadSha1 {
		return errors.New("Payload corrupted. SHA1 mismatch. Expected " + payloadSha1 + " but received " + computedHash)
	}

	return nil
}

func (a UploadBlobAction) Resume() (interface{}, error) {
	return nil, errors.New("not supported")
}

func (a UploadBlobAction) Cancel() error {
	return errors.New("not supported")
}
<commit_msg>Reformat error message creation<commit_after>package action

import (
	"bytes"
	"crypto/sha1"
	"encoding/base64"
	"encoding/hex"
	"errors"
	"github.com/cloudfoundry/bosh-utils/blobstore"
	"fmt"
)

type UploadBlobAction struct {
	blobManager blobstore.BlobManagerInterface
}

func NewUploadBlobAction(blobManager blobstore.BlobManagerInterface) UploadBlobAction {
	return UploadBlobAction{blobManager: blobManager}
}

func (a UploadBlobAction) IsAsynchronous() bool {
	return true
}

func (a UploadBlobAction) IsPersistent() bool {
	return false
}

func (a UploadBlobAction) IsLoggable() bool {
	return false
}

func (a UploadBlobAction) Run(base64Payload, payloadSha1, blobID string) (string, error) {

	decodedPayload, err := base64.StdEncoding.DecodeString(base64Payload)
	if err != nil {
		return blobID, err
	}

	if err = a.validatePayload(decodedPayload, payloadSha1); err != nil {
		return blobID, err
	}

	reader := bytes.NewReader(decodedPayload)

	err = a.blobManager.Write(blobID, reader)

	return blobID, err
}

func (a UploadBlobAction) validatePayload(payload []byte, payloadSha1 string) error {

	h := sha1.New()
	h.Write(payload)
	computedShaHex := h.Sum(nil)

	computedHash := hex.EncodeToString(computedShaHex)

	if computedHash != payloadSha1 {
		return fmt.Errorf("Payload corrupted. SHA1 mismatch. Expected %s but received %s", payloadSha1, computedHash)
	}

	return nil
}

func (a UploadBlobAction) Resume() (interface{}, error) {
	return nil, errors.New("not supported")
}

func (a UploadBlobAction) Cancel() error {
	return errors.New("not supported")
}
<|endoftext|>


<commit_before>// +build linux

// Copyright Amazon.com Inc. or its affiliates. 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. A copy of the
// License is located at
//
//	httpaws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file is distributed
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the License for the specific language governing
// permissions and limitations under the License.

package config

func parseGMSACapability() bool {
	return false
}

func parseFSxWindowsFileServerCapability() bool {
	return false
}
// GetOperatingSystemFamily() returns "linux" as operating system family for linux based ecs instances
func GetOperatingSystemFamily() string {
	return OSType
}
<commit_msg>Changes to advertise OSType while registering the container instance with cluster<commit_after>// +build linux

// Copyright Amazon.com Inc. or its affiliates. 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. A copy of the
// License is located at
//
//	httpaws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file is distributed
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the License for the specific language governing
// permissions and limitations under the License.

package config

func parseGMSACapability() bool {
	return false
}

func parseFSxWindowsFileServerCapability() bool {
	return false
}

// GetOperatingSystemFamily() returns "linux" as operating system family for linux based ecs instances
func GetOperatingSystemFamily() string {
	return OSType
}
<|endoftext|>


<commit_before>package api

import (
	"context"

	log "github.com/sirupsen/logrus"

	"github.com/bytom/account"
	"github.com/bytom/common"
	"github.com/bytom/consensus"
	"github.com/bytom/crypto/ed25519/chainkd"
	"github.com/bytom/protocol/vm/vmutil"
)

// POST /create-account
func (a *API) createAccount(ctx context.Context, ins struct {
	RootXPubs []chainkd.XPub `json:"root_xpubs"`
	Quorum    int            `json:"quorum"`
	Alias     string         `json:"alias"`
}) Response {
	acc, err := a.wallet.AccountMgr.Create(ctx, ins.RootXPubs, ins.Quorum, ins.Alias)
	if err != nil {
		return NewErrorResponse(err)
	}

	annotatedAccount := account.Annotated(acc)
	log.WithField("account ID", annotatedAccount.ID).Info("Created account")

	return NewSuccessResponse(annotatedAccount)
}

// AccountInfo
type AccountInfo struct {
	Info string `json:"account_info"`
}

// POST /delete-account
func (a *API) deleteAccount(ctx context.Context, in AccountInfo) Response {
	if err := a.wallet.AccountMgr.DeleteAccount(in.Info); err != nil {
		return NewErrorResponse(err)
	}
	return NewSuccessResponse(nil)
}

type validateAddressResp struct {
	Valid   bool `json:"valid"`
	IsLocal bool `json:"is_local"`
}

// POST /validate-address
func (a *API) validateAddress(ctx context.Context, ins struct {
	Address string `json:"address"`
}) Response {
	resp := &validateAddressResp{
		Valid:   false,
		IsLocal: false,
	}
	address, err := common.DecodeAddress(ins.Address, &consensus.ActiveNetParams)
	if err != nil {
		return NewSuccessResponse(resp)
	}

	redeemContract := address.ScriptAddress()
	program := []byte{}
	switch address.(type) {
	case *common.AddressWitnessPubKeyHash:
		program, err = vmutil.P2WPKHProgram(redeemContract)
	case *common.AddressWitnessScriptHash:
		program, err = vmutil.P2WSHProgram(redeemContract)
	default:
		return NewSuccessResponse(resp)
	}
	if err != nil {
		return NewSuccessResponse(resp)
	}

	resp.Valid = true
	resp.IsLocal = a.wallet.AccountMgr.IsLocalControlProgram(program)
	return NewSuccessResponse(resp)
}

type addressResp struct {
	AccountAlias string `json:"account_alias"`
	AccountID    string `json:"account_id"`
	Address      string `json:"address"`
	Change       bool   `json:"change"`
}

func (a *API) listAddresses(ctx context.Context, ins struct {
	AccountID    string `json:"account_id"`
	AccountAlias string `json:"account_alias"`
}) Response {
	accountID := ins.AccountID
	var target *account.Account
	if ins.AccountAlias != "" {
		acc, err := a.wallet.AccountMgr.FindByAlias(ctx, ins.AccountAlias)
		if err != nil {
			return NewErrorResponse(err)
		}
		target = acc
	} else {
		acc, err := a.wallet.AccountMgr.FindByID(ctx, accountID)
		if err != nil {
			return NewErrorResponse(err)
		}
		target = acc
	}

	cps, err := a.wallet.AccountMgr.ListControlProgram()
	if err != nil {
		return NewErrorResponse(err)
	}

	addresses := []*addressResp{}
	for _, cp := range cps {
		if cp.Address == "" || cp.AccountID != target.ID {
			continue
		}
		addresses = append(addresses, &addressResp{
			AccountAlias: target.Alias,
			AccountID:    cp.AccountID,
			Address:      cp.Address,
			Change:       cp.Change,
		})
	}
	return NewSuccessResponse(addresses)
}
<commit_msg>list-addresses sort addressResp by create index<commit_after>package api

import (
	"context"
	"sort"

	log "github.com/sirupsen/logrus"

	"github.com/bytom/account"
	"github.com/bytom/common"
	"github.com/bytom/consensus"
	"github.com/bytom/crypto/ed25519/chainkd"
	"github.com/bytom/protocol/vm/vmutil"
)

// POST /create-account
func (a *API) createAccount(ctx context.Context, ins struct {
	RootXPubs []chainkd.XPub `json:"root_xpubs"`
	Quorum    int            `json:"quorum"`
	Alias     string         `json:"alias"`
}) Response {
	acc, err := a.wallet.AccountMgr.Create(ctx, ins.RootXPubs, ins.Quorum, ins.Alias)
	if err != nil {
		return NewErrorResponse(err)
	}

	annotatedAccount := account.Annotated(acc)
	log.WithField("account ID", annotatedAccount.ID).Info("Created account")

	return NewSuccessResponse(annotatedAccount)
}

// AccountInfo is request struct for deleteAccount
type AccountInfo struct {
	Info string `json:"account_info"`
}

// POST /delete-account
func (a *API) deleteAccount(ctx context.Context, in AccountInfo) Response {
	if err := a.wallet.AccountMgr.DeleteAccount(in.Info); err != nil {
		return NewErrorResponse(err)
	}
	return NewSuccessResponse(nil)
}

type validateAddressResp struct {
	Valid   bool `json:"valid"`
	IsLocal bool `json:"is_local"`
}

// POST /validate-address
func (a *API) validateAddress(ctx context.Context, ins struct {
	Address string `json:"address"`
}) Response {
	resp := &validateAddressResp{
		Valid:   false,
		IsLocal: false,
	}
	address, err := common.DecodeAddress(ins.Address, &consensus.ActiveNetParams)
	if err != nil {
		return NewSuccessResponse(resp)
	}

	redeemContract := address.ScriptAddress()
	program := []byte{}
	switch address.(type) {
	case *common.AddressWitnessPubKeyHash:
		program, err = vmutil.P2WPKHProgram(redeemContract)
	case *common.AddressWitnessScriptHash:
		program, err = vmutil.P2WSHProgram(redeemContract)
	default:
		return NewSuccessResponse(resp)
	}
	if err != nil {
		return NewSuccessResponse(resp)
	}

	resp.Valid = true
	resp.IsLocal = a.wallet.AccountMgr.IsLocalControlProgram(program)
	return NewSuccessResponse(resp)
}

type addressResp struct {
	AccountAlias string `json:"account_alias"`
	AccountID    string `json:"account_id"`
	Address      string `json:"address"`
	Change       bool   `json:"change"`
}

type addressRespIndex struct {
	KeyIndex    uint64
	AddressResp addressResp
}

// SortByIndex implements sort.Interface for addressRespIndex slices
type SortByIndex []addressRespIndex

func (a SortByIndex) Len() int           { return len(a) }
func (a SortByIndex) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a SortByIndex) Less(i, j int) bool { return a[i].KeyIndex < a[j].KeyIndex }

func (a *API) listAddresses(ctx context.Context, ins struct {
	AccountID    string `json:"account_id"`
	AccountAlias string `json:"account_alias"`
}) Response {
	accountID := ins.AccountID
	var target *account.Account
	if ins.AccountAlias != "" {
		acc, err := a.wallet.AccountMgr.FindByAlias(ctx, ins.AccountAlias)
		if err != nil {
			return NewErrorResponse(err)
		}
		target = acc
	} else {
		acc, err := a.wallet.AccountMgr.FindByID(ctx, accountID)
		if err != nil {
			return NewErrorResponse(err)
		}
		target = acc
	}

	cps, err := a.wallet.AccountMgr.ListControlProgram()
	if err != nil {
		return NewErrorResponse(err)
	}

	addressRespIndexes := []addressRespIndex{}
	for _, cp := range cps {
		if cp.Address == "" || cp.AccountID != target.ID {
			continue
		}

		addressIndex := addressRespIndex{
			KeyIndex: cp.KeyIndex,
			AddressResp: addressResp{
				AccountAlias: target.Alias,
				AccountID:    cp.AccountID,
				Address:      cp.Address,
				Change:       cp.Change,
			},
		}
		addressRespIndexes = append(addressRespIndexes, addressIndex)
	}

	// sort AddressResp by KeyIndex
	addresses := []addressResp{}
	sort.Sort(SortByIndex(addressRespIndexes))
	for _, addr := range addressRespIndexes {
		addresses = append(addresses, addr.AddressResp)
	}

	return NewSuccessResponse(addresses)
}
<|endoftext|>


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

package inode

import (
	"fmt"
	"io"

	"github.com/googlecloudplatform/gcsfuse/gcsproxy"
	"github.com/googlecloudplatform/gcsfuse/timeutil"
	"github.com/jacobsa/fuse/fuseops"
	"github.com/jacobsa/gcloud/gcs"
	"github.com/jacobsa/gcloud/syncutil"
	"golang.org/x/net/context"
)

type FileInode struct {
	/////////////////////////
	// Dependencies
	/////////////////////////

	bucket gcs.Bucket

	/////////////////////////
	// Constant data
	/////////////////////////

	id fuseops.InodeID

	/////////////////////////
	// Mutable state
	/////////////////////////

	// A mutex that must be held when calling certain methods. See documentation
	// for each method.
	mu syncutil.InvariantMutex

	// GUARDED_BY(mu)
	lc lookupCount

	// A proxy for the backing object in GCS.
	//
	// INVARIANT: proxy.CheckInvariants() does not panic
	//
	// GUARDED_BY(mu)
	proxy *gcsproxy.ObjectProxy
}

var _ Inode = &FileInode{}

// Create a file inode for the given object in GCS. The initial lookup count is
// zero.
//
// REQUIRES: o != nil
// REQUIRES: o.Generation > 0
// REQUIRES: len(o.Name) > 0
// REQUIRES: o.Name[len(o.Name)-1] != '/'
func NewFileInode(
	clock timeutil.Clock,
	bucket gcs.Bucket,
	id fuseops.InodeID,
	o *gcs.Object) (f *FileInode) {
	// Set up the basic struct.
	f = &FileInode{
		bucket: bucket,
		id:     id,
		proxy:  gcsproxy.NewObjectProxy(clock, bucket, o),
	}

	f.lc.Init(id)

	// Set up invariant checking.
	f.mu = syncutil.NewInvariantMutex(f.checkInvariants)

	return
}

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

// LOCKS_REQUIRED(f.mu)
func (f *FileInode) checkInvariants() {
	// Make sure the name is legal.
	name := f.proxy.Name()
	if len(name) == 0 || name[len(name)-1] == '/' {
		panic("Illegal file name: " + name)
	}

	// INVARIANT: proxy.CheckInvariants() does not panic
	f.proxy.CheckInvariants()
}

////////////////////////////////////////////////////////////////////////
// Public interface
////////////////////////////////////////////////////////////////////////

func (f *FileInode) Lock() {
	f.mu.Lock()
}

func (f *FileInode) Unlock() {
	f.mu.Unlock()
}

func (f *FileInode) ID() fuseops.InodeID {
	return f.id
}

func (f *FileInode) Name() string {
	return f.proxy.Name()
}

// Return the object generation number from which this inode was branched.
//
// Does not require the lock to be held, but may spontaneously increase if the
// lock is not held.
func (f *FileInode) SourceGeneration() int64 {
	return f.proxy.SourceGeneration()
}

// LOCKS_REQUIRED(f.mu)
func (f *FileInode) IncrementLookupCount() {
	f.lc.Inc()
}

// LOCKS_REQUIRED(f.mu)
func (f *FileInode) DecrementLookupCount(n uint64) (destroy bool) {
	destroy = f.lc.Dec(n)
	return
}

// LOCKS_REQUIRED
func (f *FileInode) Destroy() (err error) {
	err = f.proxy.Destroy()
	return
}

// LOCKS_REQUIRED(f.mu)
func (f *FileInode) Attributes(
	ctx context.Context) (attrs fuseops.InodeAttributes, err error) {
	// Stat the object.
	sr, err := f.proxy.Stat(ctx)
	if err != nil {
		err = fmt.Errorf("Stat: %v", err)
		return
	}

	// Fill out the struct.
	attrs = fuseops.InodeAttributes{
		Nlink: 1,
		Size:  uint64(sr.Size),
		Mode:  0700,
		Mtime: sr.Mtime,
	}

	// If the object has been clobbered, we reflect that as the inode being
	// unlinked.
	if sr.Clobbered {
		attrs.Nlink = 0
	}

	return
}

// Serve a read op for this file, without responding.
//
// LOCKS_REQUIRED(f.mu)
func (f *FileInode) Read(
	op *fuseops.ReadFileOp) (err error) {
	// Read from the proxy.
	buf := make([]byte, op.Size)
	n, err := f.proxy.ReadAt(op.Context(), buf, op.Offset)

	// We don't return errors for EOF. Otherwise, propagate errors.
	if err == io.EOF {
		err = nil
	} else if err != nil {
		err = fmt.Errorf("ReadAt: %v", err)
		return
	}

	// Fill in the response.
	op.Data = buf[:n]

	return
}

// Serve a write op for this file, without responding.
//
// LOCKS_REQUIRED(f.mu)
func (f *FileInode) Write(
	op *fuseops.WriteFileOp) (err error) {
	// Write to the proxy. Note that the proxy guarantees that it returns an
	// error for short writes.
	_, err = f.proxy.WriteAt(op.Context(), op.Data, op.Offset)

	return
}

// Write out contents to GCS. If this fails due to the generation having been
// clobbered, treat it as a non-error (simulating the inode having been
// unlinked).
//
// After this method succeeds, SourceGeneration will return the new generation
// by which this inode should be known (which may be the same as before). If it
// fails, the generation will not change.
//
// LOCKS_REQUIRED(f.mu)
func (f *FileInode) Sync(ctx context.Context) (err error) {
	// Write out the proxy's contents if it is dirty.
	err = f.proxy.Sync(ctx)

	// Special case: a precondition error means we were clobbered, which we treat
	// as being unlinked. There's no reason to return an error in that case.
	if _, ok := err.(*gcs.PreconditionError); ok {
		err = nil
	}

	// Propagate other errors.
	if err != nil {
		err = fmt.Errorf("ObjectProxy.Sync: %v", err)
		return
	}

	return
}

// Truncate the file to the specified size.
//
// LOCKS_REQUIRED(f.mu)
func (f *FileInode) Truncate(
	ctx context.Context,
	size int64) (err error) {
	err = f.proxy.Truncate(ctx, size)
	return
}
<commit_msg>Updated FileInode.<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package inode

import (
	"fmt"
	"io"

	"github.com/googlecloudplatform/gcsfuse/gcsproxy"
	"github.com/googlecloudplatform/gcsfuse/timeutil"
	"github.com/jacobsa/fuse/fuseops"
	"github.com/jacobsa/gcloud/gcs"
	"github.com/jacobsa/gcloud/syncutil"
	"golang.org/x/net/context"
)

type FileInode struct {
	/////////////////////////
	// Dependencies
	/////////////////////////

	bucket gcs.Bucket

	/////////////////////////
	// Constant data
	/////////////////////////

	id           fuseops.InodeID
	supportNlink bool

	/////////////////////////
	// Mutable state
	/////////////////////////

	// A mutex that must be held when calling certain methods. See documentation
	// for each method.
	mu syncutil.InvariantMutex

	// GUARDED_BY(mu)
	lc lookupCount

	// A proxy for the backing object in GCS.
	//
	// INVARIANT: proxy.CheckInvariants() does not panic
	//
	// GUARDED_BY(mu)
	proxy *gcsproxy.ObjectProxy
}

var _ Inode = &FileInode{}

// Create a file inode for the given object in GCS. The initial lookup count is
// zero.
//
// If supportNlink is set, Attributes will use bucket.StatObject to find out
// whether the backing objet has been clobbered. Otherwise, Attributes will
// always show Nlink == 1.
//
// REQUIRES: o != nil
// REQUIRES: o.Generation > 0
// REQUIRES: len(o.Name) > 0
// REQUIRES: o.Name[len(o.Name)-1] != '/'
func NewFileInode(
	clock timeutil.Clock,
	bucket gcs.Bucket,
	id fuseops.InodeID,
	supportNlink bool,
	o *gcs.Object) (f *FileInode) {
	// Set up the basic struct.
	f = &FileInode{
		bucket:       bucket,
		id:           id,
		supportNlink: supportNlink,
		proxy:        gcsproxy.NewObjectProxy(clock, bucket, o),
	}

	f.lc.Init(id)

	// Set up invariant checking.
	f.mu = syncutil.NewInvariantMutex(f.checkInvariants)

	return
}

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

// LOCKS_REQUIRED(f.mu)
func (f *FileInode) checkInvariants() {
	// Make sure the name is legal.
	name := f.proxy.Name()
	if len(name) == 0 || name[len(name)-1] == '/' {
		panic("Illegal file name: " + name)
	}

	// INVARIANT: proxy.CheckInvariants() does not panic
	f.proxy.CheckInvariants()
}

////////////////////////////////////////////////////////////////////////
// Public interface
////////////////////////////////////////////////////////////////////////

func (f *FileInode) Lock() {
	f.mu.Lock()
}

func (f *FileInode) Unlock() {
	f.mu.Unlock()
}

func (f *FileInode) ID() fuseops.InodeID {
	return f.id
}

func (f *FileInode) Name() string {
	return f.proxy.Name()
}

// Return the object generation number from which this inode was branched.
//
// Does not require the lock to be held, but may spontaneously increase if the
// lock is not held.
func (f *FileInode) SourceGeneration() int64 {
	return f.proxy.SourceGeneration()
}

// LOCKS_REQUIRED(f.mu)
func (f *FileInode) IncrementLookupCount() {
	f.lc.Inc()
}

// LOCKS_REQUIRED(f.mu)
func (f *FileInode) DecrementLookupCount(n uint64) (destroy bool) {
	destroy = f.lc.Dec(n)
	return
}

// LOCKS_REQUIRED
func (f *FileInode) Destroy() (err error) {
	err = f.proxy.Destroy()
	return
}

// LOCKS_REQUIRED(f.mu)
func (f *FileInode) Attributes(
	ctx context.Context) (attrs fuseops.InodeAttributes, err error) {
	// Stat the object.
	sr, err := f.proxy.Stat(ctx, f.supportNlink)
	if err != nil {
		err = fmt.Errorf("Stat: %v", err)
		return
	}

	// Fill out the struct.
	attrs = fuseops.InodeAttributes{
		Nlink: 1,
		Size:  uint64(sr.Size),
		Mode:  0700,
		Mtime: sr.Mtime,
	}

	// If the object has been clobbered, we reflect that as the inode being
	// unlinked.
	if sr.Clobbered {
		attrs.Nlink = 0
	}

	return
}

// Serve a read op for this file, without responding.
//
// LOCKS_REQUIRED(f.mu)
func (f *FileInode) Read(
	op *fuseops.ReadFileOp) (err error) {
	// Read from the proxy.
	buf := make([]byte, op.Size)
	n, err := f.proxy.ReadAt(op.Context(), buf, op.Offset)

	// We don't return errors for EOF. Otherwise, propagate errors.
	if err == io.EOF {
		err = nil
	} else if err != nil {
		err = fmt.Errorf("ReadAt: %v", err)
		return
	}

	// Fill in the response.
	op.Data = buf[:n]

	return
}

// Serve a write op for this file, without responding.
//
// LOCKS_REQUIRED(f.mu)
func (f *FileInode) Write(
	op *fuseops.WriteFileOp) (err error) {
	// Write to the proxy. Note that the proxy guarantees that it returns an
	// error for short writes.
	_, err = f.proxy.WriteAt(op.Context(), op.Data, op.Offset)

	return
}

// Write out contents to GCS. If this fails due to the generation having been
// clobbered, treat it as a non-error (simulating the inode having been
// unlinked).
//
// After this method succeeds, SourceGeneration will return the new generation
// by which this inode should be known (which may be the same as before). If it
// fails, the generation will not change.
//
// LOCKS_REQUIRED(f.mu)
func (f *FileInode) Sync(ctx context.Context) (err error) {
	// Write out the proxy's contents if it is dirty.
	err = f.proxy.Sync(ctx)

	// Special case: a precondition error means we were clobbered, which we treat
	// as being unlinked. There's no reason to return an error in that case.
	if _, ok := err.(*gcs.PreconditionError); ok {
		err = nil
	}

	// Propagate other errors.
	if err != nil {
		err = fmt.Errorf("ObjectProxy.Sync: %v", err)
		return
	}

	return
}

// Truncate the file to the specified size.
//
// LOCKS_REQUIRED(f.mu)
func (f *FileInode) Truncate(
	ctx context.Context,
	size int64) (err error) {
	err = f.proxy.Truncate(ctx, size)
	return
}
<|endoftext|>


<commit_before>package network

import (
	"github.com/pkg/errors"

	"github.com/lxc/lxd/lxd/state"
	"github.com/lxc/lxd/shared/api"
)

var drivers = map[string]func() Network{
	"bridge":  func() Network { return &bridge{} },
	"macvlan": func() Network { return &macvlan{} },
	"sriov":   func() Network { return &sriov{} },
}

// LoadByName loads the network info from the database by name.
func LoadByName(s *state.State, name string) (Network, error) {
	id, netInfo, err := s.Cluster.GetNetworkInAnyState(name)
	if err != nil {
		return nil, err
	}

	driverFunc, ok := drivers[netInfo.Type]
	if !ok {
		return nil, ErrUnknownDriver
	}

	n := driverFunc()
	n.init(s, id, name, netInfo.Type, netInfo.Description, netInfo.Config, netInfo.Status)

	return n, nil
}

// ValidateName validates the supplied network name for the specified network type.
func ValidateName(name string, netType string) error {
	driverFunc, ok := drivers[netType]
	if !ok {
		return ErrUnknownDriver
	}

	n := driverFunc()
	n.init(nil, 0, name, netType, "", nil, "Unknown")

	err := n.ValidateName(name)
	if err != nil {
		return errors.Wrapf(err, "Network name invalid")
	}

	return nil
}

// Validate validates the supplied network name and configuration for the specified network type.
func Validate(name string, netType string, config map[string]string) error {
	driverFunc, ok := drivers[netType]
	if !ok {
		return ErrUnknownDriver
	}

	n := driverFunc()
	n.init(nil, 0, name, netType, "", config, "Unknown")

	err := n.ValidateName(name)
	if err != nil {
		return errors.Wrapf(err, "Network name invalid")
	}

	return n.Validate(config)
}

// FillConfig populates the supplied api.NetworkPost with automatically populated values.
func FillConfig(req *api.NetworksPost) error {
	driverFunc, ok := drivers[req.Type]
	if !ok {
		return ErrUnknownDriver
	}

	n := driverFunc()
	n.init(nil, 0, req.Name, req.Type, req.Description, req.Config, "Unknown")

	err := n.fillConfig(req.Config)
	if err != nil {
		return err
	}

	return nil
}
<commit_msg>lxd/network/network/load: Adds ovn network type to loader<commit_after>package network

import (
	"github.com/pkg/errors"

	"github.com/lxc/lxd/lxd/state"
	"github.com/lxc/lxd/shared/api"
)

var drivers = map[string]func() Network{
	"bridge":  func() Network { return &bridge{} },
	"macvlan": func() Network { return &macvlan{} },
	"sriov":   func() Network { return &sriov{} },
	"ovn":     func() Network { return &ovn{} },
}

// LoadByName loads the network info from the database by name.
func LoadByName(s *state.State, name string) (Network, error) {
	id, netInfo, err := s.Cluster.GetNetworkInAnyState(name)
	if err != nil {
		return nil, err
	}

	driverFunc, ok := drivers[netInfo.Type]
	if !ok {
		return nil, ErrUnknownDriver
	}

	n := driverFunc()
	n.init(s, id, name, netInfo.Type, netInfo.Description, netInfo.Config, netInfo.Status)

	return n, nil
}

// ValidateName validates the supplied network name for the specified network type.
func ValidateName(name string, netType string) error {
	driverFunc, ok := drivers[netType]
	if !ok {
		return ErrUnknownDriver
	}

	n := driverFunc()
	n.init(nil, 0, name, netType, "", nil, "Unknown")

	err := n.ValidateName(name)
	if err != nil {
		return errors.Wrapf(err, "Network name invalid")
	}

	return nil
}

// Validate validates the supplied network name and configuration for the specified network type.
func Validate(name string, netType string, config map[string]string) error {
	driverFunc, ok := drivers[netType]
	if !ok {
		return ErrUnknownDriver
	}

	n := driverFunc()
	n.init(nil, 0, name, netType, "", config, "Unknown")

	err := n.ValidateName(name)
	if err != nil {
		return errors.Wrapf(err, "Network name invalid")
	}

	return n.Validate(config)
}

// FillConfig populates the supplied api.NetworkPost with automatically populated values.
func FillConfig(req *api.NetworksPost) error {
	driverFunc, ok := drivers[req.Type]
	if !ok {
		return ErrUnknownDriver
	}

	n := driverFunc()
	n.init(nil, 0, req.Name, req.Type, req.Description, req.Config, "Unknown")

	err := n.fillConfig(req.Config)
	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package migo

import (
	"database/sql"
	"fmt"
	"log"
	"os/exec"
	"testing"

	"github.com/go-sql-driver/mysql"
	"github.com/lestrrat/go-test-mysqld"
)

func TestSeedWithForeingKey(t *testing.T) {
	conf := mysqltest.NewConfig()
	conf.SkipNetworking = false
	conf.Port = 13306

	// start new instance of mysql
	mysqld, err := mysqltest.NewMysqld(conf)
	if err != nil {
		t.Fatal("Failed to start mysqld:", err)
	}
	defer mysqld.Stop()

	// connect to instance
	sqlconf := mysql.Config{
		User:   "root",
		Addr:   "127.0.0.1:13306",
		Net:    "tcp",
		Passwd: "",
		DBName: "",
	}
	db, err := sql.Open("mysql", sqlconf.FormatDSN())
	if err != nil {
		t.Fatal("Failed to connect to database:", err)
	}
	defer db.Close()

	// create new database
	query := fmt.Sprintf("CREATE DATABASE IF NOT EXISTS test")
	if _, err := db.Exec(query); err != nil {
		t.Fatal("Failed to create database if not exist:", err)
	}
	defer func() {
		query = fmt.Sprint("DROP DATABASE test")
		if _, err := db.Exec(query); err != nil {
			t.Fatal("Failed to drop test database:", err)
		}
	}()
	query = fmt.Sprint("USE test")
	if _, err := db.Exec(query); err != nil {
		t.Fatal("Failed to use test database:", err)
	}

	// create tables
	query = fmt.Sprint("CREATE TABLE test.parent(id int NOT NULL PRIMARY KEY, name varchar(20))")
	if _, err := db.Exec(query); err != nil {
		t.Fatal("Failed to create parent table:", err)
	}
	query = fmt.Sprint("CREATE TABLE test.child(parent_id int, FOREIGN KEY(parent_id) REFERENCES parent(id), name varchar(20))")
	if _, err := db.Exec(query); err != nil {
		t.Fatal("Failed to create child table:", err)
	}

	// seeding child
	err = exec.Command("go", "run", "cmd/migo/main.go", "-S", "test/child_seed.yml", "-d", "test/seed_test_database.yml", "-e", "test", "seed").Run()
	if err != nil {
		t.Error(err.Error())
	}
	// seeding parent
	err = exec.Command("go", "run", "cmd/migo/main.go", "-S", "test/parent_seed.yml", "-d", "test/seed_test_database.yml", "-e", "test", "seed").Run()
	if err != nil {
		t.Error(err.Error())
	}

	// assert
	var id int
	var name string

	parent := db.QueryRow("SELECT id, name FROM parent LIMIT 1")
	if err != nil {
		log.Fatal(err)
	}
	parent.Scan(&id, &name)
	parentID, parentName := id, name
	if parentID != 0 || parentName != "parent0" {
		t.Error("Expected parentID is 0 and parentName is parent0 but not.")
	}

	child := db.QueryRow("SELECT parent_id, name FROM child LIMIT 1")
	if err != nil {
		log.Fatal(err)
	}
	child.Scan(&id, &name)
	childID, childName := id, name
	if childID != 0 || childName != "child0" {
		t.Error("Expected childID is 0 and childName is child0 but not.")
	}
}
<commit_msg>Fix typo<commit_after>package migo

import (
	"database/sql"
	"fmt"
	"log"
	"os/exec"
	"testing"

	"github.com/go-sql-driver/mysql"
	"github.com/lestrrat/go-test-mysqld"
)

func TestSeedWithForeignKey(t *testing.T) {
	conf := mysqltest.NewConfig()
	conf.SkipNetworking = false
	conf.Port = 13306

	// start new instance of mysql
	mysqld, err := mysqltest.NewMysqld(conf)
	if err != nil {
		t.Fatal("Failed to start mysqld:", err)
	}
	defer mysqld.Stop()

	// connect to instance
	sqlconf := mysql.Config{
		User:   "root",
		Addr:   "127.0.0.1:13306",
		Net:    "tcp",
		Passwd: "",
		DBName: "",
	}
	db, err := sql.Open("mysql", sqlconf.FormatDSN())
	if err != nil {
		t.Fatal("Failed to connect to database:", err)
	}
	defer db.Close()

	// create new database
	query := fmt.Sprintf("CREATE DATABASE IF NOT EXISTS test")
	if _, err := db.Exec(query); err != nil {
		t.Fatal("Failed to create database if not exist:", err)
	}
	defer func() {
		query = fmt.Sprint("DROP DATABASE test")
		if _, err := db.Exec(query); err != nil {
			t.Fatal("Failed to drop test database:", err)
		}
	}()
	query = fmt.Sprint("USE test")
	if _, err := db.Exec(query); err != nil {
		t.Fatal("Failed to use test database:", err)
	}

	// create tables
	query = fmt.Sprint("CREATE TABLE test.parent(id int NOT NULL PRIMARY KEY, name varchar(20))")
	if _, err := db.Exec(query); err != nil {
		t.Fatal("Failed to create parent table:", err)
	}
	query = fmt.Sprint("CREATE TABLE test.child(parent_id int, FOREIGN KEY(parent_id) REFERENCES parent(id), name varchar(20))")
	if _, err := db.Exec(query); err != nil {
		t.Fatal("Failed to create child table:", err)
	}

	// seeding child
	err = exec.Command("go", "run", "cmd/migo/main.go", "-S", "test/child_seed.yml", "-d", "test/seed_test_database.yml", "-e", "test", "seed").Run()
	if err != nil {
		t.Error(err.Error())
	}
	// seeding parent
	err = exec.Command("go", "run", "cmd/migo/main.go", "-S", "test/parent_seed.yml", "-d", "test/seed_test_database.yml", "-e", "test", "seed").Run()
	if err != nil {
		t.Error(err.Error())
	}

	// assert
	var id int
	var name string

	parent := db.QueryRow("SELECT id, name FROM parent LIMIT 1")
	if err != nil {
		log.Fatal(err)
	}
	parent.Scan(&id, &name)
	parentID, parentName := id, name
	if parentID != 0 || parentName != "parent0" {
		t.Error("Expected parentID is 0 and parentName is parent0 but not.")
	}

	child := db.QueryRow("SELECT parent_id, name FROM child LIMIT 1")
	if err != nil {
		log.Fatal(err)
	}
	child.Scan(&id, &name)
	childID, childName := id, name
	if childID != 0 || childName != "child0" {
		t.Error("Expected childID is 0 and childName is child0 but not.")
	}
}
<|endoftext|>


<commit_before>package p050

import (
	"math"
	"math/rand"
	"testing"
)

func TestRand(t *testing.T) {
	for i := 0; i < 100000; i++ {
		f, n := rand.Float64(), rand.Intn(9876543210)
		if ans := myPow(f, n); ans != math.Pow(f, float64(n)) {
			t.Fatal("error answer", f, n, ans, math.Pow(f, float64(n)))
		}
	}

}

// error answer 0.09696951891448456 2775422040480279449 0 +Inf
<commit_msg>update test code p050<commit_after>package p050

import (
	"github.com/stretchr/testify/assert"
	"math"
	"math/rand"
	"testing"
)

func TestRand(t *testing.T) {
	for i := 0; i < 100; i++ {
		f, n := rand.Float64(), rand.Intn(9876543210)
		if ans := myPow(f, n); ans != math.Pow(f, float64(n)) {
			t.Fatal("error answer", f, n, ans, math.Pow(f, float64(n)))
		}
		if ans := myPow(f, -n); ans != math.Pow(f, float64(-n)) {
			t.Fatal("error answer", f, -n, ans, math.Pow(f, float64(-n)))
		}
	}

	assert.Equal(t, 1.0, myPow(2.0, 0))
}

// error answer 0.09696951891448456 2775422040480279449 0 +Inf
<|endoftext|>


<commit_before>package rel

type FunctionNode struct {
	Expressions []Visitable
	Alias       *SqlLiteralNode
	Distinct    bool
	BaseVisitable
}

type SumNode FunctionNode
type MaxNode FunctionNode
type MinNode FunctionNode
type AvgNode FunctionNode
<commit_msg>Added predications to FunctionNode<commit_after>package rel

type FunctionNode struct {
	Expressions []Visitable
	Alias       *SqlLiteralNode
	Distinct    bool
	BaseVisitable
}

type SumNode FunctionNode
type MaxNode FunctionNode
type MinNode FunctionNode
type AvgNode FunctionNode

func (node *FunctionNode) Over(visitable Visitable) *OverNode {
	return windowPredicationOver(node, visitable)
}

func (node *FunctionNode) Eq(visitable Visitable) *EqualityNode {
  return predicationEq(node, visitable)
}

func (node *FunctionNode) EqAny(visitables ...Visitable) *GroupingNode {
  return predicationEqAny(node, visitables...)
}

func (node *FunctionNode) EqAll(visitables ...Visitable) *GroupingNode {
  return predicationEqAll(node, visitables...)
}

func (node *FunctionNode) Lt(visitable Visitable) *LessThanNode {
  return predicationLt(node, visitable)
}

func (node *FunctionNode) LtAny(visitables ...Visitable) *GroupingNode {
  return predicationLtAny(node, visitables...)
}

func (node *FunctionNode) LtAll(visitables ...Visitable) *GroupingNode {
  return predicationLtAll(node, visitables...)
}

func (node *FunctionNode) LtEq(v Visitable) *LessThanOrEqualNode {
  return &LessThanOrEqualNode{Left: node, Right: v}
}

func (node *FunctionNode) LtEqAny(visitables ...Visitable) *GroupingNode {
  return predicationLtEqAny(node, visitables...)
}

func (node *FunctionNode) LtEqAll(visitables ...Visitable) *GroupingNode {
  return predicationLtEqAll(node, visitables...)
}

func (node *FunctionNode) Gt(visitable Visitable) *GreaterThanNode {
  return predicationGt(node, visitable)
}

func (node *FunctionNode) GtAny(visitables ...Visitable) *GroupingNode {
  return predicationGtAny(node, visitables...)
}

func (node *FunctionNode) GtAll(visitables ...Visitable) *GroupingNode {
  return predicationGtAll(node, visitables...)
}

func (node *FunctionNode) GtEq(visitable Visitable) *GreaterThanOrEqualNode {
  return predicationGtEq(node, visitable)
}

func (node *FunctionNode) GtEqAny(visitables ...Visitable) *GroupingNode {
  return predicationGtEqAny(node, visitables...)
}

func (node *FunctionNode) GtEqAll(visitables ...Visitable) *GroupingNode {
  return predicationGtEqAll(node, visitables...)
}

func (node *FunctionNode) Count() *CountNode {
  return predicationCount(node)
}

func (node *FunctionNode) Extract(literal SqlLiteralNode) *ExtractNode {
  return predicationExtract(node, literal)
}

func (node *FunctionNode) In(visitables []Visitable) Visitable {
  return predicationIn(node, visitables)
}

func (node *FunctionNode) InAny(visitableslices ...[]Visitable) Visitable {
  return predicationInAny(node, visitableslices...)
}

func (node *FunctionNode) InAll(visitableslices ...[]Visitable) Visitable {
  return predicationInAll(node, visitableslices...)
}

func (node *FunctionNode) NotIn(visitables []Visitable) Visitable {
  return predicationNotIn(node, visitables)
}

func (node *FunctionNode) NotInAny(visitableslices ...[]Visitable) Visitable {
  return predicationNotInAny(node, visitableslices...)
}

func (node *FunctionNode) NotInAll(visitableslices ...[]Visitable) Visitable {
  return predicationNotInAll(node, visitableslices...)
}

func (node *FunctionNode) NotEq(visitable Visitable) *NotEqualNode {
  return predicationNotEq(node, visitable)
}

func (node *FunctionNode) NotEqAny(visitables ...Visitable) *GroupingNode {
  return predicationNotEqAny(node, visitables...)
}

func (node *FunctionNode) NotEqAll(visitables ...Visitable) *GroupingNode {
  return predicationNotEqAll(node, visitables...)
}

func (node *FunctionNode) DoesNotMatch(literal SqlLiteralNode) *DoesNotMatchNode {
  return predicationDoesNotMatch(node, literal)
}

func (node *FunctionNode) DoesNotMatchAny(literals ...SqlLiteralNode) *GroupingNode {
  return predicationDoesNotMatchAny(node, literals...)
}

func (node *FunctionNode) DoesNotMatchAll(literals ...SqlLiteralNode) *GroupingNode {
  return predicationDoesNotMatchAll(node, literals...)
}

func (node *FunctionNode) Matches(literal SqlLiteralNode) *MatchesNode {
  return predicationMatches(node, literal)
}

func (node *FunctionNode) MatchesAny(literals ...SqlLiteralNode) *GroupingNode {
  return predicationMatchesAny(node, literals...)
}

func (node *FunctionNode) MatchesAll(literals ...SqlLiteralNode) *GroupingNode {
  return predicationMatchesAll(node, literals...)
}

func (node *FunctionNode) GroupAny(visitables ...Visitable) *GroupingNode {
  return predicationGroupAny(node, visitables...)
}

func (node *FunctionNode) GroupAll(visitables ...Visitable) *GroupingNode {
  return predicationGroupAll(node, visitables...)
}
)
<|endoftext|>


<commit_before>// Package editor enables users to create edit views from their content
// structs so that admins can manage content
package editor

import (
	"bytes"
)

// Editable ensures data is editable
type Editable interface {
	SetContentID(id int)
	ContentID() int
	ContentName() string
	SetSlug(slug string)
	Editor() *Editor
	MarshalEditor() ([]byte, error)
}

// Sortable ensures data is sortable by time
type Sortable interface {
	Time() int64
	Touch() int64
	ContentID() int
}

// Editor is a view containing fields to manage content
type Editor struct {
	ViewBuf *bytes.Buffer
}

// Field is used to create the editable view for a field
// within a particular content struct
type Field struct {
	View []byte
}

// Form takes editable content and any number of Field funcs to describe the edit
// page for any content struct added by a user
func Form(post Editable, fields ...Field) ([]byte, error) {
	editor := post.Editor()

	editor.ViewBuf = &bytes.Buffer{}
	editor.ViewBuf.Write([]byte(`<table><tbody class="row"><tr class="col s8"><td>`))

	for _, f := range fields {
		addFieldToEditorView(editor, f)
	}

	editor.ViewBuf.Write([]byte(`</td></tr>`))

	// content items with Item embedded have some default fields we need to render
	editor.ViewBuf.Write([]byte(`<tr class="col s4 default-fields"><td>`))

	publishTime := `

		MM
		<select class="month __ponzu browser-default">
			<option value="1">Jan - 01</option>
			<option value="2">Feb - 02</option>
			<option value="3">Mar - 03</option>
			<option value="4">Apr - 04</option>
			<option value="5">May - 05</option>
			<option value="6">Jun - 06</option>
			<option value="7">Jul - 07</option>
			<option value="8">Aug - 08</option>
			<option value="9">Sep - 09</option>
			<option value="10">Oct - 10</option>
			<option value="11">Nov - 11</option>
			<option value="12">Dec - 12</option>
		</select>

		DD
		<input value="" class="day __ponzu" maxlength="2" type="text" placeholder="DD" />

		YYYY
		<input value="" class="year __ponzu" maxlength="4" type="text" placeholder="YYYY" />

		HH
		<input value="" class="hour __ponzu" maxlength="2" type="text" placeholder="HH" />

:

		MM
		<input value="" class="minute __ponzu" maxlength="2" type="text" placeholder="MM" />

		Period
		<select class="period __ponzu browser-default">
			<option value="AM">AM</option>
			<option value="PM">PM</option>
		</select>

	`

	editor.ViewBuf.Write([]byte(publishTime))

	addPostDefaultFieldsToEditorView(post, editor)

	submit := `

	<button class="right waves-effect waves-light btn green save-post" type="submit">Save</button>
	<button class="right waves-effect waves-light btn red delete-post" type="submit">Delete</button>

		<button class="right waves-effect waves-light btn blue approve-post" type="submit">Approve</button>

	This content is pending approval. By clicking 'Approve', it will be immediately published.

`
	editor.ViewBuf.Write([]byte(submit + `</td></tr></tbody></table>`))

	return editor.ViewBuf.Bytes(), nil
}

func addFieldToEditorView(e *Editor, f Field) {
	e.ViewBuf.Write(f.View)
}

func addPostDefaultFieldsToEditorView(p Editable, e *Editor) {
	defaults := []Field{
		Field{
			View: Input("Slug", p, map[string]string{
				"label":       "URL Slug",
				"type":        "text",
				"disabled":    "true",
				"placeholder": "Will be set automatically",
			}),
		},
		Field{
			View: Timestamp("Timestamp", p, map[string]string{
				"type":  "hidden",
				"class": "timestamp __ponzu",
			}),
		},
		Field{
			View: Timestamp("Updated", p, map[string]string{
				"type":  "hidden",
				"class": "updated __ponzu",
			}),
		},
	}

	for _, f := range defaults {
		addFieldToEditorView(e, f)
	}

}
<commit_msg>adding catch for pending status to apply a new query string to save form action<commit_after>// Package editor enables users to create edit views from their content
// structs so that admins can manage content
package editor

import (
	"bytes"
)

// Editable ensures data is editable
type Editable interface {
	SetContentID(id int)
	ContentID() int
	ContentName() string
	SetSlug(slug string)
	Editor() *Editor
	MarshalEditor() ([]byte, error)
}

// Sortable ensures data is sortable by time
type Sortable interface {
	Time() int64
	Touch() int64
	ContentID() int
}

// Editor is a view containing fields to manage content
type Editor struct {
	ViewBuf *bytes.Buffer
}

// Field is used to create the editable view for a field
// within a particular content struct
type Field struct {
	View []byte
}

// Form takes editable content and any number of Field funcs to describe the edit
// page for any content struct added by a user
func Form(post Editable, fields ...Field) ([]byte, error) {
	editor := post.Editor()

	editor.ViewBuf = &bytes.Buffer{}
	editor.ViewBuf.Write([]byte(`<table><tbody class="row"><tr class="col s8"><td>`))

	for _, f := range fields {
		addFieldToEditorView(editor, f)
	}

	editor.ViewBuf.Write([]byte(`</td></tr>`))

	// content items with Item embedded have some default fields we need to render
	editor.ViewBuf.Write([]byte(`<tr class="col s4 default-fields"><td>`))

	publishTime := `

		MM
		<select class="month __ponzu browser-default">
			<option value="1">Jan - 01</option>
			<option value="2">Feb - 02</option>
			<option value="3">Mar - 03</option>
			<option value="4">Apr - 04</option>
			<option value="5">May - 05</option>
			<option value="6">Jun - 06</option>
			<option value="7">Jul - 07</option>
			<option value="8">Aug - 08</option>
			<option value="9">Sep - 09</option>
			<option value="10">Oct - 10</option>
			<option value="11">Nov - 11</option>
			<option value="12">Dec - 12</option>
		</select>

		DD
		<input value="" class="day __ponzu" maxlength="2" type="text" placeholder="DD" />

		YYYY
		<input value="" class="year __ponzu" maxlength="4" type="text" placeholder="YYYY" />

		HH
		<input value="" class="hour __ponzu" maxlength="2" type="text" placeholder="HH" />

:

		MM
		<input value="" class="minute __ponzu" maxlength="2" type="text" placeholder="MM" />

		Period
		<select class="period __ponzu browser-default">
			<option value="AM">AM</option>
			<option value="PM">PM</option>
		</select>

	`

	editor.ViewBuf.Write([]byte(publishTime))

	addPostDefaultFieldsToEditorView(post, editor)

	submit := `

	<button class="right waves-effect waves-light btn green save-post" type="submit">Save</button>
	<button class="right waves-effect waves-light btn red delete-post" type="submit">Delete</button>

		<button class="right waves-effect waves-light btn blue approve-post" type="submit">Approve</button>

	This content is pending approval. By clicking 'Approve', it will be immediately published.

`
	editor.ViewBuf.Write([]byte(submit + `</td></tr></tbody></table>`))

	return editor.ViewBuf.Bytes(), nil
}

func addFieldToEditorView(e *Editor, f Field) {
	e.ViewBuf.Write(f.View)
}

func addPostDefaultFieldsToEditorView(p Editable, e *Editor) {
	defaults := []Field{
		Field{
			View: Input("Slug", p, map[string]string{
				"label":       "URL Slug",
				"type":        "text",
				"disabled":    "true",
				"placeholder": "Will be set automatically",
			}),
		},
		Field{
			View: Timestamp("Timestamp", p, map[string]string{
				"type":  "hidden",
				"class": "timestamp __ponzu",
			}),
		},
		Field{
			View: Timestamp("Updated", p, map[string]string{
				"type":  "hidden",
				"class": "updated __ponzu",
			}),
		},
	}

	for _, f := range defaults {
		addFieldToEditorView(e, f)
	}

}
<|endoftext|>


<commit_before>package main

import (
	"code.google.com/p/go-icap"
	"fmt"
	"io/ioutil"
	"log"
	"time"
)

// Request-modification functions.

var ISTag = fmt.Sprintf("Redwood%d", time.Now())

func handleRequest(w icap.ResponseWriter, req *icap.Request) {
	h := w.Header()
	h.Set("ISTag", ISTag)
	h.Set("Service", "Redwood content filter")

	switch req.Method {
	case "OPTIONS":
		h.Set("Methods", "REQMOD")
		h.Set("Transfer-Preview", "*")
		h.Set("Preview", "0")
		w.WriteHeader(200, nil, false)

	case "REQMOD":
		if req.Request.Host == "203.0.113.1" {
			icap.ServeLocally(w, req)
			return
		}

		user := req.Header.Get("X-Client-Username")
		if user == "" {
			user = req.Header.Get("X-Client-IP")
		}

		sc := scorecard{
			tally: URLRules.MatchingRules(req.Request.URL),
		}
		sc.calculate(user)
		if sc.action == BLOCK {
			showBlockPage(icap.NewBridgedResponseWriter(w), req.Request, &sc)
			logAccess(req.Request, nil, sc, "", 0, false, user)
			return
		}

		if changeQuery(req.Request.URL) {
			content, err := ioutil.ReadAll(req.Request.Body)
			if err != nil {
				log.Println(err)
			}
			w.WriteHeader(200, req.Request, len(content) > 0)
			if len(content) > 0 {
				w.Write(content)
			}
		} else {
			w.WriteHeader(204, nil, false)
		}

		logAccess(req.Request, nil, sc, "", 0, false, user)

	default:
		w.WriteHeader(405, nil, false)
	}
}
<commit_msg>In ICAP mode, log HTTP requests only once (either the REQMOD stage or the RESPMOD stage, but not both).<commit_after>package main

import (
	"code.google.com/p/go-icap"
	"fmt"
	"io/ioutil"
	"log"
	"time"
)

// Request-modification functions.

var ISTag = fmt.Sprintf("Redwood%d", time.Now())

func handleRequest(w icap.ResponseWriter, req *icap.Request) {
	h := w.Header()
	h.Set("ISTag", ISTag)
	h.Set("Service", "Redwood content filter")

	switch req.Method {
	case "OPTIONS":
		h.Set("Methods", "REQMOD")
		h.Set("Transfer-Preview", "*")
		h.Set("Preview", "0")
		w.WriteHeader(200, nil, false)

	case "REQMOD":
		if req.Request.Host == "203.0.113.1" {
			icap.ServeLocally(w, req)
			return
		}

		user := req.Header.Get("X-Client-Username")
		if user == "" {
			user = req.Header.Get("X-Client-IP")
		}

		sc := scorecard{
			tally: URLRules.MatchingRules(req.Request.URL),
		}
		sc.calculate(user)
		if sc.action == BLOCK {
			showBlockPage(icap.NewBridgedResponseWriter(w), req.Request, &sc)
			logAccess(req.Request, nil, sc, "", 0, false, user)
			return
		}

		if changeQuery(req.Request.URL) {
			content, err := ioutil.ReadAll(req.Request.Body)
			if err != nil {
				log.Println(err)
			}
			w.WriteHeader(200, req.Request, len(content) > 0)
			if len(content) > 0 {
				w.Write(content)
			}
		} else {
			w.WriteHeader(204, nil, false)
		}

	default:
		w.WriteHeader(405, nil, false)
	}
}
<|endoftext|>


<commit_before>package middleware

import (
	"encoding/base64"
	"errors"
	"log"
	"net/http"
	"strings"

	"github.com/ant0ine/go-json-rest/rest"
)

type TokenAuthMiddleware struct {
	Realm         string
	Authenticator func(token string) bool
	Authorizator  func(token string, request *rest.Request) bool
}

func (mw *TokenAuthMiddleware) MiddlewareFunc(handler rest.HandlerFunc) rest.HandlerFunc {
	if mw.Realm == "" {
		log.Fatal("Realm is required")
	}
	if mw.Authenticator == nil {
		log.Fatal("Authenticator is required")
	}
	if mw.Authorizator == nil {
		mw.Authorizator = func(token string, request *rest.Request) bool {
			return true
		}
	}
	return func(writer rest.ResponseWriter, request *rest.Request) {
		authHeader := request.Header.Get("Authorization")
		if authHeader == "" {
			mw.unauthorized(writer)
			return
		}
		providedToken, err := mw.decodeBasicAuthHeader(authHeader)
		if err != nil {
			rest.Error(writer, "Invalid authentication", http.StatusBadRequest)
			return
		}
		if !mw.Authenticator(providedToken) {
			mw.unauthorized(writer)
			return
		}
		if !mw.Authorizator(providedToken, request) {
			mw.unauthorized(writer)
			return
		}
		request.Env["VALID_USER_TOKEN"] = providedToken
		handler(writer, request)
	}
}

func (mw *TokenAuthMiddleware) unauthorized(writer rest.ResponseWriter) {
	writer.Header().Set("WWW-Authenticate", "Basic realm="+mw.Realm)
	rest.Error(writer, "Not Authorized", http.StatusUnauthorized)
}

func (mw *TokenAuthMiddleware) decodeBasicAuthHeader(header string) (tokwn string, err error) {
	parts := strings.SplitN(header, " ", 2)
	if !(len(parts) == 2 && parts[0] == "Token") {
		return "", errors.New("Invalid Authorization header")
	}
	_, err = base64.URLEncoding.DecodeString(parts[1])
	if err != nil {
		return "", errors.New("Token encoding not valid")
	}
	return string(parts[1]), nil
}
<commit_msg>Remove base64 decode checking<commit_after>package middleware

import (
	"errors"
	"log"
	"net/http"
	"strings"

	"github.com/ant0ine/go-json-rest/rest"
)

type TokenAuthMiddleware struct {
	Realm         string
	Authenticator func(token string) bool
	Authorizator  func(token string, request *rest.Request) bool
}

func (mw *TokenAuthMiddleware) MiddlewareFunc(handler rest.HandlerFunc) rest.HandlerFunc {
	if mw.Realm == "" {
		log.Fatal("Realm is required")
	}
	if mw.Authenticator == nil {
		log.Fatal("Authenticator is required")
	}
	if mw.Authorizator == nil {
		mw.Authorizator = func(token string, request *rest.Request) bool {
			return true
		}
	}
	return func(writer rest.ResponseWriter, request *rest.Request) {
		authHeader := request.Header.Get("Authorization")
		if authHeader == "" {
			mw.unauthorized(writer)
			return
		}
		providedToken, err := mw.decodeBasicAuthHeader(authHeader)
		if err != nil {
			rest.Error(writer, "Invalid authentication", http.StatusBadRequest)
			return
		}
		if !mw.Authenticator(providedToken) {
			mw.unauthorized(writer)
			return
		}
		if !mw.Authorizator(providedToken, request) {
			mw.unauthorized(writer)
			return
		}
		request.Env["VALID_USER_TOKEN"] = providedToken
		handler(writer, request)
	}
}

func (mw *TokenAuthMiddleware) unauthorized(writer rest.ResponseWriter) {
	writer.Header().Set("WWW-Authenticate", "Basic realm="+mw.Realm)
	rest.Error(writer, "Not Authorized", http.StatusUnauthorized)
}

func (mw *TokenAuthMiddleware) decodeBasicAuthHeader(header string) (token string, err error) {
	parts := strings.SplitN(header, " ", 2)
	if !(len(parts) == 2 && parts[0] == "Token") {
		return "", errors.New("Invalid Authorization header")
	}
	return string(parts[1]), nil
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Kubernetes Authors.

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

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

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

package endpointslice

import (
	"fmt"
	"time"

	v1 "k8s.io/api/core/v1"
	discovery "k8s.io/api/discovery/v1alpha1"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/labels"
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
	"k8s.io/apimachinery/pkg/util/wait"
	coreinformers "k8s.io/client-go/informers/core/v1"
	discoveryinformers "k8s.io/client-go/informers/discovery/v1alpha1"
	clientset "k8s.io/client-go/kubernetes"
	"k8s.io/client-go/kubernetes/scheme"
	v1core "k8s.io/client-go/kubernetes/typed/core/v1"
	corelisters "k8s.io/client-go/listers/core/v1"
	discoverylisters "k8s.io/client-go/listers/discovery/v1alpha1"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/tools/record"
	"k8s.io/client-go/util/workqueue"
	"k8s.io/klog"
	"k8s.io/kubernetes/pkg/controller"
	endpointutil "k8s.io/kubernetes/pkg/controller/util/endpoint"
	"k8s.io/kubernetes/pkg/util/metrics"
)

const (
	// maxRetries is the number of times a service will be retried before it is
	// dropped out of the queue. Any sync error, such as a failure to create or
	// update an EndpointSlice could trigger a retry. With the current
	// rate-limiter in use (5ms*2^(maxRetries-1)) the following numbers
	// represent the sequence of delays between successive queuings of a
	// service.
	//
	// 5ms, 10ms, 20ms, 40ms, 80ms, 160ms, 320ms, 640ms, 1.3s, 2.6s, 5.1s,
	// 10.2s, 20.4s, 41s, 82s
	maxRetries = 15
)

// NewController creates and initializes a new Controller
func NewController(podInformer coreinformers.PodInformer,
	serviceInformer coreinformers.ServiceInformer,
	nodeInformer coreinformers.NodeInformer,
	esInformer discoveryinformers.EndpointSliceInformer,
	maxEndpointsPerSlice int32,
	client clientset.Interface,
) *Controller {
	broadcaster := record.NewBroadcaster()
	broadcaster.StartLogging(klog.Infof)
	broadcaster.StartRecordingToSink(&v1core.EventSinkImpl{Interface: client.CoreV1().Events("")})
	recorder := broadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: "endpoint-slice-controller"})

	if client != nil && client.CoreV1().RESTClient().GetRateLimiter() != nil {
		metrics.RegisterMetricAndTrackRateLimiterUsage("endpoint_slice_controller", client.DiscoveryV1alpha1().RESTClient().GetRateLimiter())
	}

	c := &Controller{
		client:           client,
		queue:            workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "endpoint_slice"),
		workerLoopPeriod: time.Second,
	}

	serviceInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
		AddFunc: c.enqueueService,
		UpdateFunc: func(old, cur interface{}) {
			c.enqueueService(cur)
		},
		DeleteFunc: c.enqueueService,
	})
	c.serviceLister = serviceInformer.Lister()
	c.servicesSynced = serviceInformer.Informer().HasSynced

	podInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
		AddFunc:    c.addPod,
		UpdateFunc: c.updatePod,
		DeleteFunc: c.deletePod,
	})
	c.podLister = podInformer.Lister()
	c.podsSynced = podInformer.Informer().HasSynced

	c.nodeLister = nodeInformer.Lister()
	c.nodesSynced = nodeInformer.Informer().HasSynced

	c.endpointSliceLister = esInformer.Lister()
	c.endpointSlicesSynced = esInformer.Informer().HasSynced

	c.maxEndpointsPerSlice = maxEndpointsPerSlice

	c.reconciler = &reconciler{
		client:               c.client,
		nodeLister:           c.nodeLister,
		maxEndpointsPerSlice: c.maxEndpointsPerSlice,
	}
	c.triggerTimeTracker = endpointutil.NewTriggerTimeTracker()

	c.eventBroadcaster = broadcaster
	c.eventRecorder = recorder

	return c
}

// Controller manages selector-based service endpoint slices
type Controller struct {
	client           clientset.Interface
	eventBroadcaster record.EventBroadcaster
	eventRecorder    record.EventRecorder

	// serviceLister is able to list/get services and is populated by the
	// shared informer passed to NewController
	serviceLister corelisters.ServiceLister
	// servicesSynced returns true if the service shared informer has been synced at least once.
	// Added as a member to the struct to allow injection for testing.
	servicesSynced cache.InformerSynced

	// podLister is able to list/get pods and is populated by the
	// shared informer passed to NewController
	podLister corelisters.PodLister
	// podsSynced returns true if the pod shared informer has been synced at least once.
	// Added as a member to the struct to allow injection for testing.
	podsSynced cache.InformerSynced

	// endpointSliceLister is able to list/get pods and is populated by the
	// shared informer passed to NewController
	endpointSliceLister discoverylisters.EndpointSliceLister
	// endpointSlicesSynced returns true if the endpoint slice shared informer has been synced at least once.
	// Added as a member to the struct to allow injection for testing.
	endpointSlicesSynced cache.InformerSynced

	// nodeLister is able to list/get pods and is populated by the
	// shared informer passed to NewController
	nodeLister corelisters.NodeLister
	// nodesSynced returns true if the node shared informer has been synced at least once.
	// Added as a member to the struct to allow injection for testing.
	nodesSynced cache.InformerSynced

	// reconciler is an util used to reconcile EndpointSlice changes.
	reconciler *reconciler

	// triggerTimeTracker is an util used to compute and export the
	// EndpointsLastChangeTriggerTime annotation.
	triggerTimeTracker *endpointutil.TriggerTimeTracker

	// Services that need to be updated. A channel is inappropriate here,
	// because it allowes services with lots of pods to be serviced much
	// more often than services with few pods; it also would cause a
	// service that's inserted multiple times to be processed more than
	// necessary.
	queue workqueue.RateLimitingInterface

	// maxEndpointsPerSlice references the maximum number of endpoints that
	// should be added to an EndpointSlice
	maxEndpointsPerSlice int32

	// workerLoopPeriod is the time between worker runs. The workers
	// process the queue of service and pod changes
	workerLoopPeriod time.Duration
}

// Run will not return until stopCh is closed.
func (c *Controller) Run(workers int, stopCh <-chan struct{}) {
	defer utilruntime.HandleCrash()
	defer c.queue.ShutDown()

	klog.Infof("Starting endpoint controller")
	defer klog.Infof("Shutting down endpoint controller")

	if !cache.WaitForNamedCacheSync("endpoint_slice", stopCh, c.podsSynced, c.servicesSynced) {
		return
	}

	for i := 0; i < workers; i++ {
		go wait.Until(c.worker, c.workerLoopPeriod, stopCh)
	}

	go func() {
		defer utilruntime.HandleCrash()
	}()

	<-stopCh
}

// worker runs a worker thread that just dequeues items, processes them, and
// marks them done. You may run as many of these in parallel as you wish; the
// workqueue guarantees that they will not end up processing the same service
// at the same time
func (c *Controller) worker() {
	for c.processNextWorkItem() {
	}
}

func (c *Controller) processNextWorkItem() bool {
	cKey, quit := c.queue.Get()
	if quit {
		return false
	}
	defer c.queue.Done(cKey)

	err := c.syncService(cKey.(string))
	c.handleErr(err, cKey)

	return true
}

func (c *Controller) handleErr(err error, key interface{}) {
	if err == nil {
		c.queue.Forget(key)
		return
	}

	if c.queue.NumRequeues(key) < maxRetries {
		klog.Warningf("Error syncing endpoint slices for service %q, retrying. Error: %v", key, err)
		c.queue.AddRateLimited(key)
		return
	}

	klog.Warningf("Retry budget exceeded, dropping service %q out of the queue: %v", key, err)
	c.queue.Forget(key)
	utilruntime.HandleError(err)
}

func (c *Controller) syncService(key string) error {
	startTime := time.Now()
	defer func() {
		klog.V(4).Infof("Finished syncing service %q endpoint slices. (%v)", key, time.Since(startTime))
	}()

	namespace, name, err := cache.SplitMetaNamespaceKey(key)
	if err != nil {
		return err
	}

	service, err := c.serviceLister.Services(namespace).Get(name)
	if err != nil {
		if apierrors.IsNotFound(err) {
			c.triggerTimeTracker.DeleteService(namespace, name)
		}
		return err
	}

	if service.Spec.Selector == nil {
		// services without a selector receive no endpoint slices from this controller;
		// these services will receive endpoint slices that are created out-of-band via the REST API.
		return nil
	}

	klog.V(5).Infof("About to update endpoint slices for service %q", key)

	podLabelSelector := labels.Set(service.Spec.Selector).AsSelectorPreValidated()
	pods, err := c.podLister.Pods(service.Namespace).List(podLabelSelector)
	if err != nil {
		// Since we're getting stuff from a local cache, it is basically
		// impossible to get this error.
		c.eventRecorder.Eventf(service, v1.EventTypeWarning, "FailedToListPods",
			"Error listing Pods for Service %s/%s: %v", service.Namespace, service.Name, err)
		return err
	}

	esLabelSelector := labels.Set(map[string]string{discovery.LabelServiceName: service.Name}).AsSelectorPreValidated()
	endpointSlices, err := c.endpointSliceLister.EndpointSlices(service.Namespace).List(esLabelSelector)

	if err != nil {
		// Since we're getting stuff from a local cache, it is basically
		// impossible to get this error.
		c.eventRecorder.Eventf(service, v1.EventTypeWarning, "FailedToListEndpointSlices",
			"Error listing Endpoint Slices for Service %s/%s: %v", service.Namespace, service.Name, err)
		return err
	}

	// We call ComputeEndpointLastChangeTriggerTime here to make sure that the
	// state of the trigger time tracker gets updated even if the sync turns out
	// to be no-op and we don't update the EndpointSlice objects.
	lastChangeTriggerTime := c.triggerTimeTracker.
		ComputeEndpointLastChangeTriggerTime(namespace, service, pods)

	err = c.reconciler.reconcile(service, pods, endpointSlices, lastChangeTriggerTime)
	if err != nil {
		c.eventRecorder.Eventf(service, v1.EventTypeWarning, "FailedToUpdateEndpointSlices",
			"Error updating Endpoint Slices for Service %s/%s: %v", service.Namespace, service.Name, err)
		return err
	}

	return nil
}

// obj could be a *v1.Service or a DeletionalFinalStateUnknown marker item
func (c *Controller) enqueueService(obj interface{}) {
	key, err := controller.KeyFunc(obj)
	if err != nil {
		utilruntime.HandleError(fmt.Errorf("Couldn't get key for object"))
		return
	}

	c.queue.Add(key)
}

func (c *Controller) addPod(obj interface{}) {
	pod := obj.(*v1.Pod)
	services, err := endpointutil.GetPodServiceMemberships(c.serviceLister, pod)
	if err != nil {
		utilruntime.HandleError(fmt.Errorf("Unable to get pod %s/%s's service memberships: %v", pod.Namespace, pod.Name, err))
		return
	}
	for key := range services {
		c.queue.Add(key)
	}
}

func (c *Controller) updatePod(old, cur interface{}) {
	services := endpointutil.GetServicesToUpdateOnPodChange(c.serviceLister, old, cur, podEndpointChanged)
	for key := range services {
		c.queue.Add(key)
	}
}

// When a pod is deleted, enqueue the services the pod used to be a member of
// obj could be an *v1.Pod, or a DeletionFinalStateUnknown marker item.
func (c *Controller) deletePod(obj interface{}) {
	pod := endpointutil.GetPodFromDeleteAction(obj)
	if pod != nil {
		c.addPod(pod)
	}
}
<commit_msg>Fix wrong comments and inaccurate logs in endpointslice_controller<commit_after>/*
Copyright 2019 The Kubernetes Authors.

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

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

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

package endpointslice

import (
	"fmt"
	"time"

	v1 "k8s.io/api/core/v1"
	discovery "k8s.io/api/discovery/v1alpha1"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/labels"
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
	"k8s.io/apimachinery/pkg/util/wait"
	coreinformers "k8s.io/client-go/informers/core/v1"
	discoveryinformers "k8s.io/client-go/informers/discovery/v1alpha1"
	clientset "k8s.io/client-go/kubernetes"
	"k8s.io/client-go/kubernetes/scheme"
	v1core "k8s.io/client-go/kubernetes/typed/core/v1"
	corelisters "k8s.io/client-go/listers/core/v1"
	discoverylisters "k8s.io/client-go/listers/discovery/v1alpha1"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/tools/record"
	"k8s.io/client-go/util/workqueue"
	"k8s.io/klog"
	"k8s.io/kubernetes/pkg/controller"
	endpointutil "k8s.io/kubernetes/pkg/controller/util/endpoint"
	"k8s.io/kubernetes/pkg/util/metrics"
)

const (
	// maxRetries is the number of times a service will be retried before it is
	// dropped out of the queue. Any sync error, such as a failure to create or
	// update an EndpointSlice could trigger a retry. With the current
	// rate-limiter in use (5ms*2^(maxRetries-1)) the following numbers
	// represent the sequence of delays between successive queuings of a
	// service.
	//
	// 5ms, 10ms, 20ms, 40ms, 80ms, 160ms, 320ms, 640ms, 1.3s, 2.6s, 5.1s,
	// 10.2s, 20.4s, 41s, 82s
	maxRetries = 15
)

// NewController creates and initializes a new Controller
func NewController(podInformer coreinformers.PodInformer,
	serviceInformer coreinformers.ServiceInformer,
	nodeInformer coreinformers.NodeInformer,
	esInformer discoveryinformers.EndpointSliceInformer,
	maxEndpointsPerSlice int32,
	client clientset.Interface,
) *Controller {
	broadcaster := record.NewBroadcaster()
	broadcaster.StartLogging(klog.Infof)
	broadcaster.StartRecordingToSink(&v1core.EventSinkImpl{Interface: client.CoreV1().Events("")})
	recorder := broadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: "endpoint-slice-controller"})

	if client != nil && client.CoreV1().RESTClient().GetRateLimiter() != nil {
		metrics.RegisterMetricAndTrackRateLimiterUsage("endpoint_slice_controller", client.DiscoveryV1alpha1().RESTClient().GetRateLimiter())
	}

	c := &Controller{
		client:           client,
		queue:            workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "endpoint_slice"),
		workerLoopPeriod: time.Second,
	}

	serviceInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
		AddFunc: c.enqueueService,
		UpdateFunc: func(old, cur interface{}) {
			c.enqueueService(cur)
		},
		DeleteFunc: c.enqueueService,
	})
	c.serviceLister = serviceInformer.Lister()
	c.servicesSynced = serviceInformer.Informer().HasSynced

	podInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
		AddFunc:    c.addPod,
		UpdateFunc: c.updatePod,
		DeleteFunc: c.deletePod,
	})
	c.podLister = podInformer.Lister()
	c.podsSynced = podInformer.Informer().HasSynced

	c.nodeLister = nodeInformer.Lister()
	c.nodesSynced = nodeInformer.Informer().HasSynced

	c.endpointSliceLister = esInformer.Lister()
	c.endpointSlicesSynced = esInformer.Informer().HasSynced

	c.maxEndpointsPerSlice = maxEndpointsPerSlice

	c.reconciler = &reconciler{
		client:               c.client,
		nodeLister:           c.nodeLister,
		maxEndpointsPerSlice: c.maxEndpointsPerSlice,
	}
	c.triggerTimeTracker = endpointutil.NewTriggerTimeTracker()

	c.eventBroadcaster = broadcaster
	c.eventRecorder = recorder

	return c
}

// Controller manages selector-based service endpoint slices
type Controller struct {
	client           clientset.Interface
	eventBroadcaster record.EventBroadcaster
	eventRecorder    record.EventRecorder

	// serviceLister is able to list/get services and is populated by the
	// shared informer passed to NewController
	serviceLister corelisters.ServiceLister
	// servicesSynced returns true if the service shared informer has been synced at least once.
	// Added as a member to the struct to allow injection for testing.
	servicesSynced cache.InformerSynced

	// podLister is able to list/get pods and is populated by the
	// shared informer passed to NewController
	podLister corelisters.PodLister
	// podsSynced returns true if the pod shared informer has been synced at least once.
	// Added as a member to the struct to allow injection for testing.
	podsSynced cache.InformerSynced

	// endpointSliceLister is able to list/get endpoint slices and is populated by the
	// shared informer passed to NewController
	endpointSliceLister discoverylisters.EndpointSliceLister
	// endpointSlicesSynced returns true if the endpoint slice shared informer has been synced at least once.
	// Added as a member to the struct to allow injection for testing.
	endpointSlicesSynced cache.InformerSynced

	// nodeLister is able to list/get nodes and is populated by the
	// shared informer passed to NewController
	nodeLister corelisters.NodeLister
	// nodesSynced returns true if the node shared informer has been synced at least once.
	// Added as a member to the struct to allow injection for testing.
	nodesSynced cache.InformerSynced

	// reconciler is an util used to reconcile EndpointSlice changes.
	reconciler *reconciler

	// triggerTimeTracker is an util used to compute and export the
	// EndpointsLastChangeTriggerTime annotation.
	triggerTimeTracker *endpointutil.TriggerTimeTracker

	// Services that need to be updated. A channel is inappropriate here,
	// because it allows services with lots of pods to be serviced much
	// more often than services with few pods; it also would cause a
	// service that's inserted multiple times to be processed more than
	// necessary.
	queue workqueue.RateLimitingInterface

	// maxEndpointsPerSlice references the maximum number of endpoints that
	// should be added to an EndpointSlice
	maxEndpointsPerSlice int32

	// workerLoopPeriod is the time between worker runs. The workers
	// process the queue of service and pod changes
	workerLoopPeriod time.Duration
}

// Run will not return until stopCh is closed.
func (c *Controller) Run(workers int, stopCh <-chan struct{}) {
	defer utilruntime.HandleCrash()
	defer c.queue.ShutDown()

	klog.Infof("Starting endpoint slice controller")
	defer klog.Infof("Shutting down endpoint slice controller")

	if !cache.WaitForNamedCacheSync("endpoint_slice", stopCh, c.podsSynced, c.servicesSynced) {
		return
	}

	for i := 0; i < workers; i++ {
		go wait.Until(c.worker, c.workerLoopPeriod, stopCh)
	}

	go func() {
		defer utilruntime.HandleCrash()
	}()

	<-stopCh
}

// worker runs a worker thread that just dequeues items, processes them, and
// marks them done. You may run as many of these in parallel as you wish; the
// workqueue guarantees that they will not end up processing the same service
// at the same time
func (c *Controller) worker() {
	for c.processNextWorkItem() {
	}
}

func (c *Controller) processNextWorkItem() bool {
	cKey, quit := c.queue.Get()
	if quit {
		return false
	}
	defer c.queue.Done(cKey)

	err := c.syncService(cKey.(string))
	c.handleErr(err, cKey)

	return true
}

func (c *Controller) handleErr(err error, key interface{}) {
	if err == nil {
		c.queue.Forget(key)
		return
	}

	if c.queue.NumRequeues(key) < maxRetries {
		klog.Warningf("Error syncing endpoint slices for service %q, retrying. Error: %v", key, err)
		c.queue.AddRateLimited(key)
		return
	}

	klog.Warningf("Retry budget exceeded, dropping service %q out of the queue: %v", key, err)
	c.queue.Forget(key)
	utilruntime.HandleError(err)
}

func (c *Controller) syncService(key string) error {
	startTime := time.Now()
	defer func() {
		klog.V(4).Infof("Finished syncing service %q endpoint slices. (%v)", key, time.Since(startTime))
	}()

	namespace, name, err := cache.SplitMetaNamespaceKey(key)
	if err != nil {
		return err
	}

	service, err := c.serviceLister.Services(namespace).Get(name)
	if err != nil {
		if apierrors.IsNotFound(err) {
			c.triggerTimeTracker.DeleteService(namespace, name)
		}
		return err
	}

	if service.Spec.Selector == nil {
		// services without a selector receive no endpoint slices from this controller;
		// these services will receive endpoint slices that are created out-of-band via the REST API.
		return nil
	}

	klog.V(5).Infof("About to update endpoint slices for service %q", key)

	podLabelSelector := labels.Set(service.Spec.Selector).AsSelectorPreValidated()
	pods, err := c.podLister.Pods(service.Namespace).List(podLabelSelector)
	if err != nil {
		// Since we're getting stuff from a local cache, it is basically
		// impossible to get this error.
		c.eventRecorder.Eventf(service, v1.EventTypeWarning, "FailedToListPods",
			"Error listing Pods for Service %s/%s: %v", service.Namespace, service.Name, err)
		return err
	}

	esLabelSelector := labels.Set(map[string]string{discovery.LabelServiceName: service.Name}).AsSelectorPreValidated()
	endpointSlices, err := c.endpointSliceLister.EndpointSlices(service.Namespace).List(esLabelSelector)

	if err != nil {
		// Since we're getting stuff from a local cache, it is basically
		// impossible to get this error.
		c.eventRecorder.Eventf(service, v1.EventTypeWarning, "FailedToListEndpointSlices",
			"Error listing Endpoint Slices for Service %s/%s: %v", service.Namespace, service.Name, err)
		return err
	}

	// We call ComputeEndpointLastChangeTriggerTime here to make sure that the
	// state of the trigger time tracker gets updated even if the sync turns out
	// to be no-op and we don't update the EndpointSlice objects.
	lastChangeTriggerTime := c.triggerTimeTracker.
		ComputeEndpointLastChangeTriggerTime(namespace, service, pods)

	err = c.reconciler.reconcile(service, pods, endpointSlices, lastChangeTriggerTime)
	if err != nil {
		c.eventRecorder.Eventf(service, v1.EventTypeWarning, "FailedToUpdateEndpointSlices",
			"Error updating Endpoint Slices for Service %s/%s: %v", service.Namespace, service.Name, err)
		return err
	}

	return nil
}

// obj could be a *v1.Service or a DeletionalFinalStateUnknown marker item
func (c *Controller) enqueueService(obj interface{}) {
	key, err := controller.KeyFunc(obj)
	if err != nil {
		utilruntime.HandleError(fmt.Errorf("Couldn't get key for object"))
		return
	}

	c.queue.Add(key)
}

func (c *Controller) addPod(obj interface{}) {
	pod := obj.(*v1.Pod)
	services, err := endpointutil.GetPodServiceMemberships(c.serviceLister, pod)
	if err != nil {
		utilruntime.HandleError(fmt.Errorf("Unable to get pod %s/%s's service memberships: %v", pod.Namespace, pod.Name, err))
		return
	}
	for key := range services {
		c.queue.Add(key)
	}
}

func (c *Controller) updatePod(old, cur interface{}) {
	services := endpointutil.GetServicesToUpdateOnPodChange(c.serviceLister, old, cur, podEndpointChanged)
	for key := range services {
		c.queue.Add(key)
	}
}

// When a pod is deleted, enqueue the services the pod used to be a member of
// obj could be an *v1.Pod, or a DeletionFinalStateUnknown marker item.
func (c *Controller) deletePod(obj interface{}) {
	pod := endpointutil.GetPodFromDeleteAction(obj)
	if pod != nil {
		c.addPod(pod)
	}
}
<|endoftext|>


<commit_before>// +build journald

/*
Copyright 2016 The Kubernetes 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 journald

import (
	"fmt"
	"os"
	"strings"
	"time"

	"github.com/coreos/go-systemd/sdjournal"
	"github.com/golang/glog"

	"k8s.io/node-problem-detector/pkg/systemlogmonitor/logwatchers/types"
	logtypes "k8s.io/node-problem-detector/pkg/systemlogmonitor/types"
	"k8s.io/node-problem-detector/pkg/systemlogmonitor/util"
)

// Compiling go-systemd/sdjournald needs libsystemd-dev or libsystemd-journal-dev,
// which is not always available on all os distros and versions.
// So we add the build tag in this file, so that on unsupported os distro, user can
// disable this build tag.

// journaldWatcher is the log watcher for journald.
type journaldWatcher struct {
	journal *sdjournal.Journal
	cfg     types.WatcherConfig
	logCh   chan *logtypes.Log
	tomb    *util.Tomb
}

// NewJournaldWatcher is the create function of journald watcher.
func NewJournaldWatcher(cfg types.WatcherConfig) types.LogWatcher {
	return &journaldWatcher{
		cfg:  cfg,
		tomb: util.NewTomb(),
		// A capacity 1000 buffer should be enough
		logCh: make(chan *logtypes.Log, 1000),
	}
}

// Make sure NewJournaldWatcher is types.WatcherCreateFunc .
var _ types.WatcherCreateFunc = NewJournaldWatcher

// Watch starts the journal watcher.
func (j *journaldWatcher) Watch() (<-chan *logtypes.Log, error) {
	journal, err := getJournal(j.cfg)
	if err != nil {
		return nil, err
	}
	j.journal = journal
	glog.Info("Start watching journald")
	go j.watchLoop()
	return j.logCh, nil
}

// Stop stops the journald watcher.
func (j *journaldWatcher) Stop() {
	j.tomb.Stop()
}

// waitLogTimeout is the timeout waiting for new log.
const waitLogTimeout = 5 * time.Second

// watchLoop is the main watch loop of journald watcher.
func (j *journaldWatcher) watchLoop() {
	defer func() {
		if err := j.journal.Close(); err != nil {
			glog.Errorf("Failed to close journal client: %v", err)
		}
		j.tomb.Done()
	}()
	for {
		select {
		case <-j.tomb.Stopping():
			glog.Infof("Stop watching journald")
			return
		default:
		}
		// Get next log entry.
		n, err := j.journal.Next()
		if err != nil {
			glog.Errorf("Failed to get next journal entry: %v", err)
			continue
		}
		// If next reaches the end, wait for waitLogTimeout.
		if n == 0 {
			j.journal.Wait(waitLogTimeout)
			continue
		}

		entry, err := j.journal.GetEntry()
		if err != nil {
			glog.Errorf("failed to get journal entry: %v", err)
			continue
		}

		j.logCh <- translate(entry)
	}
}

const (
	// defaultJournalLogPath is the default path of journal log.
	defaultJournalLogPath = "/var/log/journal"

	// configSourceKey is the key of source configuration in the plugin configuration.
	configSourceKey = "source"
)

// getJournal returns a journal client.
func getJournal(cfg types.WatcherConfig) (*sdjournal.Journal, error) {
	// Get journal log path.
	path := defaultJournalLogPath
	if cfg.LogPath != "" {
		path = cfg.LogPath
	}
	// Get lookback duration.
	since, err := time.ParseDuration(cfg.Lookback)
	if err != nil {
		return nil, fmt.Errorf("failed to parse lookback duration %q: %v", cfg.Lookback, err)
	}
	// If the path doesn't present, NewJournalFromDir will create it instead of
	// returning error. So check the path existence ourselves.
	if _, err := os.Stat(path); err != nil {
		return nil, fmt.Errorf("failed to stat the log path %q: %v", path, err)
	}
	// Get journal client from the log path.
	journal, err := sdjournal.NewJournalFromDir(path)
	if err != nil {
		return nil, fmt.Errorf("failed to create journal client from path %q: %v", path, err)
	}
	// Seek journal client based on the lookback duration.
	start := time.Now().Add(-since)
	err = journal.SeekRealtimeUsec(uint64(start.UnixNano() / 1000))
	if err != nil {
		return nil, fmt.Errorf("failed to lookback %q: %v", since, err)
	}
	// Empty source is not allowed and treated as an error.
	source := cfg.PluginConfig[configSourceKey]
	if source == "" {
		return nil, fmt.Errorf("failed to filter journal log, empty source is not allowed")
	}
	match := sdjournal.Match{
		Field: sdjournal.SD_JOURNAL_FIELD_SYSLOG_IDENTIFIER,
		Value: source,
	}
	err = journal.AddMatch(match.String())
	if err != nil {
		return nil, fmt.Errorf("failed to add log filter %#v: %v", match, err)
	}
	return journal, nil
}

// translate translates journal entry into internal type.
func translate(entry *sdjournal.JournalEntry) *logtypes.Log {
	timestamp := time.Unix(0, int64(time.Duration(entry.RealtimeTimestamp)*time.Microsecond))
	message := strings.TrimSpace(entry.Fields["MESSAGE"])
	return &logtypes.Log{
		Timestamp: timestamp,
		Message:   message,
	}
}
<commit_msg>Fix journald plugin to only look at the current boot.<commit_after>// +build journald

/*
Copyright 2016 The Kubernetes 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 journald

import (
	"fmt"
	"os"
	"strings"
	"syscall"
	"time"

	"github.com/coreos/go-systemd/sdjournal"
	"github.com/golang/glog"

	"k8s.io/node-problem-detector/pkg/systemlogmonitor/logwatchers/types"
	logtypes "k8s.io/node-problem-detector/pkg/systemlogmonitor/types"
	"k8s.io/node-problem-detector/pkg/systemlogmonitor/util"
)

// Compiling go-systemd/sdjournald needs libsystemd-dev or libsystemd-journal-dev,
// which is not always available on all os distros and versions.
// So we add the build tag in this file, so that on unsupported os distro, user can
// disable this build tag.

// journaldWatcher is the log watcher for journald.
type journaldWatcher struct {
	journal *sdjournal.Journal
	cfg     types.WatcherConfig
	logCh   chan *logtypes.Log
	tomb    *util.Tomb
}

// NewJournaldWatcher is the create function of journald watcher.
func NewJournaldWatcher(cfg types.WatcherConfig) types.LogWatcher {
	return &journaldWatcher{
		cfg:  cfg,
		tomb: util.NewTomb(),
		// A capacity 1000 buffer should be enough
		logCh: make(chan *logtypes.Log, 1000),
	}
}

// Make sure NewJournaldWatcher is types.WatcherCreateFunc .
var _ types.WatcherCreateFunc = NewJournaldWatcher

// Watch starts the journal watcher.
func (j *journaldWatcher) Watch() (<-chan *logtypes.Log, error) {
	journal, err := getJournal(j.cfg)
	if err != nil {
		return nil, err
	}
	j.journal = journal
	glog.Info("Start watching journald")
	go j.watchLoop()
	return j.logCh, nil
}

// Stop stops the journald watcher.
func (j *journaldWatcher) Stop() {
	j.tomb.Stop()
}

// waitLogTimeout is the timeout waiting for new log.
const waitLogTimeout = 5 * time.Second

// watchLoop is the main watch loop of journald watcher.
func (j *journaldWatcher) watchLoop() {
	defer func() {
		if err := j.journal.Close(); err != nil {
			glog.Errorf("Failed to close journal client: %v", err)
		}
		j.tomb.Done()
	}()
	for {
		select {
		case <-j.tomb.Stopping():
			glog.Infof("Stop watching journald")
			return
		default:
		}
		// Get next log entry.
		n, err := j.journal.Next()
		if err != nil {
			glog.Errorf("Failed to get next journal entry: %v", err)
			continue
		}
		// If next reaches the end, wait for waitLogTimeout.
		if n == 0 {
			j.journal.Wait(waitLogTimeout)
			continue
		}

		entry, err := j.journal.GetEntry()
		if err != nil {
			glog.Errorf("failed to get journal entry: %v", err)
			continue
		}

		j.logCh <- translate(entry)
	}
}

const (
	// defaultJournalLogPath is the default path of journal log.
	defaultJournalLogPath = "/var/log/journal"

	// configSourceKey is the key of source configuration in the plugin configuration.
	configSourceKey = "source"
)

// getJournal returns a journal client.
func getJournal(cfg types.WatcherConfig) (*sdjournal.Journal, error) {
	// Get journal log path.
	path := defaultJournalLogPath
	if cfg.LogPath != "" {
		path = cfg.LogPath
	}
	// Get lookback duration.
	lookback, err := time.ParseDuration(cfg.Lookback)
	if err != nil {
		return nil, fmt.Errorf("failed to parse lookback duration %q: %v", cfg.Lookback, err)
	}
	// If the path doesn't present, NewJournalFromDir will create it instead of
	// returning error. So check the path existence ourselves.
	if _, err := os.Stat(path); err != nil {
		return nil, fmt.Errorf("failed to stat the log path %q: %v", path, err)
	}
	// Get journal client from the log path.
	journal, err := sdjournal.NewJournalFromDir(path)
	if err != nil {
		return nil, fmt.Errorf("failed to create journal client from path %q: %v", path, err)
	}
	// Use system uptime if lookback duration is longer than it.
	// Ideally, we should use monotonic timestamp + boot id in journald. However, it doesn't seem
	// to work with go-system/journal package.
	// TODO(random-liu): Use monotonic timestamp + boot id.
	var info syscall.Sysinfo_t
	if err := syscall.Sysinfo(&info); err != nil {
		return nil, fmt.Errorf("failed to get system info: %v", err)
	}
	uptime := time.Duration(info.Uptime) * time.Second
	if lookback > uptime {
		lookback = uptime
		glog.Infof("Lookback changed to system uptime: %v", lookback)
	}
	// Seek journal client based on the lookback duration.
	start := time.Now().Add(-lookback)
	err = journal.SeekRealtimeUsec(uint64(start.UnixNano() / 1000))
	if err != nil {
		return nil, fmt.Errorf("failed to lookback %q: %v", lookback, err)
	}
	// Empty source is not allowed and treated as an error.
	source := cfg.PluginConfig[configSourceKey]
	if source == "" {
		return nil, fmt.Errorf("failed to filter journal log, empty source is not allowed")
	}
	match := sdjournal.Match{
		Field: sdjournal.SD_JOURNAL_FIELD_SYSLOG_IDENTIFIER,
		Value: source,
	}
	err = journal.AddMatch(match.String())
	if err != nil {
		return nil, fmt.Errorf("failed to add log filter %#v: %v", match, err)
	}
	return journal, nil
}

// translate translates journal entry into internal type.
func translate(entry *sdjournal.JournalEntry) *logtypes.Log {
	timestamp := time.Unix(0, int64(time.Duration(entry.RealtimeTimestamp)*time.Microsecond))
	message := strings.TrimSpace(entry.Fields["MESSAGE"])
	return &logtypes.Log{
		Timestamp: timestamp,
		Message:   message,
	}
}
<|endoftext|>