<commit_before>// Copyright 2016 CNI 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.

// This is a "meta-plugin". It reads in its own netconf, it does not create
// any network interface but just changes the network sysctl.

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"path/filepath"
	"strings"

	"github.com/vishvananda/netlink"

	"github.com/containernetworking/cni/pkg/skel"
	"github.com/containernetworking/cni/pkg/types"
	"github.com/containernetworking/cni/pkg/types/current"
	"github.com/containernetworking/cni/pkg/version"

	"github.com/containernetworking/plugins/pkg/ns"
	bv "github.com/containernetworking/plugins/pkg/utils/buildversion"
)

// TuningConf represents the network tuning configuration.
type TuningConf struct {
	types.NetConf
	SysCtl  map[string]string `json:"sysctl"`
	Mac     string            `json:"mac,omitempty"`
	Promisc bool              `json:"promisc,omitempty"`
	Mtu     int               `json:"mtu,omitempty"`

	RuntimeConfig struct {
		Mac string `json:"mac,omitempty"`
	} `json:"runtimeConfig,omitempty"`
}

// MacEnvArgs represents CNI_ARG
type MacEnvArgs struct {
	types.CommonArgs
	MAC types.UnmarshallableString `json:"mac,omitempty"`
}

func parseConf(data []byte, envArgs string) (*TuningConf, error) {
	conf := TuningConf{Promisc: false}
	if err := json.Unmarshal(data, &conf); err != nil {
		return nil, fmt.Errorf("failed to load netconf: %v", err)
	}

	// Parse custom Mac from both env args
	if envArgs != "" {
		e := MacEnvArgs{}
		err := types.LoadArgs(envArgs, &e)
		if err != nil {
			return nil, err
		}

		if e.MAC != "" {
			conf.Mac = string(e.MAC)
		}
	}

	// Parse custom Mac from RuntimeConfig
	if conf.RuntimeConfig.Mac != "" {
		conf.Mac = conf.RuntimeConfig.Mac
	}

	return &conf, nil
}

func changeMacAddr(ifName string, newMacAddr string) error {
	addr, err := net.ParseMAC(newMacAddr)
	if err != nil {
		return fmt.Errorf("invalid args %v for MAC addr: %v", newMacAddr, err)
	}

	link, err := netlink.LinkByName(ifName)
	if err != nil {
		return fmt.Errorf("failed to get %q: %v", ifName, err)
	}

	err = netlink.LinkSetDown(link)
	if err != nil {
		return fmt.Errorf("failed to set %q down: %v", ifName, err)
	}
	err = netlink.LinkSetHardwareAddr(link, addr)
	if err != nil {
		return fmt.Errorf("failed to set %q address to %q: %v", ifName, newMacAddr, err)
	}
	return netlink.LinkSetUp(link)
}

func updateResultsMacAddr(config TuningConf, ifName string, newMacAddr string) {
	// Parse previous result.
	if config.PrevResult == nil {
		return
	}

	version.ParsePrevResult(&config.NetConf)
	result, _ := current.NewResultFromResult(config.PrevResult)

	for _, i := range result.Interfaces {
		if i.Name == ifName {
			i.Mac = newMacAddr
		}
	}
}

func changePromisc(ifName string, val bool) error {
	link, err := netlink.LinkByName(ifName)
	if err != nil {
		return fmt.Errorf("failed to get %q: %v", ifName, err)
	}

	if val {
		return netlink.SetPromiscOn(link)
	}
	return netlink.SetPromiscOff(link)
}

func changeMtu(ifName string, mtu int) error {
	link, err := netlink.LinkByName(ifName)
	if err != nil {
		return fmt.Errorf("failed to get %q: %v", ifName, err)
	}
	return netlink.LinkSetMTU(link, mtu)
}

func cmdAdd(args *skel.CmdArgs) error {
	tuningConf, err := parseConf(args.StdinData, args.Args)
	if err != nil {
		return err
	}

	// Parse previous result.
	if tuningConf.RawPrevResult == nil {
		return fmt.Errorf("Required prevResult missing")
	}

	if err := version.ParsePrevResult(&tuningConf.NetConf); err != nil {
		return err
	}

	_, err = current.NewResultFromResult(tuningConf.PrevResult)
	if err != nil {
		return err
	}

	// The directory /proc/sys/net is per network namespace. Enter in the
	// network namespace before writing on it.

	err = ns.WithNetNSPath(args.Netns, func(_ ns.NetNS) error {
		for key, value := range tuningConf.SysCtl {
			fileName := filepath.Join("/proc/sys", strings.Replace(key, ".", "/", -1))
			fileName = filepath.Clean(fileName)

			// Refuse to modify sysctl parameters that don't belong
			// to the network subsystem.
			if !strings.HasPrefix(fileName, "/proc/sys/net/") {
				return fmt.Errorf("invalid net sysctl key: %q", key)
			}
			content := []byte(value)
			err := ioutil.WriteFile(fileName, content, 0644)
			if err != nil {
				return err
			}
		}

		if tuningConf.Mac != "" {
			if err = changeMacAddr(args.IfName, tuningConf.Mac); err != nil {
				return err
			}
			updateResultsMacAddr(*tuningConf, args.IfName, tuningConf.Mac)
		}

		if tuningConf.Promisc != false {
			if err = changePromisc(args.IfName, true); err != nil {
				return err
			}
		}

		if tuningConf.Mtu != 0 {
			if err = changeMtu(args.IfName, tuningConf.Mtu); err != nil {
				return err
			}
		}
		return nil
	})
	if err != nil {
		return err
	}

	return types.PrintResult(tuningConf.PrevResult, tuningConf.CNIVersion)
}

func cmdDel(args *skel.CmdArgs) error {
	// TODO: the settings are not reverted to the previous values. Reverting the
	// settings is not useful when the whole container goes away but it could be
	// useful in scenarios where plugins are added and removed at runtime.
	return nil
}

func main() {
	skel.PluginMain(cmdAdd, cmdCheck, cmdDel, version.All, bv.BuildString("tuning"))
}

func cmdCheck(args *skel.CmdArgs) error {
	tuningConf, err := parseConf(args.StdinData, args.Args)
	if err != nil {
		return err
	}

	// Parse previous result.
	if tuningConf.RawPrevResult == nil {
		return fmt.Errorf("Required prevResult missing")
	}

	if err := version.ParsePrevResult(&tuningConf.NetConf); err != nil {
		return err
	}

	_, err = current.NewResultFromResult(tuningConf.PrevResult)
	if err != nil {
		return err
	}

	err = ns.WithNetNSPath(args.Netns, func(_ ns.NetNS) error {
		// Check each configured value vs what's currently in the container
		for key, confValue := range tuningConf.SysCtl {
			fileName := filepath.Join("/proc/sys", strings.Replace(key, ".", "/", -1))
			fileName = filepath.Clean(fileName)

			contents, err := ioutil.ReadFile(fileName)
			if err != nil {
				return err
			}
			curValue := strings.TrimSuffix(string(contents), "\n")
			if confValue != curValue {
				return fmt.Errorf("Error: Tuning configured value of %s is %s, current value is %s", fileName, confValue, curValue)
			}
		}

		link, err := netlink.LinkByName(args.IfName)
		if err != nil {
			return fmt.Errorf("Cannot find container link %v", args.IfName)
		}

		if tuningConf.Mac != "" {
			if tuningConf.Mac != link.Attrs().HardwareAddr.String() {
				return fmt.Errorf("Error: Tuning configured Ethernet of %s is %s, current value is %s",
					args.IfName, tuningConf.Mac, link.Attrs().HardwareAddr)
			}
		}

		if tuningConf.Promisc {
			if link.Attrs().Promisc == 0 {
				return fmt.Errorf("Error: Tuning link %s configured promisc is %v, current value is %d",
					args.IfName, tuningConf.Promisc, link.Attrs().Promisc)
			}
		} else {
			if link.Attrs().Promisc != 0 {
				return fmt.Errorf("Error: Tuning link %s configured promisc is %v, current value is %d",
					args.IfName, tuningConf.Promisc, link.Attrs().Promisc)
			}
		}

		if tuningConf.Mtu != 0 {
			if tuningConf.Mtu != link.Attrs().MTU {
				return fmt.Errorf("Error: Tuning configured MTU of %s is %d, current value is %d",
					args.IfName, tuningConf.Mtu, link.Attrs().MTU)
			}
		}
		return nil
	})
	if err != nil {
		return err
	}

	return nil
}
<commit_msg>Remove link Down/Up in MAC address change to prevent route flush<commit_after>// Copyright 2016 CNI 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.

// This is a "meta-plugin". It reads in its own netconf, it does not create
// any network interface but just changes the network sysctl.

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"path/filepath"
	"strings"

	"github.com/vishvananda/netlink"

	"github.com/containernetworking/cni/pkg/skel"
	"github.com/containernetworking/cni/pkg/types"
	"github.com/containernetworking/cni/pkg/types/current"
	"github.com/containernetworking/cni/pkg/version"

	"github.com/containernetworking/plugins/pkg/ns"
	bv "github.com/containernetworking/plugins/pkg/utils/buildversion"
)

// TuningConf represents the network tuning configuration.
type TuningConf struct {
	types.NetConf
	SysCtl  map[string]string `json:"sysctl"`
	Mac     string            `json:"mac,omitempty"`
	Promisc bool              `json:"promisc,omitempty"`
	Mtu     int               `json:"mtu,omitempty"`

	RuntimeConfig struct {
		Mac string `json:"mac,omitempty"`
	} `json:"runtimeConfig,omitempty"`
}

// MacEnvArgs represents CNI_ARG
type MacEnvArgs struct {
	types.CommonArgs
	MAC types.UnmarshallableString `json:"mac,omitempty"`
}

func parseConf(data []byte, envArgs string) (*TuningConf, error) {
	conf := TuningConf{Promisc: false}
	if err := json.Unmarshal(data, &conf); err != nil {
		return nil, fmt.Errorf("failed to load netconf: %v", err)
	}

	// Parse custom Mac from both env args
	if envArgs != "" {
		e := MacEnvArgs{}
		err := types.LoadArgs(envArgs, &e)
		if err != nil {
			return nil, err
		}

		if e.MAC != "" {
			conf.Mac = string(e.MAC)
		}
	}

	// Parse custom Mac from RuntimeConfig
	if conf.RuntimeConfig.Mac != "" {
		conf.Mac = conf.RuntimeConfig.Mac
	}

	return &conf, nil
}

func changeMacAddr(ifName string, newMacAddr string) error {
	addr, err := net.ParseMAC(newMacAddr)
	if err != nil {
		return fmt.Errorf("invalid args %v for MAC addr: %v", newMacAddr, err)
	}

	link, err := netlink.LinkByName(ifName)
	if err != nil {
		return fmt.Errorf("failed to get %q: %v", ifName, err)
	}

	return netlink.LinkSetHardwareAddr(link, addr)
}

func updateResultsMacAddr(config TuningConf, ifName string, newMacAddr string) {
	// Parse previous result.
	if config.PrevResult == nil {
		return
	}

	version.ParsePrevResult(&config.NetConf)
	result, _ := current.NewResultFromResult(config.PrevResult)

	for _, i := range result.Interfaces {
		if i.Name == ifName {
			i.Mac = newMacAddr
		}
	}
}

func changePromisc(ifName string, val bool) error {
	link, err := netlink.LinkByName(ifName)
	if err != nil {
		return fmt.Errorf("failed to get %q: %v", ifName, err)
	}

	if val {
		return netlink.SetPromiscOn(link)
	}
	return netlink.SetPromiscOff(link)
}

func changeMtu(ifName string, mtu int) error {
	link, err := netlink.LinkByName(ifName)
	if err != nil {
		return fmt.Errorf("failed to get %q: %v", ifName, err)
	}
	return netlink.LinkSetMTU(link, mtu)
}

func cmdAdd(args *skel.CmdArgs) error {
	tuningConf, err := parseConf(args.StdinData, args.Args)
	if err != nil {
		return err
	}

	// Parse previous result.
	if tuningConf.RawPrevResult == nil {
		return fmt.Errorf("Required prevResult missing")
	}

	if err := version.ParsePrevResult(&tuningConf.NetConf); err != nil {
		return err
	}

	_, err = current.NewResultFromResult(tuningConf.PrevResult)
	if err != nil {
		return err
	}

	// The directory /proc/sys/net is per network namespace. Enter in the
	// network namespace before writing on it.

	err = ns.WithNetNSPath(args.Netns, func(_ ns.NetNS) error {
		for key, value := range tuningConf.SysCtl {
			fileName := filepath.Join("/proc/sys", strings.Replace(key, ".", "/", -1))
			fileName = filepath.Clean(fileName)

			// Refuse to modify sysctl parameters that don't belong
			// to the network subsystem.
			if !strings.HasPrefix(fileName, "/proc/sys/net/") {
				return fmt.Errorf("invalid net sysctl key: %q", key)
			}
			content := []byte(value)
			err := ioutil.WriteFile(fileName, content, 0644)
			if err != nil {
				return err
			}
		}

		if tuningConf.Mac != "" {
			if err = changeMacAddr(args.IfName, tuningConf.Mac); err != nil {
				return err
			}
			updateResultsMacAddr(*tuningConf, args.IfName, tuningConf.Mac)
		}

		if tuningConf.Promisc != false {
			if err = changePromisc(args.IfName, true); err != nil {
				return err
			}
		}

		if tuningConf.Mtu != 0 {
			if err = changeMtu(args.IfName, tuningConf.Mtu); err != nil {
				return err
			}
		}
		return nil
	})
	if err != nil {
		return err
	}

	return types.PrintResult(tuningConf.PrevResult, tuningConf.CNIVersion)
}

func cmdDel(args *skel.CmdArgs) error {
	// TODO: the settings are not reverted to the previous values. Reverting the
	// settings is not useful when the whole container goes away but it could be
	// useful in scenarios where plugins are added and removed at runtime.
	return nil
}

func main() {
	skel.PluginMain(cmdAdd, cmdCheck, cmdDel, version.All, bv.BuildString("tuning"))
}

func cmdCheck(args *skel.CmdArgs) error {
	tuningConf, err := parseConf(args.StdinData, args.Args)
	if err != nil {
		return err
	}

	// Parse previous result.
	if tuningConf.RawPrevResult == nil {
		return fmt.Errorf("Required prevResult missing")
	}

	if err := version.ParsePrevResult(&tuningConf.NetConf); err != nil {
		return err
	}

	_, err = current.NewResultFromResult(tuningConf.PrevResult)
	if err != nil {
		return err
	}

	err = ns.WithNetNSPath(args.Netns, func(_ ns.NetNS) error {
		// Check each configured value vs what's currently in the container
		for key, confValue := range tuningConf.SysCtl {
			fileName := filepath.Join("/proc/sys", strings.Replace(key, ".", "/", -1))
			fileName = filepath.Clean(fileName)

			contents, err := ioutil.ReadFile(fileName)
			if err != nil {
				return err
			}
			curValue := strings.TrimSuffix(string(contents), "\n")
			if confValue != curValue {
				return fmt.Errorf("Error: Tuning configured value of %s is %s, current value is %s", fileName, confValue, curValue)
			}
		}

		link, err := netlink.LinkByName(args.IfName)
		if err != nil {
			return fmt.Errorf("Cannot find container link %v", args.IfName)
		}

		if tuningConf.Mac != "" {
			if tuningConf.Mac != link.Attrs().HardwareAddr.String() {
				return fmt.Errorf("Error: Tuning configured Ethernet of %s is %s, current value is %s",
					args.IfName, tuningConf.Mac, link.Attrs().HardwareAddr)
			}
		}

		if tuningConf.Promisc {
			if link.Attrs().Promisc == 0 {
				return fmt.Errorf("Error: Tuning link %s configured promisc is %v, current value is %d",
					args.IfName, tuningConf.Promisc, link.Attrs().Promisc)
			}
		} else {
			if link.Attrs().Promisc != 0 {
				return fmt.Errorf("Error: Tuning link %s configured promisc is %v, current value is %d",
					args.IfName, tuningConf.Promisc, link.Attrs().Promisc)
			}
		}

		if tuningConf.Mtu != 0 {
			if tuningConf.Mtu != link.Attrs().MTU {
				return fmt.Errorf("Error: Tuning configured MTU of %s is %d, current value is %d",
					args.IfName, tuningConf.Mtu, link.Attrs().MTU)
			}
		}
		return nil
	})
	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package fusefrontend_reverse

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

	"github.com/hanwen/go-fuse/fuse"
	"github.com/hanwen/go-fuse/fuse/nodefs"
	"github.com/hanwen/go-fuse/fuse/pathfs"

	"github.com/rfjakob/gocryptfs/internal/configfile"
	"github.com/rfjakob/gocryptfs/internal/contentenc"
	"github.com/rfjakob/gocryptfs/internal/cryptocore"
	"github.com/rfjakob/gocryptfs/internal/fusefrontend"
	"github.com/rfjakob/gocryptfs/internal/nametransform"
)

const (
	DirIVMode = syscall.S_IFREG | 0400
)

type reverseFS struct {
	// Embed pathfs.defaultFileSystem for a ENOSYS implementation of all methods
	pathfs.FileSystem
	// pathfs.loopbackFileSystem, see go-fuse/fuse/pathfs/loopback.go
	loopbackfs pathfs.FileSystem
	// Stores configuration arguments
	args fusefrontend.Args
	// Filename encryption helper
	nameTransform *nametransform.NameTransform
	// Content encryption helper
	contentEnc *contentenc.ContentEnc
}

// Encrypted FUSE overlay filesystem
func NewFS(args fusefrontend.Args) *reverseFS {
	cryptoCore := cryptocore.New(args.Masterkey, args.OpenSSL, true)
	contentEnc := contentenc.New(cryptoCore, contentenc.DefaultBS)
	nameTransform := nametransform.New(cryptoCore, args.LongNames)

	return &reverseFS{
		// pathfs.defaultFileSystem returns ENOSYS for all operations
		FileSystem:    pathfs.NewDefaultFileSystem(),
		loopbackfs:    pathfs.NewLoopbackFileSystem(args.Cipherdir),
		args:          args,
		nameTransform: nameTransform,
		contentEnc:    contentEnc,
	}
}

// relDir is identical to filepath.Dir excepts that it returns "" when
// filepath.Dir would return ".".
// In the FUSE API, the root directory is called "", and we actually want that.
func relDir(path string) string {
	dir := filepath.Dir(path)
	if dir == "." {
		return ""
	}
	return dir
}

// dirIVAttr handles GetAttr requests for the virtual gocryptfs.diriv files.
func (rfs *reverseFS) dirIVAttr(relPath string, context *fuse.Context) (*fuse.Attr, fuse.Status) {
	cDir := relDir(relPath)
	dir, err := rfs.decryptPath(cDir)
	if err != nil {
		fmt.Printf("decrypt err %q\n", cDir)
		return nil, fuse.ToStatus(err)
	}
	// Does the parent dir exist?
	a, status := rfs.loopbackfs.GetAttr(dir, context)
	if !status.Ok() {
		fmt.Printf("missing parent\n")
		return nil, status
	}
	// Is it a dir at all?
	if !a.IsDir() {
		fmt.Printf("not isdir\n")
		return nil, fuse.ENOTDIR
	}
	// Does the user have execute permissions?
	if a.Mode&syscall.S_IXUSR == 0 {
		fmt.Printf("not exec")
		return nil, fuse.EPERM
	}
	// All good. Let's fake the file.
	// We use the inode number of the parent dir (can this cause problems?).
	a.Mode = DirIVMode
	a.Size = nametransform.DirIVLen
	a.Nlink = 1

	return a, fuse.OK
}

// isDirIV determines if the path points to a gocryptfs.diriv file
func isDirIV(relPath string) bool {
	return filepath.Base(relPath) == nametransform.DirIVFilename
}

// GetAttr - FUSE call
func (rfs *reverseFS) GetAttr(relPath string, context *fuse.Context) (*fuse.Attr, fuse.Status) {
	if isDirIV(relPath) {
		return rfs.dirIVAttr(relPath, context)
	}
	if rfs.isFiltered(relPath) {
		return nil, fuse.EPERM
	}
	relPath, err := rfs.decryptPath(relPath)
	if err != nil {
		return nil, fuse.ToStatus(err)
	}
	a, status := rfs.loopbackfs.GetAttr(relPath, context)
	if !status.Ok() {
		return nil, status
	}
	// Calculate encrypted file size
	if a.IsRegular() {
		a.Size = rfs.contentEnc.PlainSizeToCipherSize(a.Size)
	}
	return a, fuse.OK
}

// Access - FUSE call
func (rfs *reverseFS) Access(relPath string, mode uint32, context *fuse.Context) fuse.Status {
	if isDirIV(relPath) {
		return fuse.OK
	}
	if rfs.isFiltered(relPath) {
		return fuse.EPERM
	}
	absPath, err := rfs.abs(rfs.decryptPath(relPath))
	if err != nil {
		return fuse.ToStatus(err)
	}
	return fuse.ToStatus(syscall.Access(absPath, mode))
}

// Open - FUSE call
func (rfs *reverseFS) Open(relPath string, flags uint32, context *fuse.Context) (fuseFile nodefs.File, status fuse.Status) {
	if relPath == configfile.ConfDefaultName {
		// gocryptfs.conf maps to .gocryptfs.reverse.conf in the plaintext directory
		return rfs.loopbackfs.Open(configfile.ConfReverseName, flags, context)
	}
	if isDirIV(relPath) {
		return NewDirIVFile(relDir(relPath))
	}
	if rfs.isFiltered(relPath) {
		return nil, fuse.EPERM
	}
	absPath, err := rfs.abs(rfs.decryptPath(relPath))
	if err != nil {
		return nil, fuse.ToStatus(err)
	}
	f, err := os.OpenFile(absPath, int(flags), 0666)
	if err != nil {
		return nil, fuse.ToStatus(err)
	}
	return NewFile(f, rfs.contentEnc)
}

// OpenDir - FUSE readdir call
func (rfs *reverseFS) OpenDir(cipherPath string, context *fuse.Context) ([]fuse.DirEntry, fuse.Status) {
	relPath, err := rfs.decryptPath(cipherPath)
	if err != nil {
		return nil, fuse.ToStatus(err)
	}
	// Read plaintext dir
	entries, status := rfs.loopbackfs.OpenDir(relPath, context)
	if entries == nil {
		return nil, status
	}
	// Encrypt names
	dirIV := deriveDirIV(cipherPath)
	for i := range entries {
		entries[i].Name = rfs.nameTransform.EncryptName(entries[i].Name, dirIV)
	}
	// Add virtual gocryptfs.diriv
	entries = append(entries, fuse.DirEntry{syscall.S_IFREG | 0400, nametransform.DirIVFilename})
	// Add gocryptfs.conf in the root directory,
	// maps to .gocryptfs.reverse.conf in the plaintext directory.
	if cipherPath == "" {
		_, err = os.Stat(filepath.Join(rfs.args.Cipherdir, configfile.ConfReverseName))
		if err == nil {
			entries = append(entries, fuse.DirEntry{syscall.S_IFREG | 0400, configfile.ConfDefaultName})
		}
	}

	return entries, fuse.OK
}
<commit_msg>reverse: fix GetAttr for gocryptfs.conf<commit_after>package fusefrontend_reverse

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

	"github.com/hanwen/go-fuse/fuse"
	"github.com/hanwen/go-fuse/fuse/nodefs"
	"github.com/hanwen/go-fuse/fuse/pathfs"

	"github.com/rfjakob/gocryptfs/internal/configfile"
	"github.com/rfjakob/gocryptfs/internal/contentenc"
	"github.com/rfjakob/gocryptfs/internal/cryptocore"
	"github.com/rfjakob/gocryptfs/internal/fusefrontend"
	"github.com/rfjakob/gocryptfs/internal/nametransform"
)

const (
	DirIVMode = syscall.S_IFREG | 0400
)

type reverseFS struct {
	// Embed pathfs.defaultFileSystem for a ENOSYS implementation of all methods
	pathfs.FileSystem
	// pathfs.loopbackFileSystem, see go-fuse/fuse/pathfs/loopback.go
	loopbackfs pathfs.FileSystem
	// Stores configuration arguments
	args fusefrontend.Args
	// Filename encryption helper
	nameTransform *nametransform.NameTransform
	// Content encryption helper
	contentEnc *contentenc.ContentEnc
}

// Encrypted FUSE overlay filesystem
func NewFS(args fusefrontend.Args) *reverseFS {
	cryptoCore := cryptocore.New(args.Masterkey, args.OpenSSL, true)
	contentEnc := contentenc.New(cryptoCore, contentenc.DefaultBS)
	nameTransform := nametransform.New(cryptoCore, args.LongNames)

	return &reverseFS{
		// pathfs.defaultFileSystem returns ENOSYS for all operations
		FileSystem:    pathfs.NewDefaultFileSystem(),
		loopbackfs:    pathfs.NewLoopbackFileSystem(args.Cipherdir),
		args:          args,
		nameTransform: nameTransform,
		contentEnc:    contentEnc,
	}
}

// relDir is identical to filepath.Dir excepts that it returns "" when
// filepath.Dir would return ".".
// In the FUSE API, the root directory is called "", and we actually want that.
func relDir(path string) string {
	dir := filepath.Dir(path)
	if dir == "." {
		return ""
	}
	return dir
}

// dirIVAttr handles GetAttr requests for the virtual gocryptfs.diriv files.
func (rfs *reverseFS) dirIVAttr(relPath string, context *fuse.Context) (*fuse.Attr, fuse.Status) {
	cDir := relDir(relPath)
	dir, err := rfs.decryptPath(cDir)
	if err != nil {
		fmt.Printf("decrypt err %q\n", cDir)
		return nil, fuse.ToStatus(err)
	}
	// Does the parent dir exist?
	a, status := rfs.loopbackfs.GetAttr(dir, context)
	if !status.Ok() {
		fmt.Printf("missing parent\n")
		return nil, status
	}
	// Is it a dir at all?
	if !a.IsDir() {
		fmt.Printf("not isdir\n")
		return nil, fuse.ENOTDIR
	}
	// Does the user have execute permissions?
	if a.Mode&syscall.S_IXUSR == 0 {
		fmt.Printf("not exec")
		return nil, fuse.EPERM
	}
	// All good. Let's fake the file.
	// We use the inode number of the parent dir (can this cause problems?).
	a.Mode = DirIVMode
	a.Size = nametransform.DirIVLen
	a.Nlink = 1

	return a, fuse.OK
}

// isDirIV determines if the path points to a gocryptfs.diriv file
func isDirIV(relPath string) bool {
	return filepath.Base(relPath) == nametransform.DirIVFilename
}

// GetAttr - FUSE call
func (rfs *reverseFS) GetAttr(relPath string, context *fuse.Context) (*fuse.Attr, fuse.Status) {
	if relPath == configfile.ConfDefaultName {
		return rfs.loopbackfs.GetAttr(configfile.ConfReverseName, context)
	}
	if isDirIV(relPath) {
		return rfs.dirIVAttr(relPath, context)
	}
	if rfs.isFiltered(relPath) {
		return nil, fuse.EPERM
	}
	relPath, err := rfs.decryptPath(relPath)
	if err != nil {
		return nil, fuse.ToStatus(err)
	}
	a, status := rfs.loopbackfs.GetAttr(relPath, context)
	if !status.Ok() {
		return nil, status
	}
	// Calculate encrypted file size
	if a.IsRegular() {
		a.Size = rfs.contentEnc.PlainSizeToCipherSize(a.Size)
	}
	return a, fuse.OK
}

// Access - FUSE call
func (rfs *reverseFS) Access(relPath string, mode uint32, context *fuse.Context) fuse.Status {
	if isDirIV(relPath) {
		return fuse.OK
	}
	if rfs.isFiltered(relPath) {
		return fuse.EPERM
	}
	absPath, err := rfs.abs(rfs.decryptPath(relPath))
	if err != nil {
		return fuse.ToStatus(err)
	}
	return fuse.ToStatus(syscall.Access(absPath, mode))
}

// Open - FUSE call
func (rfs *reverseFS) Open(relPath string, flags uint32, context *fuse.Context) (fuseFile nodefs.File, status fuse.Status) {
	if relPath == configfile.ConfDefaultName {
		// gocryptfs.conf maps to .gocryptfs.reverse.conf in the plaintext directory
		return rfs.loopbackfs.Open(configfile.ConfReverseName, flags, context)
	}
	if isDirIV(relPath) {
		return NewDirIVFile(relDir(relPath))
	}
	if rfs.isFiltered(relPath) {
		return nil, fuse.EPERM
	}
	absPath, err := rfs.abs(rfs.decryptPath(relPath))
	if err != nil {
		return nil, fuse.ToStatus(err)
	}
	f, err := os.OpenFile(absPath, int(flags), 0666)
	if err != nil {
		return nil, fuse.ToStatus(err)
	}
	return NewFile(f, rfs.contentEnc)
}

// OpenDir - FUSE readdir call
func (rfs *reverseFS) OpenDir(cipherPath string, context *fuse.Context) ([]fuse.DirEntry, fuse.Status) {
	relPath, err := rfs.decryptPath(cipherPath)
	if err != nil {
		return nil, fuse.ToStatus(err)
	}
	// Read plaintext dir
	entries, status := rfs.loopbackfs.OpenDir(relPath, context)
	if entries == nil {
		return nil, status
	}
	// Encrypt names
	dirIV := deriveDirIV(cipherPath)
	for i := range entries {
		// ".gocryptfs.reverse.conf" in the root directory is mapped to "gocryptfs.conf"
		if cipherPath == "" && entries[i].Name == configfile.ConfReverseName {
			entries[i].Name = configfile.ConfDefaultName
		} else {
			entries[i].Name = rfs.nameTransform.EncryptName(entries[i].Name, dirIV)
		}
	}
	// Add virtual gocryptfs.diriv
	entries = append(entries, fuse.DirEntry{syscall.S_IFREG | 0400, nametransform.DirIVFilename})

	return entries, fuse.OK
}
<|endoftext|>


<commit_before>package opennebula

import (
	"encoding/xml"
	"fmt"
	"github.com/hashicorp/terraform/helper/schema"
	"log"
	"net"
	"strconv"
	"strings"
)

type UserImages struct {
	UserImage []*UserImages `xml:"IMAGE"`
}

type UserImage struct {
	Name        string       `xml:"NAME"`
	Id          int          `xml:"ID"`
	Uid         int          `xml:"UID"`
	Gid         int          `xml:"GID"`
	Uname       string       `xml:"UNAME"`
	Gname       string       `xml:"GNAME"`
	Permissions *Permissions `xml:"PERMISSIONS"`
	DatastoreID int          `xml:"DATASTORE_ID"`
	Persistent  string       `xml:"PERSISTENT"`
}

func resourceImage() *schema.Resource {
	return &schema.Resource{
		Create: resourceImageCreate,
		Read:   resourceImageRead,
		Exists: resourceImageExists,
		Update: resourceImageUpdate,
		Delete: resourceImageDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"name": {
				Type:        schema.TypeString,
				Required:    true,
				Description: "Name of the Image",
			},
			"description": {
				Type:        schema.TypeString,
				Required:    true,
				Description: "Description of the Image, in OpenNebula's XML or String format",
			},
			"permissions": {
				Type:        schema.TypeString,
				Required:    true,
				Description: "Permissions for the Image (in Unix format, owner-group-other, use-manage-admin)",
				ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
					value := v.(string)

					if len(value) != 3 {
						errors = append(errors, fmt.Errorf("%q has specify 3 permission sets: owner-group-other", k))
					}

					all := true
					for _, c := range strings.Split(value, "") {
						if c < "0" || c > "7" {
							all = false
						}
					}
					if !all {
						errors = append(errors, fmt.Errorf("Each character in %q should specify a Unix-like permission set with a number from 0 to 7", k))
					}

					return
				},
			},

			"uid": {
				Type:        schema.TypeInt,
				Computed:    true,
				Description: "ID of the user that will own the Image",
			},
			"gid": {
				Type:        schema.TypeInt,
				Computed:    true,
				Description: "ID of the group that will own the Image",
			},
			"uname": {
				Type:        schema.TypeString,
				Computed:    true,
				Description: "Name of the user that will own the Image",
			},
			"gname": {
				Type:        schema.TypeString,
				Computed:    true,
				Description: "Name of the group that will own the Image",
			},
			"imageid": {
				Type:        schema.TypeInt,
				Required:    true,
				Description: "ID of the Image to be cloned from",
			},
		},
	}
}

func resourceImageCreate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*Client)
	// Create base object
	resp, err := client.Call(
		"one.image.clone",
		d.Get("imageid"),
		d.Get("name"),
		-1,
	)
	if err != nil {
		return err
	}

	d.SetId(resp)
	// update permisions
	if _, err = changePermissions(intId(d.Id()), permission(d.Get("permissions").(string)), client, "one.vn.chmod"); err != nil {
		return err
	}

	return resourceImageRead(d, meta)
}

func resourceImageRead(d *schema.ResourceData, meta interface{}) error {
	var img *UserImage
	var imgs *UserImages

	client := meta.(*Client)
	found := false

	// Try to find the Image by ID, if specified
	if d.Id() != "" {
		resp, err := client.Call("one.image.info", intId(d.Id()), false)
		if err == nil {
			found = true
			if err = xml.Unmarshal([]byte(resp), &img); err != nil {
				return err
			}
		} else {
			log.Printf("Could not find Image by ID %s", d.Id())
		}
	}

	// Otherwise, try to find the Image by (user, name) as the de facto compound primary key
	if d.Id() == "" || !found {
		resp, err := client.Call("one.imagepool.info", -3, -1, -1)
		if err != nil {
			return err
		}

		if err = xml.Unmarshal([]byte(resp), &imgs); err != nil {
			return err
		}

		for _, t := range imgs.UserImage {
			if t.Name == d.Get("name").(string) {
				img = t
				found = true
				break
			}
		}

		if !found || img == nil {
			d.SetId("")
			log.Printf("Could not find Image with name %s for user %s", d.Get("name").(string), client.Username)
			return nil
		}
	}

	d.SetId(strconv.Itoa(vn.Id))
	d.Set("name", img.Name)
	d.Set("uid", img.Uid)
	d.Set("gid", img.Gid)
	d.Set("uname", img.Uname)
	d.Set("gname", img.Gname)
	d.Set("imageid", img.Imageid)
	d.Set("permissions", permissionString(img.Permissions))

	return nil
}

func resourceImageExists(d *schema.ResourceData, meta interface{}) (bool, error) {
	err := resourceImageRead(d, meta)
	if err != nil || d.Id() == "" {
		return false, err
	}

	return true, nil
}

func resourceImageUpdate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*Client)

	if d.HasChange("description") {
		_, err := client.Call(
			"one.image.update",
			intId(d.Id()),
			d.Get("description").(string),
			0, // replace the whole image instead of merging it with the existing one
		)
		if err != nil {
			return err
		}
	}

	if d.HasChange("name") {
		resp, err := client.Call(
			"one.image.rename",
			intId(d.Id()),
			d.Get("name").(string),
		)
		if err != nil {
			return err
		}
		log.Printf("[INFO] Successfully updated name for Image %s\n", resp)
	}

	if d.HasChange("permissions") {
		resp, err := changePermissions(intId(d.Id()), permission(d.Get("permissions").(string)), client, "one.image.chmod")
		if err != nil {
			return err
		}
		log.Printf("[INFO] Successfully updated Image %s\n", resp)
	}

	return nil
}

func resourceImageDelete(d *schema.ResourceData, meta interface{}) error {
	err := resourceImageRead(d, meta)
	if err != nil || d.Id() == "" {
		return err
	}

	client := meta.(*Client)

	resp, err := client.Call("one.image.delete", intId(d.Id()), false)
	if err != nil {
		return err
	}

	log.Printf("[INFO] Successfully deleted Image %s\n", resp)
	return nil
}
<commit_msg>resource_image: adapt struct to handle more attributes of Images, fix copy & paste bugs<commit_after>package opennebula

import (
	"encoding/xml"
	"fmt"
	"github.com/hashicorp/terraform/helper/schema"
	"log"
	"strconv"
	"strings"
)

type UserImage struct {
	Name        string       `xml:"NAME"`
	Id          int          `xml:"ID"`
	Uid         int          `xml:"UID"`
	Gid         int          `xml:"GID"`
	Uname       string       `xml:"UNAME"`
	Gname       string       `xml:"GNAME"`
	Permissions *Permissions `xml:"PERMISSIONS"`
	RegTime     string       `xml:"REG"`
	Size        int          `xml:"SIZE"`
	State       int          `xml:"STATE"`
	Source      string       `xml:"SOURCE"`
	Path        string       `xml:"PATH"`
	Persistent  string       `xml:"PERSISTENT"`
	DatastoreID int          `xml:"DATASTORE_ID"`
	Datastore   string       `xml:"DATASTORE"`
	FsType      string       `xml:"FSTYPE"`
	RunningVMs  int          `xml:"RUNNING_VMS"`
}

type UserImages struct {
	UserImage []*UserImage `xml:"IMAGE"`
}

func resourceImage() *schema.Resource {
	return &schema.Resource{
		Create: resourceImageCreate,
		Read:   resourceImageRead,
		Exists: resourceImageExists,
		Update: resourceImageUpdate,
		Delete: resourceImageDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"name": {
				Type:        schema.TypeString,
				Required:    true,
				Description: "Name of the Image",
			},
			"description": {
				Type:        schema.TypeString,
				Required:    true,
				Description: "Description of the Image, in OpenNebula's XML or String format",
			},
			"permissions": {
				Type:        schema.TypeString,
				Required:    true,
				Description: "Permissions for the Image (in Unix format, owner-group-other, use-manage-admin)",
				ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
					value := v.(string)

					if len(value) != 3 {
						errors = append(errors, fmt.Errorf("%q has specify 3 permission sets: owner-group-other", k))
					}

					all := true
					for _, c := range strings.Split(value, "") {
						if c < "0" || c > "7" {
							all = false
						}
					}
					if !all {
						errors = append(errors, fmt.Errorf("Each character in %q should specify a Unix-like permission set with a number from 0 to 7", k))
					}

					return
				},
			},

			"uid": {
				Type:        schema.TypeInt,
				Computed:    true,
				Description: "ID of the user that will own the Image",
			},
			"gid": {
				Type:        schema.TypeInt,
				Computed:    true,
				Description: "ID of the group that will own the Image",
			},
			"uname": {
				Type:        schema.TypeString,
				Computed:    true,
				Description: "Name of the user that will own the Image",
			},
			"gname": {
				Type:        schema.TypeString,
				Computed:    true,
				Description: "Name of the group that will own the Image",
			},
			"imageid": {
				Type:        schema.TypeInt,
				Required:    true,
				Description: "ID of the Image to be cloned from",
			},
		},
	}
}

func resourceImageCreate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*Client)
	// Create base object
	resp, err := client.Call(
		"one.image.clone",
		d.Get("imageid"),
		d.Get("name"),
		-1,
	)
	if err != nil {
		return err
	}

	d.SetId(resp)
	// update permisions
	if _, err = changePermissions(intId(d.Id()), permission(d.Get("permissions").(string)), client, "one.vn.chmod"); err != nil {
		return err
	}

	return resourceImageRead(d, meta)
}

func resourceImageRead(d *schema.ResourceData, meta interface{}) error {
	var img *UserImage
	var imgs *UserImages

	client := meta.(*Client)
	found := false

	// Try to find the Image by ID, if specified
	if d.Id() != "" {
		resp, err := client.Call("one.image.info", intId(d.Id()), false)
		if err == nil {
			found = true
			if err = xml.Unmarshal([]byte(resp), &img); err != nil {
				return err
			}
		} else {
			log.Printf("Could not find Image by ID %s", d.Id())
		}
	}

	// Otherwise, try to find the Image by (user, name) as the de facto compound primary key
	if d.Id() == "" || !found {
		resp, err := client.Call("one.imagepool.info", -3, -1, -1)
		if err != nil {
			return err
		}

		if err = xml.Unmarshal([]byte(resp), &imgs); err != nil {
			return err
		}

		for _, t := range imgs.UserImage {
			if t.Name == d.Get("name").(string) {
				img = t
				found = true
				break
			}
		}

		if !found || img == nil {
			d.SetId("")
			log.Printf("Could not find Image with name %s for user %s", d.Get("name").(string), client.Username)
			return nil
		}
	}

	d.SetId(strconv.Itoa(img.Id))
	d.Set("name", img.Name)
	d.Set("uid", img.Uid)
	d.Set("gid", img.Gid)
	d.Set("uname", img.Uname)
	d.Set("gname", img.Gname)
	d.Set("permissions", permissionString(img.Permissions))

	return nil
}

func resourceImageExists(d *schema.ResourceData, meta interface{}) (bool, error) {
	err := resourceImageRead(d, meta)
	if err != nil || d.Id() == "" {
		return false, err
	}

	return true, nil
}

func resourceImageUpdate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*Client)

	if d.HasChange("description") {
		_, err := client.Call(
			"one.image.update",
			intId(d.Id()),
			d.Get("description").(string),
			0, // replace the whole image instead of merging it with the existing one
		)
		if err != nil {
			return err
		}
	}

	if d.HasChange("name") {
		resp, err := client.Call(
			"one.image.rename",
			intId(d.Id()),
			d.Get("name").(string),
		)
		if err != nil {
			return err
		}
		log.Printf("[INFO] Successfully updated name for Image %s\n", resp)
	}

	if d.HasChange("permissions") {
		resp, err := changePermissions(intId(d.Id()), permission(d.Get("permissions").(string)), client, "one.image.chmod")
		if err != nil {
			return err
		}
		log.Printf("[INFO] Successfully updated Image %s\n", resp)
	}

	return nil
}

func resourceImageDelete(d *schema.ResourceData, meta interface{}) error {
	err := resourceImageRead(d, meta)
	if err != nil || d.Id() == "" {
		return err
	}

	client := meta.(*Client)

	resp, err := client.Call("one.image.delete", intId(d.Id()), false)
	if err != nil {
		return err
	}

	log.Printf("[INFO] Successfully deleted Image %s\n", resp)
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2020 DSR Corporation
//
// 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 x509

import (
	"crypto/x509"
	"encoding/hex"
	"encoding/pem"
	"fmt"
	"strings"

	"github.com/zigbee-alliance/distributed-compliance-ledger/x/pki/types"
)

type X509Certificate struct {
	Issuer         string
	SerialNumber   string
	Subject        string
	SubjectKeyID   string
	AuthorityKeyID string
	Certificate    *x509.Certificate
}

func DecodeX509Certificate(pemCertificate string) (*X509Certificate, error) {
	block, _ := pem.Decode([]byte(pemCertificate))
	if block == nil {
		return nil, types.NewErrInvalidCertificate("Could not decode pem certificate")
	}

	cert, err := x509.ParseCertificate(block.Bytes)
	if err != nil {
		return nil, types.NewErrInvalidCertificate(fmt.Sprintf("Could not parse certificate: %v", err.Error()))
	}

	certificate := X509Certificate{
		Issuer:         cert.Issuer.String(),
		SerialNumber:   cert.SerialNumber.String(),
		Subject:        cert.Subject.String(),
		SubjectKeyID:   BytesToHex(cert.SubjectKeyId),
		AuthorityKeyID: BytesToHex(cert.AuthorityKeyId),
		Certificate:    cert,
	}

	certificate = PatchCertificate(certificate)

	return &certificate, nil
}

// This function is needed to patch the Issuer/Subject(vid/pid) field of certificate to hex format.
// https://github.com/zigbee-alliance/distributed-compliance-ledger/issues/270
func PatchCertificate(certificate X509Certificate) X509Certificate {
	oldVIDKey := "1.3.6.1.4.1.37244.2.1"
	oldPIDKey := "1.3.6.1.4.1.37244.2.2"

	newVIDKey := "vid"
	newPIDKey := "pid"

	issuer := certificate.Issuer
	issuer = FormatOID(issuer, oldVIDKey, newVIDKey)
	issuer = FormatOID(issuer, oldPIDKey, newPIDKey)

	subject := certificate.Subject
	subject = FormatOID(subject, oldVIDKey, newVIDKey)
	subject = FormatOID(subject, oldPIDKey, newPIDKey)

	certificate.Issuer = issuer
	certificate.Subject = subject

	return certificate
}

func FormatOID(header, oldKey, newKey string) string {
	subjectValues := strings.Split(header, ",")

	integerLengthToHexString := 8
	for index, value := range subjectValues {
		if strings.HasPrefix(value, oldKey) {
			// get value from header
			value = value[len(value)-integerLengthToHexString:]

			decoded, _ := hex.DecodeString(value)
			value = fmt.Sprintf("%s=0x%s", newKey, decoded)

			subjectValues[index] = value
		}
	}

	return strings.Join(subjectValues, ",")
}

func BytesToHex(bytes []byte) string {
	if bytes == nil {
		return ""
	}

	bytesHex := make([]string, len(bytes))
	for i, b := range bytes {
		bytesHex[i] = fmt.Sprintf("%X", b)
	}

	return strings.Join(bytesHex, ":")
}

func (c X509Certificate) Verify(parent *X509Certificate) error {
	roots := x509.NewCertPool()
	roots.AddCert(parent.Certificate)

	opts := x509.VerifyOptions{Roots: roots}

	if _, err := c.Certificate.Verify(opts); err != nil {
		return types.NewErrInvalidCertificate(fmt.Sprintf("Certificate verification failed. Error: %v", err))
	}

	return nil
}

func (c X509Certificate) IsSelfSigned() bool {
	if len(c.AuthorityKeyID) > 0 {
		return c.Issuer == c.Subject && c.AuthorityKeyID == c.SubjectKeyID
	} else {
		return c.Issuer == c.Subject
	}
}
<commit_msg>Refactor code<commit_after>// Copyright 2020 DSR Corporation
//
// 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 x509

import (
	"crypto/x509"
	"encoding/hex"
	"encoding/pem"
	"fmt"
	"strings"

	"github.com/zigbee-alliance/distributed-compliance-ledger/x/pki/types"
)

type X509Certificate struct {
	Issuer         string
	SerialNumber   string
	Subject        string
	SubjectKeyID   string
	AuthorityKeyID string
	Certificate    *x509.Certificate
}

func DecodeX509Certificate(pemCertificate string) (*X509Certificate, error) {
	block, _ := pem.Decode([]byte(pemCertificate))
	if block == nil {
		return nil, types.NewErrInvalidCertificate("Could not decode pem certificate")
	}

	cert, err := x509.ParseCertificate(block.Bytes)
	if err != nil {
		return nil, types.NewErrInvalidCertificate(fmt.Sprintf("Could not parse certificate: %v", err.Error()))
	}

	certificate := X509Certificate{
		Issuer:         cert.Issuer.String(),
		SerialNumber:   cert.SerialNumber.String(),
		Subject:        cert.Subject.String(),
		SubjectKeyID:   BytesToHex(cert.SubjectKeyId),
		AuthorityKeyID: BytesToHex(cert.AuthorityKeyId),
		Certificate:    cert,
	}

	certificate = PatchCertificate(certificate)

	return &certificate, nil
}

// This function is needed to patch the Issuer/Subject(vid/pid) field of certificate to hex format.
// https://github.com/zigbee-alliance/distributed-compliance-ledger/issues/270
func PatchCertificate(certificate X509Certificate) X509Certificate {
	oldVIDKey := "1.3.6.1.4.1.37244.2.1"
	oldPIDKey := "1.3.6.1.4.1.37244.2.2"

	newVIDKey := "vid"
	newPIDKey := "pid"

	issuer := certificate.Issuer
	issuer = FormatOID(issuer, oldVIDKey, newVIDKey)
	issuer = FormatOID(issuer, oldPIDKey, newPIDKey)

	subject := certificate.Subject
	subject = FormatOID(subject, oldVIDKey, newVIDKey)
	subject = FormatOID(subject, oldPIDKey, newPIDKey)

	certificate.Issuer = issuer
	certificate.Subject = subject

	return certificate
}

func FormatOID(header, oldKey, newKey string) string {
	subjectValues := strings.Split(header, ",")

	// When translating a string number into a hexadecimal number,
	// we must take 8 numbers of this string number from the end so that it needs to fit into an integer number.
	hexStringIntegerLength := 8
	for index, value := range subjectValues {
		if strings.HasPrefix(value, oldKey) {
			// get value from header
			value = value[len(value)-hexStringIntegerLength:]

			decoded, _ := hex.DecodeString(value)

			subjectValues[index] = fmt.Sprintf("%s=0x%s", newKey, decoded)
		}
	}

	return strings.Join(subjectValues, ",")
}

func BytesToHex(bytes []byte) string {
	if bytes == nil {
		return ""
	}

	bytesHex := make([]string, len(bytes))
	for i, b := range bytes {
		bytesHex[i] = fmt.Sprintf("%X", b)
	}

	return strings.Join(bytesHex, ":")
}

func (c X509Certificate) Verify(parent *X509Certificate) error {
	roots := x509.NewCertPool()
	roots.AddCert(parent.Certificate)

	opts := x509.VerifyOptions{Roots: roots}

	if _, err := c.Certificate.Verify(opts); err != nil {
		return types.NewErrInvalidCertificate(fmt.Sprintf("Certificate verification failed. Error: %v", err))
	}

	return nil
}

func (c X509Certificate) IsSelfSigned() bool {
	if len(c.AuthorityKeyID) > 0 {
		return c.Issuer == c.Subject && c.AuthorityKeyID == c.SubjectKeyID
	} else {
		return c.Issuer == c.Subject
	}
}
<|endoftext|>


<commit_before>package chanotify

import (
	"strconv"
	"sync"
	"testing"
	"time"
)

func TestNotifier(t *testing.T) {
	s := New()
	ch1 := make(chan struct{}, 1)
	ch2 := make(chan struct{}, 1)
	s.Add("1", ch1)
	s.Add("2", ch2)
	s.m.Lock()
	if len(s.doneCh) != 2 {
		t.Fatalf("expected 2 channels, got %d", len(s.doneCh))
	}
	s.m.Unlock()
	ch1 <- struct{}{}
	id1 := <-s.Chan()
	if id1.(string) != "1" {
		t.Fatalf("1 should be spawned, got %s", id1)
	}
	ch2 <- struct{}{}
	id2 := <-s.Chan()
	if id2.(string) != "2" {
		t.Fatalf("2 should be spawned, got %s", id2)
	}
	close(ch1)
	close(ch2)
	time.Sleep(100 * time.Millisecond)
	s.m.Lock()
	if len(s.doneCh) != 0 {
		t.Fatalf("expected 0 channels, got %d", len(s.doneCh))
	}
	s.m.Unlock()
}

func TestConcurrentNotifier(t *testing.T) {
	s := New()
	var chs []chan struct{}
	for i := 0; i < 8; i++ {
		ch := make(chan struct{}, 2)
		s.Add(strconv.Itoa(i), ch)
		chs = append(chs, ch)
	}
	testCounter := make(map[interface{}]int)
	done := make(chan struct{})
	go func() {
		for id := range s.Chan() {
			testCounter[id]++
		}
		close(done)
	}()
	var wg sync.WaitGroup
	for _, ch := range chs {
		wg.Add(1)
		go func(ch chan struct{}) {
			ch <- struct{}{}
			ch <- struct{}{}
			close(ch)
			wg.Done()
		}(ch)
	}
	wg.Wait()
	// wait for notifications
	time.Sleep(1 * time.Second)
	s.Close()
	<-done
	if len(testCounter) != 8 {
		t.Fatalf("expect to find exactly 8 distinct ids, got %d", len(testCounter))
	}
	for id, c := range testCounter {
		if c != 2 {
			t.Fatalf("Expected to find exactly 2 id %s, but got %d", id, c)
		}
	}
}

func TestAddToBlocked(t *testing.T) {
	s := New()
	ch := make(chan struct{}, 1)
	go func() {
		// give some time to start first select
		time.Sleep(1 * time.Second)
		s.Add("1", ch)
		ch <- struct{}{}
	}()
	val := <-s.Chan()
	if val != "1" {
		t.Fatalf("Expected 1, got %s", val)
	}
}
<commit_msg>Take advantage of having interface{} chanotify keys<commit_after>package chanotify

import (
	"sync"
	"testing"
	"time"
)

func TestNotifier(t *testing.T) {
	s := New()
	ch1 := make(chan struct{}, 1)
	ch2 := make(chan struct{}, 1)
	id1 := "1"
	id2 := "2"

	s.Add(id1, ch1)
	s.Add(id2, ch2)
	s.m.Lock()
	if len(s.doneCh) != 2 {
		t.Fatalf("want 2 channels, got %d", len(s.doneCh))
	}
	s.m.Unlock()
	ch1 <- struct{}{}
	if got, want := <-s.Chan(), id1; got != want {
		t.Fatalf("got %v; want %v", got, want)
	}
	ch2 <- struct{}{}
	if got, want := <-s.Chan(), id2; got != want {
		t.Fatalf("got %v; want %v", got, want)
	}
	close(ch1)
	close(ch2)
	time.Sleep(100 * time.Millisecond)
	s.m.Lock()
	if len(s.doneCh) != 0 {
		t.Fatalf("want 0 channels, got %d", len(s.doneCh))
	}
	s.m.Unlock()
}

func TestConcurrentNotifier(t *testing.T) {
	s := New()
	var chs []chan struct{}
	for i := 0; i < 8; i++ {
		ch := make(chan struct{}, 2)
		s.Add(i, ch)
		chs = append(chs, ch)
	}
	testCounter := make(map[interface{}]int)
	done := make(chan struct{})
	go func() {
		for id := range s.Chan() {
			testCounter[id]++
		}
		close(done)
	}()
	var wg sync.WaitGroup
	for _, ch := range chs {
		wg.Add(1)
		go func(ch chan struct{}) {
			ch <- struct{}{}
			ch <- struct{}{}
			close(ch)
			wg.Done()
		}(ch)
	}
	wg.Wait()
	// wait for notifications
	time.Sleep(1 * time.Second)
	s.Close()
	<-done
	if len(testCounter) != 8 {
		t.Fatalf("expect to find exactly 8 distinct ids, got %d", len(testCounter))
	}
	for id, c := range testCounter {
		if c != 2 {
			t.Fatalf("Expected to find exactly 2 id %s, but got %d", id, c)
		}
	}
}

func TestAddToBlocked(t *testing.T) {
	s := New()
	ch := make(chan struct{}, 1)
	id := 1
	go func() {
		// give some time to start first select
		time.Sleep(1 * time.Second)
		s.Add(id, ch)
		ch <- struct{}{}
	}()
	if got, want := <-s.Chan(), id; got != want {
		t.Fatalf("got %v; want %v", got, want)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"net/http/httptest"
	"net/url"
	"os"
	"strings"
	"testing"
	"time"

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

func TestEscapedString(t *testing.T) {
	assert.Equal(t, "\n", escapedString(`\n`), "something went wrong")
	assert.Equal(t, "hoge\\", escapedString(`hoge\`), "something went wrong")
	assert.Equal(t, "ho\rge", escapedString(`ho\rge`), "something went wrong")
	assert.Equal(t, "ho\\oge", escapedString(`ho\oge`), "something went wrong")
	assert.Equal(t, "", escapedString(``), "something went wrong")
}

func TestTLS(t *testing.T) {
	opts, err := parseArgs([]string{"-S", "-H", "www.verisign.com", "-p", "443"})
	assert.Equal(t, nil, err, "no errors")
	ckr := opts.run()
	assert.Equal(t, checkers.OK, ckr.Status, "should be OK")
}

func TestFTP(t *testing.T) {
	opts, err := parseArgs([]string{"--service=ftp", "-H", "ftp.iij.ad.jp"})
	assert.Equal(t, nil, err, "no errors")
	ckr := opts.run()
	assert.Equal(t, checkers.OK, ckr.Status, "should be OK")
}

func TestHTTP(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		time.Sleep(time.Second / 5)
		w.WriteHeader(200)
		w.Header().Set("Content-Type", "text/plain")
		fmt.Fprint(w, "OKOK")
	}))
	defer ts.Close()

	u, _ := url.Parse(ts.URL)

	host := u.Host
	hostAndPort := strings.Split(host, ":")
	host = hostAndPort[0]
	port := hostAndPort[1]

	testOk := func() {
		opts, err := parseArgs([]string{"-H", host, "-p", port, "--send", `GET / HTTP/1.1\r\n\r\n`, "-E", "-e", "OKOK"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.OK, ckr.Status, "should be OK")
		assert.Regexp(t, `seconds response time on`, ckr.Message, "Unexpected response")
	}
	testOk()

	testUnexpected := func() {
		opts, err := parseArgs(
			[]string{"-H", host, "-p", port, "--send", `GET / HTTP/1.1\r\n\r\n`, "-E", "-e", "OKOKOK"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.CRITICAL, ckr.Status, "should be CRITICAL")
		assert.Regexp(t, `Unexpected response from`, ckr.Message, "Unexpected response")
	}
	testUnexpected()

	testOverWarn := func() {
		opts, err := parseArgs(
			[]string{"-H", host, "-p", port, "--send", `GET / HTTP/1.1\r\n\r\n`, "-E", "-e", "OKOK", "-w", "0.1"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.WARNING, ckr.Status, "should be Warning")
		assert.Regexp(t, `seconds response time on`, ckr.Message, "Unexpected response")
	}
	testOverWarn()

	testOverCrit := func() {
		opts, err := parseArgs(
			[]string{"-H", host, "-p", port, "--send", "GET / HTTP/1.1\r\n\r\n", "-e", "OKOK", "-c", "0.1"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.CRITICAL, ckr.Status, "should be Critical")
		assert.Regexp(t, `seconds response time on`, ckr.Message, "Unexpected response")
	}
	testOverCrit()
}

func TestUnixDomainSocket(t *testing.T) {
	dir, err := ioutil.TempDir(os.TempDir(), "")
	if err != nil {
		t.Error(err)
	}
	defer os.RemoveAll(dir)

	sock := fmt.Sprintf("%s/test.sock", dir)

	l, err := net.Listen("unix", sock)
	if err != nil {
		t.Error(err)
	}

	go func() {
		for {
			ls, err := l.Accept()
			if err != nil {
				t.Error(err)
			}
			go func(c net.Conn) {
				defer c.Close()

				buf := make([]byte, 1024)

				_, err := c.Read(buf)

				if err == io.EOF {
					return
				}

				c.Write([]byte("OKOK"))
			}(ls)
		}
	}()

	testOk := func() {
		opts, err := parseArgs([]string{"-U", sock, "--send", `PING`, "-E", "-e", "OKOK"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.OK, ckr.Status, "should be OK")
		assert.Regexp(t, `seconds response time on`, ckr.Message, "Unexpected response")
	}
	testOk()

	testUnexpected := func() {
		opts, err := parseArgs([]string{"-U", sock, "--send", `PING`, "-E", "-e", "OKOKOK"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.CRITICAL, ckr.Status, "should be CRITICAL")
		assert.Regexp(t, `Unexpected response from`, ckr.Message, "Unexpected response")
	}
	testUnexpected()

	testOverWarn := func() {
		opts, err := parseArgs([]string{"-U", sock, "--send", `PING`, "-E", "-e", "OKOK", "-w", "0.1"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.WARNING, ckr.Status, "should be Warning")
		assert.Regexp(t, `seconds response time on`, ckr.Message, "Unexpected response")
	}
	testOverWarn()

	testOverCrit := func() {
		opts, err := parseArgs([]string{"-U", sock, "--send", `PING`, "-E", "-e", "OKOK", "-c", "0.1"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.CRITICAL, ckr.Status, "should be Critical")
		assert.Regexp(t, `seconds response time on`, ckr.Message, "Unexpected response")
	}
	testOverCrit()
}
<commit_msg>Add IPv6 test<commit_after>package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"net/http/httptest"
	"net/url"
	"os"
	"strings"
	"testing"
	"time"

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

func TestEscapedString(t *testing.T) {
	assert.Equal(t, "\n", escapedString(`\n`), "something went wrong")
	assert.Equal(t, "hoge\\", escapedString(`hoge\`), "something went wrong")
	assert.Equal(t, "ho\rge", escapedString(`ho\rge`), "something went wrong")
	assert.Equal(t, "ho\\oge", escapedString(`ho\oge`), "something went wrong")
	assert.Equal(t, "", escapedString(``), "something went wrong")
}

func TestTLS(t *testing.T) {
	opts, err := parseArgs([]string{"-S", "-H", "www.verisign.com", "-p", "443"})
	assert.Equal(t, nil, err, "no errors")
	ckr := opts.run()
	assert.Equal(t, checkers.OK, ckr.Status, "should be OK")
}

func TestFTP(t *testing.T) {
	opts, err := parseArgs([]string{"--service=ftp", "-H", "ftp.iij.ad.jp"})
	assert.Equal(t, nil, err, "no errors")
	ckr := opts.run()
	assert.Equal(t, checkers.OK, ckr.Status, "should be OK")
}

func TestHTTP(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		time.Sleep(time.Second / 5)
		w.WriteHeader(200)
		w.Header().Set("Content-Type", "text/plain")
		fmt.Fprint(w, "OKOK")
	}))
	defer ts.Close()

	u, _ := url.Parse(ts.URL)

	host := u.Host
	hostAndPort := strings.Split(host, ":")
	host = hostAndPort[0]
	port := hostAndPort[1]

	testOk := func() {
		opts, err := parseArgs([]string{"-H", host, "-p", port, "--send", `GET / HTTP/1.1\r\n\r\n`, "-E", "-e", "OKOK"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.OK, ckr.Status, "should be OK")
		assert.Regexp(t, `seconds response time on`, ckr.Message, "Unexpected response")
	}
	testOk()

	testUnexpected := func() {
		opts, err := parseArgs(
			[]string{"-H", host, "-p", port, "--send", `GET / HTTP/1.1\r\n\r\n`, "-E", "-e", "OKOKOK"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.CRITICAL, ckr.Status, "should be CRITICAL")
		assert.Regexp(t, `Unexpected response from`, ckr.Message, "Unexpected response")
	}
	testUnexpected()

	testOverWarn := func() {
		opts, err := parseArgs(
			[]string{"-H", host, "-p", port, "--send", `GET / HTTP/1.1\r\n\r\n`, "-E", "-e", "OKOK", "-w", "0.1"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.WARNING, ckr.Status, "should be Warning")
		assert.Regexp(t, `seconds response time on`, ckr.Message, "Unexpected response")
	}
	testOverWarn()

	testOverCrit := func() {
		opts, err := parseArgs(
			[]string{"-H", host, "-p", port, "--send", "GET / HTTP/1.1\r\n\r\n", "-e", "OKOK", "-c", "0.1"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.CRITICAL, ckr.Status, "should be Critical")
		assert.Regexp(t, `seconds response time on`, ckr.Message, "Unexpected response")
	}
	testOverCrit()
}

func TestUnixDomainSocket(t *testing.T) {
	dir, err := ioutil.TempDir(os.TempDir(), "")
	if err != nil {
		t.Error(err)
	}
	defer os.RemoveAll(dir)

	sock := fmt.Sprintf("%s/test.sock", dir)

	l, err := net.Listen("unix", sock)
	if err != nil {
		t.Error(err)
	}

	go func() {
		for {
			ls, err := l.Accept()
			if err != nil {
				t.Error(err)
			}
			go func(c net.Conn) {
				defer c.Close()

				buf := make([]byte, 1024)

				_, err := c.Read(buf)

				if err == io.EOF {
					return
				}

				c.Write([]byte("OKOK"))
			}(ls)
		}
	}()

	testOk := func() {
		opts, err := parseArgs([]string{"-U", sock, "--send", `PING`, "-E", "-e", "OKOK"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.OK, ckr.Status, "should be OK")
		assert.Regexp(t, `seconds response time on`, ckr.Message, "Unexpected response")
	}
	testOk()

	testUnexpected := func() {
		opts, err := parseArgs([]string{"-U", sock, "--send", `PING`, "-E", "-e", "OKOKOK"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.CRITICAL, ckr.Status, "should be CRITICAL")
		assert.Regexp(t, `Unexpected response from`, ckr.Message, "Unexpected response")
	}
	testUnexpected()

	testOverWarn := func() {
		opts, err := parseArgs([]string{"-U", sock, "--send", `PING`, "-E", "-e", "OKOK", "-w", "0.1"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.WARNING, ckr.Status, "should be Warning")
		assert.Regexp(t, `seconds response time on`, ckr.Message, "Unexpected response")
	}
	testOverWarn()

	testOverCrit := func() {
		opts, err := parseArgs([]string{"-U", sock, "--send", `PING`, "-E", "-e", "OKOK", "-c", "0.1"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.CRITICAL, ckr.Status, "should be Critical")
		assert.Regexp(t, `seconds response time on`, ckr.Message, "Unexpected response")
	}
	testOverCrit()
}

func TestHTTPIPv6(t *testing.T) {
	http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
		time.Sleep(time.Second / 5)
		w.WriteHeader(200)
		w.Header().Set("Content-Type", "text/plain")
		conn, bufrw, err := w.(http.Hijacker).Hijack()
		if err != nil {
			t.Error(err)
		}
		defer conn.Close()
		bufrw.WriteString("OKOK")
		bufrw.Flush()
	})

	l, err := net.Listen("tcp", "[::1]:0")
	if err != nil {
		t.Error(err)
	}
	defer l.Close()
	h, port, _ := net.SplitHostPort(l.Addr().String())
	host := fmt.Sprintf("[%s]", h)

	go func() {
		for {
			http.Serve(l, nil)
		}
	}()

	testOk := func() {
		opts, err := parseArgs([]string{"-H", host, "-p", port, "--send", `GET / HTTP/1.1\r\n\r\n`, "-E", "-e", "OKOK"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.OK, ckr.Status, "should be OK")
		assert.Regexp(t, `seconds response time on`, ckr.Message, "Unexpected response")
	}
	testOk()

	testUnexpected := func() {
		opts, err := parseArgs(
			[]string{"-H", host, "-p", port, "--send", `GET / HTTP/1.1\r\n\r\n`, "-E", "-e", "OKOKOK"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.CRITICAL, ckr.Status, "should be CRITICAL")
		assert.Regexp(t, `Unexpected response from`, ckr.Message, "Unexpected response")
	}
	testUnexpected()

	testOverWarn := func() {
		opts, err := parseArgs(
			[]string{"-H", host, "-p", port, "--send", `GET / HTTP/1.1\r\n\r\n`, "-E", "-e", "OKOK", "-w", "0.1"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.WARNING, ckr.Status, "should be Warning")
		assert.Regexp(t, `seconds response time on`, ckr.Message, "Unexpected response")
	}
	testOverWarn()

	testOverCrit := func() {
		opts, err := parseArgs(
			[]string{"-H", host, "-p", port, "--send", "GET / HTTP/1.1\r\n\r\n", "-e", "OKOK", "-c", "0.1"})
		assert.Equal(t, nil, err, "no errors")
		ckr := opts.run()
		assert.Equal(t, checkers.CRITICAL, ckr.Status, "should be Critical")
		assert.Regexp(t, `seconds response time on`, ckr.Message, "Unexpected response")
	}
	testOverCrit()
}
<|endoftext|>


<commit_before>package ovn

import (
	"fmt"
	"strings"
	"time"

	util "github.com/openvswitch/ovn-kubernetes/go-controller/pkg/util"
	"github.com/sirupsen/logrus"
	kapi "k8s.io/api/core/v1"
)

func (oc *Controller) syncPods(pods []interface{}) {
	// get the list of logical switch ports (equivalent to pods)
	expectedLogicalPorts := make(map[string]bool)
	for _, podInterface := range pods {
		pod, ok := podInterface.(*kapi.Pod)
		if !ok {
			logrus.Errorf("Spurious object in syncPods: %v", podInterface)
			continue
		}
		logicalPort := fmt.Sprintf("%s_%s", pod.Namespace, pod.Name)
		expectedLogicalPorts[logicalPort] = true
	}

	// get the list of logical ports from OVN
	output, stderr, err := util.RunOVNNbctlUnix("--data=bare", "--no-heading",
		"--columns=name", "find", "logical_switch_port", "external_ids:pod=true")
	if err != nil {
		logrus.Errorf("Error in obtaining list of logical ports, "+
			"stderr: %q, err: %v",
			stderr, err)
		return
	}
	existingLogicalPorts := strings.Fields(output)
	for _, existingPort := range existingLogicalPorts {
		if _, ok := expectedLogicalPorts[existingPort]; !ok {
			// not found, delete this logical port
			logrus.Infof("Stale logical port found: %s. This logical port will be deleted.", existingPort)
			out, stderr, err := util.RunOVNNbctlUnix("--if-exists", "lsp-del",
				existingPort)
			if err != nil {
				logrus.Errorf("Error in deleting pod's logical port "+
					"stdout: %q, stderr: %q err: %v",
					out, stderr, err)
			}
			oc.deletePodAcls(existingPort)
		}
	}
}

func (oc *Controller) deletePodAcls(logicalPort string) {
	// delete the ACL rules on OVN that corresponding pod has been deleted
	uuids, stderr, err := util.RunOVNNbctlUnix("--data=bare", "--no-heading",
		"--columns=_uuid", "find", "ACL",
		fmt.Sprintf("external_ids:logical_port=%s", logicalPort))
	if err != nil {
		logrus.Errorf("Error in getting list of acls "+
			"stdout: %q, stderr: %q, error: %v", uuids, stderr, err)
		return
	}

	if uuids == "" {
		logrus.Debugf("deletePodAcls: returning because find " +
			"returned no ACLs")
		return
	}

	uuidSlice := strings.Fields(uuids)
	for _, uuid := range uuidSlice {
		// Get logical switch
		out, stderr, err := util.RunOVNNbctlUnix("--data=bare",
			"--no-heading", "--columns=_uuid", "find", "logical_switch",
			fmt.Sprintf("acls{>=}%s", uuid))
		if err != nil {
			logrus.Errorf("find failed to get the logical_switch of acl "+
				"uuid=%s, stderr: %q, (%v)", uuid, stderr, err)
			continue
		}

		if out == "" {
			continue
		}
		logicalSwitch := out

		_, stderr, err = util.RunOVNNbctlUnix("remove", "logical_switch",
			logicalSwitch, "acls", uuid)
		if err != nil {
			logrus.Errorf("failed to delete the allow-from rule %s for"+
				" logical_switch=%s, logical_port=%s, stderr: %q, (%v)",
				uuid, logicalSwitch, logicalPort, stderr, err)
			continue
		}
	}
}

func (oc *Controller) getGatewayFromSwitch(logicalSwitch string) (string, string, error) {
	var gatewayIPMaskStr, stderr string
	var ok bool
	var err error
	if gatewayIPMaskStr, ok = oc.gatewayCache[logicalSwitch]; !ok {
		gatewayIPMaskStr, stderr, err = util.RunOVNNbctlUnix("--if-exists",
			"get", "logical_switch", logicalSwitch,
			"external_ids:gateway_ip")
		if err != nil {
			logrus.Errorf("Failed to get gateway IP:  %s, stderr: %q, %v",
				gatewayIPMaskStr, stderr, err)
			return "", "", err
		}
		if gatewayIPMaskStr == "" {
			return "", "", fmt.Errorf("Empty gateway IP in logical switch %s",
				logicalSwitch)
		}
		oc.gatewayCache[logicalSwitch] = gatewayIPMaskStr
	}
	gatewayIPMask := strings.Split(gatewayIPMaskStr, "/")
	gatewayIP := gatewayIPMask[0]
	mask := gatewayIPMask[1]
	logrus.Debugf("Gateway IP: %s, Mask: %s", gatewayIP, mask)
	return gatewayIP, mask, nil
}

func (oc *Controller) deleteLogicalPort(pod *kapi.Pod) {
	logrus.Infof("Deleting pod: %s", pod.Name)
	logicalPort := fmt.Sprintf("%s_%s", pod.Namespace, pod.Name)
	out, stderr, err := util.RunOVNNbctlUnix("--if-exists", "lsp-del",
		logicalPort)
	if err != nil {
		logrus.Errorf("Error in deleting pod logical port "+
			"stdout: %q, stderr: %q, (%v)",
			out, stderr, err)
	}

	ipAddress := oc.getIPFromOvnAnnotation(pod.Annotations["ovn"])

	delete(oc.logicalPortCache, logicalPort)

	oc.lspMutex.Lock()
	delete(oc.lspIngressDenyCache, logicalPort)
	delete(oc.lspEgressDenyCache, logicalPort)
	oc.lspMutex.Unlock()

	oc.deleteACLDeny(pod.Namespace, pod.Spec.NodeName, logicalPort, "Ingress")
	oc.deleteACLDeny(pod.Namespace, pod.Spec.NodeName, logicalPort, "Egress")
	oc.deletePodFromNamespaceAddressSet(pod.Namespace, ipAddress)
	return
}

func (oc *Controller) addLogicalPort(pod *kapi.Pod) {
	count := 30
	var out, stderr string
	var err error
	logicalSwitch := pod.Spec.NodeName
	for count > 0 {
		if logicalSwitch != "" {
			break
		}
		if count != 30 {
			time.Sleep(1 * time.Second)
		}
		count--
		p, err := oc.kube.GetPod(pod.Namespace, pod.Name)
		if err != nil {
			logrus.Errorf("Failed to get pod %s/%s's information from kube "+
				"API server", pod.Namespace, pod.Name)
			continue
		}
		logicalSwitch = p.Spec.NodeName
	}
	if logicalSwitch == "" {
		logrus.Errorf("Failed to find the logical switch for pod %s/%s",
			pod.Namespace, pod.Name)
		return
	}

	if !oc.logicalSwitchCache[logicalSwitch] {
		oc.logicalSwitchCache[logicalSwitch] = true
		oc.addAllowACLFromNode(logicalSwitch)
	}

	portName := fmt.Sprintf("%s_%s", pod.Namespace, pod.Name)
	logrus.Debugf("Creating logical port for %s on switch %s", portName, logicalSwitch)

	annotation, isStaticIP := pod.Annotations["ovn"]

	// If pod already has annotations, just add the lsp with static ip/mac.
	// Else, create the lsp with dynamic addresses.
	if isStaticIP {
		ipAddress := oc.getIPFromOvnAnnotation(annotation)
		macAddress := oc.getMacFromOvnAnnotation(annotation)

		out, stderr, err = util.RunOVNNbctlUnix("--may-exist", "lsp-add",
			logicalSwitch, portName, "--", "lsp-set-addresses", portName,
			fmt.Sprintf("%s %s", macAddress, ipAddress))
		if err != nil {
			logrus.Errorf("Failed to add logical port to switch "+
				"stdout: %q, stderr: %q (%v)",
				out, stderr, err)
			return
		}
	} else {
		out, stderr, err = util.RunOVNNbctlUnix("--wait=sb", "--",
			"--may-exist", "lsp-add", logicalSwitch, portName,
			"--", "lsp-set-addresses",
			portName, "dynamic", "--", "set",
			"logical_switch_port", portName,
			"external-ids:namespace="+pod.Namespace,
			"external-ids:logical_switch="+logicalSwitch,
			"external-ids:pod=true")
		if err != nil {
			logrus.Errorf("Error while creating logical port %s "+
				"stdout: %q, stderr: %q (%v)",
				portName, out, stderr, err)
			return
		}
	}

	oc.logicalPortCache[portName] = logicalSwitch

	gatewayIP, mask, err := oc.getGatewayFromSwitch(logicalSwitch)
	if err != nil {
		logrus.Errorf("Error obtaining gateway address for switch %s", logicalSwitch)
		return
	}

	count = 30
	for count > 0 {
		if isStaticIP {
			out, stderr, err = util.RunOVNNbctlUnix("get",
				"logical_switch_port", portName, "addresses")
		} else {
			out, stderr, err = util.RunOVNNbctlUnix("get",
				"logical_switch_port", portName, "dynamic_addresses")
		}
		if err == nil {
			break
		}
		logrus.Debugf("Error while obtaining addresses for %s - %v", portName,
			err)
		time.Sleep(time.Second)
		count--
	}
	if count == 0 {
		logrus.Errorf("Error while obtaining addresses for %s "+
			"stdout: %q, stderr: %q, (%v)", portName, out, stderr, err)
		return
	}

	// static addresses have format ["0a:00:00:00:00:01 192.168.1.3"], while
	// dynamic addresses have format "0a:00:00:00:00:01 192.168.1.3".
	outStr := strings.TrimLeft(out, `[`)
	outStr = strings.TrimRight(outStr, `]`)
	outStr = strings.Trim(outStr, `"`)
	addresses := strings.Split(outStr, " ")
	if len(addresses) != 2 {
		logrus.Errorf("Error while obtaining addresses for %s", portName)
		return
	}

	if !isStaticIP {
		annotation = fmt.Sprintf(`{\"ip_address\":\"%s/%s\", \"mac_address\":\"%s\", \"gateway_ip\": \"%s\"}`, addresses[1], mask, addresses[0], gatewayIP)
		logrus.Debugf("Annotation values: ip=%s/%s ; mac=%s ; gw=%s\nAnnotation=%s", addresses[1], mask, addresses[0], gatewayIP, annotation)
		err = oc.kube.SetAnnotationOnPod(pod, "ovn", annotation)
		if err != nil {
			logrus.Errorf("Failed to set annotation on pod %s - %v", pod.Name, err)
		}
	}
	oc.addPodToNamespaceAddressSet(pod.Namespace, addresses[1])

	return
}

// AddLogicalPortWithIP add logical port with static ip address
// and mac adddress for the pod
func (oc *Controller) AddLogicalPortWithIP(pod *kapi.Pod) {
	portName := fmt.Sprintf("%s_%s", pod.Namespace, pod.Name)
	logicalSwitch := pod.Spec.NodeName
	logrus.Debugf("Creating logical port for %s on switch %s", portName,
		logicalSwitch)

	annotation, ok := pod.Annotations["ovn"]
	if !ok {
		logrus.Errorf("Failed to get ovn annotation from pod!")
		return
	}
	ipAddress := oc.getIPFromOvnAnnotation(annotation)
	macAddress := oc.getMacFromOvnAnnotation(annotation)

	stdout, stderr, err := util.RunOVNNbctlUnix("--", "--may-exist", "lsp-add",
		logicalSwitch, portName, "--", "lsp-set-addresses", portName,
		fmt.Sprintf("%s %s", macAddress, ipAddress))
	if err != nil {
		logrus.Errorf("Failed to add logical port to switch, stdout: %q, "+
			"stderr: %q, error: %v", stdout, stderr, err)
		return
	}
}
<commit_msg>pods: Handle empty returns correctly.<commit_after>package ovn

import (
	"fmt"
	"strings"
	"time"

	util "github.com/openvswitch/ovn-kubernetes/go-controller/pkg/util"
	"github.com/sirupsen/logrus"
	kapi "k8s.io/api/core/v1"
)

func (oc *Controller) syncPods(pods []interface{}) {
	// get the list of logical switch ports (equivalent to pods)
	expectedLogicalPorts := make(map[string]bool)
	for _, podInterface := range pods {
		pod, ok := podInterface.(*kapi.Pod)
		if !ok {
			logrus.Errorf("Spurious object in syncPods: %v", podInterface)
			continue
		}
		logicalPort := fmt.Sprintf("%s_%s", pod.Namespace, pod.Name)
		expectedLogicalPorts[logicalPort] = true
	}

	// get the list of logical ports from OVN
	output, stderr, err := util.RunOVNNbctlUnix("--data=bare", "--no-heading",
		"--columns=name", "find", "logical_switch_port", "external_ids:pod=true")
	if err != nil {
		logrus.Errorf("Error in obtaining list of logical ports, "+
			"stderr: %q, err: %v",
			stderr, err)
		return
	}
	existingLogicalPorts := strings.Fields(output)
	for _, existingPort := range existingLogicalPorts {
		if _, ok := expectedLogicalPorts[existingPort]; !ok {
			// not found, delete this logical port
			logrus.Infof("Stale logical port found: %s. This logical port will be deleted.", existingPort)
			out, stderr, err := util.RunOVNNbctlUnix("--if-exists", "lsp-del",
				existingPort)
			if err != nil {
				logrus.Errorf("Error in deleting pod's logical port "+
					"stdout: %q, stderr: %q err: %v",
					out, stderr, err)
			}
			oc.deletePodAcls(existingPort)
		}
	}
}

func (oc *Controller) deletePodAcls(logicalPort string) {
	// delete the ACL rules on OVN that corresponding pod has been deleted
	uuids, stderr, err := util.RunOVNNbctlUnix("--data=bare", "--no-heading",
		"--columns=_uuid", "find", "ACL",
		fmt.Sprintf("external_ids:logical_port=%s", logicalPort))
	if err != nil {
		logrus.Errorf("Error in getting list of acls "+
			"stdout: %q, stderr: %q, error: %v", uuids, stderr, err)
		return
	}

	if uuids == "" {
		logrus.Debugf("deletePodAcls: returning because find " +
			"returned no ACLs")
		return
	}

	uuidSlice := strings.Fields(uuids)
	for _, uuid := range uuidSlice {
		// Get logical switch
		out, stderr, err := util.RunOVNNbctlUnix("--data=bare",
			"--no-heading", "--columns=_uuid", "find", "logical_switch",
			fmt.Sprintf("acls{>=}%s", uuid))
		if err != nil {
			logrus.Errorf("find failed to get the logical_switch of acl "+
				"uuid=%s, stderr: %q, (%v)", uuid, stderr, err)
			continue
		}

		if out == "" {
			continue
		}
		logicalSwitch := out

		_, stderr, err = util.RunOVNNbctlUnix("remove", "logical_switch",
			logicalSwitch, "acls", uuid)
		if err != nil {
			logrus.Errorf("failed to delete the allow-from rule %s for"+
				" logical_switch=%s, logical_port=%s, stderr: %q, (%v)",
				uuid, logicalSwitch, logicalPort, stderr, err)
			continue
		}
	}
}

func (oc *Controller) getGatewayFromSwitch(logicalSwitch string) (string, string, error) {
	var gatewayIPMaskStr, stderr string
	var ok bool
	var err error
	if gatewayIPMaskStr, ok = oc.gatewayCache[logicalSwitch]; !ok {
		gatewayIPMaskStr, stderr, err = util.RunOVNNbctlUnix("--if-exists",
			"get", "logical_switch", logicalSwitch,
			"external_ids:gateway_ip")
		if err != nil {
			logrus.Errorf("Failed to get gateway IP:  %s, stderr: %q, %v",
				gatewayIPMaskStr, stderr, err)
			return "", "", err
		}
		if gatewayIPMaskStr == "" {
			return "", "", fmt.Errorf("Empty gateway IP in logical switch %s",
				logicalSwitch)
		}
		oc.gatewayCache[logicalSwitch] = gatewayIPMaskStr
	}
	gatewayIPMask := strings.Split(gatewayIPMaskStr, "/")
	gatewayIP := gatewayIPMask[0]
	mask := gatewayIPMask[1]
	logrus.Debugf("Gateway IP: %s, Mask: %s", gatewayIP, mask)
	return gatewayIP, mask, nil
}

func (oc *Controller) deleteLogicalPort(pod *kapi.Pod) {
	logrus.Infof("Deleting pod: %s", pod.Name)
	logicalPort := fmt.Sprintf("%s_%s", pod.Namespace, pod.Name)
	out, stderr, err := util.RunOVNNbctlUnix("--if-exists", "lsp-del",
		logicalPort)
	if err != nil {
		logrus.Errorf("Error in deleting pod logical port "+
			"stdout: %q, stderr: %q, (%v)",
			out, stderr, err)
	}

	ipAddress := oc.getIPFromOvnAnnotation(pod.Annotations["ovn"])

	delete(oc.logicalPortCache, logicalPort)

	oc.lspMutex.Lock()
	delete(oc.lspIngressDenyCache, logicalPort)
	delete(oc.lspEgressDenyCache, logicalPort)
	oc.lspMutex.Unlock()

	oc.deleteACLDeny(pod.Namespace, pod.Spec.NodeName, logicalPort, "Ingress")
	oc.deleteACLDeny(pod.Namespace, pod.Spec.NodeName, logicalPort, "Egress")
	oc.deletePodFromNamespaceAddressSet(pod.Namespace, ipAddress)
	return
}

func (oc *Controller) addLogicalPort(pod *kapi.Pod) {
	count := 30
	var out, stderr string
	var err error
	logicalSwitch := pod.Spec.NodeName
	for count > 0 {
		if logicalSwitch != "" {
			break
		}
		if count != 30 {
			time.Sleep(1 * time.Second)
		}
		count--
		p, err := oc.kube.GetPod(pod.Namespace, pod.Name)
		if err != nil {
			logrus.Errorf("Failed to get pod %s/%s's information from kube "+
				"API server", pod.Namespace, pod.Name)
			continue
		}
		logicalSwitch = p.Spec.NodeName
	}
	if logicalSwitch == "" {
		logrus.Errorf("Failed to find the logical switch for pod %s/%s",
			pod.Namespace, pod.Name)
		return
	}

	if !oc.logicalSwitchCache[logicalSwitch] {
		oc.logicalSwitchCache[logicalSwitch] = true
		oc.addAllowACLFromNode(logicalSwitch)
	}

	portName := fmt.Sprintf("%s_%s", pod.Namespace, pod.Name)
	logrus.Debugf("Creating logical port for %s on switch %s", portName, logicalSwitch)

	annotation, isStaticIP := pod.Annotations["ovn"]

	// If pod already has annotations, just add the lsp with static ip/mac.
	// Else, create the lsp with dynamic addresses.
	if isStaticIP {
		ipAddress := oc.getIPFromOvnAnnotation(annotation)
		macAddress := oc.getMacFromOvnAnnotation(annotation)

		out, stderr, err = util.RunOVNNbctlUnix("--may-exist", "lsp-add",
			logicalSwitch, portName, "--", "lsp-set-addresses", portName,
			fmt.Sprintf("%s %s", macAddress, ipAddress))
		if err != nil {
			logrus.Errorf("Failed to add logical port to switch "+
				"stdout: %q, stderr: %q (%v)",
				out, stderr, err)
			return
		}
	} else {
		out, stderr, err = util.RunOVNNbctlUnix("--wait=sb", "--",
			"--may-exist", "lsp-add", logicalSwitch, portName,
			"--", "lsp-set-addresses",
			portName, "dynamic", "--", "set",
			"logical_switch_port", portName,
			"external-ids:namespace="+pod.Namespace,
			"external-ids:logical_switch="+logicalSwitch,
			"external-ids:pod=true")
		if err != nil {
			logrus.Errorf("Error while creating logical port %s "+
				"stdout: %q, stderr: %q (%v)",
				portName, out, stderr, err)
			return
		}
	}

	oc.logicalPortCache[portName] = logicalSwitch

	gatewayIP, mask, err := oc.getGatewayFromSwitch(logicalSwitch)
	if err != nil {
		logrus.Errorf("Error obtaining gateway address for switch %s", logicalSwitch)
		return
	}

	count = 30
	for count > 0 {
		if isStaticIP {
			out, stderr, err = util.RunOVNNbctlUnix("get",
				"logical_switch_port", portName, "addresses")
		} else {
			out, stderr, err = util.RunOVNNbctlUnix("get",
				"logical_switch_port", portName, "dynamic_addresses")
		}
		if err == nil && out != "[]" {
			break
		}
		if err != nil {
			logrus.Errorf("Error while obtaining addresses for %s - %v", portName,
				err)
			return
		}
		time.Sleep(time.Second)
		count--
	}
	if count == 0 {
		logrus.Errorf("Error while obtaining addresses for %s "+
			"stdout: %q, stderr: %q, (%v)", portName, out, stderr, err)
		return
	}

	// static addresses have format ["0a:00:00:00:00:01 192.168.1.3"], while
	// dynamic addresses have format "0a:00:00:00:00:01 192.168.1.3".
	outStr := strings.TrimLeft(out, `[`)
	outStr = strings.TrimRight(outStr, `]`)
	outStr = strings.Trim(outStr, `"`)
	addresses := strings.Split(outStr, " ")
	if len(addresses) != 2 {
		logrus.Errorf("Error while obtaining addresses for %s", portName)
		return
	}

	if !isStaticIP {
		annotation = fmt.Sprintf(`{\"ip_address\":\"%s/%s\", \"mac_address\":\"%s\", \"gateway_ip\": \"%s\"}`, addresses[1], mask, addresses[0], gatewayIP)
		logrus.Debugf("Annotation values: ip=%s/%s ; mac=%s ; gw=%s\nAnnotation=%s", addresses[1], mask, addresses[0], gatewayIP, annotation)
		err = oc.kube.SetAnnotationOnPod(pod, "ovn", annotation)
		if err != nil {
			logrus.Errorf("Failed to set annotation on pod %s - %v", pod.Name, err)
		}
	}
	oc.addPodToNamespaceAddressSet(pod.Namespace, addresses[1])

	return
}

// AddLogicalPortWithIP add logical port with static ip address
// and mac adddress for the pod
func (oc *Controller) AddLogicalPortWithIP(pod *kapi.Pod) {
	portName := fmt.Sprintf("%s_%s", pod.Namespace, pod.Name)
	logicalSwitch := pod.Spec.NodeName
	logrus.Debugf("Creating logical port for %s on switch %s", portName,
		logicalSwitch)

	annotation, ok := pod.Annotations["ovn"]
	if !ok {
		logrus.Errorf("Failed to get ovn annotation from pod!")
		return
	}
	ipAddress := oc.getIPFromOvnAnnotation(annotation)
	macAddress := oc.getMacFromOvnAnnotation(annotation)

	stdout, stderr, err := util.RunOVNNbctlUnix("--", "--may-exist", "lsp-add",
		logicalSwitch, portName, "--", "lsp-set-addresses", portName,
		fmt.Sprintf("%s %s", macAddress, ipAddress))
	if err != nil {
		logrus.Errorf("Failed to add logical port to switch, stdout: %q, "+
			"stderr: %q, error: %v", stdout, stderr, err)
		return
	}
}
<|endoftext|>


<commit_before>// Copyright 2012, Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"os"
	"strings"
	"time"

	log "github.com/golang/glog"
	"github.com/youtube/vitess/go/db"
	"github.com/youtube/vitess/go/vt/client2"
	_ "github.com/youtube/vitess/go/vt/client2/tablet"
)

var usage = `
The parameters are first the SQL command, then the bound variables.
For query arguments, we assume place-holders in the query string
in the form of :v0, :v1, etc.
`

var count = flag.Int("count", 1, "how many times to run the query")
var bindvars = FlagMap("bindvars", "bind vars as a json dictionary")
var server = flag.String("server", "localhost:6603/test_keyspace/0", "vtocc server as [user:password@]hostname:port/keyspace/shard[#keyrangestart-keyrangeend]")
var driver = flag.String("driver", "vttablet", "which driver to use (one of vttablet, vttablet-streaming, vtdb, vtdb-streaming)")
var verbose = flag.Bool("verbose", false, "show results")

func init() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
		flag.PrintDefaults()
		fmt.Fprintf(os.Stderr, usage)

	}
}

//----------------------------------

type Map map[string]interface{}

func (m *Map) String() string {
	b, err := json.Marshal(*m)
	if err != nil {
		return err.Error()
	}
	return string(b)
}

func (m *Map) Set(s string) (err error) {
	err = json.Unmarshal([]byte(s), m)
	if err != nil {
		return err
	}
	// json reads all numbers as float64
	// So, we just ditch floats for bindvars
	for k, v := range *m {
		f, ok := v.(float64)
		if ok {
			if f > 0 {
				(*m)[k] = uint64(f)
			} else {
				(*m)[k] = int64(f)
			}
		}
	}

	return nil
}

// For internal flag compatibility
func (m *Map) Get() interface{} {
	return m
}

func FlagMap(name, usage string) (m map[string]interface{}) {
	m = make(map[string]interface{})
	mm := Map(m)
	flag.Var(&mm, name, usage)
	return m
}

// FIXME(alainjobart) this is a cheap trick. Should probably use the
// query parser if we needed this to be 100% reliable.
func isDml(sql string) bool {
	lower := strings.TrimSpace(strings.ToLower(sql))
	return strings.HasPrefix(lower, "insert") || strings.HasPrefix(lower, "update")
}

func main() {
	flag.Parse()
	args := flag.Args()

	if len(args) == 0 {
		flag.Usage()
		os.Exit(1)
	}

	client2.RegisterShardedDrivers()
	conn, err := db.Open(*driver, *server)
	if err != nil {
		log.Fatalf("client error: %v", err)
	}

	log.Infof("Sending the query...")
	now := time.Now()

	// handle dml
	if isDml(args[0]) {
		t, err := conn.Begin()
		if err != nil {
			log.Fatalf("begin failed: %v", err)
		}

		r, err := conn.Exec(args[0], bindvars)
		if err != nil {
			log.Fatalf("exec failed: %v", err)
		}

		err = t.Commit()
		if err != nil {
			log.Fatalf("commit failed: %v", err)
		}

		n, err := r.RowsAffected()
		log.Infof("Total time:", time.Now().Sub(now), "Rows affected:", n)
	} else {

		// launch the query
		r, err := conn.Exec(args[0], bindvars)
		if err != nil {
			log.Fatalf("client error: %v", err)
		}

		// get the headers
		cols := r.Columns()
		if err != nil {
			log.Fatalf("client error: %v", err)
		}

		// print the header
		if *verbose {
			line := "Index"
			for _, field := range cols {
				line += "\t" + field
			}
			log.Infof(line)
		}

		// get the rows
		rowIndex := 0
		for row := r.Next(); row != nil; row = r.Next() {
			// print the line if needed
			if *verbose {
				line := fmt.Sprintf("%d", rowIndex)
				for _, value := range row {
					if value != nil {
						switch value.(type) {
						case []byte:
							line += fmt.Sprintf("\t%s", value)
						default:
							line += fmt.Sprintf("\t%v", value)
						}
					} else {
						line += "\t"
					}
				}
				log.Infof(line)
			}
			rowIndex++
		}
		if err := r.Err(); err != nil {
			log.Fatalf("Error %v\n", err)
		}
		log.Infof("Total time: %v / Row count: %v", time.Now().Sub(now), rowIndex)
	}
}
<commit_msg>Fixing log message.<commit_after>// Copyright 2012, Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"os"
	"strings"
	"time"

	log "github.com/golang/glog"
	"github.com/youtube/vitess/go/db"
	"github.com/youtube/vitess/go/vt/client2"
	_ "github.com/youtube/vitess/go/vt/client2/tablet"
)

var usage = `
The parameters are first the SQL command, then the bound variables.
For query arguments, we assume place-holders in the query string
in the form of :v0, :v1, etc.
`

var count = flag.Int("count", 1, "how many times to run the query")
var bindvars = FlagMap("bindvars", "bind vars as a json dictionary")
var server = flag.String("server", "localhost:6603/test_keyspace/0", "vtocc server as [user:password@]hostname:port/keyspace/shard[#keyrangestart-keyrangeend]")
var driver = flag.String("driver", "vttablet", "which driver to use (one of vttablet, vttablet-streaming, vtdb, vtdb-streaming)")
var verbose = flag.Bool("verbose", false, "show results")

func init() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
		flag.PrintDefaults()
		fmt.Fprintf(os.Stderr, usage)

	}
}

//----------------------------------

type Map map[string]interface{}

func (m *Map) String() string {
	b, err := json.Marshal(*m)
	if err != nil {
		return err.Error()
	}
	return string(b)
}

func (m *Map) Set(s string) (err error) {
	err = json.Unmarshal([]byte(s), m)
	if err != nil {
		return err
	}
	// json reads all numbers as float64
	// So, we just ditch floats for bindvars
	for k, v := range *m {
		f, ok := v.(float64)
		if ok {
			if f > 0 {
				(*m)[k] = uint64(f)
			} else {
				(*m)[k] = int64(f)
			}
		}
	}

	return nil
}

// For internal flag compatibility
func (m *Map) Get() interface{} {
	return m
}

func FlagMap(name, usage string) (m map[string]interface{}) {
	m = make(map[string]interface{})
	mm := Map(m)
	flag.Var(&mm, name, usage)
	return m
}

// FIXME(alainjobart) this is a cheap trick. Should probably use the
// query parser if we needed this to be 100% reliable.
func isDml(sql string) bool {
	lower := strings.TrimSpace(strings.ToLower(sql))
	return strings.HasPrefix(lower, "insert") || strings.HasPrefix(lower, "update")
}

func main() {
	flag.Parse()
	args := flag.Args()

	if len(args) == 0 {
		flag.Usage()
		os.Exit(1)
	}

	client2.RegisterShardedDrivers()
	conn, err := db.Open(*driver, *server)
	if err != nil {
		log.Fatalf("client error: %v", err)
	}

	log.Infof("Sending the query...")
	now := time.Now()

	// handle dml
	if isDml(args[0]) {
		t, err := conn.Begin()
		if err != nil {
			log.Fatalf("begin failed: %v", err)
		}

		r, err := conn.Exec(args[0], bindvars)
		if err != nil {
			log.Fatalf("exec failed: %v", err)
		}

		err = t.Commit()
		if err != nil {
			log.Fatalf("commit failed: %v", err)
		}

		n, err := r.RowsAffected()
		log.Infof("Total time: %v / Row affected: %v", time.Now().Sub(now), n)
	} else {

		// launch the query
		r, err := conn.Exec(args[0], bindvars)
		if err != nil {
			log.Fatalf("client error: %v", err)
		}

		// get the headers
		cols := r.Columns()
		if err != nil {
			log.Fatalf("client error: %v", err)
		}

		// print the header
		if *verbose {
			line := "Index"
			for _, field := range cols {
				line += "\t" + field
			}
			log.Infof(line)
		}

		// get the rows
		rowIndex := 0
		for row := r.Next(); row != nil; row = r.Next() {
			// print the line if needed
			if *verbose {
				line := fmt.Sprintf("%d", rowIndex)
				for _, value := range row {
					if value != nil {
						switch value.(type) {
						case []byte:
							line += fmt.Sprintf("\t%s", value)
						default:
							line += fmt.Sprintf("\t%v", value)
						}
					} else {
						line += "\t"
					}
				}
				log.Infof(line)
			}
			rowIndex++
		}
		if err := r.Err(); err != nil {
			log.Fatalf("Error %v\n", err)
		}
		log.Infof("Total time: %v / Row count: %v", time.Now().Sub(now), rowIndex)
	}
}
<|endoftext|>