<commit_before>package vm

import (
	"bytes"
	"fmt"
	"net"
	"net/url"
	"os"
	"strconv"
	"strings"
	"text/template"
	"time"

	bosherr "github.com/cloudfoundry/bosh-utils/errors"
	boshlog "github.com/cloudfoundry/bosh-utils/logger"
	boshsys "github.com/cloudfoundry/bosh-utils/system"
	boshuuid "github.com/cloudfoundry/bosh-utils/uuid"

	common "github.com/maximilien/bosh-softlayer-cpi/common"
	bslcommon "github.com/maximilien/bosh-softlayer-cpi/softlayer/common"
	bslcstem "github.com/maximilien/bosh-softlayer-cpi/softlayer/stemcell"
	bslcvmpool "github.com/maximilien/bosh-softlayer-cpi/softlayer/vm/pool"
	sl "github.com/maximilien/softlayer-go/softlayer"

	util "github.com/maximilien/bosh-softlayer-cpi/util"
)

const SOFTLAYER_VM_CREATOR_LOG_TAG = "SoftLayerVMCreator"

type SoftLayerCreator struct {
	softLayerClient        sl.Client
	agentEnvServiceFactory AgentEnvServiceFactory

	agentOptions  AgentOptions
	logger        boshlog.Logger
	uuidGenerator boshuuid.Generator
	fs            boshsys.FileSystem
}

func NewSoftLayerCreator(softLayerClient sl.Client, agentEnvServiceFactory AgentEnvServiceFactory, agentOptions AgentOptions, logger boshlog.Logger, uuidGenerator boshuuid.Generator, fs boshsys.FileSystem) SoftLayerCreator {
	bslcommon.TIMEOUT = 60 * time.Minute
	bslcommon.POLLING_INTERVAL = 10 * time.Second

	return SoftLayerCreator{
		softLayerClient:        softLayerClient,
		agentEnvServiceFactory: agentEnvServiceFactory,
		agentOptions:           agentOptions,
		logger:                 logger,
		uuidGenerator:          uuidGenerator,
		fs:                     fs,
	}
}

func (c SoftLayerCreator) CreateNewVM(agentID string, stemcell bslcstem.Stemcell, cloudProps VMCloudProperties, networks Networks, env Environment) (VM, error) {

	virtualGuestTemplate, err := CreateVirtualGuestTemplate(stemcell, cloudProps)

	if err != nil {
		return SoftLayerVM{}, bosherr.WrapError(err, "Creating virtual guest template")
	}

	virtualGuestService, err := c.softLayerClient.GetSoftLayer_Virtual_Guest_Service()
	if err != nil {
		return SoftLayerVM{}, bosherr.WrapError(err, "Creating VirtualGuestService from SoftLayer client")
	}

	virtualGuest, err := virtualGuestService.CreateObject(virtualGuestTemplate)
	if err != nil {
		return SoftLayerVM{}, bosherr.WrapError(err, "Creating VirtualGuest from SoftLayer client")
	}

	if cloudProps.EphemeralDiskSize == 0 {
		err = bslcommon.WaitForVirtualGuestLastCompleteTransaction(c.softLayerClient, virtualGuest.Id, "Service Setup")
		if err != nil {
			return SoftLayerVM{}, bosherr.WrapErrorf(err, "Waiting for VirtualGuest `%d` has Service Setup transaction complete", virtualGuest.Id)
		}
	} else {
		err = bslcommon.AttachEphemeralDiskToVirtualGuest(c.softLayerClient, virtualGuest.Id, cloudProps.EphemeralDiskSize, c.logger)
		if err != nil {
			return SoftLayerVM{}, bosherr.WrapError(err, fmt.Sprintf("Attaching ephemeral disk to VirtualGuest `%d`", virtualGuest.Id))
		}
	}

	virtualGuest, err = bslcommon.GetObjectDetailsOnVirtualGuest(c.softLayerClient, virtualGuest.Id)
	if err != nil {
		return SoftLayerVM{}, bosherr.WrapErrorf(err, "Cannot get details from virtual guest with id: %d.", virtualGuest.Id)
	}

	softlayerFileService := NewSoftlayerFileService(util.GetSshClient(), virtualGuest, c.logger, c.uuidGenerator, c.fs)
	agentEnvService := c.agentEnvServiceFactory.New(softlayerFileService, strconv.Itoa(virtualGuest.Id))

	if len(cloudProps.BoshIp) == 0 {
		// update /etc/hosts file of bosh-init vm
		c.updateEtcHostsOfBoshInit(fmt.Sprintf("%s  %s", virtualGuest.PrimaryBackendIpAddress, virtualGuest.FullyQualifiedDomainName))
		// Update mbus url setting for bosh director: construct mbus url with new director ip
		mbus, err := c.parseMbusURL(c.agentOptions.Mbus, virtualGuest.PrimaryBackendIpAddress)
		if err != nil {
			return SoftLayerVM{}, bosherr.WrapErrorf(err, "Cannot construct mbus url.")
		}
		c.agentOptions.Mbus = mbus
	} else {
		// Update mbus url setting
		mbus, err := c.parseMbusURL(c.agentOptions.Mbus, cloudProps.BoshIp)
		if err != nil {
			return SoftLayerVM{}, bosherr.WrapErrorf(err, "Cannot construct mbus url.")
		}
		c.agentOptions.Mbus = mbus
		// Update blobstore setting
		switch c.agentOptions.Blobstore.Type {
		case BlobstoreTypeDav:
			davConf := DavConfig(c.agentOptions.Blobstore.Options)
			c.updateDavConfig(&davConf, cloudProps.BoshIp)
		}
	}

	agentEnv := CreateAgentUserData(agentID, cloudProps, networks, env, c.agentOptions)
	if err != nil {
		return SoftLayerVM{}, bosherr.WrapErrorf(err, "Cannot agent env for virtual guest with id: %d.", virtualGuest.Id)
	}

	err = agentEnvService.Update(agentEnv)
	if err != nil {
		return SoftLayerVM{}, bosherr.WrapError(err, "Updating VM's agent env")
	}

	vm := NewSoftLayerVM(virtualGuest.Id, c.softLayerClient, util.GetSshClient(), agentEnvService, c.logger)

	if strings.ToUpper(common.GetOSEnvVariable("OS_RELOAD_ENABLED", "TRUE")) == "TRUE" && !strings.Contains(cloudProps.VmNamePrefix, "-worker") {
		db, err := bslcvmpool.OpenDB(bslcvmpool.SQLITE_DB_FILE_PATH)
		if err != nil {
			return SoftLayerVM{}, bosherr.WrapError(err, "Opening DB")
		}

		vmInfoDB := bslcvmpool.NewVMInfoDB(vm.ID(), virtualGuestTemplate.Hostname+"."+virtualGuestTemplate.Domain, "t", stemcell.Uuid(), agentID, c.logger, db)
		err = vmInfoDB.InsertVMInfo(bslcvmpool.DB_RETRY_TIMEOUT, bslcvmpool.DB_RETRY_INTERVAL)
		if err != nil {
			return SoftLayerVM{}, bosherr.WrapError(err, "Failed to insert the record into VM pool DB")
		}
	}

	return vm, nil
}

func (c SoftLayerCreator) Create(agentID string, stemcell bslcstem.Stemcell, cloudProps VMCloudProperties, networks Networks, env Environment) (VM, error) {
	if strings.ToUpper(common.GetOSEnvVariable("OS_RELOAD_ENABLED", "TRUE")) == "FALSE" {
		return c.CreateNewVM(agentID, stemcell, cloudProps, networks, env)
	}

	err := bslcvmpool.InitVMPoolDB(bslcvmpool.DB_RETRY_TIMEOUT, bslcvmpool.DB_RETRY_INTERVAL, c.logger)
	if err != nil {
		return SoftLayerVM{}, bosherr.WrapError(err, "Failed to initialize VM pool DB")
	}

	if strings.Contains(cloudProps.VmNamePrefix, "-worker") {
		vm, err := c.CreateNewVM(agentID, stemcell, cloudProps, networks, env)
		return vm, err
	}

	db, err := bslcvmpool.OpenDB(bslcvmpool.SQLITE_DB_FILE_PATH)
	if err != nil {
		return SoftLayerVM{}, bosherr.WrapError(err, "Opening DB")
	}

	vmInfoDB := bslcvmpool.NewVMInfoDB(0, "", "f", "", agentID, c.logger, db)
	defer vmInfoDB.CloseDB()

	err = vmInfoDB.QueryVMInfobyAgentID(bslcvmpool.DB_RETRY_TIMEOUT, bslcvmpool.DB_RETRY_INTERVAL)
	if err != nil {
		return SoftLayerVM{}, bosherr.WrapError(err, "Failed to query VM info by given agent ID "+agentID)
	}

	if vmInfoDB.VmProperties.Id != 0 {
		c.logger.Info(SOFTLAYER_VM_CREATOR_LOG_TAG, fmt.Sprintf("OS reload on the server id %d with stemcell %d", vmInfoDB.VmProperties.Id, stemcell.ID()))

		vm := NewSoftLayerVM(vmInfoDB.VmProperties.Id, c.softLayerClient, util.GetSshClient(), nil, c.logger)

		bslcommon.TIMEOUT = 24 * time.Hour
		err = vm.ReloadOS(stemcell)
		if err != nil {
			return SoftLayerVM{}, bosherr.WrapError(err, "Failed to reload OS")
		}

		if cloudProps.EphemeralDiskSize == 0 {
			err = bslcommon.WaitForVirtualGuestLastCompleteTransaction(c.softLayerClient, vm.ID(), "Service Setup")
			if err != nil {
				return SoftLayerVM{}, bosherr.WrapErrorf(err, "Waiting for VirtualGuest `%d` has Service Setup transaction complete", vm.ID())
			}
		} else {
			err = bslcommon.AttachEphemeralDiskToVirtualGuest(c.softLayerClient, vm.ID(), cloudProps.EphemeralDiskSize, c.logger)
			if err != nil {
				return SoftLayerVM{}, bosherr.WrapError(err, fmt.Sprintf("Attaching ephemeral disk to VirtualGuest `%d`", vm.ID()))
			}
		}

		virtualGuest, err := bslcommon.GetObjectDetailsOnVirtualGuest(c.softLayerClient, vmInfoDB.VmProperties.Id)
		if err != nil {
			return SoftLayerVM{}, bosherr.WrapErrorf(err, "Cannot get details from virtual guest with id: %d.", virtualGuest.Id)
		}

		softlayerFileService := NewSoftlayerFileService(util.GetSshClient(), virtualGuest, c.logger, c.uuidGenerator, c.fs)
		agentEnvService := c.agentEnvServiceFactory.New(softlayerFileService, strconv.Itoa(virtualGuest.Id))

		agentEnv := CreateAgentUserData(agentID, cloudProps, networks, env, c.agentOptions)
		if err != nil {
			return SoftLayerVM{}, bosherr.WrapErrorf(err, "Cannot agent env for virtual guest with id: %d.", virtualGuest.Id)
		}

		if len(cloudProps.BoshIp) == 0 {
			// update /etc/hosts file of bosh-init vm
			c.updateEtcHostsOfBoshInit(fmt.Sprintf("%s  %s", virtualGuest.PrimaryBackendIpAddress, virtualGuest.FullyQualifiedDomainName))
			// Update mbus url setting for bosh director: construct mbus url with new director ip
			mbus, err := c.parseMbusURL(c.agentOptions.Mbus, virtualGuest.PrimaryBackendIpAddress)
			if err != nil {
				return SoftLayerVM{}, bosherr.WrapErrorf(err, "Cannot construct mbus url.")
			}
			agentEnv.Mbus = mbus
		}

		err = agentEnvService.Update(agentEnv)
		if err != nil {
			return SoftLayerVM{}, bosherr.WrapError(err, "Updating VM's agent env")
		}

		vm = NewSoftLayerVM(virtualGuest.Id, c.softLayerClient, util.GetSshClient(), agentEnvService, c.logger)

		c.logger.Info(SOFTLAYER_VM_CREATOR_LOG_TAG, fmt.Sprintf("Updated in_use flag to 't' for the VM %d in VM pool", vmInfoDB.VmProperties.Id))
		vmInfoDB.VmProperties.InUse = "t"
		err = vmInfoDB.UpdateVMInfoByID(bslcvmpool.DB_RETRY_TIMEOUT, bslcvmpool.DB_RETRY_INTERVAL)
		if err != nil {
			return vm, bosherr.WrapError(err, fmt.Sprintf("Failed to query VM info by given ID %d", vm.ID()))
		} else {
			return vm, nil
		}

	}

	vmInfoDB.VmProperties.InUse = ""
	err = vmInfoDB.QueryVMInfobyAgentID(bslcvmpool.DB_RETRY_TIMEOUT, bslcvmpool.DB_RETRY_INTERVAL)
	if err != nil {
		return SoftLayerVM{}, bosherr.WrapError(err, "Failed to query VM info by given agent ID "+agentID)
	}

	if vmInfoDB.VmProperties.Id != 0 {
		return SoftLayerVM{}, bosherr.WrapError(err, "Wrong in_use status in VM with agent ID "+agentID+", Do not create a new VM")
	} else {
		return c.CreateNewVM(agentID, stemcell, cloudProps, networks, env)
	}

}

// Private methods
func (c SoftLayerCreator) updateDavConfig(config *DavConfig, directorIP string) (err error) {
	url := (*config)["endpoint"].(string)
	mbus, err := c.parseMbusURL(url, directorIP)
	if err != nil {
		return bosherr.WrapError(err, "Parsing Mbus URL")
	}

	(*config)["endpoint"] = mbus

	return nil
}

func (c SoftLayerCreator) parseMbusURL(mbusURL string, primaryBackendIpAddress string) (string, error) {
	parsedURL, err := url.Parse(mbusURL)
	if err != nil {
		return "", bosherr.WrapError(err, "Parsing Mbus URL")
	}
	var username, password, port string
	_, port, _ = net.SplitHostPort(parsedURL.Host)
	userInfo := parsedURL.User
	if userInfo != nil {
		username = userInfo.Username()
		password, _ = userInfo.Password()
		return fmt.Sprintf("%s://%s:%s@%s:%s", parsedURL.Scheme, username, password, primaryBackendIpAddress, port), nil
	}

	return fmt.Sprintf("%s://%s:%s", parsedURL.Scheme, primaryBackendIpAddress, port), nil
}

func (c SoftLayerCreator) updateEtcHostsOfBoshInit(record string) (err error) {
	buffer := bytes.NewBuffer([]byte{})
	t := template.Must(template.New("etc-hosts").Parse(ETC_HOSTS_TEMPLATE))

	err = t.Execute(buffer, record)
	if err != nil {
		return bosherr.WrapError(err, "Generating config from template")
	}

	err = c.fs.WriteFile("/etc/hosts", buffer.Bytes())
	if err != nil {
		return bosherr.WrapError(err, "Writing to /etc/hosts")
	}

	return nil
}

const ETC_HOSTS_TEMPLATE = `127.0.0.1 localhost
{{.}}
`

func (c SoftLayerCreator) appendRecordToEtcHosts(record string) (err error) {
	file, err := os.OpenFile("/etc/hosts", os.O_RDWR|os.O_APPEND, 0666)
	if err != nil {
		return bosherr.WrapError(err, "Failed to open file /etc/hosts")
	}

	defer file.Close()

	_, err = fmt.Fprintf(file, "\n %s", record)
	if err != nil {
		return bosherr.WrapErrorf(err, "Failed to append new record to /etc/hosts")
	}

	return nil
}
<commit_msg>Update softlayer_creator.go<commit_after>package vm

import (
	"bytes"
	"fmt"
	"net"
	"net/url"
	"os"
	"strconv"
	"strings"
	"text/template"

	bosherr "github.com/cloudfoundry/bosh-utils/errors"
	boshlog "github.com/cloudfoundry/bosh-utils/logger"
	boshsys "github.com/cloudfoundry/bosh-utils/system"
	boshuuid "github.com/cloudfoundry/bosh-utils/uuid"

	common "github.com/maximilien/bosh-softlayer-cpi/common"
	bslcommon "github.com/maximilien/bosh-softlayer-cpi/softlayer/common"
	bslcstem "github.com/maximilien/bosh-softlayer-cpi/softlayer/stemcell"
	bslcvmpool "github.com/maximilien/bosh-softlayer-cpi/softlayer/vm/pool"
	sl "github.com/maximilien/softlayer-go/softlayer"

	util "github.com/maximilien/bosh-softlayer-cpi/util"
)

const SOFTLAYER_VM_CREATOR_LOG_TAG = "SoftLayerVMCreator"

type SoftLayerCreator struct {
	softLayerClient        sl.Client
	agentEnvServiceFactory AgentEnvServiceFactory

	agentOptions  AgentOptions
	logger        boshlog.Logger
	uuidGenerator boshuuid.Generator
	fs            boshsys.FileSystem
}

func NewSoftLayerCreator(softLayerClient sl.Client, agentEnvServiceFactory AgentEnvServiceFactory, agentOptions AgentOptions, logger boshlog.Logger, uuidGenerator boshuuid.Generator, fs boshsys.FileSystem) SoftLayerCreator {
	bslcommon.TIMEOUT = 60 * time.Minute
	bslcommon.POLLING_INTERVAL = 10 * time.Second

	return SoftLayerCreator{
		softLayerClient:        softLayerClient,
		agentEnvServiceFactory: agentEnvServiceFactory,
		agentOptions:           agentOptions,
		logger:                 logger,
		uuidGenerator:          uuidGenerator,
		fs:                     fs,
	}
}

func (c SoftLayerCreator) CreateNewVM(agentID string, stemcell bslcstem.Stemcell, cloudProps VMCloudProperties, networks Networks, env Environment) (VM, error) {

	virtualGuestTemplate, err := CreateVirtualGuestTemplate(stemcell, cloudProps)

	if err != nil {
		return SoftLayerVM{}, bosherr.WrapError(err, "Creating virtual guest template")
	}

	virtualGuestService, err := c.softLayerClient.GetSoftLayer_Virtual_Guest_Service()
	if err != nil {
		return SoftLayerVM{}, bosherr.WrapError(err, "Creating VirtualGuestService from SoftLayer client")
	}

	virtualGuest, err := virtualGuestService.CreateObject(virtualGuestTemplate)
	if err != nil {
		return SoftLayerVM{}, bosherr.WrapError(err, "Creating VirtualGuest from SoftLayer client")
	}

	if cloudProps.EphemeralDiskSize == 0 {
		err = bslcommon.WaitForVirtualGuestLastCompleteTransaction(c.softLayerClient, virtualGuest.Id, "Service Setup")
		if err != nil {
			return SoftLayerVM{}, bosherr.WrapErrorf(err, "Waiting for VirtualGuest `%d` has Service Setup transaction complete", virtualGuest.Id)
		}
	} else {
		err = bslcommon.AttachEphemeralDiskToVirtualGuest(c.softLayerClient, virtualGuest.Id, cloudProps.EphemeralDiskSize, c.logger)
		if err != nil {
			return SoftLayerVM{}, bosherr.WrapError(err, fmt.Sprintf("Attaching ephemeral disk to VirtualGuest `%d`", virtualGuest.Id))
		}
	}

	virtualGuest, err = bslcommon.GetObjectDetailsOnVirtualGuest(c.softLayerClient, virtualGuest.Id)
	if err != nil {
		return SoftLayerVM{}, bosherr.WrapErrorf(err, "Cannot get details from virtual guest with id: %d.", virtualGuest.Id)
	}

	softlayerFileService := NewSoftlayerFileService(util.GetSshClient(), virtualGuest, c.logger, c.uuidGenerator, c.fs)
	agentEnvService := c.agentEnvServiceFactory.New(softlayerFileService, strconv.Itoa(virtualGuest.Id))

	if len(cloudProps.BoshIp) == 0 {
		// update /etc/hosts file of bosh-init vm
		c.updateEtcHostsOfBoshInit(fmt.Sprintf("%s  %s", virtualGuest.PrimaryBackendIpAddress, virtualGuest.FullyQualifiedDomainName))
		// Update mbus url setting for bosh director: construct mbus url with new director ip
		mbus, err := c.parseMbusURL(c.agentOptions.Mbus, virtualGuest.PrimaryBackendIpAddress)
		if err != nil {
			return SoftLayerVM{}, bosherr.WrapErrorf(err, "Cannot construct mbus url.")
		}
		c.agentOptions.Mbus = mbus
	} else {
		// Update mbus url setting
		mbus, err := c.parseMbusURL(c.agentOptions.Mbus, cloudProps.BoshIp)
		if err != nil {
			return SoftLayerVM{}, bosherr.WrapErrorf(err, "Cannot construct mbus url.")
		}
		c.agentOptions.Mbus = mbus
		// Update blobstore setting
		switch c.agentOptions.Blobstore.Type {
		case BlobstoreTypeDav:
			davConf := DavConfig(c.agentOptions.Blobstore.Options)
			c.updateDavConfig(&davConf, cloudProps.BoshIp)
		}
	}

	agentEnv := CreateAgentUserData(agentID, cloudProps, networks, env, c.agentOptions)
	if err != nil {
		return SoftLayerVM{}, bosherr.WrapErrorf(err, "Cannot agent env for virtual guest with id: %d.", virtualGuest.Id)
	}

	err = agentEnvService.Update(agentEnv)
	if err != nil {
		return SoftLayerVM{}, bosherr.WrapError(err, "Updating VM's agent env")
	}

	vm := NewSoftLayerVM(virtualGuest.Id, c.softLayerClient, util.GetSshClient(), agentEnvService, c.logger)

	if strings.ToUpper(common.GetOSEnvVariable("OS_RELOAD_ENABLED", "TRUE")) == "TRUE" && !strings.Contains(cloudProps.VmNamePrefix, "-worker") {
		db, err := bslcvmpool.OpenDB(bslcvmpool.SQLITE_DB_FILE_PATH)
		if err != nil {
			return SoftLayerVM{}, bosherr.WrapError(err, "Opening DB")
		}

		vmInfoDB := bslcvmpool.NewVMInfoDB(vm.ID(), virtualGuestTemplate.Hostname+"."+virtualGuestTemplate.Domain, "t", stemcell.Uuid(), agentID, c.logger, db)
		err = vmInfoDB.InsertVMInfo(bslcvmpool.DB_RETRY_TIMEOUT, bslcvmpool.DB_RETRY_INTERVAL)
		if err != nil {
			return SoftLayerVM{}, bosherr.WrapError(err, "Failed to insert the record into VM pool DB")
		}
	}

	return vm, nil
}

func (c SoftLayerCreator) Create(agentID string, stemcell bslcstem.Stemcell, cloudProps VMCloudProperties, networks Networks, env Environment) (VM, error) {
	if strings.ToUpper(common.GetOSEnvVariable("OS_RELOAD_ENABLED", "TRUE")) == "FALSE" {
		return c.CreateNewVM(agentID, stemcell, cloudProps, networks, env)
	}

	err := bslcvmpool.InitVMPoolDB(bslcvmpool.DB_RETRY_TIMEOUT, bslcvmpool.DB_RETRY_INTERVAL, c.logger)
	if err != nil {
		return SoftLayerVM{}, bosherr.WrapError(err, "Failed to initialize VM pool DB")
	}

	if strings.Contains(cloudProps.VmNamePrefix, "-worker") {
		vm, err := c.CreateNewVM(agentID, stemcell, cloudProps, networks, env)
		return vm, err
	}

	db, err := bslcvmpool.OpenDB(bslcvmpool.SQLITE_DB_FILE_PATH)
	if err != nil {
		return SoftLayerVM{}, bosherr.WrapError(err, "Opening DB")
	}

	vmInfoDB := bslcvmpool.NewVMInfoDB(0, "", "f", "", agentID, c.logger, db)
	defer vmInfoDB.CloseDB()

	err = vmInfoDB.QueryVMInfobyAgentID(bslcvmpool.DB_RETRY_TIMEOUT, bslcvmpool.DB_RETRY_INTERVAL)
	if err != nil {
		return SoftLayerVM{}, bosherr.WrapError(err, "Failed to query VM info by given agent ID "+agentID)
	}

	if vmInfoDB.VmProperties.Id != 0 {
		c.logger.Info(SOFTLAYER_VM_CREATOR_LOG_TAG, fmt.Sprintf("OS reload on the server id %d with stemcell %d", vmInfoDB.VmProperties.Id, stemcell.ID()))

		vm := NewSoftLayerVM(vmInfoDB.VmProperties.Id, c.softLayerClient, util.GetSshClient(), nil, c.logger)

		bslcommon.TIMEOUT = 24 * time.Hour
		err = vm.ReloadOS(stemcell)
		if err != nil {
			return SoftLayerVM{}, bosherr.WrapError(err, "Failed to reload OS")
		}

		if cloudProps.EphemeralDiskSize == 0 {
			err = bslcommon.WaitForVirtualGuestLastCompleteTransaction(c.softLayerClient, vm.ID(), "Service Setup")
			if err != nil {
				return SoftLayerVM{}, bosherr.WrapErrorf(err, "Waiting for VirtualGuest `%d` has Service Setup transaction complete", vm.ID())
			}
		} else {
			err = bslcommon.AttachEphemeralDiskToVirtualGuest(c.softLayerClient, vm.ID(), cloudProps.EphemeralDiskSize, c.logger)
			if err != nil {
				return SoftLayerVM{}, bosherr.WrapError(err, fmt.Sprintf("Attaching ephemeral disk to VirtualGuest `%d`", vm.ID()))
			}
		}

		virtualGuest, err := bslcommon.GetObjectDetailsOnVirtualGuest(c.softLayerClient, vmInfoDB.VmProperties.Id)
		if err != nil {
			return SoftLayerVM{}, bosherr.WrapErrorf(err, "Cannot get details from virtual guest with id: %d.", virtualGuest.Id)
		}

		softlayerFileService := NewSoftlayerFileService(util.GetSshClient(), virtualGuest, c.logger, c.uuidGenerator, c.fs)
		agentEnvService := c.agentEnvServiceFactory.New(softlayerFileService, strconv.Itoa(virtualGuest.Id))

		agentEnv := CreateAgentUserData(agentID, cloudProps, networks, env, c.agentOptions)
		if err != nil {
			return SoftLayerVM{}, bosherr.WrapErrorf(err, "Cannot agent env for virtual guest with id: %d.", virtualGuest.Id)
		}

		if len(cloudProps.BoshIp) == 0 {
			// update /etc/hosts file of bosh-init vm
			c.updateEtcHostsOfBoshInit(fmt.Sprintf("%s  %s", virtualGuest.PrimaryBackendIpAddress, virtualGuest.FullyQualifiedDomainName))
			// Update mbus url setting for bosh director: construct mbus url with new director ip
			mbus, err := c.parseMbusURL(c.agentOptions.Mbus, virtualGuest.PrimaryBackendIpAddress)
			if err != nil {
				return SoftLayerVM{}, bosherr.WrapErrorf(err, "Cannot construct mbus url.")
			}
			agentEnv.Mbus = mbus
		}

		err = agentEnvService.Update(agentEnv)
		if err != nil {
			return SoftLayerVM{}, bosherr.WrapError(err, "Updating VM's agent env")
		}

		vm = NewSoftLayerVM(virtualGuest.Id, c.softLayerClient, util.GetSshClient(), agentEnvService, c.logger)

		c.logger.Info(SOFTLAYER_VM_CREATOR_LOG_TAG, fmt.Sprintf("Updated in_use flag to 't' for the VM %d in VM pool", vmInfoDB.VmProperties.Id))
		vmInfoDB.VmProperties.InUse = "t"
		err = vmInfoDB.UpdateVMInfoByID(bslcvmpool.DB_RETRY_TIMEOUT, bslcvmpool.DB_RETRY_INTERVAL)
		if err != nil {
			return vm, bosherr.WrapError(err, fmt.Sprintf("Failed to query VM info by given ID %d", vm.ID()))
		} else {
			return vm, nil
		}

	}

	vmInfoDB.VmProperties.InUse = ""
	err = vmInfoDB.QueryVMInfobyAgentID(bslcvmpool.DB_RETRY_TIMEOUT, bslcvmpool.DB_RETRY_INTERVAL)
	if err != nil {
		return SoftLayerVM{}, bosherr.WrapError(err, "Failed to query VM info by given agent ID "+agentID)
	}

	if vmInfoDB.VmProperties.Id != 0 {
		return SoftLayerVM{}, bosherr.WrapError(err, "Wrong in_use status in VM with agent ID "+agentID+", Do not create a new VM")
	} else {
		return c.CreateNewVM(agentID, stemcell, cloudProps, networks, env)
	}

}

// Private methods
func (c SoftLayerCreator) updateDavConfig(config *DavConfig, directorIP string) (err error) {
	url := (*config)["endpoint"].(string)
	mbus, err := c.parseMbusURL(url, directorIP)
	if err != nil {
		return bosherr.WrapError(err, "Parsing Mbus URL")
	}

	(*config)["endpoint"] = mbus

	return nil
}

func (c SoftLayerCreator) parseMbusURL(mbusURL string, primaryBackendIpAddress string) (string, error) {
	parsedURL, err := url.Parse(mbusURL)
	if err != nil {
		return "", bosherr.WrapError(err, "Parsing Mbus URL")
	}
	var username, password, port string
	_, port, _ = net.SplitHostPort(parsedURL.Host)
	userInfo := parsedURL.User
	if userInfo != nil {
		username = userInfo.Username()
		password, _ = userInfo.Password()
		return fmt.Sprintf("%s://%s:%s@%s:%s", parsedURL.Scheme, username, password, primaryBackendIpAddress, port), nil
	}

	return fmt.Sprintf("%s://%s:%s", parsedURL.Scheme, primaryBackendIpAddress, port), nil
}

func (c SoftLayerCreator) updateEtcHostsOfBoshInit(record string) (err error) {
	buffer := bytes.NewBuffer([]byte{})
	t := template.Must(template.New("etc-hosts").Parse(ETC_HOSTS_TEMPLATE))

	err = t.Execute(buffer, record)
	if err != nil {
		return bosherr.WrapError(err, "Generating config from template")
	}

	err = c.fs.WriteFile("/etc/hosts", buffer.Bytes())
	if err != nil {
		return bosherr.WrapError(err, "Writing to /etc/hosts")
	}

	return nil
}

const ETC_HOSTS_TEMPLATE = `127.0.0.1 localhost
{{.}}
`

func (c SoftLayerCreator) appendRecordToEtcHosts(record string) (err error) {
	file, err := os.OpenFile("/etc/hosts", os.O_RDWR|os.O_APPEND, 0666)
	if err != nil {
		return bosherr.WrapError(err, "Failed to open file /etc/hosts")
	}

	defer file.Close()

	_, err = fmt.Fprintf(file, "\n %s", record)
	if err != nil {
		return bosherr.WrapErrorf(err, "Failed to append new record to /etc/hosts")
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2018 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

package mt7688

import (
	"periph.io/x/periph/conn/pin"
)

// All the pins supported by the CPU.
var (
	GPIO0  *Pin // I2S_SDI
	GPIO1  *Pin // I2S_SDO
	GPIO2  *Pin // I2S_WS
	GPIO3  *Pin // I2S_CLK
	GPIO4  *Pin // I2C_SCLK
	GPIO5  *Pin // I2C_SD
	GPIO6  *Pin // SPI_CS1
	GPIO7  *Pin // SPI_CLK
	GPIO8  *Pin // SPI_MOSI
	GPIO9  *Pin // SPI_MISO
	GPIO10 *Pin // SPI_CS0
	GPIO11 *Pin // GPIO0
	GPIO12 *Pin // UART_TXD0
	GPIO13 *Pin // UART_RXD0
	GPIO14 *Pin // MDI_TP_P1
	GPIO15 *Pin // MDI_TN_P1
	GPIO16 *Pin // MDI_RP_P1
	GPIO17 *Pin // MDI_RN_P1
	GPIO18 *Pin // MDI_RP_P2
	GPIO19 *Pin // MDI_RN_P2
	GPIO20 *Pin // MDI_TP_P2
	GPIO21 *Pin // MDI_TN_P2
	GPIO22 *Pin // MDI_TP_P3
	GPIO23 *Pin // MDI_TN_P3
	GPIO24 *Pin // MDI_RP_P3
	GPIO25 *Pin // MDI_RN_P3
	GPIO26 *Pin // MDI_RP_P4
	GPIO27 *Pin // MDI_RN_P4
	GPIO28 *Pin // MDI_TP_P4
	GPIO29 *Pin // MDI_TN_P4
	GPIO30 *Pin // EPHY_LED4_N_JTRST_N (7688KN)
	GPIO31 *Pin // EPHY_LED3_N_JTCLK (7688KN)
	GPIO32 *Pin // EPHY_LED2_N_JTMS (7688KN)
	GPIO33 *Pin // EPHY_LED1_N_JTDI (7688KN)
	GPIO34 *Pin // EPHY_LED0_N_JTDO (7688KN)
	GPIO35 *Pin // WLED_N (7688KN)
	GPIO36 *Pin // PERST_N
	GPIO37 *Pin // REF_CLKO
	GPIO38 *Pin // WDT_RST_N
	GPIO39 *Pin // EPHY_LED4_N_JTRST_N (7688AN)
	GPIO40 *Pin // EPHY_LED3_N_JTCLK (7688AN)
	GPIO41 *Pin // EPHY_LED2_N_JTMS (7688AN)
	GPIO42 *Pin // EPHY_LED1_N_JTDI (7688AN)
	GPIO43 *Pin // EPHY_LED0_N_JTDO (7688AN)
	GPIO44 *Pin // WLED_N (7688AN)
	GPIO45 *Pin // UART_TXD1
	GPIO46 *Pin // UART_RXD1
)

// mappingMT7688 describes the mapping of the MT7688 processor gpios to their
// alternate functions.
//
// It omits the in & out functions which are available on all gpio.
//
// The mapping is a combination of the naming from datasheet pages 25-31 and
// the GPIO Pin Function Mapping on page 108:
// https://labs.mediatek.com/fileMedia/download/9ef51e98-49b1-489a-b27e-391bac9f7bf3
var mapping = [][3]pin.Func{
	{"I2SSDI", "PCMDRX"}, // 0
	{"I2SSDO", "PCMDTX"},
	{"I2SW", "PCMCLK"},
	{"I2SCLK", "PCMFS"},
	{"I2C_SCLK"},
	{"I2C_SD"}, // 5
	{"SPI_CS1", "REF_CLKO"},
	{"SPI_CLK"},
	{"SPI_MOSI"},
	{"SPI_MISO"},
	{"SPI_CS0"}, // 10
	{"GPIO#11", "REF_CLKO", "PERST_N"},
	{"UART_TXD0"},
	{"UART_RXD0"},
	{"SPIS_CS", "", "PWM_CH0"},
	{"SPIS_CLK", "", "PWM_CH1"}, // 15
	{"SPIS_MISO", "", "UART_TXD2"},
	{"SPIS_MOSI", "", "UART_RXD2"},
	{"PWM_CH0", "", "eMMC_D7"},
	{"PWM_CH1", "", "eMMC_D6"},
	{"UART_TXD2", "PWM_CH2", "eMMC_D5"}, // 20
	{"UART_RXD2", "PWM_CH3", "eMMC_D4"},
	{"SD_WP"}, // TODO: add aliases mapping eMMC
	{"SD_CD"},
	{"SD_D1"},
	{"SD_D0"}, // 25
	{"SD_CLK"},
	{"SD_CMD"},
	{"SD_D3"},
	{"SD_D2"},
	{"EPHY_LED4_K", "", "JTAG_RST_N"}, // 30
	{"EPHY_LED3_K", "", "JTAG_CLK"},
	{"EPHY_LED2_K", "", "JTAG_TMS"},
	{"EPHY_LED1_K", "", "JTAG_TDI"},
	{"EPHY_LED0_K", "", "JTAG_TDO"},
	{"WLED_N"}, // 35
	{"PERST_N"},
	{"REF_CLKO"},
	{"WDT_RST_N"},
	{"EPHY_LED4_N", "", "JTAG_RST_N"},
	{"EPHY_LED3_N", "", "JTAG_CLK"}, // 40
	{"EPHY_LED2_N", "", "JTAG_TMS"},
	{"EPHY_LED1_N", "", "JTAG_TDI"},
	{"EPHY_LED0_N", "", "JTAG_TDO"},
	{"WLED_N"},
	{"UART_TXD1", "PWM_CH0"}, // 45
	{"UART_RXD1", "PWM_CH1"},
}

func init() {
	GPIO0 = &cpuPins[0]
	GPIO1 = &cpuPins[1]
	GPIO2 = &cpuPins[2]
	GPIO3 = &cpuPins[3]
	GPIO4 = &cpuPins[4]
	GPIO5 = &cpuPins[5]
	GPIO6 = &cpuPins[6]
	GPIO7 = &cpuPins[7]
	GPIO8 = &cpuPins[8]
	GPIO9 = &cpuPins[9]
	GPIO10 = &cpuPins[10]
	GPIO11 = &cpuPins[11]
	GPIO12 = &cpuPins[12]
	GPIO13 = &cpuPins[13]
	GPIO14 = &cpuPins[14]
	GPIO15 = &cpuPins[15]
	GPIO16 = &cpuPins[16]
	GPIO17 = &cpuPins[17]
	GPIO18 = &cpuPins[18]
	GPIO19 = &cpuPins[19]
	GPIO20 = &cpuPins[20]
	GPIO21 = &cpuPins[21]
	GPIO22 = &cpuPins[22]
	GPIO23 = &cpuPins[23]
	GPIO24 = &cpuPins[24]
	GPIO25 = &cpuPins[25]
	GPIO26 = &cpuPins[26]
	GPIO27 = &cpuPins[27]
	GPIO28 = &cpuPins[28]
	GPIO29 = &cpuPins[29]
	GPIO30 = &cpuPins[30]
	GPIO31 = &cpuPins[31]
	GPIO32 = &cpuPins[32]
	GPIO33 = &cpuPins[33]
	GPIO34 = &cpuPins[34]
	GPIO35 = &cpuPins[35]
	GPIO36 = &cpuPins[36]
	GPIO37 = &cpuPins[37]
	GPIO38 = &cpuPins[38]
	GPIO39 = &cpuPins[39]
	GPIO40 = &cpuPins[40]
	GPIO41 = &cpuPins[41]
	GPIO42 = &cpuPins[42]
	GPIO43 = &cpuPins[43]
	GPIO44 = &cpuPins[44]
	GPIO45 = &cpuPins[45]
	GPIO46 = &cpuPins[46]
}

// Mapping as
// https://labs.mediatek.com/fileMedia/download/9ef51e98-49b1-489a-b27e-391bac9f7bf3
// pages 109-110.
type gpioMap struct {
	// 0x00    RW    Direction control register (GPIO0-31)
	// 0x04    RW    Direction control register (GPIO32-63)
	// 0x08    RW    Direction control register (GPIO64-95)
	directionControl [3]uint32 // GPIO_CTRL_0~GPIO_CTRL_2
	// 0x10    RW    Polarity control register (GPIO0-31)
	// 0x14    RW    Polarity control register (GPIO32-63)
	// 0x18    RW    Polarity control register (GPIO64-95)
	polarityControl [3]uint32 // GPIO_POL_0~GPIO_POL_2
	// 0x20    RW    Data register (GPIO0-31)
	// 0x24    RW    Data register (GPIO32-63)
	// 0x28    RW    Data register (GPIO64-95)
	data [3]uint32 // GPIO_DATA_0~GPIO_DATA_2
	// 0x30    WO    Data set register (GPIO0-31)
	// 0x34    WO    Data set register (GPIO32-63)
	// 0x38    WO    Data set register (GPIO64-95)
	dataSet [3]uint32 // GPIO_DSET_0~GPIO_DSET_2
	// 0x40    WO    Data clear register (GPIO0-31)
	// 0x44    WO    Data clear register (GPIO32-63)
	// 0x48    WO    Data clear register (GPIO64-95)
	dataClear [3]uint32 // GPIO_DCLR_0~GPIO_DCLR_2
	// 0x50    RW    Rising edge interrupt enable register (GPIO0-31)
	// 0x54    RW    Rising edge interrupt enable register (GPIO32-63)
	// 0x58    RW    Rising edge interrupt enable register (GPIO64-95)
	risingEdgeIrqEnable [3]uint32 // GINT_REDGE_0~GINT_REDGE_2
	// 0x60    RW    Falling edge interrupt enable register (GPIO0-31)
	// 0x64    RW    Falling edge interrupt enable register (GPIO32-63)
	// 0x68    RW    Falling edge interrupt enable register (GPIO64-95)
	fallingEdgeIrqEnable [3]uint32 // GINT_FEDGE_0~GINT_FEDGE_2
	// 0x70    RW    High level interrupt enable register (GPIO0-31)
	// 0x74    RW    High level interrupt enable register (GPIO32-63)
	// 0x78    RW    High level interrupt enable register (GPIO64-95)
	highLevelIrqEnable [3]uint32 // GINT_HLVL_0~GINT_HLVL_2
	// 0x80    RW    Low level interrupt enable register (GPIO0-31)
	// 0x84    RW    Low level interrupt enable register (GPIO32-63)
	// 0x88    RW    Low level interrupt enable register (GPIO64-95)
	lowLevelIrqEnable [3]uint32 // GINT_LLVL_0~GINT_LLVL_2
	// 0x90    W1C   Interrupt status register (GPIO0-31)
	// 0x94    W1C   Interrupt status register (GPIO32-63)
	// 0x98    W1C   Interrupt status register (GPIO64-95)
	irqStatus [3]uint32 // GINT_STAT_0~GINT_STAT_2
	// 0xA0    W1C   Edge status register (GPIO0-31)
	// 0xA4    W1C   Edge status register (GPIO32-63)
	// 0xA8    W1C   Edge status register (GPIO64-95)
	edgeStatus [3]uint32 // GINT_EDGE_0~GINT_EDGE_2
}

// TODO: via docs: Unless specified explicitly, all the GPIO pins are in input mode after reset.
<commit_msg>mt7688: Fixes pin function naming (#313)<commit_after>// Copyright 2018 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

package mt7688

import (
	"periph.io/x/periph/conn/pin"
)

// All the pins supported by the CPU.
var (
	GPIO0  *Pin // I2S0_DIN
	GPIO1  *Pin // I2S0_DOUT
	GPIO2  *Pin // I2S0_WS
	GPIO3  *Pin // I2S0_SCK
	GPIO4  *Pin // I2C0_SCL
	GPIO5  *Pin // I2C0_SDA
	GPIO6  *Pin // SPI0_CS1, CLK0
	GPIO7  *Pin // SPI0_CLK
	GPIO8  *Pin // SPI0_MOSI
	GPIO9  *Pin // SPI0_MISO
	GPIO10 *Pin // SPI0_CS0
	GPIO11 *Pin // CLK0
	GPIO12 *Pin // UART0_TX
	GPIO13 *Pin // UART0_RX
	GPIO14 *Pin // PWM0
	GPIO15 *Pin // PWM1
	GPIO16 *Pin // UART2_TX
	GPIO17 *Pin // UART2_RX
	GPIO18 *Pin // PWM0
	GPIO19 *Pin // PWM1
	GPIO20 *Pin // UART2_TX, PWM2
	GPIO21 *Pin // UART2_RX, PWM3
	GPIO22 *Pin
	GPIO23 *Pin
	GPIO24 *Pin
	GPIO25 *Pin
	GPIO26 *Pin
	GPIO27 *Pin
	GPIO28 *Pin
	GPIO29 *Pin
	GPIO30 *Pin // JTAG0_TRST (7688KN)
	GPIO31 *Pin // JTAG0_TCK  (7688KN)
	GPIO32 *Pin // JTAG0_TMS  (7688KN)
	GPIO33 *Pin // JTAG0_TDI  (7688KN)
	GPIO34 *Pin // JTAG0_TDO  (7688KN)
	GPIO35 *Pin
	GPIO36 *Pin
	GPIO37 *Pin // CLKO
	GPIO38 *Pin
	GPIO39 *Pin // JTAG0_TRST (7688AN)
	GPIO40 *Pin // JTAG0_TCK  (7688AN)
	GPIO41 *Pin // JTAG0_TMS  (7688AN)
	GPIO42 *Pin // JTAG0_TDI  (7688AN)
	GPIO43 *Pin // JTAG0_TDO  (7688AN)
	GPIO44 *Pin
	GPIO45 *Pin // UART1_TX, PWM0
	GPIO46 *Pin // UART1_RX, PWM1
)

// mappingMT7688 describes the mapping of the MT7688 processor gpios to their
// alternate functions.
//
// It omits the in & out functions which are available on all gpio.
//
// The mapping is a combination of the naming from datasheet pages 25-31 and
// the GPIO Pin Function Mapping on page 108:
// https://labs.mediatek.com/fileMedia/download/9ef51e98-49b1-489a-b27e-391bac9f7bf3
var mapping = [][3]pin.Func{
	{"I2S0_DIN"}, // 0
	{"I2S0_DOUT"},
	{"I2S0_WS"},
	{"I2S0_SCK"},
	{"I2C0_SCL"},
	{"I2C0_SDA"}, // 5
	{"SPI0_CS1", "", "CLK0"},
	{"SPI0_CLK"},
	{"SPI0_MOSI"},
	{"SPI0_MISO"},
	{"SPI0_CS0"}, // 10
	{"", "CLK0"},
	{"UART0_TX"},
	{"UART0_RX"},
	{"", "", "PWM0"},
	{"", "", "PWM1"}, // 15
	{"", "", "UART2_TX"},
	{"", "", "UART2_RX"},
	{"PWM0"},
	{"PWM1"},
	{"UART2_TX", "PWM2"}, // 20
	{"UART2_RX", "PWM3"},
	{""},
	{""},
	{""},
	{""}, // 25
	{""},
	{""},
	{""},
	{""},
	{"", "", "JTAG0_TRST"}, // 30
	{"", "", "JTAG0_TCK"},
	{"", "", "JTAG0_TMS"},
	{"", "", "JTAG0_TDI"},
	{"", "", "JTAG0_TDO"},
	{""}, // 35
	{""},
	{"CLK0"},
	{""},
	{"", "", "JTAG0_TRST"},
	{"", "", "JTAG0_TCK"}, // 40
	{"", "", "JTAG0_TMS"},
	{"", "", "JTAG0_TDI"},
	{"", "", "JTAG0_TDO"},
	{""},
	{"UART1_TX", "PWM0"}, // 45
	{"UART1_RX", "PWM1"},
}

func init() {
	GPIO0 = &cpuPins[0]
	GPIO1 = &cpuPins[1]
	GPIO2 = &cpuPins[2]
	GPIO3 = &cpuPins[3]
	GPIO4 = &cpuPins[4]
	GPIO5 = &cpuPins[5]
	GPIO6 = &cpuPins[6]
	GPIO7 = &cpuPins[7]
	GPIO8 = &cpuPins[8]
	GPIO9 = &cpuPins[9]
	GPIO10 = &cpuPins[10]
	GPIO11 = &cpuPins[11]
	GPIO12 = &cpuPins[12]
	GPIO13 = &cpuPins[13]
	GPIO14 = &cpuPins[14]
	GPIO15 = &cpuPins[15]
	GPIO16 = &cpuPins[16]
	GPIO17 = &cpuPins[17]
	GPIO18 = &cpuPins[18]
	GPIO19 = &cpuPins[19]
	GPIO20 = &cpuPins[20]
	GPIO21 = &cpuPins[21]
	GPIO22 = &cpuPins[22]
	GPIO23 = &cpuPins[23]
	GPIO24 = &cpuPins[24]
	GPIO25 = &cpuPins[25]
	GPIO26 = &cpuPins[26]
	GPIO27 = &cpuPins[27]
	GPIO28 = &cpuPins[28]
	GPIO29 = &cpuPins[29]
	GPIO30 = &cpuPins[30]
	GPIO31 = &cpuPins[31]
	GPIO32 = &cpuPins[32]
	GPIO33 = &cpuPins[33]
	GPIO34 = &cpuPins[34]
	GPIO35 = &cpuPins[35]
	GPIO36 = &cpuPins[36]
	GPIO37 = &cpuPins[37]
	GPIO38 = &cpuPins[38]
	GPIO39 = &cpuPins[39]
	GPIO40 = &cpuPins[40]
	GPIO41 = &cpuPins[41]
	GPIO42 = &cpuPins[42]
	GPIO43 = &cpuPins[43]
	GPIO44 = &cpuPins[44]
	GPIO45 = &cpuPins[45]
	GPIO46 = &cpuPins[46]
}

// Mapping as
// https://labs.mediatek.com/fileMedia/download/9ef51e98-49b1-489a-b27e-391bac9f7bf3
// pages 109-110.
type gpioMap struct {
	// 0x00    RW    Direction control register (GPIO0-31)
	// 0x04    RW    Direction control register (GPIO32-63)
	// 0x08    RW    Direction control register (GPIO64-95)
	directionControl [3]uint32 // GPIO_CTRL_0~GPIO_CTRL_2
	// 0x10    RW    Polarity control register (GPIO0-31)
	// 0x14    RW    Polarity control register (GPIO32-63)
	// 0x18    RW    Polarity control register (GPIO64-95)
	polarityControl [3]uint32 // GPIO_POL_0~GPIO_POL_2
	// 0x20    RW    Data register (GPIO0-31)
	// 0x24    RW    Data register (GPIO32-63)
	// 0x28    RW    Data register (GPIO64-95)
	data [3]uint32 // GPIO_DATA_0~GPIO_DATA_2
	// 0x30    WO    Data set register (GPIO0-31)
	// 0x34    WO    Data set register (GPIO32-63)
	// 0x38    WO    Data set register (GPIO64-95)
	dataSet [3]uint32 // GPIO_DSET_0~GPIO_DSET_2
	// 0x40    WO    Data clear register (GPIO0-31)
	// 0x44    WO    Data clear register (GPIO32-63)
	// 0x48    WO    Data clear register (GPIO64-95)
	dataClear [3]uint32 // GPIO_DCLR_0~GPIO_DCLR_2
	// 0x50    RW    Rising edge interrupt enable register (GPIO0-31)
	// 0x54    RW    Rising edge interrupt enable register (GPIO32-63)
	// 0x58    RW    Rising edge interrupt enable register (GPIO64-95)
	risingEdgeIrqEnable [3]uint32 // GINT_REDGE_0~GINT_REDGE_2
	// 0x60    RW    Falling edge interrupt enable register (GPIO0-31)
	// 0x64    RW    Falling edge interrupt enable register (GPIO32-63)
	// 0x68    RW    Falling edge interrupt enable register (GPIO64-95)
	fallingEdgeIrqEnable [3]uint32 // GINT_FEDGE_0~GINT_FEDGE_2
	// 0x70    RW    High level interrupt enable register (GPIO0-31)
	// 0x74    RW    High level interrupt enable register (GPIO32-63)
	// 0x78    RW    High level interrupt enable register (GPIO64-95)
	highLevelIrqEnable [3]uint32 // GINT_HLVL_0~GINT_HLVL_2
	// 0x80    RW    Low level interrupt enable register (GPIO0-31)
	// 0x84    RW    Low level interrupt enable register (GPIO32-63)
	// 0x88    RW    Low level interrupt enable register (GPIO64-95)
	lowLevelIrqEnable [3]uint32 // GINT_LLVL_0~GINT_LLVL_2
	// 0x90    W1C   Interrupt status register (GPIO0-31)
	// 0x94    W1C   Interrupt status register (GPIO32-63)
	// 0x98    W1C   Interrupt status register (GPIO64-95)
	irqStatus [3]uint32 // GINT_STAT_0~GINT_STAT_2
	// 0xA0    W1C   Edge status register (GPIO0-31)
	// 0xA4    W1C   Edge status register (GPIO32-63)
	// 0xA8    W1C   Edge status register (GPIO64-95)
	edgeStatus [3]uint32 // GINT_EDGE_0~GINT_EDGE_2
}

// TODO: via docs: Unless specified explicitly, all the GPIO pins are in input mode after reset.
<|endoftext|>


<commit_before>package overlay

import (
	"fmt"
	"net"
	"strings"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/hashicorp/serf/serf"
)

type ovNotify struct {
	action string
	eid    string
	nid    string
}

type logWriter struct{}

func (l *logWriter) Write(p []byte) (int, error) {
	str := string(p)

	switch {
	case strings.Contains(str, "[WARN]"):
		logrus.Warn(str)
	case strings.Contains(str, "[DEBUG]"):
		logrus.Debug(str)
	case strings.Contains(str, "[INFO]"):
		logrus.Info(str)
	case strings.Contains(str, "[ERR]"):
		logrus.Error(str)
	}

	return len(p), nil
}

func (d *driver) serfInit() error {
	var err error

	config := serf.DefaultConfig()
	config.Init()
	config.MemberlistConfig.BindAddr = d.bindAddress

	d.eventCh = make(chan serf.Event, 4)
	config.EventCh = d.eventCh
	config.UserCoalescePeriod = 1 * time.Second
	config.UserQuiescentPeriod = 50 * time.Millisecond

	config.LogOutput = &logWriter{}
	config.MemberlistConfig.LogOutput = config.LogOutput

	s, err := serf.Create(config)
	if err != nil {
		return fmt.Errorf("failed to create cluster node: %v", err)
	}
	defer func() {
		if err != nil {
			s.Shutdown()
		}
	}()

	d.serfInstance = s

	d.notifyCh = make(chan ovNotify)
	d.exitCh = make(chan chan struct{})

	go d.startSerfLoop(d.eventCh, d.notifyCh, d.exitCh)
	return nil
}

func (d *driver) serfJoin(neighIP string) error {
	if neighIP == "" {
		return fmt.Errorf("no neighbor to join")
	}
	if _, err := d.serfInstance.Join([]string{neighIP}, false); err != nil {
		return fmt.Errorf("Failed to join the cluster at neigh IP %s: %v",
			neighIP, err)
	}
	return nil
}

func (d *driver) notifyEvent(event ovNotify) {
	n := d.network(event.nid)
	ep := n.endpoint(event.eid)

	ePayload := fmt.Sprintf("%s %s %s %s", event.action, ep.addr.IP.String(),
		net.IP(ep.addr.Mask).String(), ep.mac.String())
	eName := fmt.Sprintf("jl %s %s %s", d.serfInstance.LocalMember().Addr.String(),
		event.nid, event.eid)

	if err := d.serfInstance.UserEvent(eName, []byte(ePayload), true); err != nil {
		logrus.Errorf("Sending user event failed: %v\n", err)
	}
}

func (d *driver) processEvent(u serf.UserEvent) {
	logrus.Debugf("Received user event name:%s, payload:%s\n", u.Name,
		string(u.Payload))

	var dummy, action, vtepStr, nid, eid, ipStr, maskStr, macStr string
	if _, err := fmt.Sscan(u.Name, &dummy, &vtepStr, &nid, &eid); err != nil {
		fmt.Printf("Failed to scan name string: %v\n", err)
	}

	if _, err := fmt.Sscan(string(u.Payload), &action,
		&ipStr, &maskStr, &macStr); err != nil {
		fmt.Printf("Failed to scan value string: %v\n", err)
	}

	logrus.Debugf("Parsed data = %s/%s/%s/%s/%s/%s\n", nid, eid, vtepStr, ipStr, maskStr, macStr)

	mac, err := net.ParseMAC(macStr)
	if err != nil {
		logrus.Errorf("Failed to parse mac: %v\n", err)
	}

	if d.serfInstance.LocalMember().Addr.String() == vtepStr {
		return
	}

	switch action {
	case "join":
		if err := d.peerAdd(nid, eid, net.ParseIP(ipStr), net.IPMask(net.ParseIP(maskStr).To4()), mac,
			net.ParseIP(vtepStr), true); err != nil {
			logrus.Errorf("Peer add failed in the driver: %v\n", err)
		}
	case "leave":
		if err := d.peerDelete(nid, eid, net.ParseIP(ipStr), net.IPMask(net.ParseIP(maskStr).To4()), mac,
			net.ParseIP(vtepStr), true); err != nil {
			logrus.Errorf("Peer delete failed in the driver: %v\n", err)
		}
	}
}

func (d *driver) processQuery(q *serf.Query) {
	logrus.Debugf("Received query name:%s, payload:%s\n", q.Name,
		string(q.Payload))

	var nid, ipStr string
	if _, err := fmt.Sscan(string(q.Payload), &nid, &ipStr); err != nil {
		fmt.Printf("Failed to scan query payload string: %v\n", err)
	}

	peerMac, peerIPMask, vtep, err := d.peerDbSearch(nid, net.ParseIP(ipStr))
	if err != nil {
		return
	}

	q.Respond([]byte(fmt.Sprintf("%s %s %s", peerMac.String(), net.IP(peerIPMask).String(), vtep.String())))
}

func (d *driver) resolvePeer(nid string, peerIP net.IP) (net.HardwareAddr, net.IPMask, net.IP, error) {
	qPayload := fmt.Sprintf("%s %s", string(nid), peerIP.String())
	resp, err := d.serfInstance.Query("peerlookup", []byte(qPayload), nil)
	if err != nil {
		return nil, nil, nil, fmt.Errorf("resolving peer by querying the cluster failed: %v", err)
	}

	respCh := resp.ResponseCh()
	select {
	case r := <-respCh:
		var macStr, maskStr, vtepStr string
		if _, err := fmt.Sscan(string(r.Payload), &macStr, &maskStr, &vtepStr); err != nil {
			return nil, nil, nil, fmt.Errorf("bad response %q for the resolve query: %v", string(r.Payload), err)
		}

		mac, err := net.ParseMAC(macStr)
		if err != nil {
			return nil, nil, nil, fmt.Errorf("failed to parse mac: %v", err)
		}

		return mac, net.IPMask(net.ParseIP(maskStr).To4()), net.ParseIP(vtepStr), nil

	case <-time.After(time.Second):
		return nil, nil, nil, fmt.Errorf("timed out resolving peer by querying the cluster")
	}
}

func (d *driver) startSerfLoop(eventCh chan serf.Event, notifyCh chan ovNotify,
	exitCh chan chan struct{}) {

	for {
		select {
		case notify, ok := <-notifyCh:
			if !ok {
				break
			}

			d.notifyEvent(notify)
		case ch, ok := <-exitCh:
			if !ok {
				break
			}

			if err := d.serfInstance.Leave(); err != nil {
				logrus.Errorf("failed leaving the cluster: %v\n", err)
			}

			d.serfInstance.Shutdown()
			close(ch)
			return
		case e, ok := <-eventCh:
			if !ok {
				break
			}

			if e.EventType() == serf.EventQuery {
				d.processQuery(e.(*serf.Query))
				break
			}

			u, ok := e.(serf.UserEvent)
			if !ok {
				break
			}
			d.processEvent(u)
		}
	}
}

func (d *driver) isSerfAlive() bool {
	d.Lock()
	serfInstance := d.serfInstance
	d.Unlock()
	if serfInstance == nil || serfInstance.State() != serf.SerfAlive {
		return false
	}
	return true
}
<commit_msg>Do not attempt serf query when not initialized<commit_after>package overlay

import (
	"fmt"
	"net"
	"strings"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/hashicorp/serf/serf"
)

type ovNotify struct {
	action string
	eid    string
	nid    string
}

type logWriter struct{}

func (l *logWriter) Write(p []byte) (int, error) {
	str := string(p)

	switch {
	case strings.Contains(str, "[WARN]"):
		logrus.Warn(str)
	case strings.Contains(str, "[DEBUG]"):
		logrus.Debug(str)
	case strings.Contains(str, "[INFO]"):
		logrus.Info(str)
	case strings.Contains(str, "[ERR]"):
		logrus.Error(str)
	}

	return len(p), nil
}

func (d *driver) serfInit() error {
	var err error

	config := serf.DefaultConfig()
	config.Init()
	config.MemberlistConfig.BindAddr = d.bindAddress

	d.eventCh = make(chan serf.Event, 4)
	config.EventCh = d.eventCh
	config.UserCoalescePeriod = 1 * time.Second
	config.UserQuiescentPeriod = 50 * time.Millisecond

	config.LogOutput = &logWriter{}
	config.MemberlistConfig.LogOutput = config.LogOutput

	s, err := serf.Create(config)
	if err != nil {
		return fmt.Errorf("failed to create cluster node: %v", err)
	}
	defer func() {
		if err != nil {
			s.Shutdown()
		}
	}()

	d.serfInstance = s

	d.notifyCh = make(chan ovNotify)
	d.exitCh = make(chan chan struct{})

	go d.startSerfLoop(d.eventCh, d.notifyCh, d.exitCh)
	return nil
}

func (d *driver) serfJoin(neighIP string) error {
	if neighIP == "" {
		return fmt.Errorf("no neighbor to join")
	}
	if _, err := d.serfInstance.Join([]string{neighIP}, false); err != nil {
		return fmt.Errorf("Failed to join the cluster at neigh IP %s: %v",
			neighIP, err)
	}
	return nil
}

func (d *driver) notifyEvent(event ovNotify) {
	n := d.network(event.nid)
	ep := n.endpoint(event.eid)

	ePayload := fmt.Sprintf("%s %s %s %s", event.action, ep.addr.IP.String(),
		net.IP(ep.addr.Mask).String(), ep.mac.String())
	eName := fmt.Sprintf("jl %s %s %s", d.serfInstance.LocalMember().Addr.String(),
		event.nid, event.eid)

	if err := d.serfInstance.UserEvent(eName, []byte(ePayload), true); err != nil {
		logrus.Errorf("Sending user event failed: %v\n", err)
	}
}

func (d *driver) processEvent(u serf.UserEvent) {
	logrus.Debugf("Received user event name:%s, payload:%s\n", u.Name,
		string(u.Payload))

	var dummy, action, vtepStr, nid, eid, ipStr, maskStr, macStr string
	if _, err := fmt.Sscan(u.Name, &dummy, &vtepStr, &nid, &eid); err != nil {
		fmt.Printf("Failed to scan name string: %v\n", err)
	}

	if _, err := fmt.Sscan(string(u.Payload), &action,
		&ipStr, &maskStr, &macStr); err != nil {
		fmt.Printf("Failed to scan value string: %v\n", err)
	}

	logrus.Debugf("Parsed data = %s/%s/%s/%s/%s/%s\n", nid, eid, vtepStr, ipStr, maskStr, macStr)

	mac, err := net.ParseMAC(macStr)
	if err != nil {
		logrus.Errorf("Failed to parse mac: %v\n", err)
	}

	if d.serfInstance.LocalMember().Addr.String() == vtepStr {
		return
	}

	switch action {
	case "join":
		if err := d.peerAdd(nid, eid, net.ParseIP(ipStr), net.IPMask(net.ParseIP(maskStr).To4()), mac,
			net.ParseIP(vtepStr), true); err != nil {
			logrus.Errorf("Peer add failed in the driver: %v\n", err)
		}
	case "leave":
		if err := d.peerDelete(nid, eid, net.ParseIP(ipStr), net.IPMask(net.ParseIP(maskStr).To4()), mac,
			net.ParseIP(vtepStr), true); err != nil {
			logrus.Errorf("Peer delete failed in the driver: %v\n", err)
		}
	}
}

func (d *driver) processQuery(q *serf.Query) {
	logrus.Debugf("Received query name:%s, payload:%s\n", q.Name,
		string(q.Payload))

	var nid, ipStr string
	if _, err := fmt.Sscan(string(q.Payload), &nid, &ipStr); err != nil {
		fmt.Printf("Failed to scan query payload string: %v\n", err)
	}

	peerMac, peerIPMask, vtep, err := d.peerDbSearch(nid, net.ParseIP(ipStr))
	if err != nil {
		return
	}

	q.Respond([]byte(fmt.Sprintf("%s %s %s", peerMac.String(), net.IP(peerIPMask).String(), vtep.String())))
}

func (d *driver) resolvePeer(nid string, peerIP net.IP) (net.HardwareAddr, net.IPMask, net.IP, error) {
	if d.serfInstance == nil {
		return nil, nil, nil, fmt.Errorf("could not resolve peer: serf instance not initialized")
	}

	qPayload := fmt.Sprintf("%s %s", string(nid), peerIP.String())
	resp, err := d.serfInstance.Query("peerlookup", []byte(qPayload), nil)
	if err != nil {
		return nil, nil, nil, fmt.Errorf("resolving peer by querying the cluster failed: %v", err)
	}

	respCh := resp.ResponseCh()
	select {
	case r := <-respCh:
		var macStr, maskStr, vtepStr string
		if _, err := fmt.Sscan(string(r.Payload), &macStr, &maskStr, &vtepStr); err != nil {
			return nil, nil, nil, fmt.Errorf("bad response %q for the resolve query: %v", string(r.Payload), err)
		}

		mac, err := net.ParseMAC(macStr)
		if err != nil {
			return nil, nil, nil, fmt.Errorf("failed to parse mac: %v", err)
		}

		return mac, net.IPMask(net.ParseIP(maskStr).To4()), net.ParseIP(vtepStr), nil

	case <-time.After(time.Second):
		return nil, nil, nil, fmt.Errorf("timed out resolving peer by querying the cluster")
	}
}

func (d *driver) startSerfLoop(eventCh chan serf.Event, notifyCh chan ovNotify,
	exitCh chan chan struct{}) {

	for {
		select {
		case notify, ok := <-notifyCh:
			if !ok {
				break
			}

			d.notifyEvent(notify)
		case ch, ok := <-exitCh:
			if !ok {
				break
			}

			if err := d.serfInstance.Leave(); err != nil {
				logrus.Errorf("failed leaving the cluster: %v\n", err)
			}

			d.serfInstance.Shutdown()
			close(ch)
			return
		case e, ok := <-eventCh:
			if !ok {
				break
			}

			if e.EventType() == serf.EventQuery {
				d.processQuery(e.(*serf.Query))
				break
			}

			u, ok := e.(serf.UserEvent)
			if !ok {
				break
			}
			d.processEvent(u)
		}
	}
}

func (d *driver) isSerfAlive() bool {
	d.Lock()
	serfInstance := d.serfInstance
	d.Unlock()
	if serfInstance == nil || serfInstance.State() != serf.SerfAlive {
		return false
	}
	return true
}
<|endoftext|>


<commit_before>package golog

const (
	INFO int = iota
	WARNING
	ERROR
	FATAL
)

type PackageLogger struct {
	LocationLogger
	MultiLogOuter
	failFunc func()
}

func newPackageLoggerCommon(outer MultiLogOuter, minloglevel_flag *int,
failFunc func(), locFunc func(skip int) *LogLocation) *PackageLogger {
	ret := &PackageLogger{failFunc: failFunc, MultiLogOuter: outer}

	ret.LocationLogger = NewLocationLogger(
		&loggerImpl{outer, minloglevel_flag, func() { ret.failFunc() }},
		FullLocation)

	return ret
}

func NewDefaultPackageLogger() *PackageLogger {
	return newPackageLoggerCommon(
		NewDefaultMultiLogOuter(),
		flag_minloglevel,
		ExitError,
		FullLocation)
}

func NewPackageLogger(outer MultiLogOuter, minloglevel int,
failFunc func(), locFunc func(skip int) *LogLocation) *PackageLogger {
	return newPackageLoggerCommon(outer, &minloglevel, failFunc, locFunc)
}

// Associates TestController with a the "testing LogOuter and updates
// l.FailNow() to call t.FailNow().
func (l *PackageLogger) StartTestLogging(t TestController) {
	l.MultiLogOuter.AddLogOuter("testing", NewTestLogOuter(t))
	// TODO(awreece) Save old failFunc so we can restore it properly.
	l.failFunc = func() { t.FailNow() }
}

// Removes the testing logger and restores l.FailNow() to its previous state.
func (l *PackageLogger) StopTestLogging() {
	l.MultiLogOuter.RemoveLogOuter("testing")
	// TODO(awreece) Restored to saved failFunc.
	l.failFunc = ExitError
}
func (l *PackageLogger) Info(msg ...interface{}) {
	l.LogDepth(INFO, printClosure(msg...), 1)
}
func (l *PackageLogger) Infof(fmt string, vals ...interface{}) {
	l.LogDepth(INFO, printfClosure(fmt, vals...), 1)
}
func (l *PackageLogger) Infoc(closure func() string) {
	l.LogDepth(INFO, closure, 1)
}
func (l *PackageLogger) Warning(msg ...interface{}) {
	l.LogDepth(WARNING, printClosure(msg...), 1)
}
func (l *PackageLogger) Warningf(fmt string, vals ...interface{}) {
	l.LogDepth(WARNING, printfClosure(fmt, vals...), 1)
}
func (l *PackageLogger) Warningc(closure func() string) {
	l.LogDepth(WARNING, closure, 1)
}
func (l *PackageLogger) Error(msg ...interface{}) {
	l.LogDepth(ERROR, printClosure(msg...), 1)
}
func (l *PackageLogger) Errorf(fmt string, vals ...interface{}) {
	l.LogDepth(ERROR, printfClosure(fmt, vals...), 1)
}
func (l *PackageLogger) Errorc(closure func() string) {
	l.LogDepth(ERROR, closure, 1)
}
func (l *PackageLogger) Fatal(msg ...interface{}) {
	l.LogDepth(FATAL, printClosure(msg...), 1)
	l.FailNow()
}
func (l *PackageLogger) Fatalf(fmt string, vals ...interface{}) {
	l.LogDepth(FATAL, printfClosure(fmt, vals...), 1)
	l.FailNow()
}
func (l *PackageLogger) Fatalc(closure func() string) {
	l.LogDepth(FATAL, closure, 1)
	l.FailNow()
}
<commit_msg>Comment pacakge logger wrapper functions<commit_after>package golog

const (
	INFO int = iota
	WARNING
	ERROR
	FATAL
)

type PackageLogger struct {
	LocationLogger
	MultiLogOuter
	failFunc func()
}

func newPackageLoggerCommon(outer MultiLogOuter, minloglevel_flag *int,
failFunc func(), locFunc func(skip int) *LogLocation) *PackageLogger {
	ret := &PackageLogger{failFunc: failFunc, MultiLogOuter: outer}

	ret.LocationLogger = NewLocationLogger(
		&loggerImpl{outer, minloglevel_flag, func() { ret.failFunc() }},
		FullLocation)

	return ret
}

func NewDefaultPackageLogger() *PackageLogger {
	return newPackageLoggerCommon(
		NewDefaultMultiLogOuter(),
		flag_minloglevel,
		ExitError,
		FullLocation)
}

func NewPackageLogger(outer MultiLogOuter, minloglevel int,
failFunc func(), locFunc func(skip int) *LogLocation) *PackageLogger {
	return newPackageLoggerCommon(outer, &minloglevel, failFunc, locFunc)
}

// Associates TestController with a the "testing LogOuter and updates
// l.FailNow() to call t.FailNow().
func (l *PackageLogger) StartTestLogging(t TestController) {
	l.MultiLogOuter.AddLogOuter("testing", NewTestLogOuter(t))
	// TODO(awreece) Save old failFunc so we can restore it properly.
	l.failFunc = func() { t.FailNow() }
}

// Removes the testing logger and restores l.FailNow() to its previous state.
func (l *PackageLogger) StopTestLogging() {
	l.MultiLogOuter.RemoveLogOuter("testing")
	// TODO(awreece) Restored to saved failFunc.
	l.failFunc = ExitError
}

// Log the message at level INFO, only formatting if message will be logged.
func (l *PackageLogger) Info(msg ...interface{}) {
	l.LogDepth(INFO, printClosure(msg...), 1)
}

// Log the message at level INFO, only fomatting if message will be logged.
func (l *PackageLogger) Infof(fmt string, vals ...interface{}) {
	l.LogDepth(INFO, printfClosure(fmt, vals...), 1)
}

// Log the message at level INFO, only evaluating the closure if the message
// will be logged.
func (l *PackageLogger) Infoc(closure func() string) {
	l.LogDepth(INFO, closure, 1)
}

// Log the message at level WARNING, only formatting if message will be logged.
func (l *PackageLogger) Warning(msg ...interface{}) {
	l.LogDepth(WARNING, printClosure(msg...), 1)
}

// Log the message at level WARNING, only fomatting if message will be logged.
func (l *PackageLogger) Warningf(fmt string, vals ...interface{}) {
	l.LogDepth(WARNING, printfClosure(fmt, vals...), 1)
}

// Log the message at level WARNING, only evaluating the closure if the message
// will be logged.
func (l *PackageLogger) Warningc(closure func() string) {
	l.LogDepth(WARNING, closure, 1)
}

// Log the message at level ERROR, only formatting if message will be logged.
func (l *PackageLogger) Error(msg ...interface{}) {
	l.LogDepth(ERROR, printClosure(msg...), 1)
}

// Log the message at level ERROR, only formatting if message will be logged.
func (l *PackageLogger) Errorf(fmt string, vals ...interface{}) {
	l.LogDepth(ERROR, printfClosure(fmt, vals...), 1)
}

// Log the message at level ERROR, only evaluating the closure if the message
// will be logged.
func (l *PackageLogger) Errorc(closure func() string) {
	l.LogDepth(ERROR, closure, 1)
}

// Log the message at level FATAL, only formatting if the message will be
// logged. Also call l.FailNow().
func (l *PackageLogger) Fatal(msg ...interface{}) {
	l.LogDepth(FATAL, printClosure(msg...), 1)
	l.FailNow()
}

// Log the message at level FATAL, only formatting if the message will be
// logged. Also call l.FailNow().
func (l *PackageLogger) Fatalf(fmt string, vals ...interface{}) {
	l.LogDepth(FATAL, printfClosure(fmt, vals...), 1)
	l.FailNow()
}

// Log the message at level FATAL, only evaluating the clousre if the message
// will be logged. Also call l.FailNow().
func (l *PackageLogger) Fatalc(closure func() string) {
	l.LogDepth(FATAL, closure, 1)
	l.FailNow()
}
<|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 influxdb

import (
	"fmt"
	"net/url"
	"strings"
	"sync"
	"time"

	influxdb_common "k8s.io/heapster/common/influxdb"
	"k8s.io/heapster/metrics/core"

	"github.com/golang/glog"
	influxdb "github.com/influxdb/influxdb/client"
)

type influxdbSink struct {
	client influxdb_common.InfluxdbClient
	sync.RWMutex
	c        influxdb_common.InfluxdbConfig
	dbExists bool
}

const (
	// Value Field name
	valueField = "value"
	// Event special tags
	dbNotFoundError = "database not found"

	// Maximum number of influxdb Points to be sent in one batch.
	maxSendBatchSize = 10000
)

func (sink *influxdbSink) resetConnection() {
	glog.Infof("Influxdb connection reset")
	sink.dbExists = false
	sink.client = nil
}

func (sink *influxdbSink) ExportData(dataBatch *core.DataBatch) {
	sink.Lock()
	defer sink.Unlock()

	dataPoints := make([]influxdb.Point, 0, 0)
	for _, metricSet := range dataBatch.MetricSets {
		for metricName, metricValue := range metricSet.MetricValues {

			var value interface{}
			if core.ValueInt64 == metricValue.ValueType {
				value = metricValue.IntValue
			} else if core.ValueFloat == metricValue.ValueType {
				value = metricValue.FloatValue
			} else {
				continue
			}

			point := influxdb.Point{
				Measurement: metricName,
				Tags:        metricSet.Labels,
				Fields: map[string]interface{}{
					"value": value,
				},
				Time: dataBatch.Timestamp.UTC(),
			}
			dataPoints = append(dataPoints, point)
			if len(dataPoints) >= maxSendBatchSize {
				sink.sendData(dataPoints)
				dataPoints = make([]influxdb.Point, 0, 0)
			}
		}

		for _, labeledMetric := range metricSet.LabeledMetrics {

			var value interface{}
			if core.ValueInt64 == labeledMetric.ValueType {
				value = labeledMetric.IntValue
			} else if core.ValueFloat == labeledMetric.ValueType {
				value = labeledMetric.FloatValue
			} else {
				continue
			}

			point := influxdb.Point{
				Measurement: labeledMetric.Name,
				Tags:        make(map[string]string),
				Fields: map[string]interface{}{
					"value": value,
				},
				Time: dataBatch.Timestamp.UTC(),
			}
			for key, value := range metricSet.Labels {
				point.Tags[key] = value
			}
			for key, value := range labeledMetric.Labels {
				point.Tags[key] = value
			}

			dataPoints = append(dataPoints, point)
			if len(dataPoints) >= maxSendBatchSize {
				sink.sendData(dataPoints)
				dataPoints = make([]influxdb.Point, 0, 0)
			}
		}
	}
	if len(dataPoints) >= 0 {
		sink.sendData(dataPoints)
	}
}

func (sink *influxdbSink) sendData(dataPoints []influxdb.Point) {
	if err := sink.createDatabase(); err != nil {
		glog.Errorf("Failed to create infuxdb: %v", err)
		return
	}
	bp := influxdb.BatchPoints{
		Points:          dataPoints,
		Database:        sink.c.DbName,
		RetentionPolicy: "default",
	}

	start := time.Now()
	if _, err := sink.client.Write(bp); err != nil {
		if strings.Contains(err.Error(), dbNotFoundError) {
			sink.resetConnection()
		} else if _, _, err := sink.client.Ping(); err != nil {
			glog.Errorf("InfluxDB ping failed: %v", err)
			sink.resetConnection()
		}
	}
	end := time.Now()
	glog.V(4).Infof("Exported %d data to influxDB in %s", len(dataPoints), end.Sub(start))
}

func (sink *influxdbSink) Name() string {
	return "InfluxDB Sink"
}

func (sink *influxdbSink) Stop() {
	// nothing needs to be done.
}

func (sink *influxdbSink) createDatabase() error {
	if sink.client == nil {
		client, err := influxdb_common.NewClient(sink.c)
		if err != nil {
			return err
		}
		sink.client = client
	}

	if sink.dbExists {
		return nil
	}
	q := influxdb.Query{
		Command: fmt.Sprintf("CREATE DATABASE %s", sink.c.DbName),
	}
	if resp, err := sink.client.Query(q); err != nil {
		if !(resp != nil && resp.Err != nil && strings.Contains(resp.Err.Error(), "already exists")) {
			return fmt.Errorf("Database creation failed: %v", err)
		}
	}
	sink.dbExists = true
	glog.Infof("Created database %q on influxDB server at %q", sink.c.DbName, sink.c.Host)
	return nil
}

// Returns a thread-compatible implementation of influxdb interactions.
func new(c influxdb_common.InfluxdbConfig) core.DataSink {
	client, err := influxdb_common.NewClient(c)
	if err != nil {
		glog.Errorf("issues while creating an InfluxDB sink: %v, will retry on use", err)
	}
	return &influxdbSink{
		client: client, // can be nil
		c:      c,
	}
}

func CreateInfluxdbSink(uri *url.URL) (core.DataSink, error) {
	config, err := influxdb_common.BuildConfig(uri)
	if err != nil {
		return nil, err
	}
	sink := new(*config)
	glog.Infof("created influxdb sink with options: host:%s user:%s db:%s", config.Host, config.User, config.DbName)
	return sink, nil
}
<commit_msg>Fix influxdb float export<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 influxdb

import (
	"fmt"
	"net/url"
	"strings"
	"sync"
	"time"

	influxdb_common "k8s.io/heapster/common/influxdb"
	"k8s.io/heapster/metrics/core"

	"github.com/golang/glog"
	influxdb "github.com/influxdb/influxdb/client"
)

type influxdbSink struct {
	client influxdb_common.InfluxdbClient
	sync.RWMutex
	c        influxdb_common.InfluxdbConfig
	dbExists bool
}

const (
	// Value Field name
	valueField = "value"
	// Event special tags
	dbNotFoundError = "database not found"

	// Maximum number of influxdb Points to be sent in one batch.
	maxSendBatchSize = 10000
)

func (sink *influxdbSink) resetConnection() {
	glog.Infof("Influxdb connection reset")
	sink.dbExists = false
	sink.client = nil
}

func (sink *influxdbSink) ExportData(dataBatch *core.DataBatch) {
	sink.Lock()
	defer sink.Unlock()

	dataPoints := make([]influxdb.Point, 0, 0)
	for _, metricSet := range dataBatch.MetricSets {
		for metricName, metricValue := range metricSet.MetricValues {

			var value interface{}
			if core.ValueInt64 == metricValue.ValueType {
				value = metricValue.IntValue
			} else if core.ValueFloat == metricValue.ValueType {
				value = float64(metricValue.FloatValue)
			} else {
				continue
			}

			point := influxdb.Point{
				Measurement: metricName,
				Tags:        metricSet.Labels,
				Fields: map[string]interface{}{
					"value": value,
				},
				Time: dataBatch.Timestamp.UTC(),
			}
			dataPoints = append(dataPoints, point)
			if len(dataPoints) >= maxSendBatchSize {
				sink.sendData(dataPoints)
				dataPoints = make([]influxdb.Point, 0, 0)
			}
		}

		for _, labeledMetric := range metricSet.LabeledMetrics {

			var value interface{}
			if core.ValueInt64 == labeledMetric.ValueType {
				value = labeledMetric.IntValue
			} else if core.ValueFloat == labeledMetric.ValueType {
				value = float64(labeledMetric.FloatValue)
			} else {
				continue
			}

			point := influxdb.Point{
				Measurement: labeledMetric.Name,
				Tags:        make(map[string]string),
				Fields: map[string]interface{}{
					"value": value,
				},
				Time: dataBatch.Timestamp.UTC(),
			}
			for key, value := range metricSet.Labels {
				point.Tags[key] = value
			}
			for key, value := range labeledMetric.Labels {
				point.Tags[key] = value
			}

			dataPoints = append(dataPoints, point)
			if len(dataPoints) >= maxSendBatchSize {
				sink.sendData(dataPoints)
				dataPoints = make([]influxdb.Point, 0, 0)
			}
		}
	}
	if len(dataPoints) >= 0 {
		sink.sendData(dataPoints)
	}
}

func (sink *influxdbSink) sendData(dataPoints []influxdb.Point) {
	if err := sink.createDatabase(); err != nil {
		glog.Errorf("Failed to create infuxdb: %v", err)
		return
	}
	bp := influxdb.BatchPoints{
		Points:          dataPoints,
		Database:        sink.c.DbName,
		RetentionPolicy: "default",
	}

	start := time.Now()
	if _, err := sink.client.Write(bp); err != nil {
		if strings.Contains(err.Error(), dbNotFoundError) {
			sink.resetConnection()
		} else if _, _, err := sink.client.Ping(); err != nil {
			glog.Errorf("InfluxDB ping failed: %v", err)
			sink.resetConnection()
		}
	}
	end := time.Now()
	glog.V(4).Infof("Exported %d data to influxDB in %s", len(dataPoints), end.Sub(start))
}

func (sink *influxdbSink) Name() string {
	return "InfluxDB Sink"
}

func (sink *influxdbSink) Stop() {
	// nothing needs to be done.
}

func (sink *influxdbSink) createDatabase() error {
	if sink.client == nil {
		client, err := influxdb_common.NewClient(sink.c)
		if err != nil {
			return err
		}
		sink.client = client
	}

	if sink.dbExists {
		return nil
	}
	q := influxdb.Query{
		Command: fmt.Sprintf("CREATE DATABASE %s", sink.c.DbName),
	}
	if resp, err := sink.client.Query(q); err != nil {
		if !(resp != nil && resp.Err != nil && strings.Contains(resp.Err.Error(), "already exists")) {
			return fmt.Errorf("Database creation failed: %v", err)
		}
	}
	sink.dbExists = true
	glog.Infof("Created database %q on influxDB server at %q", sink.c.DbName, sink.c.Host)
	return nil
}

// Returns a thread-compatible implementation of influxdb interactions.
func new(c influxdb_common.InfluxdbConfig) core.DataSink {
	client, err := influxdb_common.NewClient(c)
	if err != nil {
		glog.Errorf("issues while creating an InfluxDB sink: %v, will retry on use", err)
	}
	return &influxdbSink{
		client: client, // can be nil
		c:      c,
	}
}

func CreateInfluxdbSink(uri *url.URL) (core.DataSink, error) {
	config, err := influxdb_common.BuildConfig(uri)
	if err != nil {
		return nil, err
	}
	sink := new(*config)
	glog.Infof("created influxdb sink with options: host:%s user:%s db:%s", config.Host, config.User, config.DbName)
	return sink, nil
}
<|endoftext|>


<commit_before>package mod

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

	"github.com/pkg/errors"
)

var SyslModules = os.Getenv("SYSL_MODULES") != "off"

type Module struct {
	Name    string
	Dir     string
	Version string
}

type Modules []*Module

var modules Modules

func (m *Modules) Add(v *Module) {
	*m = append(*m, v)
}

func (m *Modules) GetByFilename(filename, ver string) *Module {
	for _, mod := range *m {
		if hasPathPrefix(mod.Name, filename) {
			if ver != "" && mod.Version != ver {
				continue
			}
			return mod
		}
	}

	return nil
}

func fileExists(filename string) bool {
	info, err := os.Stat(filename)
	if os.IsNotExist(err) {
		return false
	}
	return !info.IsDir()
}

func Find(name string, ver string) (*Module, error) {
	if !fileExists("go.mod") {
		return nil, errors.New("no go.mod file, run `go mod init` first")
	}

	mod := modules.GetByFilename(name, ver)
	if mod != nil {
		return mod, nil
	}

	err := goGetByFilepath(name, ver)
	if err != nil {
		return nil, fmt.Errorf("%s not found", name)
	}

	if err = modules.Load(); err != nil {
		return nil, fmt.Errorf("error loading modules: %s", err.Error())
	}

	if modules == nil {
		return nil, fmt.Errorf("modules list is empty")
	}

	mod = modules.GetByFilename(name, ver)
	if mod == nil {
		return nil, fmt.Errorf("error finding module of file %s", name)
	}
	return mod, nil
}

func hasPathPrefix(prefix, s string) bool {
	prefix = filepath.Clean(prefix)
	s = filepath.Clean(s)

	if len(s) > len(prefix) {
		return s[len(prefix)] == filepath.Separator && s[:len(prefix)] == prefix
	}

	return s == prefix
}
<commit_msg>load modules before go get (#917)<commit_after>package mod

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

	"github.com/pkg/errors"
)

var SyslModules = os.Getenv("SYSL_MODULES") != "off"

type Module struct {
	Name    string
	Dir     string
	Version string
}

type Modules []*Module

var modules Modules

func (m *Modules) Add(v *Module) {
	*m = append(*m, v)
}

func (m *Modules) Len() int {
	return len(*m)
}

func (m *Modules) GetByFilename(filename, ver string) *Module {
	for i, mod := range *m {
		if hasPathPrefix(mod.Name, filename) {
			if i != 0 && ver != "" && mod.Version != ver {
				continue
			}
			return mod
		}
	}

	return nil
}

func fileExists(filename string) bool {
	info, err := os.Stat(filename)
	if os.IsNotExist(err) {
		return false
	}
	return !info.IsDir()
}

func Find(name string, ver string) (*Module, error) {
	if !fileExists("go.mod") {
		return nil, errors.New("no go.mod file, run `go mod init` first")
	}

	if modules.Len() == 0 {
		if err := modules.Load(); err != nil {
			return nil, fmt.Errorf("error loading modules: %s", err.Error())
		}
	}

	mod := modules.GetByFilename(name, ver)
	if mod != nil {
		return mod, nil
	}

	err := goGetByFilepath(name, ver)
	if err != nil {
		return nil, fmt.Errorf("%s not found", name)
	}

	if err = modules.Load(); err != nil {
		return nil, fmt.Errorf("error loading modules: %s", err.Error())
	}

	if modules == nil {
		return nil, fmt.Errorf("modules list is empty")
	}

	mod = modules.GetByFilename(name, ver)
	if mod == nil {
		return nil, fmt.Errorf("error finding module of file %s", name)
	}
	return mod, nil
}

func hasPathPrefix(prefix, s string) bool {
	prefix = filepath.Clean(prefix)
	s = filepath.Clean(s)

	if len(s) > len(prefix) {
		return s[len(prefix)] == filepath.Separator && s[:len(prefix)] == prefix
	}

	return s == prefix
}
<|endoftext|>


<commit_before>package ui

import (
	"strings"
)

// Styling specifies how to change a Style. It can also be applied to a Segment
// or Text.
type Styling interface{ transform(*Style) }

// StyleText returns a new Text with the given Styling's applied. It does not
// modify the given Text.
func StyleText(t Text, ts ...Styling) Text {
	newt := make(Text, len(t))
	for i, seg := range t {
		newt[i] = StyleSegment(seg, ts...)
	}
	return newt
}

// StyleSegment returns a new Segment with the given Styling's applied. It does
// not modify the given Segment.
func StyleSegment(seg *Segment, ts ...Styling) *Segment {
	return &Segment{Text: seg.Text, Style: ApplyStyling(seg.Style, ts...)}
}

// ApplyStyling returns a new Style with the given Styling's applied.
func ApplyStyling(s Style, ts ...Styling) Style {
	for _, t := range ts {
		if t != nil {
			t.transform(&s)
		}
	}
	return s
}

// Stylings joins several transformers into one.
func Stylings(ts ...Styling) Styling { return jointStyling(ts) }

// Common stylings.
var (
	FgDefault Styling = setForeground{nil}

	FgBlack   Styling = setForeground{Black}
	FgRed     Styling = setForeground{Red}
	FgGreen   Styling = setForeground{Green}
	FgYellow  Styling = setForeground{Yellow}
	FgBlue    Styling = setForeground{Blue}
	FgMagenta Styling = setForeground{Magenta}
	FgCyan    Styling = setForeground{Cyan}
	FgWhite   Styling = setForeground{White}

	FgBrightBlack   Styling = setForeground{BrightBlack}
	FgBrightRed     Styling = setForeground{BrightRed}
	FgBrightGreen   Styling = setForeground{BrightGreen}
	FgBrightYellow  Styling = setForeground{BrightYellow}
	FgBrightBlue    Styling = setForeground{BrightBlue}
	FgBrightMagenta Styling = setForeground{BrightMagenta}
	FgBrightCyan    Styling = setForeground{BrightCyan}
	FgBrightWhite   Styling = setForeground{BrightWhite}

	BgDefault Styling = setBackground{nil}

	BgBlack   Styling = setBackground{Black}
	BgRed     Styling = setBackground{Red}
	BgGreen   Styling = setBackground{Green}
	BgYellow  Styling = setBackground{Yellow}
	BgBlue    Styling = setBackground{Blue}
	BgMagenta Styling = setBackground{Magenta}
	BgCyan    Styling = setBackground{Cyan}
	BgWhite   Styling = setBackground{White}

	BgBrightBlack   Styling = setBackground{BrightBlack}
	BgBrightRed     Styling = setBackground{BrightRed}
	BgBrightGreen   Styling = setBackground{BrightGreen}
	BgBrightYellow  Styling = setBackground{BrightYellow}
	BgBrightBlue    Styling = setBackground{BrightBlue}
	BgBrightMagenta Styling = setBackground{BrightMagenta}
	BgBrightCyan    Styling = setBackground{BrightCyan}
	BgBrightWhite   Styling = setBackground{BrightWhite}

	Bold       Styling = boolOn(accessBold)
	Dim        Styling = boolOn(accessDim)
	Italic     Styling = boolOn(accessItalic)
	Underlined Styling = boolOn(accessUnderlined)
	Blink      Styling = boolOn(accessBlink)
	Inverse    Styling = boolOn(accessInverse)

	NoBold       Styling = boolOff(accessBold)
	NoDim        Styling = boolOff(accessDim)
	NoItalic     Styling = boolOff(accessItalic)
	NoUnderlined Styling = boolOff(accessUnderlined)
	NoBlink      Styling = boolOff(accessBlink)
	NoInverse    Styling = boolOff(accessInverse)

	ToggleBold       Styling = boolToggle(accessBold)
	ToggleDim        Styling = boolToggle(accessDim)
	ToggleItalic     Styling = boolToggle(accessItalic)
	ToggleUnderlined Styling = boolToggle(accessUnderlined)
	ToggleBlink      Styling = boolToggle(accessBlink)
	ToggleInverse    Styling = boolToggle(accessInverse)
)

type setForeground struct{ c Color }
type setBackground struct{ c Color }
type boolOn func(*Style) *bool
type boolOff func(*Style) *bool
type boolToggle func(*Style) *bool

func (t setForeground) transform(s *Style) { s.Foreground = t.c }
func (t setBackground) transform(s *Style) { s.Background = t.c }
func (t boolOn) transform(s *Style)        { *t(s) = true }
func (t boolOff) transform(s *Style)       { *t(s) = false }
func (t boolToggle) transform(s *Style)    { p := t(s); *p = !*p }

func accessBold(s *Style) *bool       { return &s.Bold }
func accessDim(s *Style) *bool        { return &s.Dim }
func accessItalic(s *Style) *bool     { return &s.Italic }
func accessUnderlined(s *Style) *bool { return &s.Underlined }
func accessBlink(s *Style) *bool      { return &s.Blink }
func accessInverse(s *Style) *bool    { return &s.Inverse }

type jointStyling []Styling

func (t jointStyling) transform(s *Style) {
	for _, t := range t {
		t.transform(s)
	}
}

// ParseStyling parses a text representation of Styling, which are kebab
// case counterparts to the names of the builtin Styling's. For example,
// ToggleInverse is expressed as "toggle-inverse".
//
// Multiple stylings can be joined by spaces, which is equivalent to calling
// Stylings.
//
// If the given string is invalid, ParseStyling returns nil.
func ParseStyling(s string) Styling {
	if !strings.ContainsRune(s, ' ') {
		return parseOneStyling(s)
	}
	var joint jointStyling
	for _, subs := range strings.Split(s, " ") {
		parsed := parseOneStyling(subs)
		if parsed == nil {
			return nil
		}
		joint = append(joint, parseOneStyling(subs))
	}
	return joint
}

var boolFieldAccessor = map[string]func(*Style) *bool{
	"bold":       accessBold,
	"dim":        accessDim,
	"italic":     accessItalic,
	"underlined": accessUnderlined,
	"blink":      accessBlink,
	"inverse":    accessInverse,
}

func parseOneStyling(name string) Styling {
	switch {
	case name == "default" || name == "fg-default":
		return FgDefault
	case strings.HasPrefix(name, "fg-"):
		if color := parseColor(name[len("fg-"):]); color != nil {
			return setForeground{color}
		}
	case name == "bg-default":
		return BgDefault
	case strings.HasPrefix(name, "bg-"):
		if color := parseColor(name[len("bg-"):]); color != nil {
			return setBackground{color}
		}
	case strings.HasPrefix(name, "no-"):
		if f, ok := boolFieldAccessor[name[len("no-"):]]; ok {
			return boolOff(f)
		}
	case strings.HasPrefix(name, "toggle-"):
		if f, ok := boolFieldAccessor[name[len("toggle-"):]]; ok {
			return boolToggle(f)
		}
	default:
		if f, ok := boolFieldAccessor[name]; ok {
			return boolOn(f)
		}
		if color := parseColor(name); color != nil {
			return setForeground{color}
		}
	}
	return nil
}
<commit_msg>pkg/ui: Export Fg and Bg.<commit_after>package ui

import (
	"strings"
)

// Styling specifies how to change a Style. It can also be applied to a Segment
// or Text.
type Styling interface{ transform(*Style) }

// StyleText returns a new Text with the given Styling's applied. It does not
// modify the given Text.
func StyleText(t Text, ts ...Styling) Text {
	newt := make(Text, len(t))
	for i, seg := range t {
		newt[i] = StyleSegment(seg, ts...)
	}
	return newt
}

// StyleSegment returns a new Segment with the given Styling's applied. It does
// not modify the given Segment.
func StyleSegment(seg *Segment, ts ...Styling) *Segment {
	return &Segment{Text: seg.Text, Style: ApplyStyling(seg.Style, ts...)}
}

// ApplyStyling returns a new Style with the given Styling's applied.
func ApplyStyling(s Style, ts ...Styling) Style {
	for _, t := range ts {
		if t != nil {
			t.transform(&s)
		}
	}
	return s
}

// Stylings joins several transformers into one.
func Stylings(ts ...Styling) Styling { return jointStyling(ts) }

// Common stylings.
var (
	FgDefault Styling = setForeground{nil}

	FgBlack   Styling = setForeground{Black}
	FgRed     Styling = setForeground{Red}
	FgGreen   Styling = setForeground{Green}
	FgYellow  Styling = setForeground{Yellow}
	FgBlue    Styling = setForeground{Blue}
	FgMagenta Styling = setForeground{Magenta}
	FgCyan    Styling = setForeground{Cyan}
	FgWhite   Styling = setForeground{White}

	FgBrightBlack   Styling = setForeground{BrightBlack}
	FgBrightRed     Styling = setForeground{BrightRed}
	FgBrightGreen   Styling = setForeground{BrightGreen}
	FgBrightYellow  Styling = setForeground{BrightYellow}
	FgBrightBlue    Styling = setForeground{BrightBlue}
	FgBrightMagenta Styling = setForeground{BrightMagenta}
	FgBrightCyan    Styling = setForeground{BrightCyan}
	FgBrightWhite   Styling = setForeground{BrightWhite}

	BgDefault Styling = setBackground{nil}

	BgBlack   Styling = setBackground{Black}
	BgRed     Styling = setBackground{Red}
	BgGreen   Styling = setBackground{Green}
	BgYellow  Styling = setBackground{Yellow}
	BgBlue    Styling = setBackground{Blue}
	BgMagenta Styling = setBackground{Magenta}
	BgCyan    Styling = setBackground{Cyan}
	BgWhite   Styling = setBackground{White}

	BgBrightBlack   Styling = setBackground{BrightBlack}
	BgBrightRed     Styling = setBackground{BrightRed}
	BgBrightGreen   Styling = setBackground{BrightGreen}
	BgBrightYellow  Styling = setBackground{BrightYellow}
	BgBrightBlue    Styling = setBackground{BrightBlue}
	BgBrightMagenta Styling = setBackground{BrightMagenta}
	BgBrightCyan    Styling = setBackground{BrightCyan}
	BgBrightWhite   Styling = setBackground{BrightWhite}

	Bold       Styling = boolOn(accessBold)
	Dim        Styling = boolOn(accessDim)
	Italic     Styling = boolOn(accessItalic)
	Underlined Styling = boolOn(accessUnderlined)
	Blink      Styling = boolOn(accessBlink)
	Inverse    Styling = boolOn(accessInverse)

	NoBold       Styling = boolOff(accessBold)
	NoDim        Styling = boolOff(accessDim)
	NoItalic     Styling = boolOff(accessItalic)
	NoUnderlined Styling = boolOff(accessUnderlined)
	NoBlink      Styling = boolOff(accessBlink)
	NoInverse    Styling = boolOff(accessInverse)

	ToggleBold       Styling = boolToggle(accessBold)
	ToggleDim        Styling = boolToggle(accessDim)
	ToggleItalic     Styling = boolToggle(accessItalic)
	ToggleUnderlined Styling = boolToggle(accessUnderlined)
	ToggleBlink      Styling = boolToggle(accessBlink)
	ToggleInverse    Styling = boolToggle(accessInverse)
)

// Fg returns a Styling that sets the foreground color.
func Fg(c Color) Styling { return setForeground{c} }

// Bg returns a Styling that sets the background color.
func Bg(c Color) Styling { return setBackground{c} }

type setForeground struct{ c Color }
type setBackground struct{ c Color }
type boolOn func(*Style) *bool
type boolOff func(*Style) *bool
type boolToggle func(*Style) *bool

func (t setForeground) transform(s *Style) { s.Foreground = t.c }
func (t setBackground) transform(s *Style) { s.Background = t.c }
func (t boolOn) transform(s *Style)        { *t(s) = true }
func (t boolOff) transform(s *Style)       { *t(s) = false }
func (t boolToggle) transform(s *Style)    { p := t(s); *p = !*p }

func accessBold(s *Style) *bool       { return &s.Bold }
func accessDim(s *Style) *bool        { return &s.Dim }
func accessItalic(s *Style) *bool     { return &s.Italic }
func accessUnderlined(s *Style) *bool { return &s.Underlined }
func accessBlink(s *Style) *bool      { return &s.Blink }
func accessInverse(s *Style) *bool    { return &s.Inverse }

type jointStyling []Styling

func (t jointStyling) transform(s *Style) {
	for _, t := range t {
		t.transform(s)
	}
}

// ParseStyling parses a text representation of Styling, which are kebab
// case counterparts to the names of the builtin Styling's. For example,
// ToggleInverse is expressed as "toggle-inverse".
//
// Multiple stylings can be joined by spaces, which is equivalent to calling
// Stylings.
//
// If the given string is invalid, ParseStyling returns nil.
func ParseStyling(s string) Styling {
	if !strings.ContainsRune(s, ' ') {
		return parseOneStyling(s)
	}
	var joint jointStyling
	for _, subs := range strings.Split(s, " ") {
		parsed := parseOneStyling(subs)
		if parsed == nil {
			return nil
		}
		joint = append(joint, parseOneStyling(subs))
	}
	return joint
}

var boolFieldAccessor = map[string]func(*Style) *bool{
	"bold":       accessBold,
	"dim":        accessDim,
	"italic":     accessItalic,
	"underlined": accessUnderlined,
	"blink":      accessBlink,
	"inverse":    accessInverse,
}

func parseOneStyling(name string) Styling {
	switch {
	case name == "default" || name == "fg-default":
		return FgDefault
	case strings.HasPrefix(name, "fg-"):
		if color := parseColor(name[len("fg-"):]); color != nil {
			return setForeground{color}
		}
	case name == "bg-default":
		return BgDefault
	case strings.HasPrefix(name, "bg-"):
		if color := parseColor(name[len("bg-"):]); color != nil {
			return setBackground{color}
		}
	case strings.HasPrefix(name, "no-"):
		if f, ok := boolFieldAccessor[name[len("no-"):]]; ok {
			return boolOff(f)
		}
	case strings.HasPrefix(name, "toggle-"):
		if f, ok := boolFieldAccessor[name[len("toggle-"):]]; ok {
			return boolToggle(f)
		}
	default:
		if f, ok := boolFieldAccessor[name]; ok {
			return boolOn(f)
		}
		if color := parseColor(name); color != nil {
			return setForeground{color}
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"encoding/json"
	"errors"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"gotest/rbg/config"
	"gotest/rbg/logs"
	"gotest/rbg/task"
	"io/ioutil"
	"net"
	"net/http"
	"net/rpc"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"time"
)

var (
	server_preferences *config.ServerConfig    // 配置文件实例
	dao                *sql.DB                 // 数据库实例
	log                *logs.BeeLogger         // 日志实例
	clientConns        map[string]*net.TCPConn // 每个客户端的连接集合
	smtp               *sql.Stmt
)

// 需要传输数据的结构
type Obj struct {
	Date                string    // 日期
	Time                string    // 时间
	InTime              time.Time // 插入时间
	SerialNumber        string    // 流水号
	Type                string    // 交易类型
	CardId              string    // 预留卡号
	FaceValue           int       // 面值
	Version             int       // 版本号
	CurrencyCode        int       // 币种
	SerialNumberInTimes int       // 该钞在本笔交易内序号
	CurrencyNumber      string    // 冠字号码
	Ima                 []byte    // 冠字号图像数据
	ImaPath             string    // 冠字号保存图像路径
	ClientName          string    // 客户端设备名称
	ClientIP            string    // 客户端IP
	Remark              string    // 备注
}

// 接收数据处理方法
func (o *Obj) SendToServer(obj *Obj, replay *string) error {
	// 图像保存
	if "" != obj.ImaPath {
		obj.ImaPath = filepath.Join(server_preferences.BMP_SAVE_PATH, obj.ClientName, obj.Date, obj.SerialNumber+".bmp")
	REGO:
		f, err := os.Create(obj.ImaPath)
		if err != nil {
			err = os.MkdirAll(obj.ImaPath[:strings.LastIndex(obj.ImaPath, "\\")], 0666)
			if err != nil {
				log.Error("保存bmp失败：%s", obj.SerialNumber)
				*replay = config.SAVE_BMP_ERROR
				return nil
			}
			log.Info("创建目录：", obj.ClientName)
			goto REGO
		}
		defer f.Close()
		f.Write(obj.Ima)
	}

	// 数据存库

	//insert_sql := "INSERT INTO T_BR(SDATE,STIME,INTIME,CARDID,BILLNO,BILLBN) VALUES(?,?,?,?,?,?)"
	str_time, _ := time.Parse("2006-01-02 15:04:05", (obj.Date[0:4] + "-" + obj.Date[4:6] + "-" + obj.Date[6:8] + " " + obj.Time))
	_, err := smtp.Exec(obj.Date, obj.Time, str_time, obj.SerialNumber, obj.Type, obj.CardId, obj.FaceValue, obj.Version, obj.CurrencyCode, obj.SerialNumberInTimes, obj.CurrencyNumber, obj.ImaPath, obj.ClientName, obj.ClientIP, obj.Remark)
	if err != nil {
		log.Error("%s%s", "保存到数据库失败：", obj.CurrencyNumber)
		log.Error("%s", err)
		*replay = config.SAVE_TO_DB_ERROR
		return nil
	}
	*replay = "OK"
	return nil
}

func init() {
	loadConfig()

	openDB()
}

func main() {
	// 以下为清理过期数据，每天22点，23点各执行一次
	dataClearTask := task.NewTask("dataClearTask", "00 00 22,23 * * * ", dataClear)
	task.AddTask("dataClearTask", dataClearTask)
	task.StartTask()

	sql := "INSERT INTO T_BR(DATE,TIME,INTIME,SERIALNUMBER,TYPE,CARDID,FACEVALUE,VERSION,CURRENCYCODE,SERIALNUMBERINTIMES,BILLBN,IMAPATH,CLIENTNAME,CLIENTIP,REMARK)VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"
	var e error
	smtp, e = dao.Prepare(sql)
	if e != nil {
		log.Error(e.Error())
	}
	defer smtp.Close()
	cpus := runtime.NumCPU()
	runtime.GOMAXPROCS(cpus)
	defer dao.Close()
	clientConns = make(map[string]*net.TCPConn, 100)

	u := new(Obj)
	rpc.Register(u)

	go func() {
		for {
			select {
			case <-time.After(3 * time.Second):
				for k, v := range clientConns {
					log.Info("%s,%v", k, v)
				}
			}
		}
	}()

	// http：方式
	exit := make(chan bool)
	rpc.HandleHTTP()
	err := http.ListenAndServe(server_preferences.SERVER_IP_PORT, nil)
	checkError(err)
	<-exit

	// tcp 方式
	// tcpAddr, err := net.ResolveTCPAddr("tcp", server_preferences.SERVER_IP_PORT)
	// checkError(err)
	// listener, err := net.ListenTCP("tcp", tcpAddr)
	// checkError(err)

	// log.Info("服务端已经启动!")
	// for {
	// 	conn, err := listener.AcceptTCP()
	// 	conn.Write([]byte("ok"))
	// 	if err != nil {
	// 		log.Error("rpc.Server: accept Error:%s", err)
	// 	}
	// 	ip := strings.Split(conn.RemoteAddr().String(), ":")[0]

	// 	if v, ok := clientConns[ip]; ok {
	// 		v.Close()
	// 		continue
	// 	}
	// 	clientConns[ip] = conn
	// 	conn.SetKeepAlive(true)
	// 	conn.SetKeepAlivePeriod(120 * time.Second)
	// 	log.Info("IP [ %s ] 已经成功连接到服务器...[%d]", ip, len(clientConns))
	// 	go rpc.ServeConn(conn)
	// }

}

// 加载配置文件
func loadConfig() {
	pwd, _ := os.Getwd()
	file, e := ioutil.ReadFile(filepath.Join(pwd, "Server.Preferences.json"))
	if e != nil {
		fmt.Println("读取配置文件失败!请与管理员联系!" + e.Error())
		os.Exit(1)
	}

	logfile := filepath.Join(pwd, "logs", "server.log")
	os.MkdirAll(logfile[0:len(logfile)-10], 0666)
	log = logs.NewLogger(100000)
	_, e = os.Stat(logfile)
	if nil != e {
		os.Create(logfile)
	}
	log.SetLogger("file", `{"filename":"`+strings.Replace(logfile, "\\", "/", -1)+`"}`)
	log.SetLogger("console", "")
	server_preferences = new(config.ServerConfig)
	e = json.Unmarshal(file, server_preferences)
	if e != nil {
		os.Exit(2)
	}
}

// 获取数据库
func openDB() {
	db, err := sql.Open("mysql", server_preferences.DATABASE_USER_NAME+":"+server_preferences.DATABASE_PASSWORD+"@tcp(127.0.0.1:3306)/"+server_preferences.DATABASE_NAME+"?charset=utf8") // &timeout=60s
	if err != nil {
		errmsg := "错误：连接数据库连接失败!"
		fmt.Println(errmsg)
		os.Exit(1)
	}
	err = db.Ping()
	if err != nil {
		fmt.Println(">>>>", err.Error())
		os.Exit(1)
	}

	db.SetMaxIdleConns(server_preferences.DB_MAX_IDLE_CONNS)
	db.SetMaxOpenConns(server_preferences.DB_MAX_OPEN_CONNS)
	dao = db

}

// 关闭客户端连接
func CloseConn() {
	if nil != dao {
		dao.Close()
		dao = nil
	}
}

func checkError(err error) {
	if err != nil {
		log.Warn("Fatal error: %s", err.Error())
		os.Exit(1)
	}
}

// 清理过期数据
func dataClear() error {
	dayLastYear := time.Now().Add(time.Hour * -(server_preferences.DATA_KEEPING_DAYS * 24)).Format("20060102")
	_, err := dao.Exec("DELETE FROM T_BR WHERE DATE = ? ", dayLastYear)
	if err != nil {
		log.Warn("删除数据库过期数据失败: %s", err.Error())
		return errors.New("删除数据库过期数据失败：" + err.Error())
	}
	files, err := ioutil.ReadDir(server_preferences.BMP_SAVE_PATH)
	if err != nil {
		log.Warn("未找到BMP目录: %s", err.Error())
		return errors.New("未找到BMP目录：" + err.Error())
	}
	for _, file := range files {
		clientName := file.Name()
		fmt.Println(server_preferences.BMP_SAVE_PATH, clientName, dayLastYear)
		err = os.RemoveAll(filepath.Join(server_preferences.BMP_SAVE_PATH, clientName, dayLastYear))
		if err != nil {
			log.Warn("删除过期BMP失败: %s", err.Error())
			return errors.New("删除过期BMP失败:" + err.Error())
		}
	}
	log.Info("清理过期数据成功！")
	return nil
}
<commit_msg>增加serverIP绑定失败提示<commit_after>package main

import (
	"database/sql"
	"encoding/json"
	"errors"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"gotest/rbg/config"
	"gotest/rbg/logs"
	"gotest/rbg/task"
	"io/ioutil"
	"net"
	"net/http"
	"net/rpc"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"time"
)

var (
	server_preferences *config.ServerConfig    // 配置文件实例
	dao                *sql.DB                 // 数据库实例
	log                *logs.BeeLogger         // 日志实例
	clientConns        map[string]*net.TCPConn // 每个客户端的连接集合
	smtp               *sql.Stmt
)

// 需要传输数据的结构
type Obj struct {
	Date                string    // 日期
	Time                string    // 时间
	InTime              time.Time // 插入时间
	SerialNumber        string    // 流水号
	Type                string    // 交易类型
	CardId              string    // 预留卡号
	FaceValue           int       // 面值
	Version             int       // 版本号
	CurrencyCode        int       // 币种
	SerialNumberInTimes int       // 该钞在本笔交易内序号
	CurrencyNumber      string    // 冠字号码
	Ima                 []byte    // 冠字号图像数据
	ImaPath             string    // 冠字号保存图像路径
	ClientName          string    // 客户端设备名称
	ClientIP            string    // 客户端IP
	Remark              string    // 备注
}

// 接收数据处理方法
func (o *Obj) SendToServer(obj *Obj, replay *string) error {
	// 图像保存
	if "" != obj.ImaPath {
		obj.ImaPath = filepath.Join(server_preferences.BMP_SAVE_PATH, obj.ClientName, obj.Date, obj.SerialNumber+".bmp")
	REGO:
		f, err := os.Create(obj.ImaPath)
		if err != nil {
			err = os.MkdirAll(obj.ImaPath[:strings.LastIndex(obj.ImaPath, "\\")], 0666)
			if err != nil {
				log.Error("保存bmp失败：%s", obj.SerialNumber)
				*replay = config.SAVE_BMP_ERROR
				return nil
			}
			log.Info("创建目录：", obj.ClientName)
			goto REGO
		}
		defer f.Close()
		f.Write(obj.Ima)
	}

	// 数据存库

	//insert_sql := "INSERT INTO T_BR(SDATE,STIME,INTIME,CARDID,BILLNO,BILLBN) VALUES(?,?,?,?,?,?)"
	str_time, _ := time.Parse("2006-01-02 15:04:05", (obj.Date[0:4] + "-" + obj.Date[4:6] + "-" + obj.Date[6:8] + " " + obj.Time))
	_, err := smtp.Exec(obj.Date, obj.Time, str_time, obj.SerialNumber, obj.Type, obj.CardId, obj.FaceValue, obj.Version, obj.CurrencyCode, obj.SerialNumberInTimes, obj.CurrencyNumber, obj.ImaPath, obj.ClientName, obj.ClientIP, obj.Remark)
	if err != nil {
		log.Error("%s%s", "保存到数据库失败：", obj.CurrencyNumber)
		log.Error("%s", err)
		*replay = config.SAVE_TO_DB_ERROR
		return nil
	}
	*replay = "OK"
	return nil
}

func init() {
	loadConfig()

	openDB()
}

func main() {
	// 以下为清理过期数据，每天22点，23点各执行一次
	dataClearTask := task.NewTask("dataClearTask", "00 00 22,23 * * * ", dataClear)
	task.AddTask("dataClearTask", dataClearTask)
	task.StartTask()

	sql := "INSERT INTO T_BR(DATE,TIME,INTIME,SERIALNUMBER,TYPE,CARDID,FACEVALUE,VERSION,CURRENCYCODE,SERIALNUMBERINTIMES,BILLBN,IMAPATH,CLIENTNAME,CLIENTIP,REMARK)VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"
	var e error
	smtp, e = dao.Prepare(sql)
	if e != nil {
		log.Error(e.Error())
	}
	defer smtp.Close()
	cpus := runtime.NumCPU()
	runtime.GOMAXPROCS(cpus)
	defer dao.Close()
	clientConns = make(map[string]*net.TCPConn, 100)

	u := new(Obj)
	rpc.Register(u)

	go func() {
		for {
			select {
			case <-time.After(3 * time.Second):
				for k, v := range clientConns {
					log.Info("%s,%v", k, v)
				}
			}
		}
	}()

	// http：方式
	exit := make(chan bool)
	rpc.HandleHTTP()
	err := http.ListenAndServe(server_preferences.SERVER_IP_PORT, nil)
	if err != nil {
		log.Error("绑定IP失败，请检查IP与端口是否正确! [%s]", server_preferences.SERVER_IP_PORT)
		//exit(1)
	}
	<-exit

	// tcp 方式
	// tcpAddr, err := net.ResolveTCPAddr("tcp", server_preferences.SERVER_IP_PORT)
	// checkError(err)
	// listener, err := net.ListenTCP("tcp", tcpAddr)
	// checkError(err)

	// log.Info("服务端已经启动!")
	// for {
	// 	conn, err := listener.AcceptTCP()
	// 	conn.Write([]byte("ok"))
	// 	if err != nil {
	// 		log.Error("rpc.Server: accept Error:%s", err)
	// 	}
	// 	ip := strings.Split(conn.RemoteAddr().String(), ":")[0]

	// 	if v, ok := clientConns[ip]; ok {
	// 		v.Close()
	// 		continue
	// 	}
	// 	clientConns[ip] = conn
	// 	conn.SetKeepAlive(true)
	// 	conn.SetKeepAlivePeriod(120 * time.Second)
	// 	log.Info("IP [ %s ] 已经成功连接到服务器...[%d]", ip, len(clientConns))
	// 	go rpc.ServeConn(conn)
	// }

}

// 加载配置文件
func loadConfig() {
	pwd, _ := os.Getwd()
	file, e := ioutil.ReadFile(filepath.Join(pwd, "Server.Preferences.json"))
	if e != nil {
		fmt.Println("读取配置文件失败!请与管理员联系!" + e.Error())
		os.Exit(1)
	}

	logfile := filepath.Join(pwd, "logs", "server.log")
	os.MkdirAll(logfile[0:len(logfile)-10], 0666)
	log = logs.NewLogger(100000)
	_, e = os.Stat(logfile)
	if nil != e {
		os.Create(logfile)
	}
	log.SetLogger("file", `{"filename":"`+strings.Replace(logfile, "\\", "/", -1)+`"}`)
	log.SetLogger("console", "")
	server_preferences = new(config.ServerConfig)
	e = json.Unmarshal(file, server_preferences)
	if e != nil {
		os.Exit(2)
	}
}

// 获取数据库
func openDB() {
	db, err := sql.Open("mysql", server_preferences.DATABASE_USER_NAME+":"+server_preferences.DATABASE_PASSWORD+"@tcp(127.0.0.1:3306)/"+server_preferences.DATABASE_NAME+"?charset=utf8") // &timeout=60s
	if err != nil {
		errmsg := "错误：连接数据库连接失败!"
		fmt.Println(errmsg)
		os.Exit(1)
	}
	err = db.Ping()
	if err != nil {
		fmt.Println(">>>>", err.Error())
		os.Exit(1)
	}

	db.SetMaxIdleConns(server_preferences.DB_MAX_IDLE_CONNS)
	db.SetMaxOpenConns(server_preferences.DB_MAX_OPEN_CONNS)
	dao = db

}

// 关闭客户端连接
func CloseConn() {
	if nil != dao {
		dao.Close()
		dao = nil
	}
}

// 清理过期数据
func dataClear() error {
	dayLastYear := time.Now().Add(time.Hour * -(server_preferences.DATA_KEEPING_DAYS * 24)).Format("20060102")
	_, err := dao.Exec("DELETE FROM T_BR WHERE DATE = ? ", dayLastYear)
	if err != nil {
		log.Warn("删除数据库过期数据失败: %s", err.Error())
		return errors.New("删除数据库过期数据失败：" + err.Error())
	}
	files, err := ioutil.ReadDir(server_preferences.BMP_SAVE_PATH)
	if err != nil {
		log.Warn("未找到BMP目录: %s", err.Error())
		return errors.New("未找到BMP目录：" + err.Error())
	}
	for _, file := range files {
		clientName := file.Name()
		fmt.Println(server_preferences.BMP_SAVE_PATH, clientName, dayLastYear)
		err = os.RemoveAll(filepath.Join(server_preferences.BMP_SAVE_PATH, clientName, dayLastYear))
		if err != nil {
			log.Warn("删除过期BMP失败: %s", err.Error())
			return errors.New("删除过期BMP失败:" + err.Error())
		}
	}
	log.Info("清理过期数据成功！")
	return nil
}
<|endoftext|>