<commit_before>/*******************************************************************************
*
* Copyright 2017 SAP SE
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You should have received a copy of the License along with this
* program. If not, 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 plugins

import (
	"github.com/gophercloud/gophercloud"
	"github.com/gophercloud/gophercloud/openstack"
	"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/limits"
	"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/quotasets"
	"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
	"github.com/gophercloud/gophercloud/pagination"
	"github.com/sapcc/limes/pkg/limes"
)

type novaPlugin struct {
	cfg             limes.ServiceConfiguration
	scrapeInstances bool
}

var novaResources = []limes.ResourceInfo{
	{
		Name: "cores",
		Unit: limes.UnitNone,
	},
	{
		Name: "instances",
		Unit: limes.UnitNone,
	},
	{
		Name: "ram",
		Unit: limes.UnitMebibytes,
	},
}

func init() {
	limes.RegisterQuotaPlugin(func(c limes.ServiceConfiguration, scrapeSubresources map[string]bool) limes.QuotaPlugin {
		return &novaPlugin{
			cfg:             c,
			scrapeInstances: scrapeSubresources["instances"],
		}
	})
}

//ServiceInfo implements the limes.QuotaPlugin interface.
func (p *novaPlugin) ServiceInfo() limes.ServiceInfo {
	return limes.ServiceInfo{
		Type: "compute",
		Area: "compute",
	}
}

//Resources implements the limes.QuotaPlugin interface.
func (p *novaPlugin) Resources() []limes.ResourceInfo {
	return novaResources
}

func (p *novaPlugin) Client(provider *gophercloud.ProviderClient) (*gophercloud.ServiceClient, error) {
	return openstack.NewComputeV2(provider,
		gophercloud.EndpointOpts{Availability: gophercloud.AvailabilityPublic},
	)
}

//Scrape implements the limes.QuotaPlugin interface.
func (p *novaPlugin) Scrape(provider *gophercloud.ProviderClient, domainUUID, projectUUID string) (map[string]limes.ResourceData, error) {
	client, err := p.Client(provider)
	if err != nil {
		return nil, err
	}

	quotas, err := quotasets.Get(client, projectUUID).Extract()
	if err != nil {
		return nil, err
	}

	limits, err := limits.Get(client, limits.GetOpts{TenantID: projectUUID}).Extract()
	if err != nil {
		return nil, err
	}

	var instanceData []interface{}
	if p.scrapeInstances {
		listOpts := novaServerListOpts{
			AllTenants: true,
			TenantID:   projectUUID,
		}

		err := servers.List(client, listOpts).EachPage(func(page pagination.Page) (bool, error) {
			instances, err := servers.ExtractServers(page)
			if err != nil {
				return false, err
			}

			for _, instance := range instances {
				instanceData = append(instanceData, map[string]interface{}{
					"id":     instance.ID,
					"name":   instance.Name,
					"status": instance.Status,
					//TODO: get flavor object and report "cores"/"ram" instead of "flavor_id" (but cache the flavors!)
					"flavor_id": instance.Flavor["id"],
				})
			}
			return true, nil
		})
		if err != nil {
			return nil, err
		}
	}

	return map[string]limes.ResourceData{
		"cores": {
			Quota: int64(quotas.Cores),
			Usage: uint64(limits.Absolute.TotalCoresUsed),
		},
		"instances": {
			Quota:        int64(quotas.Instances),
			Usage:        uint64(limits.Absolute.TotalInstancesUsed),
			Subresources: instanceData,
		},
		"ram": {
			Quota: int64(quotas.Ram),
			Usage: uint64(limits.Absolute.TotalRAMUsed),
		},
	}, nil
}

//SetQuota implements the limes.QuotaPlugin interface.
func (p *novaPlugin) SetQuota(provider *gophercloud.ProviderClient, domainUUID, projectUUID string, quotas map[string]uint64) error {
	client, err := p.Client(provider)
	if err != nil {
		return err
	}

	return quotasets.Update(client, projectUUID, quotasets.UpdateOpts{
		Cores:     makeIntPointer(int(quotas["cores"])),
		Instances: makeIntPointer(int(quotas["instances"])),
		Ram:       makeIntPointer(int(quotas["ram"])),
	}).Err
}

func makeIntPointer(value int) *int {
	return &value
}

type novaServerListOpts struct {
	AllTenants bool   `q:"all_tenants"`
	TenantID   string `q:"tenant_id"`
}

func (opts novaServerListOpts) ToServerListQuery() (string, error) {
	q, err := gophercloud.BuildQueryString(opts)
	return q.String(), err
}
<commit_msg>Resolving flavors for compute instance subresource<commit_after>/*******************************************************************************
*
* Copyright 2017 SAP SE
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You should have received a copy of the License along with this
* program. If not, 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 plugins

import (
	"github.com/gophercloud/gophercloud"
	"github.com/gophercloud/gophercloud/openstack"
	"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/limits"
	"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/quotasets"
	"github.com/gophercloud/gophercloud/openstack/compute/v2/flavors"
	"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
	"github.com/gophercloud/gophercloud/pagination"
	"github.com/sapcc/limes/pkg/limes"
)

type novaPlugin struct {
	cfg             limes.ServiceConfiguration
	scrapeInstances bool
	flavors 	map[string]*flavors.Flavor
}

var novaResources = []limes.ResourceInfo{
	{
		Name: "cores",
		Unit: limes.UnitNone,
	},
	{
		Name: "instances",
		Unit: limes.UnitNone,
	},
	{
		Name: "ram",
		Unit: limes.UnitMebibytes,
	},
}

func init() {
	limes.RegisterQuotaPlugin(func(c limes.ServiceConfiguration, scrapeSubresources map[string]bool) limes.QuotaPlugin {
		return &novaPlugin{
			cfg:             c,
			scrapeInstances: scrapeSubresources["instances"],
		}
	})
}

//ServiceInfo implements the limes.QuotaPlugin interface.
func (p *novaPlugin) ServiceInfo() limes.ServiceInfo {
	return limes.ServiceInfo{
		Type: "compute",
		Area: "compute",
	}
}

//Resources implements the limes.QuotaPlugin interface.
func (p *novaPlugin) Resources() []limes.ResourceInfo {
	return novaResources
}

func (p *novaPlugin) Client(provider *gophercloud.ProviderClient) (*gophercloud.ServiceClient, error) {
	return openstack.NewComputeV2(provider,
		gophercloud.EndpointOpts{Availability: gophercloud.AvailabilityPublic},
	)
}

//Scrape implements the limes.QuotaPlugin interface.
func (p *novaPlugin) Scrape(provider *gophercloud.ProviderClient, domainUUID, projectUUID string) (map[string]limes.ResourceData, error) {
	client, err := p.Client(provider)
	if err != nil {
		return nil, err
	}

	quotas, err := quotasets.Get(client, projectUUID).Extract()
	if err != nil {
		return nil, err
	}

	limits, err := limits.Get(client, limits.GetOpts{TenantID: projectUUID}).Extract()
	if err != nil {
		return nil, err
	}

	var instanceData []interface{}
	if p.scrapeInstances {
		listOpts := novaServerListOpts{
			AllTenants: true,
			TenantID:   projectUUID,
		}

		err := servers.List(client, listOpts).EachPage(func(page pagination.Page) (bool, error) {
			instances, err := servers.ExtractServers(page)
			if err != nil {
				return false, err
			}

			for _, instance := range instances {
				subResource := map[string]interface{}{
					"id":     instance.ID,
					"name":   instance.Name,
					"status": instance.Status,
				}
				flavor, err := p.getFlavor(client, instance.Flavor["id"].(string))
				if err == nil {
					subResource["ram"]  = flavor.RAM
					subResource["vcpu"] = flavor.VCPUs
					subResource["disk"] = flavor.Disk
				}
				instanceData = append(instanceData, subResource)
			}
			return true, nil
		})
		if err != nil {
			return nil, err
		}
	}

	return map[string]limes.ResourceData{
		"cores": {
			Quota: int64(quotas.Cores),
			Usage: uint64(limits.Absolute.TotalCoresUsed),
		},
		"instances": {
			Quota:        int64(quotas.Instances),
			Usage:        uint64(limits.Absolute.TotalInstancesUsed),
			Subresources: instanceData,
		},
		"ram": {
			Quota: int64(quotas.Ram),
			Usage: uint64(limits.Absolute.TotalRAMUsed),
		},
	}, nil
}

//SetQuota implements the limes.QuotaPlugin interface.
func (p *novaPlugin) SetQuota(provider *gophercloud.ProviderClient, domainUUID, projectUUID string, quotas map[string]uint64) error {
	client, err := p.Client(provider)
	if err != nil {
		return err
	}

	return quotasets.Update(client, projectUUID, quotasets.UpdateOpts{
		Cores:     makeIntPointer(int(quotas["cores"])),
		Instances: makeIntPointer(int(quotas["instances"])),
		Ram:       makeIntPointer(int(quotas["ram"])),
	}).Err
}

//Getting and caching flavor details
//Changing a flavor is not supported from OpenStack, so no invalidating of the cache needed
//Acces to the map is not thread safe
func (p *novaPlugin) getFlavor(client *gophercloud.ServiceClient, flavorID string) (*flavors.Flavor, error) {
	if p.flavors == nil {
		p.flavors = make(map[string]*flavors.Flavor)
	}

	if flavor, ok := p.flavors[flavorID]; ok {
		return flavor, nil
	}

	flavor, err := flavors.Get(client, flavorID).Extract()
	if err == nil {
		p.flavors[flavorID] = flavor
	}
	return flavor, err
}

func makeIntPointer(value int) *int {
	return &value
}

type novaServerListOpts struct {
	AllTenants bool   `q:"all_tenants"`
	TenantID   string `q:"tenant_id"`
}

func (opts novaServerListOpts) ToServerListQuery() (string, error) {
	q, err := gophercloud.BuildQueryString(opts)
	return q.String(), err
}
<|endoftext|>


<commit_before>package cmd

import (
	"encoding/json"
	"fmt"
	"github.com/astaxie/beego/logs"
	"github.com/qiniu/api.v7/storage"
	"github.com/qiniu/qshell/iqshell"
	"github.com/spf13/cobra"
	"io/ioutil"
	"os"
	"strings"
	"time"
)

var qUploadCmd = &cobra.Command{
	Use:   "qupload <quploadConfigFile>",
	Short: "Batch upload files to the qiniu bucket",
	Args:  cobra.ExactArgs(1),
	Run:   QiniuUpload,
}

var (
	successFname   string
	failureFname   string
	overwriteFname string
	upthreadCount  int64
	uploadConfig   iqshell.UploadConfig
)

func init() {
	qUploadCmd.Flags().StringVarP(&successFname, "success-list", "s", "", "upload success (all) file list")
	qUploadCmd.Flags().StringVarP(&failureFname, "failure-list", "f", "", "upload failure file list")
	qUploadCmd.Flags().StringVarP(&overwriteFname, "overwrite-list", "w", "", "upload success (overwrite) file list")
	qUploadCmd.Flags().Int64VarP(&upthreadCount, "worker", "c", 1, "worker count")
	qUploadCmd.Flags().StringVarP(&callbackUrls, "callback-urls", "l", "", "upload callback urls, separated by comma")
	qUploadCmd.Flags().StringVarP(&callbackHost, "callback-host", "T", "", "upload callback host")
	RootCmd.AddCommand(qUploadCmd)
}

func parseUploadConfigFile(uploadConfigFile string, uploadConfig *iqshell.UploadConfig) (err error) {
	//read upload config
	if uploadConfigFile == "" {
		err = fmt.Errorf("config filename is empty")
		return
	}
	fp, oErr := os.Open(uploadConfigFile)
	if oErr != nil {
		err = fmt.Errorf("Open upload config file ``%s`: %v\n", uploadConfigFile, oErr)
		return
	}
	defer fp.Close()

	configData, rErr := ioutil.ReadAll(fp)
	if rErr != nil {
		err = fmt.Errorf("Read upload config file `%s`: %v\n", uploadConfigFile, rErr)
		return
	}
	uErr := json.Unmarshal(configData, uploadConfig)
	if uErr != nil {
		err = fmt.Errorf("Parse upload config file `%s`: %v\n", uploadConfigFile, uErr)
		return
	}
	return
}

func QiniuUpload(cmd *cobra.Command, params []string) {

	configFile := params[0]

	pErr := parseUploadConfigFile(configFile, &uploadConfig)
	if pErr != nil {
		logs.Error(fmt.Sprintf("parse config file: %s: %v\n", configFile, pErr))
		os.Exit(iqshell.STATUS_HALT)
	}

	if uploadConfig.FileType != 1 && uploadConfig.FileType != 0 {
		logs.Error("Wrong Filetype, It should be 0 or 1 ")
		os.Exit(iqshell.STATUS_HALT)
	}

	srcFileInfo, err := os.Stat(uploadConfig.SrcDir)
	if err != nil {
		logs.Error("Upload config error for parameter `SrcDir`,", err)
		os.Exit(iqshell.STATUS_HALT)
	}

	if !srcFileInfo.IsDir() {
		logs.Error("Upload src dir should be a directory")
		os.Exit(iqshell.STATUS_HALT)
	}
	policy := storage.PutPolicy{}

	if (callbackUrls == "" && callbackHost != "") || (callbackUrls != "" && callbackHost == "") {
		fmt.Fprintf(os.Stderr, "callbackUrls and callback must exist at the same time\n")
		os.Exit(1)
	}
	if (uploadConfig.CallbackUrls == "" && uploadConfig.CallbackHost != "") || (uploadConfig.CallbackUrls != "" && uploadConfig.CallbackHost == "") {
		fmt.Fprintf(os.Stderr, "callbackUrls and callback must exist at the same time\n")
		os.Exit(1)
	}
	if (callbackHost != "" && callbackUrls != "") || (uploadConfig.CallbackHost != "" && uploadConfig.CallbackUrls != "") {
		callbackUrls = strings.Replace(callbackUrls, ",", ";", -1)
		policy.CallbackHost = callbackHost
		policy.CallbackURL = callbackUrls
		policy.CallbackBody = "key=$(key)&hash=$(etag)"
		policy.CallbackBodyType = "application/x-www-form-urlencoded"
	}
	uploadConfig.PutPolicy = policy

	//upload
	if upthreadCount < iqshell.MIN_UPLOAD_THREAD_COUNT || upthreadCount > iqshell.MAX_UPLOAD_THREAD_COUNT {
		logs.Info("Tip: you can set <ThreadCount> value between %d and %d to improve speed\n",
			iqshell.MIN_UPLOAD_THREAD_COUNT, iqshell.MAX_UPLOAD_THREAD_COUNT)

		if upthreadCount < iqshell.MIN_UPLOAD_THREAD_COUNT {
			upthreadCount = iqshell.MIN_UPLOAD_THREAD_COUNT
		} else if upthreadCount > iqshell.MAX_UPLOAD_THREAD_COUNT {
			upthreadCount = iqshell.MAX_UPLOAD_THREAD_COUNT
		}
	}

	fileExporter, fErr := iqshell.NewFileExporter(successFname, failureFname, overwriteFname)
	if fErr != nil {
		logs.Error("initialize fileExporter: ", fErr)
		os.Exit(iqshell.STATUS_HALT)
	}
	iqshell.QiniuUpload(int(upthreadCount), &uploadConfig, fileExporter)
}
<commit_msg>rm time package<commit_after>package cmd

import (
	"encoding/json"
	"fmt"
	"github.com/astaxie/beego/logs"
	"github.com/qiniu/api.v7/storage"
	"github.com/qiniu/qshell/iqshell"
	"github.com/spf13/cobra"
	"io/ioutil"
	"os"
	"strings"
)

var qUploadCmd = &cobra.Command{
	Use:   "qupload <quploadConfigFile>",
	Short: "Batch upload files to the qiniu bucket",
	Args:  cobra.ExactArgs(1),
	Run:   QiniuUpload,
}

var (
	successFname   string
	failureFname   string
	overwriteFname string
	upthreadCount  int64
	uploadConfig   iqshell.UploadConfig
)

func init() {
	qUploadCmd.Flags().StringVarP(&successFname, "success-list", "s", "", "upload success (all) file list")
	qUploadCmd.Flags().StringVarP(&failureFname, "failure-list", "f", "", "upload failure file list")
	qUploadCmd.Flags().StringVarP(&overwriteFname, "overwrite-list", "w", "", "upload success (overwrite) file list")
	qUploadCmd.Flags().Int64VarP(&upthreadCount, "worker", "c", 1, "worker count")
	qUploadCmd.Flags().StringVarP(&callbackUrls, "callback-urls", "l", "", "upload callback urls, separated by comma")
	qUploadCmd.Flags().StringVarP(&callbackHost, "callback-host", "T", "", "upload callback host")
	RootCmd.AddCommand(qUploadCmd)
}

func parseUploadConfigFile(uploadConfigFile string, uploadConfig *iqshell.UploadConfig) (err error) {
	//read upload config
	if uploadConfigFile == "" {
		err = fmt.Errorf("config filename is empty")
		return
	}
	fp, oErr := os.Open(uploadConfigFile)
	if oErr != nil {
		err = fmt.Errorf("Open upload config file ``%s`: %v\n", uploadConfigFile, oErr)
		return
	}
	defer fp.Close()

	configData, rErr := ioutil.ReadAll(fp)
	if rErr != nil {
		err = fmt.Errorf("Read upload config file `%s`: %v\n", uploadConfigFile, rErr)
		return
	}
	uErr := json.Unmarshal(configData, uploadConfig)
	if uErr != nil {
		err = fmt.Errorf("Parse upload config file `%s`: %v\n", uploadConfigFile, uErr)
		return
	}
	return
}

func QiniuUpload(cmd *cobra.Command, params []string) {

	configFile := params[0]

	pErr := parseUploadConfigFile(configFile, &uploadConfig)
	if pErr != nil {
		logs.Error(fmt.Sprintf("parse config file: %s: %v\n", configFile, pErr))
		os.Exit(iqshell.STATUS_HALT)
	}

	if uploadConfig.FileType != 1 && uploadConfig.FileType != 0 {
		logs.Error("Wrong Filetype, It should be 0 or 1 ")
		os.Exit(iqshell.STATUS_HALT)
	}

	srcFileInfo, err := os.Stat(uploadConfig.SrcDir)
	if err != nil {
		logs.Error("Upload config error for parameter `SrcDir`,", err)
		os.Exit(iqshell.STATUS_HALT)
	}

	if !srcFileInfo.IsDir() {
		logs.Error("Upload src dir should be a directory")
		os.Exit(iqshell.STATUS_HALT)
	}
	policy := storage.PutPolicy{}

	if (callbackUrls == "" && callbackHost != "") || (callbackUrls != "" && callbackHost == "") {
		fmt.Fprintf(os.Stderr, "callbackUrls and callback must exist at the same time\n")
		os.Exit(1)
	}
	if (uploadConfig.CallbackUrls == "" && uploadConfig.CallbackHost != "") || (uploadConfig.CallbackUrls != "" && uploadConfig.CallbackHost == "") {
		fmt.Fprintf(os.Stderr, "callbackUrls and callback must exist at the same time\n")
		os.Exit(1)
	}
	if (callbackHost != "" && callbackUrls != "") || (uploadConfig.CallbackHost != "" && uploadConfig.CallbackUrls != "") {
		callbackUrls = strings.Replace(callbackUrls, ",", ";", -1)
		policy.CallbackHost = callbackHost
		policy.CallbackURL = callbackUrls
		policy.CallbackBody = "key=$(key)&hash=$(etag)"
		policy.CallbackBodyType = "application/x-www-form-urlencoded"
	}
	uploadConfig.PutPolicy = policy

	//upload
	if upthreadCount < iqshell.MIN_UPLOAD_THREAD_COUNT || upthreadCount > iqshell.MAX_UPLOAD_THREAD_COUNT {
		logs.Info("Tip: you can set <ThreadCount> value between %d and %d to improve speed\n",
			iqshell.MIN_UPLOAD_THREAD_COUNT, iqshell.MAX_UPLOAD_THREAD_COUNT)

		if upthreadCount < iqshell.MIN_UPLOAD_THREAD_COUNT {
			upthreadCount = iqshell.MIN_UPLOAD_THREAD_COUNT
		} else if upthreadCount > iqshell.MAX_UPLOAD_THREAD_COUNT {
			upthreadCount = iqshell.MAX_UPLOAD_THREAD_COUNT
		}
	}

	fileExporter, fErr := iqshell.NewFileExporter(successFname, failureFname, overwriteFname)
	if fErr != nil {
		logs.Error("initialize fileExporter: ", fErr)
		os.Exit(iqshell.STATUS_HALT)
	}
	iqshell.QiniuUpload(int(upthreadCount), &uploadConfig, fileExporter)
}
<|endoftext|>


<commit_before>package cmd

import "github.com/spf13/cobra"

func init() {
	RootCmd.AddCommand(versionCmd)
}

var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Display the version of mbt",
	Run: func(cmd *cobra.Command, args []string) {
		println("0.14.4")
	},
}
<commit_msg>Bump version - v0.14.5<commit_after>package cmd

import "github.com/spf13/cobra"

func init() {
	RootCmd.AddCommand(versionCmd)
}

var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Display the version of mbt",
	Run: func(cmd *cobra.Command, args []string) {
		println("0.14.5")
	},
}
<|endoftext|>


<commit_before>// Copyright © 2017 NAME HERE <EMAIL ADDRESS>
//
// 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 cmd

import (
	"fmt"

	"github.com/spf13/cobra"
)

// versionCmd represents the auth command
var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Print the version number of planrockr-cli",
	Long:  `All software has versions. This is planrockr-cli's`,
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Println("planrockr-cli v1.0.2")
	},
}

func init() {
	RootCmd.AddCommand(versionCmd)
}
<commit_msg>Update version.go<commit_after>// Copyright © 2017 NAME HERE <EMAIL ADDRESS>
//
// 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 cmd

import (
	"fmt"

	"github.com/spf13/cobra"
)

// versionCmd represents the auth command
var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Print the version number of planrockr-cli",
	Long:  `All software has versions. This is planrockr-cli's`,
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Println("planrockr-cli v1.0.3")
	},
}

func init() {
	RootCmd.AddCommand(versionCmd)
}
<|endoftext|>


<commit_before>/*
Copyright 2018 MBT Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

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

package cmd

import "github.com/spf13/cobra"

func init() {
	RootCmd.AddCommand(versionCmd)
}

var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Display the version of mbt",
	Run: func(cmd *cobra.Command, args []string) {
		println("0.15.1")
	},
}
<commit_msg>Bump version - v0.16.0<commit_after>/*
Copyright 2018 MBT Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

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

package cmd

import "github.com/spf13/cobra"

func init() {
	RootCmd.AddCommand(versionCmd)
}

var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Display the version of mbt",
	Run: func(cmd *cobra.Command, args []string) {
		println("0.16.0")
	},
}
<|endoftext|>


<commit_before>package conf

import (
	"io/ioutil"
	"log"
	"os"
	"runtime"
	"time"

	yaml "gopkg.in/yaml.v2"
)

type (
	serverConf struct {
		MaxProc    int                    `yaml:"maxProc"`
		Port       string                 `yaml:"port"`
		Log        string                 `yaml:"log"`
		Props      map[string]interface{} `yaml:"props"`
		Jwt        *jwtConf               `yaml:"jwt"`
		DataSource *dataSource            `yaml:"dataSource"`
		Redis      *redisConf             `yaml:"redis"`
		MongoDb    *mongoDb               `yaml:"mongo"`
	}

	jwtConf struct {
		ContextKey    string        `yaml:"contextKey"`
		SigningKey    string        `yaml:"signingKey"`
		AuthScheme    string        `yaml:"authScheme"`
		SigningMethod string        `yaml:"signingMethod"`
		Expires       time.Duration `yaml:"expires"`
	}
	redisConf struct {
		Addr         string `yaml:"addr"`
		Password     string `yaml:"password"`
		DB           int    `yaml:"db"`
		PoolSize     int    `yaml:"poolSize"`
		MaxRetries   int    `yaml:"maxRetries"`
		MinIdleConns int    `yaml:"minIdle"`
		Stats        bool   `yaml:"stats"`
	}
	dataSource struct {
		Host            string `yaml:"host"`
		Port            int16  `yaml:"port"`
		User            string `yaml:"user"`
		Password        string `yaml:"password"`
		DB              string `yaml:"db"`
		MaxIdleConns    int    `yaml:"maxIdleConns"`
		MaxOpenConns    int    `yaml:"maxOpenConns"`
		ConnMaxLifetime int    `yaml:"connMaxLifetime"`
		Log             bool   `yaml:"log"`
	}
	mongoDb struct {
		Url       string `yaml:"url"`
		Database  string `yaml:"db"`
		User      string `yaml:"user"`
		Password  string `yaml:"password"`
		Timeout   int    `yaml:"timeout"`
		PoolLimit int    `yaml:"poolLimit"`
	}
)

var ServerConf = &serverConf{}

func init() {

}
func LoadConf() {
	currentDir, _ := os.Getwd()
	yamlFile, err := ioutil.ReadFile(currentDir + "/conf.yaml")
	if err != nil {
		log.Printf("yamlFile.Get err   #%v ", err)
		return
	}
	err = yaml.Unmarshal(yamlFile, ServerConf)
	if err != nil {
		log.Fatalf("Unmarshal: %v", err)
		os.Exit(-1)
	}
	// 设置go processor数量
	if ServerConf.MaxProc == 0 {
		ServerConf.MaxProc = runtime.NumCPU()
	}
	if len(ServerConf.Log) == 0 {
		ServerConf.Log = "server.log"
	}
}
<commit_msg>调整配置文件路径<commit_after>package conf

import (
	"io/ioutil"
	"log"
	"os"
	"runtime"
	"time"

	yaml "gopkg.in/yaml.v2"
)

type (
	serverConf struct {
		MaxProc    int                    `yaml:"maxProc"`
		Port       string                 `yaml:"port"`
		Log        string                 `yaml:"log"`
		Props      map[string]interface{} `yaml:"props"`
		Jwt        *jwtConf               `yaml:"jwt"`
		DataSource *dataSource            `yaml:"dataSource"`
		Redis      *redisConf             `yaml:"redis"`
		MongoDb    *mongoDb               `yaml:"mongo"`
	}

	jwtConf struct {
		ContextKey    string        `yaml:"contextKey"`
		SigningKey    string        `yaml:"signingKey"`
		AuthScheme    string        `yaml:"authScheme"`
		SigningMethod string        `yaml:"signingMethod"`
		Expires       time.Duration `yaml:"expires"`
	}
	redisConf struct {
		Addr         string `yaml:"addr"`
		Password     string `yaml:"password"`
		DB           int    `yaml:"db"`
		PoolSize     int    `yaml:"poolSize"`
		MaxRetries   int    `yaml:"maxRetries"`
		MinIdleConns int    `yaml:"minIdle"`
		Stats        bool   `yaml:"stats"`
	}
	dataSource struct {
		Host            string `yaml:"host"`
		Port            int16  `yaml:"port"`
		User            string `yaml:"user"`
		Password        string `yaml:"password"`
		DB              string `yaml:"db"`
		MaxIdleConns    int    `yaml:"maxIdleConns"`
		MaxOpenConns    int    `yaml:"maxOpenConns"`
		ConnMaxLifetime int    `yaml:"connMaxLifetime"`
		Log             bool   `yaml:"log"`
	}
	mongoDb struct {
		Url       string `yaml:"url"`
		Database  string `yaml:"db"`
		User      string `yaml:"user"`
		Password  string `yaml:"password"`
		Timeout   int    `yaml:"timeout"`
		PoolLimit int    `yaml:"poolLimit"`
	}
)

var ServerConf = &serverConf{}

func init() {

}
func LoadDefaultConf() {
	currentDir, _ := os.Getwd()
	LoadConf(currentDir + "/conf.yaml")
}

func LoadConf(conf string) {
	yamlFile, err := ioutil.ReadFile(conf)
	if err != nil {
		log.Printf("yamlFile.Get err   #%v ", err)
		return
	}
	err = yaml.Unmarshal(yamlFile, ServerConf)
	if err != nil {
		log.Fatalf("Unmarshal: %v", err)
		os.Exit(-1)
	}
	// 设置go processor数量
	if ServerConf.MaxProc == 0 {
		ServerConf.MaxProc = runtime.NumCPU()
	}
	if len(ServerConf.Log) == 0 {
		ServerConf.Log = "server.log"
	}
}
<|endoftext|>


<commit_before>package conf

import (
	"fmt"
	"github.com/spf13/viper"
)

func GetConf() map[string]interface{} {
	viper.SetConfigName("microb_dev_config")
	viper.AddConfigPath(".")
	viper.SetDefault("http_host", ":8080")
	viper.SetDefault("centrifugo_host", "localhost")
	viper.SetDefault("centrifugo_port", 8001)
	viper.SetDefault("db_host", "localhost")
	viper.SetDefault("db_port", 28015)
	viper.SetDefault("db_user", "admin")
	viper.SetDefault("db_password", "")
	viper.SetDefault("hits_log", true)
	viper.SetDefault("hits_monitor", true)
	defaut_hits_chan := "$"+viper.Get("domain").(string)+"_hits"
	viper.SetDefault("hits_channel", defaut_hits_chan)
	err := viper.ReadInConfig()
	if err != nil {
	    panic(fmt.Errorf("Fatal error config file: %s \n", err))
	}
	conf := make(map[string]interface{})
	conf["http_host"] = viper.Get("http_host")
	conf["centrifugo_host"] = viper.Get("centrifugo_host")
	conf["centrifugo_port"] = viper.Get("centrifugo_port")
	conf["centrifugo_secret_key"] = viper.Get("centrifugo_secret_key")
	conf["db_host"] = viper.Get("db_host")
	conf["db_port"] = viper.Get("db_port")
	conf["db_user"] = viper.Get("db_user")
	conf["db_password"] = viper.Get("db_password")
	conf["domain"] = viper.Get("domain")
	conf["hits_log"] = viper.Get("hits_log")
	conf["hits_monitor"] = viper.Get("hits_monitor")
	conf["hits_channel"] = viper.Get("hits_channel")
	return conf
}
<commit_msg>Correction<commit_after>package conf

import (
	"fmt"
	"github.com/spf13/viper"
)

func GetConf() map[string]interface{} {
	viper.SetConfigName("microb_dev_config")
	viper.AddConfigPath(".")
	viper.SetDefault("http_host", ":8080")
	viper.SetDefault("centrifugo_host", "localhost")
	viper.SetDefault("centrifugo_port", 8001)
	viper.SetDefault("db_host", "localhost")
	viper.SetDefault("db_port", 28015)
	viper.SetDefault("db_user", "admin")
	viper.SetDefault("db_password", "")
	viper.SetDefault("hits_log", true)
	viper.SetDefault("hits_monitor", true)
	viper.SetDefault("hits_channel", "$microb_hits")
	err := viper.ReadInConfig()
	if err != nil {
	    panic(fmt.Errorf("Fatal error config file: %s \n", err))
	}
	conf := make(map[string]interface{})
	conf["http_host"] = viper.Get("http_host")
	conf["centrifugo_host"] = viper.Get("centrifugo_host")
	conf["centrifugo_port"] = viper.Get("centrifugo_port")
	conf["centrifugo_secret_key"] = viper.Get("centrifugo_secret_key")
	conf["db_host"] = viper.Get("db_host")
	conf["db_port"] = viper.Get("db_port")
	conf["db_user"] = viper.Get("db_user")
	conf["db_password"] = viper.Get("db_password")
	conf["domain"] = viper.Get("domain")
	conf["hits_log"] = viper.Get("hits_log")
	conf["hits_monitor"] = viper.Get("hits_monitor")
	conf["hits_channel"] = viper.Get("hits_channel")
	return conf
}
<|endoftext|>


<commit_before>package ovs

import (
	"fmt"
	"strconv"
	"strings"

	"github.com/golang/glog"

	utilversion "k8s.io/kubernetes/pkg/util/version"
	"k8s.io/utils/exec"
)

// Interface represents an interface to OVS
type Interface interface {
	// AddBridge creates the bridge associated with the interface, optionally setting
	// properties on it (as with "ovs-vsctl set Bridge ..."). If the bridge already
	// exists this errors.
	AddBridge(properties ...string) error

	// DeleteBridge deletes the bridge associated with the interface. The boolean
	// that can be passed determines if a bridge not existing is an error. Passing
	// true will delete bridge --if-exists, passing false will error if the bridge
	// does not exist.
	DeleteBridge(ifExists bool) error

	// AddPort adds an interface to the bridge, requesting the indicated port
	// number, and optionally setting properties on it (as with "ovs-vsctl set
	// Interface ..."). Returns the allocated port number (or an error).
	AddPort(port string, ofportRequest int, properties ...string) (int, error)

	// DeletePort removes an interface from the bridge. (It is not an
	// error if the interface is not currently a bridge port.)
	DeletePort(port string) error

	// GetOFPort returns the OpenFlow port number of a given network interface
	// attached to a bridge.
	GetOFPort(port string) (int, error)

	// SetFrags sets the fragmented-packet-handling mode (as with
	// "ovs-ofctl set-frags")
	SetFrags(mode string) error

	// Create creates a record in the OVS database, as with "ovs-vsctl create" and
	// returns the UUID of the newly-created item.
	// NOTE: This only works for QoS; for all other tables the created object will
	// immediately be garbage-collected; we'd need an API that calls "create" and "set"
	// in the same "ovs-vsctl" call.
	Create(table string, values ...string) (string, error)

	// Destroy deletes the indicated record in the OVS database. It is not an error if
	// the record does not exist
	Destroy(table, record string) error

	// Get gets the indicated value from the OVS database. For multi-valued or
	// map-valued columns, the data is returned in the same format as "ovs-vsctl get".
	Get(table, record, column string) (string, error)

	// Set sets one or more columns on a record in the OVS database, as with
	// "ovs-vsctl set"
	Set(table, record string, values ...string) error

	// Clear unsets the indicated columns in the OVS database. It is not an error if
	// the value is already unset
	Clear(table, record string, columns ...string) error

	// Find finds records in the OVS database that match the given condition.
	// It returns the value of the given column of matching records.
	Find(table, column, condition string) ([]string, error)

	// DumpFlows dumps the flow table for the bridge and returns it as an array of
	// strings, one per flow. If flow is not "" then it describes the flows to dump.
	DumpFlows(flow string, args ...interface{}) ([]string, error)

	// NewTransaction begins a new OVS transaction. If an error occurs at
	// any step in the transaction, it will be recorded until
	// EndTransaction(), and any further calls on the transaction will be
	// ignored.
	NewTransaction() Transaction
}

// Transaction manages a single set of OVS flow modifications
type Transaction interface {
	// AddFlow adds a flow to the bridge. The arguments are passed to fmt.Sprintf().
	AddFlow(flow string, args ...interface{})

	// DeleteFlows deletes all matching flows from the bridge. The arguments are
	// passed to fmt.Sprintf().
	DeleteFlows(flow string, args ...interface{})

	// EndTransaction ends an OVS transaction and returns any error that occurred
	// during the transaction. You should not use the transaction again after
	// calling this function.
	EndTransaction() error
}

const (
	OVS_OFCTL = "ovs-ofctl"
	OVS_VSCTL = "ovs-vsctl"
)

// ovsExec implements ovs.Interface via calls to ovs-ofctl and ovs-vsctl
type ovsExec struct {
	execer exec.Interface
	bridge string
}

// New returns a new ovs.Interface
func New(execer exec.Interface, bridge string, minVersion string) (Interface, error) {
	if _, err := execer.LookPath(OVS_OFCTL); err != nil {
		return nil, fmt.Errorf("OVS is not installed")
	}
	if _, err := execer.LookPath(OVS_VSCTL); err != nil {
		return nil, fmt.Errorf("OVS is not installed")
	}

	ovsif := &ovsExec{execer: execer, bridge: bridge}

	if minVersion != "" {
		minVer := utilversion.MustParseGeneric(minVersion)

		out, err := ovsif.exec(OVS_VSCTL, "--version")
		if err != nil {
			return nil, fmt.Errorf("could not check OVS version is %s or higher", minVersion)
		}
		// First output line should end with version
		lines := strings.Split(out, "\n")
		spc := strings.LastIndex(lines[0], " ")
		instVer, err := utilversion.ParseGeneric(lines[0][spc+1:])
		if err != nil {
			return nil, fmt.Errorf("could not find OVS version in %q", lines[0])
		}
		if !instVer.AtLeast(minVer) {
			return nil, fmt.Errorf("found OVS %v, need %s or later", instVer, minVersion)
		}
	}

	return ovsif, nil
}

func (ovsif *ovsExec) exec(cmd string, args ...string) (string, error) {
	switch cmd {
	case OVS_OFCTL:
		args = append([]string{"-O", "OpenFlow13"}, args...)
	case OVS_VSCTL:
		args = append([]string{"--timeout=30"}, args...)
	}
	glog.V(4).Infof("Executing: %s %s", cmd, strings.Join(args, " "))

	output, err := ovsif.execer.Command(cmd, args...).CombinedOutput()
	if err != nil {
		glog.V(2).Infof("Error executing %s: %s", cmd, string(output))
		return "", err
	}

	outStr := string(output)
	if outStr != "" {
		// If output is a single line, strip the trailing newline
		nl := strings.Index(outStr, "\n")
		if nl == len(outStr)-1 {
			outStr = outStr[:nl]
		}
	}
	return outStr, nil
}

func (ovsif *ovsExec) AddBridge(properties ...string) error {
	args := []string{"add-br", ovsif.bridge}
	if len(properties) > 0 {
		args = append(args, "--", "set", "Bridge", ovsif.bridge)
		args = append(args, properties...)
	}
	_, err := ovsif.exec(OVS_VSCTL, args...)
	return err
}

func (ovsif *ovsExec) DeleteBridge(ifExists bool) error {
	args := []string{"del-br", ovsif.bridge}

	if ifExists {
		args = append([]string{"--if-exists"}, args...)
	}
	_, err := ovsif.exec(OVS_VSCTL, args...)
	return err
}

func (ovsif *ovsExec) GetOFPort(port string) (int, error) {
	ofportStr, err := ovsif.exec(OVS_VSCTL, "get", "Interface", port, "ofport")
	if err != nil {
		return -1, fmt.Errorf("failed to get OVS port for %s: %v", port, err)
	}
	ofport, err := strconv.Atoi(ofportStr)
	if err != nil {
		return -1, fmt.Errorf("could not parse allocated ofport %q: %v", ofportStr, err)
	}
	if ofport == -1 {
		errStr, err := ovsif.exec(OVS_VSCTL, "get", "Interface", port, "error")
		if err != nil || errStr == "" {
			errStr = "unknown error"
		}
		return -1, fmt.Errorf("error on port %s: %s", port, errStr)
	}
	return ofport, nil
}

func (ovsif *ovsExec) AddPort(port string, ofportRequest int, properties ...string) (int, error) {
	args := []string{"--may-exist", "add-port", ovsif.bridge, port}
	if ofportRequest > 0 || len(properties) > 0 {
		args = append(args, "--", "set", "Interface", port)
		if ofportRequest > 0 {
			args = append(args, fmt.Sprintf("ofport_request=%d", ofportRequest))
		}
		if len(properties) > 0 {
			args = append(args, properties...)
		}
	}
	_, err := ovsif.exec(OVS_VSCTL, args...)
	if err != nil {
		return -1, err
	}
	ofport, err := ovsif.GetOFPort(port)
	if err != nil {
		return -1, err
	}
	if ofportRequest > 0 && ofportRequest != ofport {
		return -1, fmt.Errorf("allocated ofport (%d) did not match request (%d)", ofport, ofportRequest)
	}
	return ofport, nil
}

func (ovsif *ovsExec) DeletePort(port string) error {
	_, err := ovsif.exec(OVS_VSCTL, "--if-exists", "del-port", ovsif.bridge, port)
	return err
}

func (ovsif *ovsExec) SetFrags(mode string) error {
	_, err := ovsif.exec(OVS_OFCTL, "set-frags", ovsif.bridge, mode)
	return err
}

func (ovsif *ovsExec) Create(table string, values ...string) (string, error) {
	args := append([]string{"create", table}, values...)
	return ovsif.exec(OVS_VSCTL, args...)
}

func (ovsif *ovsExec) Destroy(table, record string) error {
	_, err := ovsif.exec(OVS_VSCTL, "--if-exists", "destroy", table, record)
	return err
}

func (ovsif *ovsExec) Get(table, record, column string) (string, error) {
	return ovsif.exec(OVS_VSCTL, "get", table, record, column)
}

func (ovsif *ovsExec) Set(table, record string, values ...string) error {
	args := append([]string{"set", table, record}, values...)
	_, err := ovsif.exec(OVS_VSCTL, args...)
	return err
}

// Returns the given column of records that match the condition
func (ovsif *ovsExec) Find(table, column, condition string) ([]string, error) {
	output, err := ovsif.exec(OVS_VSCTL, "--no-heading", "--columns="+column, "find", table, condition)
	if err != nil {
		return nil, err
	}
	values := strings.Split(output, "\n\n")
	// We want "bare" values for strings, but we can't pass --bare to ovs-vsctl because
	// it breaks more complicated types. So try passing each value through Unquote();
	// if it fails, that means the value wasn't a quoted string, so use it as-is.
	for i, val := range values {
		if unquoted, err := strconv.Unquote(val); err == nil {
			values[i] = unquoted
		}
	}
	return values, nil
}

func (ovsif *ovsExec) Clear(table, record string, columns ...string) error {
	args := append([]string{"--if-exists", "clear", table, record}, columns...)
	_, err := ovsif.exec(OVS_VSCTL, args...)
	return err
}

type ovsExecTx struct {
	ovsif *ovsExec
	err   error
}

func (tx *ovsExecTx) exec(cmd string, args ...string) (string, error) {
	out := ""
	if tx.err == nil {
		out, tx.err = tx.ovsif.exec(cmd, args...)
	}
	return out, tx.err
}

func (ovsif *ovsExec) NewTransaction() Transaction {
	return &ovsExecTx{ovsif: ovsif}
}

func (tx *ovsExecTx) AddFlow(flow string, args ...interface{}) {
	if len(args) > 0 {
		flow = fmt.Sprintf(flow, args...)
	}
	tx.exec(OVS_OFCTL, "add-flow", tx.ovsif.bridge, flow)
}

func (tx *ovsExecTx) DeleteFlows(flow string, args ...interface{}) {
	if len(args) > 0 {
		flow = fmt.Sprintf(flow, args...)
	}
	tx.exec(OVS_OFCTL, "del-flows", tx.ovsif.bridge, flow)
}

func (tx *ovsExecTx) EndTransaction() error {
	err := tx.err
	tx.err = nil
	return err
}

func (ovsif *ovsExec) DumpFlows(flow string, args ...interface{}) ([]string, error) {
	if len(args) > 0 {
		flow = fmt.Sprintf(flow, args...)
	}
	out, err := ovsif.exec(OVS_OFCTL, "dump-flows", ovsif.bridge, flow)
	if err != nil {
		return nil, err
	}

	lines := strings.Split(out, "\n")
	flows := make([]string, 0, len(lines))
	for _, line := range lines {
		if strings.Contains(line, "cookie=") {
			flows = append(flows, line)
		}
	}
	return flows, nil
}
<commit_msg>Added internal bundle() method to ovsExec interface<commit_after>package ovs

import (
	"bytes"
	"fmt"
	"strconv"
	"strings"

	"github.com/golang/glog"

	utilversion "k8s.io/kubernetes/pkg/util/version"
	"k8s.io/utils/exec"
)

// Interface represents an interface to OVS
type Interface interface {
	// AddBridge creates the bridge associated with the interface, optionally setting
	// properties on it (as with "ovs-vsctl set Bridge ..."). If the bridge already
	// exists this errors.
	AddBridge(properties ...string) error

	// DeleteBridge deletes the bridge associated with the interface. The boolean
	// that can be passed determines if a bridge not existing is an error. Passing
	// true will delete bridge --if-exists, passing false will error if the bridge
	// does not exist.
	DeleteBridge(ifExists bool) error

	// AddPort adds an interface to the bridge, requesting the indicated port
	// number, and optionally setting properties on it (as with "ovs-vsctl set
	// Interface ..."). Returns the allocated port number (or an error).
	AddPort(port string, ofportRequest int, properties ...string) (int, error)

	// DeletePort removes an interface from the bridge. (It is not an
	// error if the interface is not currently a bridge port.)
	DeletePort(port string) error

	// GetOFPort returns the OpenFlow port number of a given network interface
	// attached to a bridge.
	GetOFPort(port string) (int, error)

	// SetFrags sets the fragmented-packet-handling mode (as with
	// "ovs-ofctl set-frags")
	SetFrags(mode string) error

	// Create creates a record in the OVS database, as with "ovs-vsctl create" and
	// returns the UUID of the newly-created item.
	// NOTE: This only works for QoS; for all other tables the created object will
	// immediately be garbage-collected; we'd need an API that calls "create" and "set"
	// in the same "ovs-vsctl" call.
	Create(table string, values ...string) (string, error)

	// Destroy deletes the indicated record in the OVS database. It is not an error if
	// the record does not exist
	Destroy(table, record string) error

	// Get gets the indicated value from the OVS database. For multi-valued or
	// map-valued columns, the data is returned in the same format as "ovs-vsctl get".
	Get(table, record, column string) (string, error)

	// Set sets one or more columns on a record in the OVS database, as with
	// "ovs-vsctl set"
	Set(table, record string, values ...string) error

	// Clear unsets the indicated columns in the OVS database. It is not an error if
	// the value is already unset
	Clear(table, record string, columns ...string) error

	// Find finds records in the OVS database that match the given condition.
	// It returns the value of the given column of matching records.
	Find(table, column, condition string) ([]string, error)

	// DumpFlows dumps the flow table for the bridge and returns it as an array of
	// strings, one per flow. If flow is not "" then it describes the flows to dump.
	DumpFlows(flow string, args ...interface{}) ([]string, error)

	// NewTransaction begins a new OVS transaction. If an error occurs at
	// any step in the transaction, it will be recorded until
	// EndTransaction(), and any further calls on the transaction will be
	// ignored.
	NewTransaction() Transaction
}

// Transaction manages a single set of OVS flow modifications
type Transaction interface {
	// AddFlow adds a flow to the bridge. The arguments are passed to fmt.Sprintf().
	AddFlow(flow string, args ...interface{})

	// DeleteFlows deletes all matching flows from the bridge. The arguments are
	// passed to fmt.Sprintf().
	DeleteFlows(flow string, args ...interface{})

	// EndTransaction ends an OVS transaction and returns any error that occurred
	// during the transaction. You should not use the transaction again after
	// calling this function.
	EndTransaction() error
}

const (
	OVS_OFCTL = "ovs-ofctl"
	OVS_VSCTL = "ovs-vsctl"
)

// ovsExec implements ovs.Interface via calls to ovs-ofctl and ovs-vsctl
type ovsExec struct {
	execer exec.Interface
	bridge string
}

// New returns a new ovs.Interface
func New(execer exec.Interface, bridge string, minVersion string) (Interface, error) {
	if _, err := execer.LookPath(OVS_OFCTL); err != nil {
		return nil, fmt.Errorf("OVS is not installed")
	}
	if _, err := execer.LookPath(OVS_VSCTL); err != nil {
		return nil, fmt.Errorf("OVS is not installed")
	}

	ovsif := &ovsExec{execer: execer, bridge: bridge}

	if minVersion != "" {
		minVer := utilversion.MustParseGeneric(minVersion)

		out, err := ovsif.exec(OVS_VSCTL, "--version")
		if err != nil {
			return nil, fmt.Errorf("could not check OVS version is %s or higher", minVersion)
		}
		// First output line should end with version
		lines := strings.Split(out, "\n")
		spc := strings.LastIndex(lines[0], " ")
		instVer, err := utilversion.ParseGeneric(lines[0][spc+1:])
		if err != nil {
			return nil, fmt.Errorf("could not find OVS version in %q", lines[0])
		}
		if !instVer.AtLeast(minVer) {
			return nil, fmt.Errorf("found OVS %v, need %s or later", instVer, minVersion)
		}
	}

	return ovsif, nil
}

func (ovsif *ovsExec) execWithStdin(cmd string, stdinArgs []string, args ...string) (string, error) {
	switch cmd {
	case OVS_OFCTL:
		args = append([]string{"-O", "OpenFlow13"}, args...)
	case OVS_VSCTL:
		args = append([]string{"--timeout=30"}, args...)
	}

	kcmd := ovsif.execer.Command(cmd, args...)
	if stdinArgs != nil {
		stdinString := strings.Join(stdinArgs, "\n")
		stdin := bytes.NewBufferString(stdinString)
		kcmd.SetStdin(stdin)

		glog.V(4).Infof("Executing: %s %s <<\n%s", cmd, strings.Join(args, " "), stdinString)
	} else {
		glog.V(4).Infof("Executing: %s %s", cmd, strings.Join(args, " "))
	}

	output, err := kcmd.CombinedOutput()
	if err != nil {
		glog.V(2).Infof("Error executing %s: %s", cmd, string(output))
		return "", err
	}

	outStr := string(output)
	if outStr != "" {
		// If output is a single line, strip the trailing newline
		nl := strings.Index(outStr, "\n")
		if nl == len(outStr)-1 {
			outStr = outStr[:nl]
		}
	}
	return outStr, nil
}

func (ovsif *ovsExec) exec(cmd string, args ...string) (string, error) {
	return ovsif.execWithStdin(cmd, nil, args...)
}

func (ovsif *ovsExec) AddBridge(properties ...string) error {
	args := []string{"add-br", ovsif.bridge}
	if len(properties) > 0 {
		args = append(args, "--", "set", "Bridge", ovsif.bridge)
		args = append(args, properties...)
	}
	_, err := ovsif.exec(OVS_VSCTL, args...)
	return err
}

func (ovsif *ovsExec) DeleteBridge(ifExists bool) error {
	args := []string{"del-br", ovsif.bridge}

	if ifExists {
		args = append([]string{"--if-exists"}, args...)
	}
	_, err := ovsif.exec(OVS_VSCTL, args...)
	return err
}

func (ovsif *ovsExec) GetOFPort(port string) (int, error) {
	ofportStr, err := ovsif.exec(OVS_VSCTL, "get", "Interface", port, "ofport")
	if err != nil {
		return -1, fmt.Errorf("failed to get OVS port for %s: %v", port, err)
	}
	ofport, err := strconv.Atoi(ofportStr)
	if err != nil {
		return -1, fmt.Errorf("could not parse allocated ofport %q: %v", ofportStr, err)
	}
	if ofport == -1 {
		errStr, err := ovsif.exec(OVS_VSCTL, "get", "Interface", port, "error")
		if err != nil || errStr == "" {
			errStr = "unknown error"
		}
		return -1, fmt.Errorf("error on port %s: %s", port, errStr)
	}
	return ofport, nil
}

func (ovsif *ovsExec) AddPort(port string, ofportRequest int, properties ...string) (int, error) {
	args := []string{"--may-exist", "add-port", ovsif.bridge, port}
	if ofportRequest > 0 || len(properties) > 0 {
		args = append(args, "--", "set", "Interface", port)
		if ofportRequest > 0 {
			args = append(args, fmt.Sprintf("ofport_request=%d", ofportRequest))
		}
		if len(properties) > 0 {
			args = append(args, properties...)
		}
	}
	_, err := ovsif.exec(OVS_VSCTL, args...)
	if err != nil {
		return -1, err
	}
	ofport, err := ovsif.GetOFPort(port)
	if err != nil {
		return -1, err
	}
	if ofportRequest > 0 && ofportRequest != ofport {
		return -1, fmt.Errorf("allocated ofport (%d) did not match request (%d)", ofport, ofportRequest)
	}
	return ofport, nil
}

func (ovsif *ovsExec) DeletePort(port string) error {
	_, err := ovsif.exec(OVS_VSCTL, "--if-exists", "del-port", ovsif.bridge, port)
	return err
}

func (ovsif *ovsExec) SetFrags(mode string) error {
	_, err := ovsif.exec(OVS_OFCTL, "set-frags", ovsif.bridge, mode)
	return err
}

func (ovsif *ovsExec) Create(table string, values ...string) (string, error) {
	args := append([]string{"create", table}, values...)
	return ovsif.exec(OVS_VSCTL, args...)
}

func (ovsif *ovsExec) Destroy(table, record string) error {
	_, err := ovsif.exec(OVS_VSCTL, "--if-exists", "destroy", table, record)
	return err
}

func (ovsif *ovsExec) Get(table, record, column string) (string, error) {
	return ovsif.exec(OVS_VSCTL, "get", table, record, column)
}

func (ovsif *ovsExec) Set(table, record string, values ...string) error {
	args := append([]string{"set", table, record}, values...)
	_, err := ovsif.exec(OVS_VSCTL, args...)
	return err
}

// Returns the given column of records that match the condition
func (ovsif *ovsExec) Find(table, column, condition string) ([]string, error) {
	output, err := ovsif.exec(OVS_VSCTL, "--no-heading", "--columns="+column, "find", table, condition)
	if err != nil {
		return nil, err
	}
	values := strings.Split(output, "\n\n")
	// We want "bare" values for strings, but we can't pass --bare to ovs-vsctl because
	// it breaks more complicated types. So try passing each value through Unquote();
	// if it fails, that means the value wasn't a quoted string, so use it as-is.
	for i, val := range values {
		if unquoted, err := strconv.Unquote(val); err == nil {
			values[i] = unquoted
		}
	}
	return values, nil
}

func (ovsif *ovsExec) Clear(table, record string, columns ...string) error {
	args := append([]string{"--if-exists", "clear", table, record}, columns...)
	_, err := ovsif.exec(OVS_VSCTL, args...)
	return err
}

type ovsExecTx struct {
	ovsif *ovsExec
	err   error
}

func (tx *ovsExecTx) exec(cmd string, args ...string) (string, error) {
	out := ""
	if tx.err == nil {
		out, tx.err = tx.ovsif.exec(cmd, args...)
	}
	return out, tx.err
}

func (ovsif *ovsExec) NewTransaction() Transaction {
	return &ovsExecTx{ovsif: ovsif}
}

func (tx *ovsExecTx) AddFlow(flow string, args ...interface{}) {
	if len(args) > 0 {
		flow = fmt.Sprintf(flow, args...)
	}
	tx.exec(OVS_OFCTL, "add-flow", tx.ovsif.bridge, flow)
}

func (tx *ovsExecTx) DeleteFlows(flow string, args ...interface{}) {
	if len(args) > 0 {
		flow = fmt.Sprintf(flow, args...)
	}
	tx.exec(OVS_OFCTL, "del-flows", tx.ovsif.bridge, flow)
}

func (tx *ovsExecTx) EndTransaction() error {
	err := tx.err
	tx.err = nil
	return err
}

func (ovsif *ovsExec) DumpFlows(flow string, args ...interface{}) ([]string, error) {
	if len(args) > 0 {
		flow = fmt.Sprintf(flow, args...)
	}
	out, err := ovsif.exec(OVS_OFCTL, "dump-flows", ovsif.bridge, flow)
	if err != nil {
		return nil, err
	}

	lines := strings.Split(out, "\n")
	flows := make([]string, 0, len(lines))
	for _, line := range lines {
		if strings.Contains(line, "cookie=") {
			flows = append(flows, line)
		}
	}
	return flows, nil
}

// bundle executes all given flows as a single atomic transaction
func (ovsif *ovsExec) bundle(flows []string) error {
	if len(flows) == 0 {
		return nil
	}

	_, err := ovsif.execWithStdin(OVS_OFCTL, flows, "bundle", ovsif.bridge, "-")
	return err
}
<|endoftext|>


<commit_before>// Copyright 2016, 2020 Tamás Gulácsi
//
//
//    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.

// protoc-gen-grpc generates a grpcer.Client from the given protoc file.
package main

import (
	"bytes"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"text/template"
	"time"

	"golang.org/x/sync/errgroup"

	"github.com/golang/protobuf/protoc-gen-go/descriptor"
	protoc "github.com/golang/protobuf/protoc-gen-go/plugin"
	"google.golang.org/protobuf/proto"
)

func main() {
	data, err := ioutil.ReadAll(os.Stdin)
	if err != nil {
		log.Fatal(err)
	}

	var req protoc.CodeGeneratorRequest
	if err = proto.Unmarshal(data, &req); err != nil {
		log.Fatal(err)
	}

	var resp protoc.CodeGeneratorResponse
	if err := Generate(&resp, req); err != nil {
		log.Fatal(err)
	}
	data, err = proto.Marshal(&resp)
	if err != nil {
		log.Fatal(err)
	}
	if _, err = os.Stdout.Write(data); err != nil {
		log.Fatal(err)
	}
}

func Generate(resp *protoc.CodeGeneratorResponse, req protoc.CodeGeneratorRequest) error {
	destPkg := req.GetParameter()
	if destPkg == "" {
		destPkg = "main"
	}

	// Find roots.
	rootNames := req.GetFileToGenerate()
	files := req.GetProtoFile()
	roots := make(map[string]*descriptor.FileDescriptorProto, len(rootNames))
	allTypes := make(map[string]*descriptor.DescriptorProto, 1024)
	var found int
	for i := len(files) - 1; i >= 0; i-- {
		f := files[i]
		for _, m := range f.GetMessageType() {
			allTypes["."+f.GetPackage()+"."+m.GetName()] = m
		}
		if found == len(rootNames) {
			continue
		}
		for _, root := range rootNames {
			if f.GetName() == root {
				roots[root] = files[i]
				found++
				break
			}
		}
	}

	msgTypes := make(map[string]*descriptor.DescriptorProto, len(allTypes))
	for _, root := range roots {
		//k := "." + root.GetName() + "."
		var k string
		for _, svc := range root.GetService() {
			for _, m := range svc.GetMethod() {
				if kk := k + m.GetInputType(); len(kk) > len(k) {
					msgTypes[kk] = allTypes[kk]
				}
				if kk := k + m.GetOutputType(); len(kk) > len(k) {
					msgTypes[kk] = allTypes[kk]
				}
			}
		}
	}

	var grp errgroup.Group
	resp.File = make([]*protoc.CodeGeneratorResponse_File, 0, len(roots))
	var mu sync.Mutex
	for _, root := range roots {
		root := root
		pkg := root.GetName()
		for _, svc := range root.GetService() {
			grp.Go(func() error {
				destFn := strings.TrimSuffix(filepath.Base(pkg), ".proto") + ".grpcer.go"
				content, err := genGo(destPkg, pkg, svc, root.GetDependency())
				mu.Lock()
				resp.File = append(resp.File, &protoc.CodeGeneratorResponse_File{
					Name:    &destFn,
					Content: &content,
				})
				mu.Unlock()
				return err
			})
		}
	}

	if err := grp.Wait(); err != nil {
		errS := err.Error()
		resp.Error = &errS
	}
	return nil
}

var goTmpl = template.Must(template.
	New("go").
	Funcs(template.FuncMap{
		"trimLeft":    strings.TrimLeft,
		"trimLeftDot": func(s string) string { return strings.TrimLeft(s, ".") },
		"base": func(s string) string {
			if i := strings.LastIndexByte(s, '.'); i >= 0 {
				return s[i+1:]
			}
			return s
		},
		"now": func(patterns ...string) string {
			pattern := time.RFC3339
			if len(patterns) > 0 {
				pattern = patterns[0]
			}
			return time.Now().Format(pattern)
		},
		"changePkgTo": func(from, to, what string) string {
			if j := strings.LastIndexByte(from, '/'); j >= 0 {
				from = from[j+1:]
			}
			if from != "" {
				if strings.HasPrefix(what, from+".") {
					return to + what[len(from):]
				}
				return what
			}
			i := strings.IndexByte(what, '.')
			if i < 0 {
				return what
			}
			return to + what[i:]
		},
	}).
	Parse(`// Generated with protoc-gen-grpcer
//	from "{{.ProtoFile}}"
//	at   {{now}}
//
// DO NOT EDIT!

package {{.Package}}

import (
	"io"
	"errors"
	"context"

	grpc "google.golang.org/grpc"
	grpcer "github.com/UNO-SOFT/grpcer"

	pb "{{.Import}}"
	{{range .Dependencies}}"{{.}}"
	{{end}}
)

{{ $import := .Import }}

type client struct {
	pb.{{.GetName}}Client
	m map[string]inputAndCall
}

func (c client) List() []string {
	names := make([]string, 0, len(c.m))
	for k := range c.m {
		names = append(names, k)
	}
	return names
}

func (c client) Input(name string) interface{} {
	iac := c.m[name]
	if iac.Input == nil {
		return nil
	}
	return iac.Input()
}

func (c client) Call(name string, ctx context.Context, in interface{}, opts ...grpc.CallOption) (grpcer.Receiver, error) {
	iac := c.m[name]
	if iac.Call == nil {
		return nil, fmt.Errorf("name %q not found", name)
	}
	return iac.Call(ctx, in, opts...)
}
func NewClient(cc *grpc.ClientConn) grpcer.Client {
	c := pb.New{{.GetName}}Client(cc)
	return client{
		{{.GetName}}Client: c,
		m: map[string]inputAndCall{
		{{range .GetMethod}}"{{.GetName}}": inputAndCall{
			Input: func() interface{} { return new({{ trimLeftDot .GetInputType | changePkgTo $import "pb" }}) },
			Call: func(ctx context.Context, in interface{}, opts ...grpc.CallOption) (grpcer.Receiver, error) {
				input := in.(*{{ trimLeftDot .GetInputType | changePkgTo $import "pb" }})
				res, err := c.{{.Name}}(ctx, input, opts...)
				if err != nil {
					return &onceRecv{Out:res}, err
				}
				{{if .GetServerStreaming -}}
				return multiRecv(func() (interface{}, error) { return res.Recv() }), nil
				{{else -}}
				return &onceRecv{Out:res}, err
				{{end}}
			},
		},
		{{end}}
		},
	}
}

type inputAndCall struct {
	Input func() interface{}
	Call func(ctx context.Context, in interface{}, opts ...grpc.CallOption) (grpcer.Receiver, error)
}

type onceRecv struct {
	Out interface{}
	done bool
}
func (o *onceRecv) Recv() (interface{}, error) {
	if o.done {
		return nil, io.EOF
	}
	out := o.Out
	o.done, o.Out = true, nil
	return out, nil
}

type multiRecv func() (interface{}, error)
func (m multiRecv) Recv() (interface{}, error) {
	return m()
}

var _ = multiRecv(nil) // against "unused"

`))

func genGo(destPkg, protoFn string, svc *descriptor.ServiceDescriptorProto, dependencies []string) (string, error) {
	if destPkg == "" {
		destPkg = "main"
	}
	needed := make(map[string]struct{}, len(dependencies))
	for _, m := range svc.GetMethod() {
		//for _, t := range []string{m.GetInputType(), m.GetOutputType()} {
		t := m.GetInputType()
		if !strings.HasPrefix(t, ".") {
			continue
		}
		t = t[1:]
		needed[strings.SplitN(t, ".", 2)[0]] = struct{}{}
	}
	deps := make([]string, 0, len(dependencies))
	for _, dep := range dependencies {
		k := filepath.Dir(dep)
		if _, ok := needed[filepath.Base(k)]; !ok {
			continue
		}
		deps = append(deps, k)
	}
	var buf bytes.Buffer
	err := goTmpl.Execute(&buf, struct {
		ProtoFile, Package, Import string
		Dependencies               []string
		*descriptor.ServiceDescriptorProto
	}{
		ProtoFile:              protoFn,
		Package:                destPkg,
		Import:                 filepath.Dir(protoFn),
		Dependencies:           deps,
		ServiceDescriptorProto: svc,
	})
	return buf.String(), err
}

// vim: set fileencoding=utf-8 noet:
<commit_msg>protoc-gen-grpcer: fmt is needed, errors not<commit_after>// Copyright 2016, 2020 Tamás Gulácsi
//
//
//    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.

// protoc-gen-grpc generates a grpcer.Client from the given protoc file.
package main

import (
	"bytes"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"text/template"
	"time"

	"golang.org/x/sync/errgroup"

	"github.com/golang/protobuf/protoc-gen-go/descriptor"
	protoc "github.com/golang/protobuf/protoc-gen-go/plugin"
	"google.golang.org/protobuf/proto"
)

func main() {
	data, err := ioutil.ReadAll(os.Stdin)
	if err != nil {
		log.Fatal(err)
	}

	var req protoc.CodeGeneratorRequest
	if err = proto.Unmarshal(data, &req); err != nil {
		log.Fatal(err)
	}

	var resp protoc.CodeGeneratorResponse
	if err := Generate(&resp, req); err != nil {
		log.Fatal(err)
	}
	data, err = proto.Marshal(&resp)
	if err != nil {
		log.Fatal(err)
	}
	if _, err = os.Stdout.Write(data); err != nil {
		log.Fatal(err)
	}
}

func Generate(resp *protoc.CodeGeneratorResponse, req protoc.CodeGeneratorRequest) error {
	destPkg := req.GetParameter()
	if destPkg == "" {
		destPkg = "main"
	}

	// Find roots.
	rootNames := req.GetFileToGenerate()
	files := req.GetProtoFile()
	roots := make(map[string]*descriptor.FileDescriptorProto, len(rootNames))
	allTypes := make(map[string]*descriptor.DescriptorProto, 1024)
	var found int
	for i := len(files) - 1; i >= 0; i-- {
		f := files[i]
		for _, m := range f.GetMessageType() {
			allTypes["."+f.GetPackage()+"."+m.GetName()] = m
		}
		if found == len(rootNames) {
			continue
		}
		for _, root := range rootNames {
			if f.GetName() == root {
				roots[root] = files[i]
				found++
				break
			}
		}
	}

	msgTypes := make(map[string]*descriptor.DescriptorProto, len(allTypes))
	for _, root := range roots {
		//k := "." + root.GetName() + "."
		var k string
		for _, svc := range root.GetService() {
			for _, m := range svc.GetMethod() {
				if kk := k + m.GetInputType(); len(kk) > len(k) {
					msgTypes[kk] = allTypes[kk]
				}
				if kk := k + m.GetOutputType(); len(kk) > len(k) {
					msgTypes[kk] = allTypes[kk]
				}
			}
		}
	}

	var grp errgroup.Group
	resp.File = make([]*protoc.CodeGeneratorResponse_File, 0, len(roots))
	var mu sync.Mutex
	for _, root := range roots {
		root := root
		pkg := root.GetName()
		for _, svc := range root.GetService() {
			grp.Go(func() error {
				destFn := strings.TrimSuffix(filepath.Base(pkg), ".proto") + ".grpcer.go"
				content, err := genGo(destPkg, pkg, svc, root.GetDependency())
				mu.Lock()
				resp.File = append(resp.File, &protoc.CodeGeneratorResponse_File{
					Name:    &destFn,
					Content: &content,
				})
				mu.Unlock()
				return err
			})
		}
	}

	if err := grp.Wait(); err != nil {
		errS := err.Error()
		resp.Error = &errS
	}
	return nil
}

var goTmpl = template.Must(template.
	New("go").
	Funcs(template.FuncMap{
		"trimLeft":    strings.TrimLeft,
		"trimLeftDot": func(s string) string { return strings.TrimLeft(s, ".") },
		"base": func(s string) string {
			if i := strings.LastIndexByte(s, '.'); i >= 0 {
				return s[i+1:]
			}
			return s
		},
		"now": func(patterns ...string) string {
			pattern := time.RFC3339
			if len(patterns) > 0 {
				pattern = patterns[0]
			}
			return time.Now().Format(pattern)
		},
		"changePkgTo": func(from, to, what string) string {
			if j := strings.LastIndexByte(from, '/'); j >= 0 {
				from = from[j+1:]
			}
			if from != "" {
				if strings.HasPrefix(what, from+".") {
					return to + what[len(from):]
				}
				return what
			}
			i := strings.IndexByte(what, '.')
			if i < 0 {
				return what
			}
			return to + what[i:]
		},
	}).
	Parse(`// Generated with protoc-gen-grpcer
//	from "{{.ProtoFile}}"
//	at   {{now}}
//
// DO NOT EDIT!

package {{.Package}}

import (
	"context"
	"fmt"
	"io"

	grpc "google.golang.org/grpc"
	grpcer "github.com/UNO-SOFT/grpcer"

	pb "{{.Import}}"
	{{range .Dependencies}}"{{.}}"
	{{end}}
)

{{ $import := .Import }}

type client struct {
	pb.{{.GetName}}Client
	m map[string]inputAndCall
}

func (c client) List() []string {
	names := make([]string, 0, len(c.m))
	for k := range c.m {
		names = append(names, k)
	}
	return names
}

func (c client) Input(name string) interface{} {
	iac := c.m[name]
	if iac.Input == nil {
		return nil
	}
	return iac.Input()
}

func (c client) Call(name string, ctx context.Context, in interface{}, opts ...grpc.CallOption) (grpcer.Receiver, error) {
	iac := c.m[name]
	if iac.Call == nil {
		return nil, fmt.Errorf("name %q not found", name)
	}
	return iac.Call(ctx, in, opts...)
}
func NewClient(cc *grpc.ClientConn) grpcer.Client {
	c := pb.New{{.GetName}}Client(cc)
	return client{
		{{.GetName}}Client: c,
		m: map[string]inputAndCall{
		{{range .GetMethod}}"{{.GetName}}": inputAndCall{
			Input: func() interface{} { return new({{ trimLeftDot .GetInputType | changePkgTo $import "pb" }}) },
			Call: func(ctx context.Context, in interface{}, opts ...grpc.CallOption) (grpcer.Receiver, error) {
				input := in.(*{{ trimLeftDot .GetInputType | changePkgTo $import "pb" }})
				res, err := c.{{.Name}}(ctx, input, opts...)
				if err != nil {
					return &onceRecv{Out:res}, err
				}
				{{if .GetServerStreaming -}}
				return multiRecv(func() (interface{}, error) { return res.Recv() }), nil
				{{else -}}
				return &onceRecv{Out:res}, err
				{{end}}
			},
		},
		{{end}}
		},
	}
}

type inputAndCall struct {
	Input func() interface{}
	Call func(ctx context.Context, in interface{}, opts ...grpc.CallOption) (grpcer.Receiver, error)
}

type onceRecv struct {
	Out interface{}
	done bool
}
func (o *onceRecv) Recv() (interface{}, error) {
	if o.done {
		return nil, io.EOF
	}
	out := o.Out
	o.done, o.Out = true, nil
	return out, nil
}

type multiRecv func() (interface{}, error)
func (m multiRecv) Recv() (interface{}, error) {
	return m()
}

var _ = multiRecv(nil) // against "unused"

`))

func genGo(destPkg, protoFn string, svc *descriptor.ServiceDescriptorProto, dependencies []string) (string, error) {
	if destPkg == "" {
		destPkg = "main"
	}
	needed := make(map[string]struct{}, len(dependencies))
	for _, m := range svc.GetMethod() {
		//for _, t := range []string{m.GetInputType(), m.GetOutputType()} {
		t := m.GetInputType()
		if !strings.HasPrefix(t, ".") {
			continue
		}
		t = t[1:]
		needed[strings.SplitN(t, ".", 2)[0]] = struct{}{}
	}
	deps := make([]string, 0, len(dependencies))
	for _, dep := range dependencies {
		k := filepath.Dir(dep)
		if _, ok := needed[filepath.Base(k)]; !ok {
			continue
		}
		deps = append(deps, k)
	}
	var buf bytes.Buffer
	err := goTmpl.Execute(&buf, struct {
		ProtoFile, Package, Import string
		Dependencies               []string
		*descriptor.ServiceDescriptorProto
	}{
		ProtoFile:              protoFn,
		Package:                destPkg,
		Import:                 filepath.Dir(protoFn),
		Dependencies:           deps,
		ServiceDescriptorProto: svc,
	})
	return buf.String(), err
}

// vim: set fileencoding=utf-8 noet:
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"github.com/BurntSushi/toml"
	"github.com/fsouza/go-dockerclient"
	"io"
	"net"
	"net/http"
	"net/http/httputil"
	"os"
	"os/exec"
	"os/signal"
	"strings"
	"sync"
	"syscall"
	"time"
)

var (
	watch       bool
	notifyCmd   string
	onlyExposed bool
	configFile  string
	configs     ConfigFile
	interval    int
	wg          sync.WaitGroup
)

type Event struct {
	ContainerId string `json:"id"`
	Status      string `json:"status"`
	Image       string `json:"from"`
}

type Address struct {
	IP   string
	Port string
}
type RuntimeContainer struct {
	ID        string
	Addresses []Address
	Image     DockerImage
	Env       map[string]string
}

type DockerImage struct {
	Registry   string
	Repository string
	Tag        string
}

func (i *DockerImage) String() string {
	ret := i.Repository
	if i.Registry != "" {
		ret = i.Registry + "/" + i.Repository
	}
	if i.Tag != "" {
		ret = ret + ":" + i.Tag
	}
	return ret
}

func splitDockerImage(img string) (string, string, string) {

	index := 0
	repository := img
	var registry, tag string
	if strings.Contains(img, "/") {
		separator := strings.Index(img, "/")
		registry = img[index:separator]
		index = separator + 1
		repository = img[index:]
	}

	if strings.Contains(img, ":") {
		separator := strings.Index(img, ":")
		repository = img[index:separator]
		index = separator + 1
		tag = img[index:]
	}

	return registry, repository, tag
}

type Config struct {
	Template    string
	Dest        string
	Watch       bool
	NotifyCmd   string
	OnlyExposed bool
	Interval    int
}

type ConfigFile struct {
	Config []Config
}

func (c *ConfigFile) filterWatches() ConfigFile {
	configWithWatches := []Config{}

	for _, config := range c.Config {
		if config.Watch {
			configWithWatches = append(configWithWatches, config)
		}
	}
	return ConfigFile{
		Config: configWithWatches,
	}
}

func (r *RuntimeContainer) Equals(o RuntimeContainer) bool {
	return r.ID == o.ID && r.Image == o.Image
}

func usage() {
	println("Usage: docker-gen [-config file] [-watch=false] [-notify=\"restart xyz\"] [-interval=0] <template> [<dest>]")
}

func newConn() (*httputil.ClientConn, error) {
	conn, err := net.Dial("unix", "/var/run/docker.sock")
	if err != nil {
		return nil, err
	}
	return httputil.NewClientConn(conn, nil), nil
}

func getEvents() chan *Event {
	eventChan := make(chan *Event, 100)
	go func() {
		defer close(eventChan)

	restart:

		c, err := newConn()
		if err != nil {
			fmt.Printf("cannot connect to docker: %s\n", err)
			return
		}
		defer c.Close()

		req, err := http.NewRequest("GET", "/events", nil)
		if err != nil {
			fmt.Printf("bad request for events: %s\n", err)
			return
		}

		resp, err := c.Do(req)
		if err != nil {
			fmt.Printf("cannot connect to events endpoint: %s\n", err)
			return
		}
		defer resp.Body.Close()

		// handle signals to stop the socket
		sigChan := make(chan os.Signal, 1)
		signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT)
		go func() {
			for sig := range sigChan {
				fmt.Printf("received signal '%v', exiting\n", sig)

				c.Close()
				close(eventChan)
				os.Exit(0)
			}
		}()

		dec := json.NewDecoder(resp.Body)
		for {
			var event *Event
			if err := dec.Decode(&event); err != nil {
				if err == io.EOF {
					break
				}
				fmt.Printf("cannot decode json: %s\n", err)
				goto restart
			}
			eventChan <- event
		}
		fmt.Printf("closing event channel\n")
	}()
	return eventChan
}

func getContainers(client *docker.Client) ([]*RuntimeContainer, error) {
	apiContainers, err := client.ListContainers(docker.ListContainersOptions{
		All: false,
	})
	if err != nil {
		return nil, err
	}

	containers := []*RuntimeContainer{}
	for _, apiContainer := range apiContainers {
		container, err := client.InspectContainer(apiContainer.ID)
		if err != nil {
			fmt.Printf("error inspecting container: %s: %s\n", apiContainer.ID, err)
			continue
		}

		registry, repository, tag := splitDockerImage(container.Config.Image)
		runtimeContainer := &RuntimeContainer{
			ID: container.ID,
			Image: DockerImage{
				Registry:   registry,
				Repository: repository,
				Tag:        tag,
			},
			Addresses: []Address{},
			Env:       make(map[string]string),
		}
		for k, _ := range container.NetworkSettings.Ports {
			runtimeContainer.Addresses = append(runtimeContainer.Addresses,
				Address{
					IP:   container.NetworkSettings.IPAddress,
					Port: k.Port(),
				})
		}

		for _, entry := range container.Config.Env {
			parts := strings.Split(entry, "=")
			runtimeContainer.Env[parts[0]] = parts[1]
		}

		containers = append(containers, runtimeContainer)
	}
	return containers, nil

}
func generateFromContainers(client *docker.Client) {
	containers, err := getContainers(client)
	if err != nil {
		fmt.Printf("error listing containers: %s\n", err)
		return
	}
	for _, config := range configs.Config {
		changed := generateFile(config, containers)
		if changed {
			runNotifyCmd(config)
		}
	}
}

func runNotifyCmd(config Config) {
	if config.NotifyCmd == "" {
		return
	}

	args := strings.Split(config.NotifyCmd, " ")
	cmd := exec.Command(args[0], args[1:]...)
	out, err := cmd.CombinedOutput()
	if err != nil {
		fmt.Printf("error running notify command: %s, %s\n", config.NotifyCmd, err)
		fmt.Println(string(out))
	}
}

func loadConfig(file string) error {
	_, err := toml.DecodeFile(file, &configs)
	if err != nil {
		return err
	}
	return nil
}

func generateAtInterval(client *docker.Client, configs ConfigFile) {
	for _, config := range configs.Config {

		if config.Interval == 0 {
			continue
		}

		wg.Add(1)
		ticker := time.NewTicker(time.Duration(config.Interval) * time.Second)
		quit := make(chan struct{})
		go func() {
			for {
				select {
				case <-ticker.C:
					containers, err := getContainers(client)
					if err != nil {
						fmt.Printf("error listing containers: %s\n", err)
						continue
					}
					// ignore changed return value. always run notify command
					generateFile(config, containers)
					runNotifyCmd(config)
				case <-quit:
					ticker.Stop()
					return
				}
			}
			wg.Done()
		}()
	}
}

func generateFromEvents(client *docker.Client, configs ConfigFile) {
	configs = configs.filterWatches()
	if len(configs.Config) == 0 {
		return
	}

	wg.Add(1)
	eventChan := getEvents()
	for {
		event := <-eventChan
		if event.Status == "start" || event.Status == "stop" || event.Status == "die" {
			generateFromContainers(client)
		}
	}
	wg.Done()

}

func main() {
	flag.BoolVar(&watch, "watch", false, "watch for container changes")
	flag.BoolVar(&onlyExposed, "only-exposed", false, "only include containers with exposed ports")
	flag.StringVar(&notifyCmd, "notify", "", "run command after template is regenerated")
	flag.StringVar(&configFile, "config", "", "config file with template directives")
	flag.IntVar(&interval, "interval", 0, "notify command interval (s)")
	flag.Parse()

	if flag.NArg() < 1 && configFile == "" {
		usage()
		os.Exit(1)
	}

	if configFile != "" {
		err := loadConfig(configFile)
		if err != nil {
			fmt.Printf("error loading config %s: %s\n", configFile, err)
			os.Exit(1)
		}
	} else {
		config := Config{
			Template:    flag.Arg(0),
			Dest:        flag.Arg(1),
			Watch:       watch,
			NotifyCmd:   notifyCmd,
			OnlyExposed: onlyExposed,
			Interval:    interval,
		}
		configs = ConfigFile{
			Config: []Config{config}}
	}

	endpoint := "unix:///var/run/docker.sock"
	client, err := docker.NewClient(endpoint)

	if err != nil {
		panic(err)
	}

	generateFromContainers(client)
	generateAtInterval(client, configs)
	generateFromEvents(client, configs)
	wg.Wait()
}
<commit_msg>go vet fix: range variable config enclosed by function<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"github.com/BurntSushi/toml"
	"github.com/fsouza/go-dockerclient"
	"io"
	"net"
	"net/http"
	"net/http/httputil"
	"os"
	"os/exec"
	"os/signal"
	"strings"
	"sync"
	"syscall"
	"time"
)

var (
	watch       bool
	notifyCmd   string
	onlyExposed bool
	configFile  string
	configs     ConfigFile
	interval    int
	wg          sync.WaitGroup
)

type Event struct {
	ContainerId string `json:"id"`
	Status      string `json:"status"`
	Image       string `json:"from"`
}

type Address struct {
	IP   string
	Port string
}
type RuntimeContainer struct {
	ID        string
	Addresses []Address
	Image     DockerImage
	Env       map[string]string
}

type DockerImage struct {
	Registry   string
	Repository string
	Tag        string
}

func (i *DockerImage) String() string {
	ret := i.Repository
	if i.Registry != "" {
		ret = i.Registry + "/" + i.Repository
	}
	if i.Tag != "" {
		ret = ret + ":" + i.Tag
	}
	return ret
}

func splitDockerImage(img string) (string, string, string) {

	index := 0
	repository := img
	var registry, tag string
	if strings.Contains(img, "/") {
		separator := strings.Index(img, "/")
		registry = img[index:separator]
		index = separator + 1
		repository = img[index:]
	}

	if strings.Contains(img, ":") {
		separator := strings.Index(img, ":")
		repository = img[index:separator]
		index = separator + 1
		tag = img[index:]
	}

	return registry, repository, tag
}

type Config struct {
	Template    string
	Dest        string
	Watch       bool
	NotifyCmd   string
	OnlyExposed bool
	Interval    int
}

type ConfigFile struct {
	Config []Config
}

func (c *ConfigFile) filterWatches() ConfigFile {
	configWithWatches := []Config{}

	for _, config := range c.Config {
		if config.Watch {
			configWithWatches = append(configWithWatches, config)
		}
	}
	return ConfigFile{
		Config: configWithWatches,
	}
}

func (r *RuntimeContainer) Equals(o RuntimeContainer) bool {
	return r.ID == o.ID && r.Image == o.Image
}

func usage() {
	println("Usage: docker-gen [-config file] [-watch=false] [-notify=\"restart xyz\"] [-interval=0] <template> [<dest>]")
}

func newConn() (*httputil.ClientConn, error) {
	conn, err := net.Dial("unix", "/var/run/docker.sock")
	if err != nil {
		return nil, err
	}
	return httputil.NewClientConn(conn, nil), nil
}

func getEvents() chan *Event {
	eventChan := make(chan *Event, 100)
	go func() {
		defer close(eventChan)

	restart:

		c, err := newConn()
		if err != nil {
			fmt.Printf("cannot connect to docker: %s\n", err)
			return
		}
		defer c.Close()

		req, err := http.NewRequest("GET", "/events", nil)
		if err != nil {
			fmt.Printf("bad request for events: %s\n", err)
			return
		}

		resp, err := c.Do(req)
		if err != nil {
			fmt.Printf("cannot connect to events endpoint: %s\n", err)
			return
		}
		defer resp.Body.Close()

		// handle signals to stop the socket
		sigChan := make(chan os.Signal, 1)
		signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT)
		go func() {
			for sig := range sigChan {
				fmt.Printf("received signal '%v', exiting\n", sig)

				c.Close()
				close(eventChan)
				os.Exit(0)
			}
		}()

		dec := json.NewDecoder(resp.Body)
		for {
			var event *Event
			if err := dec.Decode(&event); err != nil {
				if err == io.EOF {
					break
				}
				fmt.Printf("cannot decode json: %s\n", err)
				goto restart
			}
			eventChan <- event
		}
		fmt.Printf("closing event channel\n")
	}()
	return eventChan
}

func getContainers(client *docker.Client) ([]*RuntimeContainer, error) {
	apiContainers, err := client.ListContainers(docker.ListContainersOptions{
		All: false,
	})
	if err != nil {
		return nil, err
	}

	containers := []*RuntimeContainer{}
	for _, apiContainer := range apiContainers {
		container, err := client.InspectContainer(apiContainer.ID)
		if err != nil {
			fmt.Printf("error inspecting container: %s: %s\n", apiContainer.ID, err)
			continue
		}

		registry, repository, tag := splitDockerImage(container.Config.Image)
		runtimeContainer := &RuntimeContainer{
			ID: container.ID,
			Image: DockerImage{
				Registry:   registry,
				Repository: repository,
				Tag:        tag,
			},
			Addresses: []Address{},
			Env:       make(map[string]string),
		}
		for k, _ := range container.NetworkSettings.Ports {
			runtimeContainer.Addresses = append(runtimeContainer.Addresses,
				Address{
					IP:   container.NetworkSettings.IPAddress,
					Port: k.Port(),
				})
		}

		for _, entry := range container.Config.Env {
			parts := strings.Split(entry, "=")
			runtimeContainer.Env[parts[0]] = parts[1]
		}

		containers = append(containers, runtimeContainer)
	}
	return containers, nil

}
func generateFromContainers(client *docker.Client) {
	containers, err := getContainers(client)
	if err != nil {
		fmt.Printf("error listing containers: %s\n", err)
		return
	}
	for _, config := range configs.Config {
		changed := generateFile(config, containers)
		if changed {
			runNotifyCmd(config)
		}
	}
}

func runNotifyCmd(config Config) {
	if config.NotifyCmd == "" {
		return
	}

	args := strings.Split(config.NotifyCmd, " ")
	cmd := exec.Command(args[0], args[1:]...)
	out, err := cmd.CombinedOutput()
	if err != nil {
		fmt.Printf("error running notify command: %s, %s\n", config.NotifyCmd, err)
		fmt.Println(string(out))
	}
}

func loadConfig(file string) error {
	_, err := toml.DecodeFile(file, &configs)
	if err != nil {
		return err
	}
	return nil
}

func generateAtInterval(client *docker.Client, configs ConfigFile) {
	for _, config := range configs.Config {

		if config.Interval == 0 {
			continue
		}

		wg.Add(1)
		ticker := time.NewTicker(time.Duration(config.Interval) * time.Second)
		quit := make(chan struct{})
		configCopy := config
		go func() {
			for {
				select {
				case <-ticker.C:
					containers, err := getContainers(client)
					if err != nil {
						fmt.Printf("error listing containers: %s\n", err)
						continue
					}
					// ignore changed return value. always run notify command
					generateFile(configCopy, containers)
					runNotifyCmd(configCopy)
				case <-quit:
					ticker.Stop()
					return
				}
			}
			wg.Done()
		}()
	}
}

func generateFromEvents(client *docker.Client, configs ConfigFile) {
	configs = configs.filterWatches()
	if len(configs.Config) == 0 {
		return
	}

	wg.Add(1)
	eventChan := getEvents()
	for {
		event := <-eventChan
		if event.Status == "start" || event.Status == "stop" || event.Status == "die" {
			generateFromContainers(client)
		}
	}
	wg.Done()

}

func main() {
	flag.BoolVar(&watch, "watch", false, "watch for container changes")
	flag.BoolVar(&onlyExposed, "only-exposed", false, "only include containers with exposed ports")
	flag.StringVar(&notifyCmd, "notify", "", "run command after template is regenerated")
	flag.StringVar(&configFile, "config", "", "config file with template directives")
	flag.IntVar(&interval, "interval", 0, "notify command interval (s)")
	flag.Parse()

	if flag.NArg() < 1 && configFile == "" {
		usage()
		os.Exit(1)
	}

	if configFile != "" {
		err := loadConfig(configFile)
		if err != nil {
			fmt.Printf("error loading config %s: %s\n", configFile, err)
			os.Exit(1)
		}
	} else {
		config := Config{
			Template:    flag.Arg(0),
			Dest:        flag.Arg(1),
			Watch:       watch,
			NotifyCmd:   notifyCmd,
			OnlyExposed: onlyExposed,
			Interval:    interval,
		}
		configs = ConfigFile{
			Config: []Config{config}}
	}

	endpoint := "unix:///var/run/docker.sock"
	client, err := docker.NewClient(endpoint)

	if err != nil {
		panic(err)
	}

	generateFromContainers(client)
	generateAtInterval(client, configs)
	generateFromEvents(client, configs)
	wg.Wait()
}
<|endoftext|>


<commit_before>package discovery

import (
	"encoding/binary"

	"github.com/go-errors/errors"
	"github.com/lightningnetwork/lnd/channeldb"
	"github.com/lightningnetwork/lnd/lnwallet"
	"github.com/lightningnetwork/lnd/lnwire"
	"github.com/roasbeef/btcd/btcec"
)

// newProofKey constructs new announcement signature message key.
func newProofKey(chanID uint64, isRemote bool) waitingProofKey {
	return waitingProofKey{
		chanID:   chanID,
		isRemote: isRemote,
	}
}

// ToBytes represents the key in the byte format.
func (k waitingProofKey) ToBytes() []byte {
	var key [10]byte

	var b uint8
	if k.isRemote {
		b = 0
	} else {
		b = 1
	}

	binary.BigEndian.PutUint64(key[:], k.chanID)
	key[9] = b

	return key[:]
}

// createChanAnnouncement helper function which creates the channel announcement
// by the given channeldb objects.
func createChanAnnouncement(chanProof *channeldb.ChannelAuthProof,
	chanInfo *channeldb.ChannelEdgeInfo,
	e1, e2 *channeldb.ChannelEdgePolicy) (
	*lnwire.ChannelAnnouncement,
	*lnwire.ChannelUpdateAnnouncement,
	*lnwire.ChannelUpdateAnnouncement) {
	// First, using the parameters of the channel, along with the
	// channel authentication chanProof, we'll create re-create the
	// original authenticated channel announcement.
	chanID := lnwire.NewShortChanIDFromInt(chanInfo.ChannelID)
	chanAnn := &lnwire.ChannelAnnouncement{
		NodeSig1:       chanProof.NodeSig1,
		NodeSig2:       chanProof.NodeSig2,
		ShortChannelID: chanID,
		BitcoinSig1:    chanProof.BitcoinSig1,
		BitcoinSig2:    chanProof.BitcoinSig2,
		NodeID1:        chanInfo.NodeKey1,
		NodeID2:        chanInfo.NodeKey2,
		BitcoinKey1:    chanInfo.BitcoinKey1,
		BitcoinKey2:    chanInfo.BitcoinKey2,
	}

	// We'll unconditionally queue the channel's existence chanProof as
	// it will need to be processed before either of the channel
	// update networkMsgs.

	// Since it's up to a node's policy as to whether they
	// advertise the edge in dire direction, we don't create an
	// advertisement if the edge is nil.
	var edge1Ann, edge2Ann *lnwire.ChannelUpdateAnnouncement
	if e1 != nil {
		edge1Ann = &lnwire.ChannelUpdateAnnouncement{
			Signature:                 e1.Signature,
			ShortChannelID:            chanID,
			Timestamp:                 uint32(e1.LastUpdate.Unix()),
			Flags:                     0,
			TimeLockDelta:             e1.TimeLockDelta,
			HtlcMinimumMsat:           uint32(e1.MinHTLC),
			FeeBaseMsat:               uint32(e1.FeeBaseMSat),
			FeeProportionalMillionths: uint32(e1.FeeProportionalMillionths),
		}
	}
	if e2 != nil {
		edge2Ann = &lnwire.ChannelUpdateAnnouncement{
			Signature:                 e2.Signature,
			ShortChannelID:            chanID,
			Timestamp:                 uint32(e2.LastUpdate.Unix()),
			Flags:                     1,
			TimeLockDelta:             e2.TimeLockDelta,
			HtlcMinimumMsat:           uint32(e2.MinHTLC),
			FeeBaseMsat:               uint32(e2.FeeBaseMSat),
			FeeProportionalMillionths: uint32(e2.FeeProportionalMillionths),
		}
	}

	return chanAnn, edge1Ann, edge2Ann
}

// copyPubKey is copying the public key and setting curve.
// NOTE: At the moment of creation the function was need only because we are
// setting the curve to nil in the read message function and in order to
// properly validate the signatures we need to set the curve again.
func copyPubKey(pub *btcec.PublicKey) *btcec.PublicKey {
	return &btcec.PublicKey{
		Curve: btcec.S256(),
		X:     pub.X,
		Y:     pub.Y,
	}
}

// SignAnnouncement helper function which is used for signing the announce
// messages.
func SignAnnouncement(signer *lnwallet.MessageSigner,
	msg lnwire.Message) (*btcec.Signature, error) {
	var data []byte
	var err error
	switch m := msg.(type) {
	case *lnwire.ChannelAnnouncement:
		data, err = m.DataToSign()
	case *lnwire.ChannelUpdateAnnouncement:
		data, err = m.DataToSign()
	case *lnwire.NodeAnnouncement:
		data, err = m.DataToSign()
	default:
		return nil, errors.New("can't sign message " +
			"of this format")
	}
	if err != nil {
		return nil, errors.Errorf("can't get data to sign: %v", err)
	}

	return signer.SignData(data)
}
<commit_msg>discovery: utilize exactly 9 bytes for serialized waitingProofKey<commit_after>package discovery

import (
	"encoding/binary"

	"github.com/go-errors/errors"
	"github.com/lightningnetwork/lnd/channeldb"
	"github.com/lightningnetwork/lnd/lnwallet"
	"github.com/lightningnetwork/lnd/lnwire"
	"github.com/roasbeef/btcd/btcec"
)

// newProofKey constructs a new announcement signature message key.
func newProofKey(chanID uint64, isRemote bool) waitingProofKey {
	return waitingProofKey{
		chanID:   chanID,
		isRemote: isRemote,
	}
}

// ToBytes returns a serialized representation of the key.
func (k waitingProofKey) ToBytes() []byte {
	var key [9]byte

	var b uint8
	if k.isRemote {
		b = 0
	} else {
		b = 1
	}

	binary.BigEndian.PutUint64(key[:8], k.chanID)
	key[8] = b

	return key[:]
}

// createChanAnnouncement helper function which creates the channel announcement
// by the given channeldb objects.
func createChanAnnouncement(chanProof *channeldb.ChannelAuthProof,
	chanInfo *channeldb.ChannelEdgeInfo,
	e1, e2 *channeldb.ChannelEdgePolicy) (
	*lnwire.ChannelAnnouncement,
	*lnwire.ChannelUpdateAnnouncement,
	*lnwire.ChannelUpdateAnnouncement) {
	// First, using the parameters of the channel, along with the
	// channel authentication chanProof, we'll create re-create the
	// original authenticated channel announcement.
	chanID := lnwire.NewShortChanIDFromInt(chanInfo.ChannelID)
	chanAnn := &lnwire.ChannelAnnouncement{
		NodeSig1:       chanProof.NodeSig1,
		NodeSig2:       chanProof.NodeSig2,
		ShortChannelID: chanID,
		BitcoinSig1:    chanProof.BitcoinSig1,
		BitcoinSig2:    chanProof.BitcoinSig2,
		NodeID1:        chanInfo.NodeKey1,
		NodeID2:        chanInfo.NodeKey2,
		BitcoinKey1:    chanInfo.BitcoinKey1,
		BitcoinKey2:    chanInfo.BitcoinKey2,
	}

	// We'll unconditionally queue the channel's existence chanProof as
	// it will need to be processed before either of the channel
	// update networkMsgs.

	// Since it's up to a node's policy as to whether they
	// advertise the edge in dire direction, we don't create an
	// advertisement if the edge is nil.
	var edge1Ann, edge2Ann *lnwire.ChannelUpdateAnnouncement
	if e1 != nil {
		edge1Ann = &lnwire.ChannelUpdateAnnouncement{
			Signature:                 e1.Signature,
			ShortChannelID:            chanID,
			Timestamp:                 uint32(e1.LastUpdate.Unix()),
			Flags:                     0,
			TimeLockDelta:             e1.TimeLockDelta,
			HtlcMinimumMsat:           uint32(e1.MinHTLC),
			FeeBaseMsat:               uint32(e1.FeeBaseMSat),
			FeeProportionalMillionths: uint32(e1.FeeProportionalMillionths),
		}
	}
	if e2 != nil {
		edge2Ann = &lnwire.ChannelUpdateAnnouncement{
			Signature:                 e2.Signature,
			ShortChannelID:            chanID,
			Timestamp:                 uint32(e2.LastUpdate.Unix()),
			Flags:                     1,
			TimeLockDelta:             e2.TimeLockDelta,
			HtlcMinimumMsat:           uint32(e2.MinHTLC),
			FeeBaseMsat:               uint32(e2.FeeBaseMSat),
			FeeProportionalMillionths: uint32(e2.FeeProportionalMillionths),
		}
	}

	return chanAnn, edge1Ann, edge2Ann
}

// copyPubKey is copying the public key and setting curve.
// NOTE: At the moment of creation the function was need only because we are
// setting the curve to nil in the read message function and in order to
// properly validate the signatures we need to set the curve again.
func copyPubKey(pub *btcec.PublicKey) *btcec.PublicKey {
	return &btcec.PublicKey{
		Curve: btcec.S256(),
		X:     pub.X,
		Y:     pub.Y,
	}
}

// SignAnnouncement helper function which is used for signing the announce
// messages.
func SignAnnouncement(signer *lnwallet.MessageSigner,
	msg lnwire.Message) (*btcec.Signature, error) {
	var data []byte
	var err error
	switch m := msg.(type) {
	case *lnwire.ChannelAnnouncement:
		data, err = m.DataToSign()
	case *lnwire.ChannelUpdateAnnouncement:
		data, err = m.DataToSign()
	case *lnwire.NodeAnnouncement:
		data, err = m.DataToSign()
	default:
		return nil, errors.New("can't sign message " +
			"of this format")
	}
	if err != nil {
		return nil, errors.Errorf("can't get data to sign: %v", err)
	}

	return signer.SignData(data)
}
<|endoftext|>