<commit_before>/*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 saltnodemanager

import (
	"errors"
	"fmt"
	"github.com/skyrings/skyring-common/conf"
	"github.com/skyrings/skyring-common/db"
	"github.com/skyrings/skyring-common/models"
	"github.com/skyrings/skyring-common/monitoring"
	"github.com/skyrings/skyring-common/tools/logger"
	"github.com/skyrings/skyring-common/tools/uuid"
	"github.com/skyrings/skyring/backend/salt"
	"github.com/skyrings/skyring/nodemanager"
	"gopkg.in/mgo.v2/bson"
	"io"
	"net"
)

const (
	NodeManagerName = "SaltNodeManager"
)

var (
	salt_backend = salt.New()
)

type SaltNodeManager struct {
}

func init() {
	nodemanager.RegisterNodeManager(NodeManagerName, func(config io.Reader) (nodemanager.NodeManagerInterface, error) {
		return NewSaltNodeManager(config)
	})
}

func NewSaltNodeManager(config io.Reader) (*SaltNodeManager, error) {
	return &SaltNodeManager{}, nil
}

func (a SaltNodeManager) AcceptNode(node string, fingerprint string, ctxt string) (bool, error) {
	if status, err := salt_backend.AcceptNode(node, fingerprint, false, ctxt); err != nil {
		return false, err
	} else if !status {
		return false, errors.New(fmt.Sprintf("Unable to accept the node: %s", node))
	} else {
		return true, nil

	}
}

func (a SaltNodeManager) AddNode(master string, node string, port uint, fingerprint string, username string, password string, ctxt string) (bool, error) {
	if status, err := salt_backend.AddNode(master, node, port, fingerprint, username, password, ctxt); err != nil {
		return false, err
	} else if !status {
		return false, errors.New(fmt.Sprintf("Unable to add the node: %s", node))
	} else {
		return true, nil
	}
}

func GetStorageNodeInstance(hostname string, sProfiles []models.StorageProfile) (*models.Node, bool) {
	var storage_node models.Node
	storage_node.Hostname = hostname
	storage_node.Enabled = true
	storage_node.NodeId, _ = salt_backend.GetNodeID(hostname)
	networkInfo, err := salt_backend.GetNodeNetwork(hostname)
	if err != nil {
		logger.Get().Error(fmt.Sprintf("Error getting network details for node: %s. error: %v", hostname, err))
		return nil, false
	}
	storage_node.NetworkInfo = networkInfo
	addrs, err := net.LookupHost(hostname)
	if err != nil {
		logger.Get().Error(fmt.Sprintf("Error looking up node IP for: %s. error: %v", hostname, err))
		return nil, false
	}
	storage_node.ManagementIP4 = addrs[0]
	ok, err := salt_backend.NodeUp(hostname)
	if err != nil {
		logger.Get().Error(fmt.Sprintf("Error getting status of node: %s. error: %v", hostname, err))
		return nil, false
	}
	if ok {
		storage_node.Status = models.NODE_STATUS_OK
	} else {
		storage_node.Status = models.NODE_STATUS_ERROR
	}
	disks, err := salt_backend.GetNodeDisk(hostname, "")
	if err != nil {
		logger.Get().Error(fmt.Sprintf("Error getting disk details for node: %s. error: %v", hostname, err))
		return nil, false
	}
	for _, disk := range disks {
		dId, err := uuid.New()
		if err != nil {
			logger.Get().Error(fmt.Sprintf("Unable to generate uuid for disk : %s. error: %v", disk.DevName, err))
			return nil, false
		}
		disk.DiskId = *dId
		applyStorageProfile(&disk, sProfiles)
		storage_node.StorageDisks = append(storage_node.StorageDisks, disk)
	}

	cpus, err := salt_backend.GetNodeCpu(hostname)
	if err != nil {
		logger.Get().Error(fmt.Sprintf("Error getting cpu details for node: %s. error: %v", hostname, err))
		return nil, false
	}
	for _, cpu := range cpus {
		storage_node.CPUs = append(storage_node.CPUs, cpu)
	}

	osInfo, err := salt_backend.GetNodeOs(hostname)
	if err != nil {
		logger.Get().Error(fmt.Sprintf("Error getting os details for node: %s", hostname))
		return nil, false
	}
	storage_node.OS = osInfo

	memoryInfo, err := salt_backend.GetNodeMemory(hostname)
	if err != nil {
		logger.Get().Error(fmt.Sprintf("Error getting memory details for node: %s", hostname))
		return nil, false
	}
	storage_node.Memory = memoryInfo

	if !storage_node.NodeId.IsZero() && len(storage_node.NetworkInfo.Subnet) != 0 && len(storage_node.StorageDisks) != 0 {
		return &storage_node, true
	} else {
		return nil, false
	}
}

func (a SaltNodeManager) IsNodeUp(hostname string) (bool, error) {
	ok, err := salt_backend.NodeUp(hostname)
	if err != nil {
		logger.Get().Error(fmt.Sprintf("Error getting status of node: %s. error: %v", hostname, err))
		return false, nil
	}
	return ok, nil
}

func (a SaltNodeManager) GetUnmanagedNodes() (*models.UnmanagedNodes, error) {
	if nodes, err := salt_backend.GetNodes(); err != nil {
		return nil, err
	} else {
		var retNodes models.UnmanagedNodes
		for _, node := range nodes.Unmanage {
			var retNode models.UnmanagedNode
			retNode.Name = node.Name
			retNode.SaltFingerprint = node.Fingerprint
			retNodes = append(retNodes, retNode)
		}
		return &retNodes, nil
	}
}

func (a SaltNodeManager) SyncStorageDisks(node string, sProfiles []models.StorageProfile, ctxt string) (bool, error) {
	disks, err := salt_backend.GetNodeDisk(node, ctxt)
	if err != nil {
		return false, err
	}
	for _, disk := range disks {
		dId, err := uuid.New()
		if err != nil {
			logger.Get().Error(fmt.Sprintf("%s-Unable to generate uuid for disk : %s. error: %v", ctxt, disk.DevName, err))
			return false, err
		}
		disk.DiskId = *dId
		applyStorageProfile(&disk, sProfiles)
	}
	sessionCopy := db.GetDatastore().Copy()
	defer sessionCopy.Close()
	coll := sessionCopy.DB(conf.SystemConfig.DBConfig.Database).C(models.COLL_NAME_STORAGE_NODES)
	if len(disks) != 0 {
		if err := coll.Update(bson.M{"hostname": node}, bson.M{"$set": bson.M{"storagedisks": disks}}); err != nil {
			logger.Get().Error("%s-Error updating the disk details for node: %s. error: %v", ctxt, node, err)
			return false, err
		}
	}
	return true, nil
}

func (a SaltNodeManager) DisableNode(node string) (bool, error) {
	if ok, err := salt_backend.DisableService(node, "collectd", true); err != nil || !ok {
		logger.Get().Error(fmt.Sprintf("Error disabling services on node: %s. error: %v", node, err))
		return false, err
	}

	// Disable any POST actions for participating nodes
	sessionCopy := db.GetDatastore().Copy()
	defer sessionCopy.Close()
	coll := sessionCopy.DB(conf.SystemConfig.DBConfig.Database).C(models.COLL_NAME_STORAGE_NODES)
	if err := coll.Update(bson.M{"hostname": node}, bson.M{"$set": bson.M{"enabled": false}}); err != nil {
		logger.Get().Error("Error updating managed state of node: %s. error: %v", node, err)
		return false, err
	}

	return true, nil
}

func (a SaltNodeManager) EnableNode(node string) (bool, error) {
	if ok, err := salt_backend.EnableService(node, "collectd", true); err != nil || !ok {
		logger.Get().Error("Error enabling services on node: %s. error: %v", node, err)
		return false, err
	}

	// Enable any POST actions for node
	sessionCopy := db.GetDatastore().Copy()
	defer sessionCopy.Close()
	coll := sessionCopy.DB(conf.SystemConfig.DBConfig.Database).C(models.COLL_NAME_STORAGE_NODES)
	if err := coll.Update(bson.M{"hostname": node}, bson.M{"$set": bson.M{"enabled": true}}); err != nil {
		logger.Get().Error("Error updating manage state of node: %s. error: %v", node, err)
		return false, err
	}

	return true, nil
}

func (a SaltNodeManager) RemoveNode(node string) (bool, error) {
	if ok, err := salt_backend.DisableService(node, "collectd", true); err != nil || !ok {
		return false, err
	}

	if ok, err := salt_backend.IgnoreNode(node); err != nil || !ok {
		return false, err
	}

	return true, nil
}

func (a SaltNodeManager) IgnoreNode(node string) (bool, error) {
	if ok, err := salt_backend.IgnoreNode(node); err != nil || !ok {
		logger.Get().Error(fmt.Sprintf("Error rejecting node: %s. error: %v", node, err))
		return false, err
	}

	return true, nil
}

func (a SaltNodeManager) SetUpMonitoring(node string, master string) (map[string]interface{}, error) {
	// The plugins to be setup includes the editable plugins and also the write plugin
	return a.EnforceMonitoring(append(monitoring.SupportedMonitoringPlugins, monitoring.MonitoringWritePlugin), []string{node}, master, monitoring.GetDefaultThresholdValues())
}

func (a SaltNodeManager) EnforceMonitoring(plugin_names []string, nodes []string, master string, plugins []monitoring.Plugin) (map[string]interface{}, error) {
	failed_nodes, err := salt_backend.AddMonitoringPlugin(plugin_names, nodes, master, monitoring.ToSaltPillarCompat(plugins))
	return failed_nodes, err
}

func (a SaltNodeManager) UpdateMonitoringConfiguration(nodes []string, config []monitoring.Plugin) (map[string]string, error) {
	failed_nodes, err := salt_backend.UpdateMonitoringConfiguration(nodes, config)
	return failed_nodes, err
}

func (a SaltNodeManager) EnableMonitoringPlugin(nodes []string, pluginName string) (map[string]string, error) {
	failed_nodes, err := salt_backend.EnableMonitoringPlugin(nodes, pluginName)
	return failed_nodes, err
}

func (a SaltNodeManager) DisableMonitoringPlugin(nodes []string, pluginName string) (map[string]string, error) {
	failed_nodes, err := salt_backend.DisableMonitoringPlugin(nodes, pluginName)
	return failed_nodes, err
}

func (a SaltNodeManager) RemoveMonitoringPlugin(nodes []string, pluginName string) (map[string]string, error) {
	failed_nodes, err := salt_backend.RemoveMonitoringPlugin(nodes, pluginName)
	return failed_nodes, err
}

func (a SaltNodeManager) AddMonitoringPlugin(nodes []string, master string, plugin monitoring.Plugin) (map[string]interface{}, error) {
	failed_nodes, err := salt_backend.AddMonitoringPlugin([]string{plugin.Name}, nodes, "", monitoring.ToSaltPillarCompat([]monitoring.Plugin{plugin}))
	return failed_nodes, err
}

func (a SaltNodeManager) SyncModules(node string) (bool, error) {
	if ok, err := salt_backend.SyncModules(node); !ok || err != nil {
		return false, err
	}
	return true, nil
}

func applyStorageProfile(disk *models.Disk, sProfiles []models.StorageProfile) error {

	for _, sProfile := range sProfiles {

		//TODO check the speed

		//Check the disk type
		//Now only check whether the disk is SSD or not. REST are supported
		//once the API is avaialable
		diskType := sProfile.Rule.Type
		switch diskType {
		case models.SSD:
			if disk.SSD {
				disk.StorageProfile = sProfile.Name
				return nil
			}
		}
	}
	//Not Matched, so add to generic profile
	disk.StorageProfile = models.DefaultProfile3
	return nil
}

func GetFingerPrint(hostname string) (string, error) {
	fingerprint, err := salt_backend.GetFingerPrint(hostname)
	return fingerprint, err
}
<commit_msg>syncDisks: Patch to fix the sync disk functionality.<commit_after>/*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 saltnodemanager

import (
	"errors"
	"fmt"
	"github.com/skyrings/skyring-common/conf"
	"github.com/skyrings/skyring-common/db"
	"github.com/skyrings/skyring-common/models"
	"github.com/skyrings/skyring-common/monitoring"
	"github.com/skyrings/skyring-common/tools/logger"
	"github.com/skyrings/skyring-common/tools/uuid"
	"github.com/skyrings/skyring/backend/salt"
	"github.com/skyrings/skyring/nodemanager"
	"gopkg.in/mgo.v2/bson"
	"io"
	"net"
)

const (
	NodeManagerName = "SaltNodeManager"
)

var (
	salt_backend = salt.New()
)

type SaltNodeManager struct {
}

func init() {
	nodemanager.RegisterNodeManager(NodeManagerName, func(config io.Reader) (nodemanager.NodeManagerInterface, error) {
		return NewSaltNodeManager(config)
	})
}

func NewSaltNodeManager(config io.Reader) (*SaltNodeManager, error) {
	return &SaltNodeManager{}, nil
}

func (a SaltNodeManager) AcceptNode(node string, fingerprint string, ctxt string) (bool, error) {
	if status, err := salt_backend.AcceptNode(node, fingerprint, false, ctxt); err != nil {
		return false, err
	} else if !status {
		return false, errors.New(fmt.Sprintf("Unable to accept the node: %s", node))
	} else {
		return true, nil

	}
}

func (a SaltNodeManager) AddNode(master string, node string, port uint, fingerprint string, username string, password string, ctxt string) (bool, error) {
	if status, err := salt_backend.AddNode(master, node, port, fingerprint, username, password, ctxt); err != nil {
		return false, err
	} else if !status {
		return false, errors.New(fmt.Sprintf("Unable to add the node: %s", node))
	} else {
		return true, nil
	}
}

func GetStorageNodeInstance(hostname string, sProfiles []models.StorageProfile) (*models.Node, bool) {
	var storage_node models.Node
	storage_node.Hostname = hostname
	storage_node.Enabled = true
	storage_node.NodeId, _ = salt_backend.GetNodeID(hostname)
	networkInfo, err := salt_backend.GetNodeNetwork(hostname)
	if err != nil {
		logger.Get().Error(fmt.Sprintf("Error getting network details for node: %s. error: %v", hostname, err))
		return nil, false
	}
	storage_node.NetworkInfo = networkInfo
	addrs, err := net.LookupHost(hostname)
	if err != nil {
		logger.Get().Error(fmt.Sprintf("Error looking up node IP for: %s. error: %v", hostname, err))
		return nil, false
	}
	storage_node.ManagementIP4 = addrs[0]
	ok, err := salt_backend.NodeUp(hostname)
	if err != nil {
		logger.Get().Error(fmt.Sprintf("Error getting status of node: %s. error: %v", hostname, err))
		return nil, false
	}
	if ok {
		storage_node.Status = models.NODE_STATUS_OK
	} else {
		storage_node.Status = models.NODE_STATUS_ERROR
	}
	disks, err := salt_backend.GetNodeDisk(hostname, "")
	if err != nil {
		logger.Get().Error(fmt.Sprintf("Error getting disk details for node: %s. error: %v", hostname, err))
		return nil, false
	}
	for _, disk := range disks {
		dId, err := uuid.New()
		if err != nil {
			logger.Get().Error(fmt.Sprintf("Unable to generate uuid for disk : %s. error: %v", disk.DevName, err))
			return nil, false
		}
		disk.DiskId = *dId
		applyStorageProfile(&disk, sProfiles)
		storage_node.StorageDisks = append(storage_node.StorageDisks, disk)
	}

	cpus, err := salt_backend.GetNodeCpu(hostname)
	if err != nil {
		logger.Get().Error(fmt.Sprintf("Error getting cpu details for node: %s. error: %v", hostname, err))
		return nil, false
	}
	for _, cpu := range cpus {
		storage_node.CPUs = append(storage_node.CPUs, cpu)
	}

	osInfo, err := salt_backend.GetNodeOs(hostname)
	if err != nil {
		logger.Get().Error(fmt.Sprintf("Error getting os details for node: %s", hostname))
		return nil, false
	}
	storage_node.OS = osInfo

	memoryInfo, err := salt_backend.GetNodeMemory(hostname)
	if err != nil {
		logger.Get().Error(fmt.Sprintf("Error getting memory details for node: %s", hostname))
		return nil, false
	}
	storage_node.Memory = memoryInfo

	if !storage_node.NodeId.IsZero() && len(storage_node.NetworkInfo.Subnet) != 0 && len(storage_node.StorageDisks) != 0 {
		return &storage_node, true
	} else {
		return nil, false
	}
}

func (a SaltNodeManager) IsNodeUp(hostname string) (bool, error) {
	ok, err := salt_backend.NodeUp(hostname)
	if err != nil {
		logger.Get().Error(fmt.Sprintf("Error getting status of node: %s. error: %v", hostname, err))
		return false, nil
	}
	return ok, nil
}

func (a SaltNodeManager) GetUnmanagedNodes() (*models.UnmanagedNodes, error) {
	if nodes, err := salt_backend.GetNodes(); err != nil {
		return nil, err
	} else {
		var retNodes models.UnmanagedNodes
		for _, node := range nodes.Unmanage {
			var retNode models.UnmanagedNode
			retNode.Name = node.Name
			retNode.SaltFingerprint = node.Fingerprint
			retNodes = append(retNodes, retNode)
		}
		return &retNodes, nil
	}
}

func (a SaltNodeManager) SyncStorageDisks(node string, sProfiles []models.StorageProfile, ctxt string) (bool, error) {
	disks, err := salt_backend.GetNodeDisk(node, ctxt)
	if err != nil {
		return false, err
	}
	sessionCopy := db.GetDatastore().Copy()
	defer sessionCopy.Close()
	coll := sessionCopy.DB(conf.SystemConfig.DBConfig.Database).C(models.COLL_NAME_STORAGE_NODES)
	var storage_node models.Node
	var updated_disks []models.Disk

	if err := coll.Find(bson.M{"hostname": node}).One(&storage_node); err != nil {
		logger.Get().Error("%s-Error updating the disk details for node: %s. error: %v", ctxt, node, err)
		return false, err
	}
	var present bool
	for _, disk := range disks {
		present = false
		for _, stored_disk := range storage_node.StorageDisks {
			if disk.DevName == stored_disk.DevName {
				present = true
				updated_disks = append(updated_disks, stored_disk)
				break
			}
		}
		if !present {
			dId, err := uuid.New()
			if err != nil {
				logger.Get().Error(fmt.Sprintf("%s-Unable to generate uuid for disk : %s. error: %v", ctxt, disk.DevName, err))
				return false, err
			}
			disk.DiskId = *dId
			applyStorageProfile(&disk, sProfiles)
			updated_disks = append(updated_disks, disk)
		}
	}
	if err := coll.Update(bson.M{"hostname": node}, bson.M{"$set": bson.M{"storagedisks": updated_disks}}); err != nil {
		logger.Get().Error("%s-Error updating the disk details for node: %s. error: %v", ctxt, node, err)
		return false, err
	}
	return true, nil
}

func (a SaltNodeManager) DisableNode(node string) (bool, error) {
	if ok, err := salt_backend.DisableService(node, "collectd", true); err != nil || !ok {
		logger.Get().Error(fmt.Sprintf("Error disabling services on node: %s. error: %v", node, err))
		return false, err
	}

	// Disable any POST actions for participating nodes
	sessionCopy := db.GetDatastore().Copy()
	defer sessionCopy.Close()
	coll := sessionCopy.DB(conf.SystemConfig.DBConfig.Database).C(models.COLL_NAME_STORAGE_NODES)
	if err := coll.Update(bson.M{"hostname": node}, bson.M{"$set": bson.M{"enabled": false}}); err != nil {
		logger.Get().Error("Error updating managed state of node: %s. error: %v", node, err)
		return false, err
	}

	return true, nil
}

func (a SaltNodeManager) EnableNode(node string) (bool, error) {
	if ok, err := salt_backend.EnableService(node, "collectd", true); err != nil || !ok {
		logger.Get().Error("Error enabling services on node: %s. error: %v", node, err)
		return false, err
	}

	// Enable any POST actions for node
	sessionCopy := db.GetDatastore().Copy()
	defer sessionCopy.Close()
	coll := sessionCopy.DB(conf.SystemConfig.DBConfig.Database).C(models.COLL_NAME_STORAGE_NODES)
	if err := coll.Update(bson.M{"hostname": node}, bson.M{"$set": bson.M{"enabled": true}}); err != nil {
		logger.Get().Error("Error updating manage state of node: %s. error: %v", node, err)
		return false, err
	}

	return true, nil
}

func (a SaltNodeManager) RemoveNode(node string) (bool, error) {
	if ok, err := salt_backend.DisableService(node, "collectd", true); err != nil || !ok {
		return false, err
	}

	if ok, err := salt_backend.IgnoreNode(node); err != nil || !ok {
		return false, err
	}

	return true, nil
}

func (a SaltNodeManager) IgnoreNode(node string) (bool, error) {
	if ok, err := salt_backend.IgnoreNode(node); err != nil || !ok {
		logger.Get().Error(fmt.Sprintf("Error rejecting node: %s. error: %v", node, err))
		return false, err
	}

	return true, nil
}

func (a SaltNodeManager) SetUpMonitoring(node string, master string) (map[string]interface{}, error) {
	// The plugins to be setup includes the editable plugins and also the write plugin
	return a.EnforceMonitoring(append(monitoring.SupportedMonitoringPlugins, monitoring.MonitoringWritePlugin), []string{node}, master, monitoring.GetDefaultThresholdValues())
}

func (a SaltNodeManager) EnforceMonitoring(plugin_names []string, nodes []string, master string, plugins []monitoring.Plugin) (map[string]interface{}, error) {
	failed_nodes, err := salt_backend.AddMonitoringPlugin(plugin_names, nodes, master, monitoring.ToSaltPillarCompat(plugins))
	return failed_nodes, err
}

func (a SaltNodeManager) UpdateMonitoringConfiguration(nodes []string, config []monitoring.Plugin) (map[string]string, error) {
	failed_nodes, err := salt_backend.UpdateMonitoringConfiguration(nodes, config)
	return failed_nodes, err
}

func (a SaltNodeManager) EnableMonitoringPlugin(nodes []string, pluginName string) (map[string]string, error) {
	failed_nodes, err := salt_backend.EnableMonitoringPlugin(nodes, pluginName)
	return failed_nodes, err
}

func (a SaltNodeManager) DisableMonitoringPlugin(nodes []string, pluginName string) (map[string]string, error) {
	failed_nodes, err := salt_backend.DisableMonitoringPlugin(nodes, pluginName)
	return failed_nodes, err
}

func (a SaltNodeManager) RemoveMonitoringPlugin(nodes []string, pluginName string) (map[string]string, error) {
	failed_nodes, err := salt_backend.RemoveMonitoringPlugin(nodes, pluginName)
	return failed_nodes, err
}

func (a SaltNodeManager) AddMonitoringPlugin(nodes []string, master string, plugin monitoring.Plugin) (map[string]interface{}, error) {
	failed_nodes, err := salt_backend.AddMonitoringPlugin([]string{plugin.Name}, nodes, "", monitoring.ToSaltPillarCompat([]monitoring.Plugin{plugin}))
	return failed_nodes, err
}

func (a SaltNodeManager) SyncModules(node string) (bool, error) {
	if ok, err := salt_backend.SyncModules(node); !ok || err != nil {
		return false, err
	}
	return true, nil
}

func applyStorageProfile(disk *models.Disk, sProfiles []models.StorageProfile) error {

	for _, sProfile := range sProfiles {

		//TODO check the speed

		//Check the disk type
		//Now only check whether the disk is SSD or not. REST are supported
		//once the API is avaialable
		diskType := sProfile.Rule.Type
		switch diskType {
		case models.SSD:
			if disk.SSD {
				disk.StorageProfile = sProfile.Name
				return nil
			}
		}
	}
	//Not Matched, so add to generic profile
	disk.StorageProfile = models.DefaultProfile3
	return nil
}

func GetFingerPrint(hostname string) (string, error) {
	fingerprint, err := salt_backend.GetFingerPrint(hostname)
	return fingerprint, err
}
<|endoftext|>


<commit_before>package parse

import "./comb"

const (
	bracketChars = "()[]{}"
	commentChar  = ';'
	invalidChars = "\x00"
	quoteChar    = '`'
	quoteString  = "quote"
	spaceChars   = " \t\n\r"
	specialChar  = '$'
)

func Parse(source string) []interface{} {
	m, err := newState(source).module()()

	if err != nil {
		panic(err.Error())
	}

	return m.([]interface{})
}

func (s *state) module() comb.Parser {
	return s.Exhaust(s.Wrap(s.blank(), s.expressions(), s.None()))
}

func (s *state) expressions() comb.Parser {
	return s.Lazy(s.strictExpressions)
}

func (s *state) strictExpressions() comb.Parser {
	return s.Many(s.expression())
}

func (s *state) expression() comb.Parser {
	ps := []comb.Parser{s.atom(), s.list(), s.array(), s.dict()}

	return s.strip(s.Or(append(ps, s.quotes(ps...)...)...))
}

func (s *state) atom() comb.Parser {
	return s.Or(s.stringLiteral(), s.identifier())
}

func (s *state) identifier() comb.Parser {
	return s.stringify(s.Many1(s.NotInString(
		bracketChars + string(commentChar) + invalidChars + string(quoteChar) +
			spaceChars + string(specialChar))))
}

func (s *state) stringLiteral() comb.Parser {
	b := s.blank()
	c := s.Char('"')

	return s.App(prependQuote, s.stringify(s.Wrap(
		c,
		s.Many(s.Or(s.NotInString("\"\\"), s.String("\\\""), s.String("\\\\"))),
		s.And(c, b))))
}

func prependQuote(x interface{}) interface{} {
	return []interface{}{quoteString, x}
}

func (s *state) list() comb.Parser {
	return s.sequence('(', ')')
}

func (s *state) array() comb.Parser {
	return s.sequence('[', ']')
}

func (s *state) dict() comb.Parser {
	return s.sequence('{', '}')
}

func (s *state) sequence(l, r rune) comb.Parser {
	return s.wrapChars(l, s.expressions(), r)
}

func (s *state) comment() comb.Parser {
	return s.Void(s.And(
		s.Char(commentChar),
		s.Many(s.NotChar('\n')), s.Char('\n')))
}

func (s *state) wrapChars(l rune, p comb.Parser, r rune) comb.Parser {
	return s.Wrap(s.strippedChar(l), p, s.strippedChar(r))
}

func (s *state) strippedChar(r rune) comb.Parser {
	return s.strip(s.Char(r))
}

func (s *state) strip(p comb.Parser) comb.Parser {
	b := s.blank()
	return s.Wrap(s.None(), p, b)
}

func (s *state) blank() comb.Parser {
	return s.Void(s.Many(s.Or(s.space(), s.comment())))
}

func (s *state) space() comb.Parser {
	return s.Void(s.Many1(s.InString(spaceChars)))
}

func (s *state) quote(p comb.Parser) comb.Parser {
	return s.And(s.Replace(quoteString, s.Char(quoteChar)), p)
}

func (s *state) quotes(ps ...comb.Parser) []comb.Parser {
	qs := make([]comb.Parser, len(ps))

	for i, p := range ps {
		qs[i] = s.quote(p)
	}

	return qs
}

func (s *state) stringify(p comb.Parser) comb.Parser {
	return s.App(stringifyChars, p)
}

func stringifyChars(any interface{}) interface{} {
	xs := any.([]interface{})
	rs := make([]rune, len(xs))

	for i, x := range xs {
		rs[i] = x.(rune)
	}

	return string(rs)
}
<commit_msg>Remove strippedChar()<commit_after>package parse

import "./comb"

const (
	bracketChars = "()[]{}"
	commentChar  = ';'
	invalidChars = "\x00"
	quoteChar    = '`'
	quoteString  = "quote"
	spaceChars   = " \t\n\r"
	specialChar  = '$'
)

func Parse(source string) []interface{} {
	m, err := newState(source).module()()

	if err != nil {
		panic(err.Error())
	}

	return m.([]interface{})
}

func (s *state) module() comb.Parser {
	return s.Exhaust(s.Wrap(s.blank(), s.expressions(), s.None()))
}

func (s *state) expressions() comb.Parser {
	return s.Lazy(s.strictExpressions)
}

func (s *state) strictExpressions() comb.Parser {
	return s.Many(s.expression())
}

func (s *state) expression() comb.Parser {
	ps := []comb.Parser{s.atom(), s.list(), s.array(), s.dict()}

	return s.strip(s.Or(append(ps, s.quotes(ps...)...)...))
}

func (s *state) atom() comb.Parser {
	return s.Or(s.stringLiteral(), s.identifier())
}

func (s *state) identifier() comb.Parser {
	return s.stringify(s.Many1(s.NotInString(
		bracketChars + string(commentChar) + invalidChars + string(quoteChar) +
			spaceChars + string(specialChar))))
}

func (s *state) stringLiteral() comb.Parser {
	b := s.blank()
	c := s.Char('"')

	return s.App(prependQuote, s.stringify(s.Wrap(
		c,
		s.Many(s.Or(s.NotInString("\"\\"), s.String("\\\""), s.String("\\\\"))),
		s.And(c, b))))
}

func prependQuote(x interface{}) interface{} {
	return []interface{}{quoteString, x}
}

func (s *state) list() comb.Parser {
	return s.sequence('(', ')')
}

func (s *state) array() comb.Parser {
	return s.sequence('[', ']')
}

func (s *state) dict() comb.Parser {
	return s.sequence('{', '}')
}

func (s *state) sequence(l, r rune) comb.Parser {
	return s.wrapChars(l, s.expressions(), r)
}

func (s *state) comment() comb.Parser {
	return s.Void(s.And(
		s.Char(commentChar),
		s.Many(s.NotChar('\n')), s.Char('\n')))
}

func (s *state) wrapChars(l rune, p comb.Parser, r rune) comb.Parser {
	return s.Wrap(s.strip(s.Char(l)), p, s.strip(s.Char(r)))
}

func (s *state) strip(p comb.Parser) comb.Parser {
	b := s.blank()
	return s.Wrap(s.None(), p, b)
}

func (s *state) blank() comb.Parser {
	return s.Void(s.Many(s.Or(s.space(), s.comment())))
}

func (s *state) space() comb.Parser {
	return s.Void(s.Many1(s.InString(spaceChars)))
}

func (s *state) quote(p comb.Parser) comb.Parser {
	return s.And(s.Replace(quoteString, s.Char(quoteChar)), p)
}

func (s *state) quotes(ps ...comb.Parser) []comb.Parser {
	qs := make([]comb.Parser, len(ps))

	for i, p := range ps {
		qs[i] = s.quote(p)
	}

	return qs
}

func (s *state) stringify(p comb.Parser) comb.Parser {
	return s.App(stringifyChars, p)
}

func stringifyChars(any interface{}) interface{} {
	xs := any.([]interface{})
	rs := make([]rune, len(xs))

	for i, x := range xs {
		rs[i] = x.(rune)
	}

	return string(rs)
}
<|endoftext|>


<commit_before>package atlas

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"reflect"
	"strconv"
)

// MeasurementResp contains all the results of the measurements
type MeasurementResp struct {
	Measurements []int
}

var (
	// If nothing is specified, use this
	defProbeSet = ProbeSet{
		{
			Requested: 10,
			Type:      "area",
			Value:     "WW",
			Tags:      nil,
		},
	}
)

// NewMeasurement create a new MeasurementRequest and fills some fields
func (c *Client) NewMeasurement() (req *MeasurementRequest) {
	var defs []Definition

	req = &MeasurementRequest{
		Definitions: defs,
		IsOneoff:    true,
		Probes:      defProbeSet,
	}
	return
}

// NewProbeSet create a set of probes for later requests
func NewProbeSet(howmany int) (ps *ProbeSet) {
	ps = &ProbeSet{
		{
			Requested: howmany,
			Type:      "area",
			Value:     "WW",
			Tags:      nil,
		},
	}
	return
}

// SetParams set a few parameters in a definition list
/*
The goal here is to give a dictionary of string and let it figure out each field's type
depending on the recipient's type in the struct.
*/
func (d *Definition) setParams(fields map[string]string) {
	sdef := reflect.ValueOf(d).Elem()
	typeOfDef := sdef.Type()
	for k, v := range fields {
		// Check the field is present
		if f, ok := typeOfDef.FieldByName(k); ok {
			// Use the right type
			switch f.Type.Name() {
			case "float":
				vf, _ := strconv.ParseFloat(v, 32)
				sdef.FieldByName(k).SetFloat(vf)
			case "int":
				vi, _ := strconv.ParseInt(v, 10, 32)
				sdef.FieldByName(k).SetInt(vi)
			case "string":
				sdef.FieldByName(k).SetString(v)
			case "bool":
				vb, _ := strconv.ParseBool(v)
				sdef.FieldByName(k).SetBool(vb)
			default:
				log.Printf("Unsupported type: %s", f.Type.Name())
			}
		}
	}
}

// AddDefinition create a new MeasurementRequest and fills some fields
func (m *MeasurementRequest) AddDefinition(fields map[string]string) *MeasurementRequest {
	def := new(Definition)
	def.setParams(fields)
	m.Definitions = append(m.Definitions, *def)

	return m
}

// createMeasurement creates a measurement for all types
func (c *Client) createMeasurement(t string, d *MeasurementRequest) (m *MeasurementResp, err error) {
	opts := make(map[string]string)
	req := c.prepareRequest("POST", fmt.Sprintf("measurements/%s", t), opts)

	body, err := json.Marshal(d)
	if err != nil {
		return
	}

	buf := bytes.NewReader(body)
	req.Body = ioutil.NopCloser(buf)
	req.ContentLength = int64(buf.Len())

	if c.config.Verbose {
		c.log.Printf("req: %#v", req)
		c.log.Printf("body: %s", body)
	}
	resp, err := c.call(req)
	if c.config.Verbose {
		c.log.Printf("resp: %v", resp)
	}
	if err != nil {
		c.log.Printf("err: %v", err)
		//return
	}

	err = c.handleAPIResponsese(resp)
	if err != nil {
		return
	}

	m = &MeasurementResp{}
	rbody, _ := ioutil.ReadAll(resp.Body)
	defer resp.Body.Close()

	err = json.Unmarshal(rbody, m)
	// Only display if debug/verbose
	if c.config.Verbose {
		fmt.Printf("m: %v\nresp: %#v\nd: %v\n", m, string(rbody), d)
	}
	if err != nil {
		err = fmt.Errorf("err: %v - m:%v", err, m)
		return
	}

	return
}

// DNS creates a measurement
func (c *Client) DNS(d *MeasurementRequest) (m *MeasurementResp, err error) {
	return c.createMeasurement("dns", d)
}

// HTTP creates a measurement
func (c *Client) HTTP(d *MeasurementRequest) (m *MeasurementResp, err error) {
	return c.createMeasurement("http", d)
}

// NTP creates a measurement
func (c *Client) NTP(d *MeasurementRequest) (m *MeasurementResp, err error) {
	return c.createMeasurement("ntp", d)
}

// Ping creates a measurement
func (c *Client) Ping(d *MeasurementRequest) (m *MeasurementResp, err error) {
	return c.createMeasurement("ping", d)
}

// SSLCert creates a measurement
func (c *Client) SSLCert(d *MeasurementRequest) (m *MeasurementResp, err error) {
	return c.createMeasurement("sslcert", d)
}

// Traceroute creates a measurement
func (c *Client) Traceroute(d *MeasurementRequest) (m *MeasurementResp, err error) {
	return c.createMeasurement("traceroute", d)
}
<commit_msg>Get the probeset parameters from configuration/options.<commit_after>package atlas

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"reflect"
	"strconv"
)

// MeasurementResp contains all the results of the measurements
type MeasurementResp struct {
	Measurements []int
}

// NewMeasurement create a new MeasurementRequest and fills some fields
func (c *Client) NewMeasurement() (req *MeasurementRequest) {
	var defs []Definition

	req = &MeasurementRequest{
		Definitions: defs,
		IsOneoff:    true,
		Probes:      *NewProbeSet(c.config.PoolSize, c.config.AreaType, c.config.AreaValue),
	}
	return
}

// NewProbeSet create a set of probes for later requests
func NewProbeSet(howmany int, settype, value string) (ps *ProbeSet) {
	if howmany == 0 {
		howmany = 10
	}

	if settype == "" {
		settype = "area"
	}

	if value == "" {
		value = "WW"
	}

	ps = &ProbeSet{
		{
			Requested: howmany,
			Type:      settype,
			Value:     value,
			Tags:      nil,
		},
	}
	return
}

// SetParams set a few parameters in a definition list
/*
The goal here is to give a dictionary of string and let it figure out each field's type
depending on the recipient's type in the struct.
*/
func (d *Definition) setParams(fields map[string]string) {
	sdef := reflect.ValueOf(d).Elem()
	typeOfDef := sdef.Type()
	for k, v := range fields {
		// Check the field is present
		if f, ok := typeOfDef.FieldByName(k); ok {
			// Use the right type
			switch f.Type.Name() {
			case "float":
				vf, _ := strconv.ParseFloat(v, 32)
				sdef.FieldByName(k).SetFloat(vf)
			case "int":
				vi, _ := strconv.ParseInt(v, 10, 32)
				sdef.FieldByName(k).SetInt(vi)
			case "string":
				sdef.FieldByName(k).SetString(v)
			case "bool":
				vb, _ := strconv.ParseBool(v)
				sdef.FieldByName(k).SetBool(vb)
			default:
				log.Printf("Unsupported type: %s", f.Type.Name())
			}
		}
	}
}

// AddDefinition create a new MeasurementRequest and fills some fields
func (m *MeasurementRequest) AddDefinition(fields map[string]string) *MeasurementRequest {
	def := new(Definition)
	def.setParams(fields)
	m.Definitions = append(m.Definitions, *def)

	return m
}

// createMeasurement creates a measurement for all types
func (c *Client) createMeasurement(t string, d *MeasurementRequest) (m *MeasurementResp, err error) {
	opts := make(map[string]string)
	req := c.prepareRequest("POST", fmt.Sprintf("measurements/%s", t), opts)

	body, err := json.Marshal(d)
	if err != nil {
		return
	}

	buf := bytes.NewReader(body)
	req.Body = ioutil.NopCloser(buf)
	req.ContentLength = int64(buf.Len())

	if c.config.Verbose {
		c.log.Printf("req: %#v", req)
		c.log.Printf("body: %s", body)
	}
	resp, err := c.call(req)
	if c.config.Verbose {
		c.log.Printf("resp: %v", resp)
	}
	if err != nil {
		c.log.Printf("err: %v", err)
		//return
	}

	err = c.handleAPIResponsese(resp)
	if err != nil {
		return
	}

	m = &MeasurementResp{}
	rbody, _ := ioutil.ReadAll(resp.Body)
	defer resp.Body.Close()

	err = json.Unmarshal(rbody, m)
	// Only display if debug/verbose
	if c.config.Verbose {
		fmt.Printf("m: %v\nresp: %#v\nd: %v\n", m, string(rbody), d)
	}
	if err != nil {
		err = fmt.Errorf("err: %v - m:%v", err, m)
		return
	}

	return
}

// DNS creates a measurement
func (c *Client) DNS(d *MeasurementRequest) (m *MeasurementResp, err error) {
	return c.createMeasurement("dns", d)
}

// HTTP creates a measurement
func (c *Client) HTTP(d *MeasurementRequest) (m *MeasurementResp, err error) {
	return c.createMeasurement("http", d)
}

// NTP creates a measurement
func (c *Client) NTP(d *MeasurementRequest) (m *MeasurementResp, err error) {
	return c.createMeasurement("ntp", d)
}

// Ping creates a measurement
func (c *Client) Ping(d *MeasurementRequest) (m *MeasurementResp, err error) {
	return c.createMeasurement("ping", d)
}

// SSLCert creates a measurement
func (c *Client) SSLCert(d *MeasurementRequest) (m *MeasurementResp, err error) {
	return c.createMeasurement("sslcert", d)
}

// Traceroute creates a measurement
func (c *Client) Traceroute(d *MeasurementRequest) (m *MeasurementResp, err error) {
	return c.createMeasurement("traceroute", d)
}
<|endoftext|>


<commit_before>/*
Copyright 2017 Google Inc.

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

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

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

package tabletmanager

import (
	"fmt"
	"time"

	"golang.org/x/net/context"
	"vitess.io/vitess/go/vt/logutil"
	"vitess.io/vitess/go/vt/mysqlctl"
	"vitess.io/vitess/go/vt/topo/topoproto"
	"vitess.io/vitess/go/vt/topotools"
	"vitess.io/vitess/go/vt/vterrors"

	topodatapb "vitess.io/vitess/go/vt/proto/topodata"
)

// Backup takes a db backup and sends it to the BackupStorage
func (agent *ActionAgent) Backup(ctx context.Context, concurrency int, logger logutil.Logger, allowMaster bool) error {
	if err := agent.lock(ctx); err != nil {
		return err
	}
	defer agent.unlock()

	if agent.Cnf == nil {
		return fmt.Errorf("cannot perform backup without my.cnf, please restart vttablet with a my.cnf file specified")
	}

	// Check tablet type current process has.
	// During a network partition it is possible that from the topology perspective this is no longer the master,
	// but the process didn't find out about this.
	// It is not safe to take backups from tablet in this state
	currentTablet := agent.Tablet()
	if !allowMaster && currentTablet.Type == topodatapb.TabletType_MASTER {
		return fmt.Errorf("type MASTER cannot take backup. if you really need to do this, rerun the backup command with -allow_master")
	}

	tablet, err := agent.TopoServer.GetTablet(ctx, agent.TabletAlias)
	if err != nil {
		return err
	}
	if !allowMaster && tablet.Type == topodatapb.TabletType_MASTER {
		return fmt.Errorf("type MASTER cannot take backup. if you really need to do this, rerun the backup command with -allow_master")
	}
	originalType := tablet.Type

	engine, err := mysqlctl.GetBackupEngine()
	if err != nil {
		return vterrors.Wrap(err, "failed to find backup engine")
	}
	builtin, _ := engine.(*mysqlctl.BuiltinBackupEngine)
	if builtin != nil {
		// update our type to BACKUP
		if _, err := topotools.ChangeType(ctx, agent.TopoServer, tablet.Alias, topodatapb.TabletType_BACKUP); err != nil {
			return err
		}

		// let's update our internal state (stop query service and other things)
		if err := agent.refreshTablet(ctx, "before backup"); err != nil {
			return err
		}
	}
	// create the loggers: tee to console and source
	l := logutil.NewTeeLogger(logutil.NewConsoleLogger(), logger)

	// now we can run the backup
	dir := fmt.Sprintf("%v/%v", tablet.Keyspace, tablet.Shard)
	name := fmt.Sprintf("%v.%v", time.Now().UTC().Format("2006-01-02.150405"), topoproto.TabletAliasString(tablet.Alias))
	returnErr := mysqlctl.Backup(ctx, agent.Cnf, agent.MysqlDaemon, l, dir, name, concurrency, agent.hookExtraEnv())

	if builtin != nil {

		bgCtx := context.Background()
		// Starting from here we won't be able to recover if we get stopped by a cancelled
		// context. It is also possible that the context already timed out during the
		// above call to Backup. Thus we use the background context to get through to the finish.

		// change our type back to the original value
		_, err = topotools.ChangeType(bgCtx, agent.TopoServer, tablet.Alias, originalType)
		if err != nil {
			// failure in changing the topology type is probably worse,
			// so returning that (we logged the snapshot error anyway)
			if returnErr != nil {
				l.Errorf("mysql backup command returned error: %v", returnErr)
			}
			returnErr = err
		}

		// let's update our internal state (start query service and other things)
		if err := agent.refreshTablet(bgCtx, "after backup"); err != nil {
			return err
		}
	}
	// and re-run health check to be sure to capture any replication delay
	agent.runHealthCheckLocked()

	return returnErr
}

// RestoreFromBackup deletes all local data and restores anew from the latest backup.
func (agent *ActionAgent) RestoreFromBackup(ctx context.Context, logger logutil.Logger) error {
	if err := agent.lock(ctx); err != nil {
		return err
	}
	defer agent.unlock()

	tablet, err := agent.TopoServer.GetTablet(ctx, agent.TabletAlias)
	if err != nil {
		return err
	}
	if tablet.Type == topodatapb.TabletType_MASTER {
		return fmt.Errorf("type MASTER cannot restore from backup, if you really need to do this, restart vttablet in replica mode")
	}

	// create the loggers: tee to console and source
	l := logutil.NewTeeLogger(logutil.NewConsoleLogger(), logger)

	// now we can run restore
	err = agent.restoreDataLocked(ctx, l, 0 /* waitForBackupInterval */, true /* deleteBeforeRestore */)

	// re-run health check to be sure to capture any replication delay
	agent.runHealthCheckLocked()

	return err
}
<commit_msg>don't take the action lock while running xtrabackup because that prevents tablet from updating its replication lag<commit_after>/*
Copyright 2017 Google Inc.

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

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

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

package tabletmanager

import (
	"fmt"
	"time"

	"golang.org/x/net/context"
	"vitess.io/vitess/go/vt/logutil"
	"vitess.io/vitess/go/vt/mysqlctl"
	"vitess.io/vitess/go/vt/topo/topoproto"
	"vitess.io/vitess/go/vt/topotools"
	"vitess.io/vitess/go/vt/vterrors"

	topodatapb "vitess.io/vitess/go/vt/proto/topodata"
)

// Backup takes a db backup and sends it to the BackupStorage
func (agent *ActionAgent) Backup(ctx context.Context, concurrency int, logger logutil.Logger, allowMaster bool) error {
	if agent.Cnf == nil {
		return fmt.Errorf("cannot perform backup without my.cnf, please restart vttablet with a my.cnf file specified")
	}

	// Check tablet type current process has.
	// During a network partition it is possible that from the topology perspective this is no longer the master,
	// but the process didn't find out about this.
	// It is not safe to take backups from tablet in this state
	currentTablet := agent.Tablet()
	if !allowMaster && currentTablet.Type == topodatapb.TabletType_MASTER {
		return fmt.Errorf("type MASTER cannot take backup. if you really need to do this, rerun the backup command with -allow_master")
	}
	engine, err := mysqlctl.GetBackupEngine()
	if err != nil {
		return vterrors.Wrap(err, "failed to find backup engine")
	}
	builtin, _ := engine.(*mysqlctl.BuiltinBackupEngine)
	// get Tablet info from topo so that it is up to date
	tablet, err := agent.TopoServer.GetTablet(ctx, agent.TabletAlias)
	if err != nil {
		return err
	}
	originalType := tablet.Type
	if builtin != nil {
		if err := agent.lock(ctx); err != nil {
			return err
		}
		defer agent.unlock()

		tablet, err := agent.TopoServer.GetTablet(ctx, agent.TabletAlias)
		if err != nil {
			return err
		}

		// update our type to BACKUP
		if _, err := topotools.ChangeType(ctx, agent.TopoServer, tablet.Alias, topodatapb.TabletType_BACKUP); err != nil {
			return err
		}

		// let's update our internal state (stop query service and other things)
		if err := agent.refreshTablet(ctx, "before backup"); err != nil {
			return err
		}
	}
	// create the loggers: tee to console and source
	l := logutil.NewTeeLogger(logutil.NewConsoleLogger(), logger)

	// now we can run the backup
	dir := fmt.Sprintf("%v/%v", tablet.Keyspace, tablet.Shard)
	name := fmt.Sprintf("%v.%v", time.Now().UTC().Format("2006-01-02.150405"), topoproto.TabletAliasString(tablet.Alias))
	returnErr := mysqlctl.Backup(ctx, agent.Cnf, agent.MysqlDaemon, l, dir, name, concurrency, agent.hookExtraEnv())

	if builtin != nil {
		bgCtx := context.Background()
		// Starting from here we won't be able to recover if we get stopped by a cancelled
		// context. It is also possible that the context already timed out during the
		// above call to Backup. Thus we use the background context to get through to the finish.

		// change our type back to the original value
		_, err = topotools.ChangeType(bgCtx, agent.TopoServer, tablet.Alias, originalType)
		if err != nil {
			// failure in changing the topology type is probably worse,
			// so returning that (we logged the snapshot error anyway)
			if returnErr != nil {
				l.Errorf("mysql backup command returned error: %v", returnErr)
			}
			returnErr = err
		}

		// let's update our internal state (start query service and other things)
		if err := agent.refreshTablet(bgCtx, "after backup"); err != nil {
			return err
		}
	}
	// and re-run health check to be sure to capture any replication delay
	agent.runHealthCheckLocked()

	return returnErr
}

// RestoreFromBackup deletes all local data and restores anew from the latest backup.
func (agent *ActionAgent) RestoreFromBackup(ctx context.Context, logger logutil.Logger) error {
	if err := agent.lock(ctx); err != nil {
		return err
	}
	defer agent.unlock()

	tablet, err := agent.TopoServer.GetTablet(ctx, agent.TabletAlias)
	if err != nil {
		return err
	}
	if tablet.Type == topodatapb.TabletType_MASTER {
		return fmt.Errorf("type MASTER cannot restore from backup, if you really need to do this, restart vttablet in replica mode")
	}

	// create the loggers: tee to console and source
	l := logutil.NewTeeLogger(logutil.NewConsoleLogger(), logger)

	// now we can run restore
	err = agent.restoreDataLocked(ctx, l, 0 /* waitForBackupInterval */, true /* deleteBeforeRestore */)

	// re-run health check to be sure to capture any replication delay
	agent.runHealthCheckLocked()

	return err
}
<|endoftext|>


<commit_before>package request

import (
	"math"
	"net/url"
	"path"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/kennygrant/sanitize"
)

const (
	DEFAULT_REPLY_LIMIT = 3
	MAX_REPLY_LIMIT     = 25
	MAX_LIMIT           = 25
	ORDER_ASC           = "ASC"
	ORDER_DESC          = "DESC"
)

type Query struct {
	Id                   int64     `url:"id,omitempty"`
	Skip                 int       `url:"skip"`
	Limit                int       `url:"limit"`
	To                   time.Time `url:"to"`
	From                 time.Time `url:"from"`
	GroupName            string    `url:"groupName"`
	GroupChannelId       int64     `url:"groupChannelId"`
	Type                 string    `url:"type"`
	Privacy              string    `url:"privacy"`
	AccountId            int64     `url:"accountId"`
	AccountNickname      string    `url:"accountNickname"`
	Name                 string    `url:"name"`
	Slug                 string    `url:"slug"`
	SortOrder            string    `url:"sortOrder"`
	ShowExempt           bool      `url:"showExempt"`
	ShowModerationNeeded bool      `url:showModerationNeeded`
	ReplyLimit           int       `url:"replyLimit"`
	ReplySkip            int       `url:"replySkip"`
	AddIsInteracted      bool      `url:"addIsInteracted"`
	ObjectId             int64     `url:"objectId"`
	Exclude              map[string]interface{}
	Sort                 map[string]string
}

func NewQuery() *Query {
	return &Query{
		Exclude: make(map[string]interface{}, 0),
		Sort:    make(map[string]string, 0),
		Limit:   MAX_LIMIT,
	}
}

func (q *Query) ExcludeField(field string, value interface{}) {
	q.Exclude[field] = value
}

func (q *Query) AddSortField(field, order string) {
	if order != ORDER_ASC && order != ORDER_DESC {
		return
	}

	q.Sort[field] = order
}

func (q *Query) MapURL(u *url.URL) *Query {
	urlQuery := u.Query()

	q.Skip, _ = strconv.Atoi(urlQuery.Get("skip"))
	q.Limit, _ = strconv.Atoi(urlQuery.Get("limit"))

	q.Name = urlQuery.Get("name")
	if q.Name != "" {
		q.Name = escapeString(q.Name)
	}

	q.Slug = urlQuery.Get("slug")
	if q.Slug != "" {
		q.Slug = sanitize.Name(q.Slug)
	}

	q.GroupName = urlQuery.Get("groupName")
	if q.GroupName != "" {
		q.GroupName = sanitize.Name(q.GroupName)
	}

	q.Type = urlQuery.Get("type")
	if q.Type != "" {
		q.Type = sanitize.Name(q.Type)
	}

	q.Privacy = urlQuery.Get("privacy")
	if q.Privacy != "" {
		q.Privacy = sanitize.Name(q.Privacy)
	}

	q.Id, _ = GetURIInt64(u, "id")
	q.AccountId, _ = GetURIInt64(u, "accountId")

	q.AccountNickname = urlQuery.Get("accountNickname")
	if q.AccountNickname != "" {
		q.AccountNickname = sanitize.Name(q.AccountNickname)
	}

	q.GroupChannelId, _ = GetURIInt64(u, "groupChannelId")

	if to := urlQuery.Get("to"); to != "" {
		q.To, _ = time.Parse(time.RFC3339, to)
	}

	if from := urlQuery.Get("from"); from != "" {
		q.From, _ = time.Parse(time.RFC3339, from)
	}

	if showExempt := urlQuery.Get("showExempt"); showExempt != "" {
		isExempt, _ := strconv.ParseBool(showExempt)
		q.ShowExempt = isExempt
	}

	if showModerationNeeded := urlQuery.Get("showModerationNeeded"); showModerationNeeded != "" {
		i, _ := strconv.ParseBool(showModerationNeeded)
		q.ShowModerationNeeded = i
	}

	if addIsInteracted := urlQuery.Get("addIsInteracted"); addIsInteracted != "" {
		addIsInteracted, _ := strconv.ParseBool(addIsInteracted)
		q.AddIsInteracted = addIsInteracted
	}

	if replyLimit := urlQuery.Get("replyLimit"); replyLimit != "" {
		replyLimit, _ := strconv.Atoi(replyLimit)
		q.ReplyLimit = replyLimit
	}

	if replySkip := urlQuery.Get("replySkip"); replySkip != "" {
		replySkip, _ := strconv.Atoi(replySkip)
		q.ReplySkip = replySkip
	}

	if sortOrder := urlQuery.Get("sortOrder"); sortOrder != "" && IsIn(sortOrder, "ASC", "DESC") {
		q.SortOrder = sortOrder
	}

	q.ObjectId, _ = GetURIInt64(u, "objectId")

	return q
}

func (q *Query) Clone() *Query {
	cq := NewQuery()
	*cq = *q

	return cq
}

func (q *Query) SetDefaults() *Query {
	if q.Skip == 0 {
		// no need to do something
	}

	if q.Limit <= 0 || q.Limit > MAX_LIMIT {
		q.Limit = MAX_LIMIT
	}

	if q.To.IsZero() {
		q.To = time.Now().UTC()
	}

	if q.GroupName == "" {
		q.GroupName = "koding"
	}

	if q.ReplyLimit == 0 {
		q.ReplyLimit = DEFAULT_REPLY_LIMIT
	} else {
		q.ReplyLimit = int(math.Min(float64(q.ReplyLimit), float64(MAX_REPLY_LIMIT)))
	}

	if q.SortOrder == "" {
		q.SortOrder = "DESC"
	}

	q.AddIsInteracted = true

	return q
}

// Sanitize method is taken from "github.com/kennygrant/sanitize" package.
// Removed toLowerCase call from Name method in that package.
func escapeString(text string) string {
	fileName := path.Clean(path.Base(text))
	fileName = strings.Trim(fileName, " ")

	// Replace certain joining characters with a dash
	seps, err := regexp.Compile(`[ &_=+:]`)
	if err == nil {
		fileName = seps.ReplaceAllString(fileName, "-")
	}

	// Remove all other unrecognised characters - NB we do allow any printable characters
	legal, err := regexp.Compile(`[^[:alnum:]-.]`)
	if err == nil {
		fileName = legal.ReplaceAllString(fileName, "")
	}

	// Remove any double dashes caused by existing - in name
	fileName = strings.Replace(fileName, "--", "-", -1)

	// NB this may be of length 0, caller must check
	return fileName
}

func IsIn(s string, ts ...string) bool {
	for _, t := range ts {
		if t == s {
			return true
		}
	}

	return false
}
<commit_msg>social: max limit for message is added<commit_after>package request

import (
	"math"
	"net/url"
	"path"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/kennygrant/sanitize"
)

const (
	DEFAULT_REPLY_LIMIT = 3
	MAX_REPLY_LIMIT     = 25
	MAX_LIMIT           = 25
	// message list limit is only used for getting messages
	MAX_MESSAGE_LIST_LIMIT = 50
	ORDER_ASC              = "ASC"
	ORDER_DESC             = "DESC"
)

var MessageLimit int

type Query struct {
	Id                   int64     `url:"id,omitempty"`
	Skip                 int       `url:"skip"`
	Limit                int       `url:"limit"`
	To                   time.Time `url:"to"`
	From                 time.Time `url:"from"`
	GroupName            string    `url:"groupName"`
	GroupChannelId       int64     `url:"groupChannelId"`
	Type                 string    `url:"type"`
	Privacy              string    `url:"privacy"`
	AccountId            int64     `url:"accountId"`
	AccountNickname      string    `url:"accountNickname"`
	Name                 string    `url:"name"`
	Slug                 string    `url:"slug"`
	SortOrder            string    `url:"sortOrder"`
	ShowExempt           bool      `url:"showExempt"`
	ShowModerationNeeded bool      `url:showModerationNeeded`
	ReplyLimit           int       `url:"replyLimit"`
	ReplySkip            int       `url:"replySkip"`
	AddIsInteracted      bool      `url:"addIsInteracted"`
	ObjectId             int64     `url:"objectId"`
	Exclude              map[string]interface{}
	Sort                 map[string]string
}

func NewQuery() *Query {
	return &Query{
		Exclude: make(map[string]interface{}, 0),
		Sort:    make(map[string]string, 0),
		Limit:   MAX_LIMIT,
	}
}

func (q *Query) ExcludeField(field string, value interface{}) {
	q.Exclude[field] = value
}

func (q *Query) AddSortField(field, order string) {
	if order != ORDER_ASC && order != ORDER_DESC {
		return
	}

	q.Sort[field] = order
}

func (q *Query) MapURL(u *url.URL) *Query {
	urlQuery := u.Query()

	q.Skip, _ = strconv.Atoi(urlQuery.Get("skip"))
	q.Limit, _ = strconv.Atoi(urlQuery.Get("limit"))

	q.Name = urlQuery.Get("name")
	if q.Name != "" {
		q.Name = escapeString(q.Name)
	}

	q.Slug = urlQuery.Get("slug")
	if q.Slug != "" {
		q.Slug = sanitize.Name(q.Slug)
	}

	q.GroupName = urlQuery.Get("groupName")
	if q.GroupName != "" {
		q.GroupName = sanitize.Name(q.GroupName)
	}

	q.Type = urlQuery.Get("type")
	if q.Type != "" {
		q.Type = sanitize.Name(q.Type)
	}

	q.Privacy = urlQuery.Get("privacy")
	if q.Privacy != "" {
		q.Privacy = sanitize.Name(q.Privacy)
	}

	q.Id, _ = GetURIInt64(u, "id")
	q.AccountId, _ = GetURIInt64(u, "accountId")

	q.AccountNickname = urlQuery.Get("accountNickname")
	if q.AccountNickname != "" {
		q.AccountNickname = sanitize.Name(q.AccountNickname)
	}

	q.GroupChannelId, _ = GetURIInt64(u, "groupChannelId")

	if to := urlQuery.Get("to"); to != "" {
		q.To, _ = time.Parse(time.RFC3339, to)
	}

	if from := urlQuery.Get("from"); from != "" {
		q.From, _ = time.Parse(time.RFC3339, from)
	}

	if showExempt := urlQuery.Get("showExempt"); showExempt != "" {
		isExempt, _ := strconv.ParseBool(showExempt)
		q.ShowExempt = isExempt
	}

	if showModerationNeeded := urlQuery.Get("showModerationNeeded"); showModerationNeeded != "" {
		i, _ := strconv.ParseBool(showModerationNeeded)
		q.ShowModerationNeeded = i
	}

	if addIsInteracted := urlQuery.Get("addIsInteracted"); addIsInteracted != "" {
		addIsInteracted, _ := strconv.ParseBool(addIsInteracted)
		q.AddIsInteracted = addIsInteracted
	}

	if replyLimit := urlQuery.Get("replyLimit"); replyLimit != "" {
		replyLimit, _ := strconv.Atoi(replyLimit)
		q.ReplyLimit = replyLimit
	}

	if replySkip := urlQuery.Get("replySkip"); replySkip != "" {
		replySkip, _ := strconv.Atoi(replySkip)
		q.ReplySkip = replySkip
	}

	if sortOrder := urlQuery.Get("sortOrder"); sortOrder != "" && IsIn(sortOrder, "ASC", "DESC") {
		q.SortOrder = sortOrder
	}

	q.ObjectId, _ = GetURIInt64(u, "objectId")

	return q
}

func (q *Query) Clone() *Query {
	cq := NewQuery()
	*cq = *q

	return cq
}

func (q *Query) SetDefaults() *Query {
	if q.Skip == 0 {
		// no need to do something
	}

	if q.Limit <= 0 || q.Limit > MAX_MESSAGE_LIST_LIMIT {
		MessageLimit = MAX_MESSAGE_LIST_LIMIT
	} else {
		MessageLimit = q.Limit
	}

	if q.Limit <= 0 || q.Limit > MAX_LIMIT {
		q.Limit = MAX_LIMIT
	}

	if q.To.IsZero() {
		q.To = time.Now().UTC()
	}

	if q.GroupName == "" {
		q.GroupName = "koding"
	}

	if q.ReplyLimit == 0 {
		q.ReplyLimit = DEFAULT_REPLY_LIMIT
	} else {
		q.ReplyLimit = int(math.Min(float64(q.ReplyLimit), float64(MAX_REPLY_LIMIT)))
	}

	if q.SortOrder == "" {
		q.SortOrder = "DESC"
	}

	q.AddIsInteracted = true

	return q
}

// Sanitize method is taken from "github.com/kennygrant/sanitize" package.
// Removed toLowerCase call from Name method in that package.
func escapeString(text string) string {
	fileName := path.Clean(path.Base(text))
	fileName = strings.Trim(fileName, " ")

	// Replace certain joining characters with a dash
	seps, err := regexp.Compile(`[ &_=+:]`)
	if err == nil {
		fileName = seps.ReplaceAllString(fileName, "-")
	}

	// Remove all other unrecognised characters - NB we do allow any printable characters
	legal, err := regexp.Compile(`[^[:alnum:]-.]`)
	if err == nil {
		fileName = legal.ReplaceAllString(fileName, "")
	}

	// Remove any double dashes caused by existing - in name
	fileName = strings.Replace(fileName, "--", "-", -1)

	// NB this may be of length 0, caller must check
	return fileName
}

func IsIn(s string, ts ...string) bool {
	for _, t := range ts {
		if t == s {
			return true
		}
	}

	return false
}
<|endoftext|>


<commit_before>package monitor

import (
	"errors"
	"fmt"
	"time"

	docker "github.com/ncodes/go-dockerclient"
	"github.com/olebedev/emitter"
	logging "github.com/op/go-logging"
)

var log = logging.MustGetLogger("launcher.monitor")

// ErrNoContainerFound represents a error about not finding containers
var ErrNoContainerFound = errors.New("no container found")

// HandleFunc is the expected function signature
type HandleFunc func(map[string]interface{})

// Report represents the result of the monitors checks
type Report struct {
	DiskUsage int64
	NetTx     uint64
	NetRx     uint64
}

// Monitor defines a launcher monitor module checking resource
// useage of a cocoon code. This module provides a pubsub feature that allows
// other external modules to subscribe to events from it and to also emit events to
// the module.
type Monitor struct {
	emitter     *emitter.Emitter
	containerID string
	stop        bool
	dckClient   *docker.Client
}

// NewMonitor creates a new monitor instance.
func NewMonitor() *Monitor {
	e := emitter.New(10)
	return &Monitor{
		emitter: e,
	}
}

// SetContainerID sets the id of the container to monitor
func (m *Monitor) SetContainerID(cID string) {
	m.containerID = cID
}

// SetDockerClient sets the docker client
func (m *Monitor) SetDockerClient(dckClient *docker.Client) {
	m.dckClient = dckClient
}

// GetEmitter returns the monitor's emitter
func (m *Monitor) GetEmitter() *emitter.Emitter {
	return m.emitter
}

// Stop the monitor
func (m *Monitor) Stop() {
	m.stop = true
	m.emitter.Off("*")
}

// Reset resets the monitor
func (m *Monitor) Reset() {
	m.Stop()
	m.emitter = emitter.New(10)
	m.stop = false
}

// getContainerRootSize fetches the total
// size of all the files in the container.
func (m *Monitor) getContainerRootSize() (int64, error) {
	containers, err := m.dckClient.ListContainers(docker.ListContainersOptions{
		All:   true,
		Size:  true,
		Limit: 1,
		Filters: map[string][]string{
			"id": []string{m.containerID},
		},
	})
	if err != nil {
		return 0, fmt.Errorf("failed to list containers. %s", err)
	}

	if len(containers) == 0 {
		return 0, ErrNoContainerFound
	}

	return containers[0].SizeRw, nil
}

// getContainerNetworkIO returns the current Net IO usage of the container
func (m *Monitor) getContainerNetworkIO() (uint64, uint64, error) {
	var stats = make(chan *docker.Stats)
	var done = make(chan bool)
	go func() {
		m.dckClient.Stats(docker.StatsOptions{
			ID:      m.containerID,
			Stats:   stats,
			Timeout: 5 * time.Second,
			Done:    done,
		})
	}()

	for s := range stats {
		close(done)
		rxBytes := uint64(0)
		txBytes := uint64(0)
		for _, n := range s.Networks {
			rxBytes += n.RxBytes
			txBytes += n.TxBytes
		}
		return rxBytes, txBytes, nil
	}

	return 0, 0, nil
}

// Monitor starts the monitor
func (m *Monitor) Monitor() {
	for !m.stop {

		size, err := m.getContainerRootSize()
		if err != nil && err != ErrNoContainerFound {
			log.Error(err.Error())
		}

		rxBytes, txBytes, err := m.getContainerNetworkIO()
		if err != nil {
			log.Error(err.Error())
		}

		log.Infof("Rx Bytes: %d / Tx Bytes: %d", rxBytes, txBytes)

		report := Report{
			DiskUsage: size,
			NetRx:     txBytes,
			NetTx:     txBytes,
		}

		<-m.emitter.Emit("monitor.report", report)
		time.Sleep(1 * time.Second)
	}
}
<commit_msg>update to debug<commit_after>package monitor

import (
	"errors"
	"fmt"
	"time"

	docker "github.com/ncodes/go-dockerclient"
	"github.com/olebedev/emitter"
	logging "github.com/op/go-logging"
)

var log = logging.MustGetLogger("launcher.monitor")

// ErrNoContainerFound represents a error about not finding containers
var ErrNoContainerFound = errors.New("no container found")

// HandleFunc is the expected function signature
type HandleFunc func(map[string]interface{})

// Report represents the result of the monitors checks
type Report struct {
	DiskUsage int64
	NetTx     uint64
	NetRx     uint64
}

// Monitor defines a launcher monitor module checking resource
// useage of a cocoon code. This module provides a pubsub feature that allows
// other external modules to subscribe to events from it and to also emit events to
// the module.
type Monitor struct {
	emitter     *emitter.Emitter
	containerID string
	stop        bool
	dckClient   *docker.Client
}

// NewMonitor creates a new monitor instance.
func NewMonitor() *Monitor {
	e := emitter.New(10)
	return &Monitor{
		emitter: e,
	}
}

// SetContainerID sets the id of the container to monitor
func (m *Monitor) SetContainerID(cID string) {
	m.containerID = cID
}

// SetDockerClient sets the docker client
func (m *Monitor) SetDockerClient(dckClient *docker.Client) {
	m.dckClient = dckClient
}

// GetEmitter returns the monitor's emitter
func (m *Monitor) GetEmitter() *emitter.Emitter {
	return m.emitter
}

// Stop the monitor
func (m *Monitor) Stop() {
	m.stop = true
	m.emitter.Off("*")
}

// Reset resets the monitor
func (m *Monitor) Reset() {
	m.Stop()
	m.emitter = emitter.New(10)
	m.stop = false
}

// getContainerRootSize fetches the total
// size of all the files in the container.
func (m *Monitor) getContainerRootSize() (int64, error) {
	containers, err := m.dckClient.ListContainers(docker.ListContainersOptions{
		All:   true,
		Size:  true,
		Limit: 1,
		Filters: map[string][]string{
			"id": []string{m.containerID},
		},
	})
	if err != nil {
		return 0, fmt.Errorf("failed to list containers. %s", err)
	}

	if len(containers) == 0 {
		return 0, ErrNoContainerFound
	}

	return containers[0].SizeRw, nil
}

// getContainerNetworkIO returns the current Net IO usage of the container
func (m *Monitor) getContainerNetworkIO() (uint64, uint64, error) {
	var stats = make(chan *docker.Stats)
	var done = make(chan bool)
	go func() {
		m.dckClient.Stats(docker.StatsOptions{
			ID:      m.containerID,
			Stats:   stats,
			Timeout: 5 * time.Second,
			Done:    done,
		})
	}()

	for s := range stats {
		close(done)
		rxBytes := uint64(0)
		txBytes := uint64(0)
		for _, n := range s.Networks {
			rxBytes += n.RxBytes
			txBytes += n.TxBytes
		}
		return rxBytes, txBytes, nil
	}

	return 0, 0, nil
}

// Monitor starts the monitor
func (m *Monitor) Monitor() {
	for !m.stop {

		size, err := m.getContainerRootSize()
		if err != nil && err != ErrNoContainerFound {
			log.Error(err.Error())
		}

		rxBytes, txBytes, err := m.getContainerNetworkIO()
		if err != nil {
			log.Error(err.Error())
		}

		log.Debugf("Rx Bytes: %d / Tx Bytes: %d", rxBytes, txBytes)

		report := Report{
			DiskUsage: size,
			NetRx:     txBytes,
			NetTx:     txBytes,
		}

		<-m.emitter.Emit("monitor.report", report)
		time.Sleep(1 * time.Second)
	}
}
<|endoftext|>


<commit_before>package middleware

import (
	"net/http"
	"time"

	"code.cloudfoundry.org/lager"
	"code.cloudfoundry.org/runtimeschema/metric"
)

const (
	requestLatency = metric.Duration("RequestLatency")
	requestCount   = metric.Counter("RequestCount")
)

type LoggableHandlerFunc func(logger lager.Logger, w http.ResponseWriter, r *http.Request)

func LogWrap(logger, accessLogger lager.Logger, loggableHandlerFunc LoggableHandlerFunc) http.HandlerFunc {
	lagerDataFromReq := func(r *http.Request) lager.Data {
		return lager.Data{
			"method":  r.Method,
			"request": r.URL.String(),
		}
	}

	if accessLogger != nil {
		return func(w http.ResponseWriter, r *http.Request) {
			requestLog := logger.Session("request", lagerDataFromReq(r))
			requestAccessLogger := accessLogger.Session("request", lagerDataFromReq(r))

			requestAccessLogger.Info("serving")
			requestLog.Debug("serving")

			loggableHandlerFunc(requestLog, w, r)

			requestAccessLogger.Info("done")
			requestLog.Debug("done")
		}
	} else {
		return func(w http.ResponseWriter, r *http.Request) {
			requestLog := logger.Session("request", lagerDataFromReq(r))

			requestLog.Debug("serving")

			loggableHandlerFunc(requestLog, w, r)

			requestLog.Debug("done")
		}
	}
}

func NewLatencyEmitter(logger lager.Logger) LatencyEmitter {
	return LatencyEmitter{
		logger: logger,
	}
}

type LatencyEmitter struct {
	logger lager.Logger
}

func (l LatencyEmitter) EmitLatency(f http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		startTime := time.Now()
		f(w, r)
		err := requestLatency.Send(time.Since(startTime))
		if err != nil {
			l.logger.Error("failed-to-send-request-latency-metric", err)
		}
	}
}

func RequestCountWrap(handler http.Handler) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		requestCount.Increment()
		handler.ServeHTTP(w, r)
	}
}
<commit_msg>include the request duration in the access log<commit_after>package middleware

import (
	"net/http"
	"time"

	"code.cloudfoundry.org/lager"
	"code.cloudfoundry.org/runtimeschema/metric"
)

const (
	requestLatency = metric.Duration("RequestLatency")
	requestCount   = metric.Counter("RequestCount")
)

type LoggableHandlerFunc func(logger lager.Logger, w http.ResponseWriter, r *http.Request)

func LogWrap(logger, accessLogger lager.Logger, loggableHandlerFunc LoggableHandlerFunc) http.HandlerFunc {
	lagerDataFromReq := func(r *http.Request) lager.Data {
		return lager.Data{
			"method":  r.Method,
			"request": r.URL.String(),
		}
	}

	if accessLogger != nil {
		return func(w http.ResponseWriter, r *http.Request) {
			requestLog := logger.Session("request", lagerDataFromReq(r))
			requestAccessLogger := accessLogger.Session("request", lagerDataFromReq(r))

			requestAccessLogger.Info("serving")
			requestLog.Debug("serving")

			start := time.Now()
			loggableHandlerFunc(requestLog, w, r)

			defer requestAccessLogger.Info("done", lager.Data{"duration": time.Since(start)})
			defer requestLog.Debug("done")
		}
	} else {
		return func(w http.ResponseWriter, r *http.Request) {
			requestLog := logger.Session("request", lagerDataFromReq(r))

			requestLog.Debug("serving")

			loggableHandlerFunc(requestLog, w, r)

			defer requestLog.Debug("done")
		}
	}
}

func NewLatencyEmitter(logger lager.Logger) LatencyEmitter {
	return LatencyEmitter{
		logger: logger,
	}
}

type LatencyEmitter struct {
	logger lager.Logger
}

func (l LatencyEmitter) EmitLatency(f http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		startTime := time.Now()
		f(w, r)
		err := requestLatency.Send(time.Since(startTime))
		if err != nil {
			l.logger.Error("failed-to-send-request-latency-metric", err)
		}
	}
}

func RequestCountWrap(handler http.Handler) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		requestCount.Increment()
		handler.ServeHTTP(w, r)
	}
}
<|endoftext|>


<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package http

// HTTP status codes, defined in RFC 2616.
const (
	StatusContinue           = 100
	StatusSwitchingProtocols = 101

	StatusOK                   = 200
	StatusCreated              = 201
	StatusAccepted             = 202
	StatusNonAuthoritativeInfo = 203
	StatusNoContent            = 204
	StatusResetContent         = 205
	StatusPartialContent       = 206

	StatusMultipleChoices   = 300
	StatusMovedPermanently  = 301
	StatusFound             = 302
	StatusSeeOther          = 303
	StatusNotModified       = 304
	StatusUseProxy          = 305
	StatusTemporaryRedirect = 307

	StatusBadRequest                   = 400
	StatusUnauthorized                 = 401
	StatusPaymentRequired              = 402
	StatusForbidden                    = 403
	StatusNotFound                     = 404
	StatusMethodNotAllowed             = 405
	StatusNotAcceptable                = 406
	StatusProxyAuthRequired            = 407
	StatusRequestTimeout               = 408
	StatusConflict                     = 409
	StatusGone                         = 410
	StatusLengthRequired               = 411
	StatusPreconditionFailed           = 412
	StatusRequestEntityTooLarge        = 413
	StatusRequestURITooLong            = 414
	StatusUnsupportedMediaType         = 415
	StatusRequestedRangeNotSatisfiable = 416
	StatusExpectationFailed            = 417
	StatusTeapot                       = 418
	StatusPreconditionRequired         = 428
	StatusTooManyRequests              = 429
	StatusRequestHeaderFieldsTooLarge  = 431
	StatusUnavailableForLegalReasons   = 451

	StatusInternalServerError           = 500
	StatusNotImplemented                = 501
	StatusBadGateway                    = 502
	StatusServiceUnavailable            = 503
	StatusGatewayTimeout                = 504
	StatusHTTPVersionNotSupported       = 505
	StatusNetworkAuthenticationRequired = 511
)

var statusText = map[int]string{
	StatusContinue:           "Continue",
	StatusSwitchingProtocols: "Switching Protocols",

	StatusOK:                   "OK",
	StatusCreated:              "Created",
	StatusAccepted:             "Accepted",
	StatusNonAuthoritativeInfo: "Non-Authoritative Information",
	StatusNoContent:            "No Content",
	StatusResetContent:         "Reset Content",
	StatusPartialContent:       "Partial Content",

	StatusMultipleChoices:   "Multiple Choices",
	StatusMovedPermanently:  "Moved Permanently",
	StatusFound:             "Found",
	StatusSeeOther:          "See Other",
	StatusNotModified:       "Not Modified",
	StatusUseProxy:          "Use Proxy",
	StatusTemporaryRedirect: "Temporary Redirect",

	StatusBadRequest:                   "Bad Request",
	StatusUnauthorized:                 "Unauthorized",
	StatusPaymentRequired:              "Payment Required",
	StatusForbidden:                    "Forbidden",
	StatusNotFound:                     "Not Found",
	StatusMethodNotAllowed:             "Method Not Allowed",
	StatusNotAcceptable:                "Not Acceptable",
	StatusProxyAuthRequired:            "Proxy Authentication Required",
	StatusRequestTimeout:               "Request Timeout",
	StatusConflict:                     "Conflict",
	StatusGone:                         "Gone",
	StatusLengthRequired:               "Length Required",
	StatusPreconditionFailed:           "Precondition Failed",
	StatusRequestEntityTooLarge:        "Request Entity Too Large",
	StatusRequestURITooLong:            "Request URI Too Long",
	StatusUnsupportedMediaType:         "Unsupported Media Type",
	StatusRequestedRangeNotSatisfiable: "Requested Range Not Satisfiable",
	StatusExpectationFailed:            "Expectation Failed",
	StatusTeapot:                       "I'm a teapot",
	StatusPreconditionRequired:         "Precondition Required",
	StatusTooManyRequests:              "Too Many Requests",
	StatusRequestHeaderFieldsTooLarge:  "Request Header Fields Too Large",
	StatusUnavailableForLegalReasons:   "Unavailable For Legal Reasons",

	StatusInternalServerError:           "Internal Server Error",
	StatusNotImplemented:                "Not Implemented",
	StatusBadGateway:                    "Bad Gateway",
	StatusServiceUnavailable:            "Service Unavailable",
	StatusGatewayTimeout:                "Gateway Timeout",
	StatusHTTPVersionNotSupported:       "HTTP Version Not Supported",
	StatusNetworkAuthenticationRequired: "Network Authentication Required",
}

// StatusText returns a text for the HTTP status code. It returns the empty
// string if the code is unknown.
func StatusText(code int) string {
	return statusText[code]
}
<commit_msg>net/http: add missing HTTP status codes<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package http

// HTTP status codes as registered with IANA.
// See: http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
const (
	StatusContinue           = 100 // RFC 7231, 6.2.1
	StatusSwitchingProtocols = 101 // RFC 7231, 6.2.2
	StatusProcessing         = 102 // RFC 2518, 10.1

	StatusOK                   = 200 // RFC 7231, 6.3.1
	StatusCreated              = 201 // RFC 7231, 6.3.2
	StatusAccepted             = 202 // RFC 7231, 6.3.3
	StatusNonAuthoritativeInfo = 203 // RFC 7231, 6.3.4
	StatusNoContent            = 204 // RFC 7231, 6.3.5
	StatusResetContent         = 205 // RFC 7231, 6.3.6
	StatusPartialContent       = 206 // RFC 7233, 4.1
	StatusMultiStatus          = 207 // RFC 4918, 11.1
	StatusAlreadyReported      = 208 // RFC 5842, 7.1
	StatusIMUsed               = 226 // RFC 3229, 10.4.1

	StatusMultipleChoices   = 300 // RFC 7231, 6.4.1
	StatusMovedPermanently  = 301 // RFC 7231, 6.4.2
	StatusFound             = 302 // RFC 7231, 6.4.3
	StatusSeeOther          = 303 // RFC 7231, 6.4.4
	StatusNotModified       = 304 // RFC 7232, 4.1
	StatusUseProxy          = 305 // RFC 7231, 6.4.5
	_                       = 306 // RFC 7231, 6.4.6 (Unused)
	StatusTemporaryRedirect = 307 // RFC 7231, 6.4.7
	StatusPermanentRedirect = 308 // RFC 7538, 3

	StatusBadRequest                   = 400 // RFC 7231, 6.5.1
	StatusUnauthorized                 = 401 // RFC 7235, 3.1
	StatusPaymentRequired              = 402 // RFC 7231, 6.5.2
	StatusForbidden                    = 403 // RFC 7231, 6.5.3
	StatusNotFound                     = 404 // RFC 7231, 6.5.4
	StatusMethodNotAllowed             = 405 // RFC 7231, 6.5.5
	StatusNotAcceptable                = 406 // RFC 7231, 6.5.6
	StatusProxyAuthRequired            = 407 // RFC 7235, 3.2
	StatusRequestTimeout               = 408 // RFC 7231, 6.5.7
	StatusConflict                     = 409 // RFC 7231, 6.5.8
	StatusGone                         = 410 // RFC 7231, 6.5.9
	StatusLengthRequired               = 411 // RFC 7231, 6.5.10
	StatusPreconditionFailed           = 412 // RFC 7232, 4.2
	StatusRequestEntityTooLarge        = 413 // RFC 7231, 6.5.11
	StatusRequestURITooLong            = 414 // RFC 7231, 6.5.12
	StatusUnsupportedMediaType         = 415 // RFC 7231, 6.5.13
	StatusRequestedRangeNotSatisfiable = 416 // RFC 7233, 4.4
	StatusExpectationFailed            = 417 // RFC 7231, 6.5.14
	StatusTeapot                       = 418 // RFC 7168, 2.3.3
	StatusUnprocessableEntity          = 422 // RFC 4918, 11.2
	StatusLocked                       = 423 // RFC 4918, 11.3
	StatusFailedDependency             = 424 // RFC 4918, 11.4
	StatusUpgradeRequired              = 426 // RFC 7231, 6.5.15
	StatusPreconditionRequired         = 428 // RFC 6585, 3
	StatusTooManyRequests              = 429 // RFC 6585, 4
	StatusRequestHeaderFieldsTooLarge  = 431 // RFC 6585, 5
	StatusUnavailableForLegalReasons   = 451 // RFC 7725, 3

	StatusInternalServerError           = 500 // RFC 7231, 6.6.1
	StatusNotImplemented                = 501 // RFC 7231, 6.6.2
	StatusBadGateway                    = 502 // RFC 7231, 6.6.3
	StatusServiceUnavailable            = 503 // RFC 7231, 6.6.4
	StatusGatewayTimeout                = 504 // RFC 7231, 6.6.5
	StatusHTTPVersionNotSupported       = 505 // RFC 7231, 6.6.6
	StatusVariantAlsoNegotiates         = 506 // RFC 2295, 8.1
	StatusInsufficientStorage           = 507 // RFC 4918, 11.5
	StatusLoopDetected                  = 508 // RFC 5842, 7.2
	StatusNotExtended                   = 510 // RFC 2774, 7
	StatusNetworkAuthenticationRequired = 511 // RFC 6585, 6
)

var statusText = map[int]string{
	StatusContinue:           "Continue",
	StatusSwitchingProtocols: "Switching Protocols",
	StatusProcessing:         "Processing",

	StatusOK:                   "OK",
	StatusCreated:              "Created",
	StatusAccepted:             "Accepted",
	StatusNonAuthoritativeInfo: "Non-Authoritative Information",
	StatusNoContent:            "No Content",
	StatusResetContent:         "Reset Content",
	StatusPartialContent:       "Partial Content",
	StatusMultiStatus:          "Multi-Status",
	StatusAlreadyReported:      "Already Reported",
	StatusIMUsed:               "IM Used",

	StatusMultipleChoices:   "Multiple Choices",
	StatusMovedPermanently:  "Moved Permanently",
	StatusFound:             "Found",
	StatusSeeOther:          "See Other",
	StatusNotModified:       "Not Modified",
	StatusUseProxy:          "Use Proxy",
	StatusTemporaryRedirect: "Temporary Redirect",
	StatusPermanentRedirect: "Permanent Redirect",

	StatusBadRequest:                   "Bad Request",
	StatusUnauthorized:                 "Unauthorized",
	StatusPaymentRequired:              "Payment Required",
	StatusForbidden:                    "Forbidden",
	StatusNotFound:                     "Not Found",
	StatusMethodNotAllowed:             "Method Not Allowed",
	StatusNotAcceptable:                "Not Acceptable",
	StatusProxyAuthRequired:            "Proxy Authentication Required",
	StatusRequestTimeout:               "Request Timeout",
	StatusConflict:                     "Conflict",
	StatusGone:                         "Gone",
	StatusLengthRequired:               "Length Required",
	StatusPreconditionFailed:           "Precondition Failed",
	StatusRequestEntityTooLarge:        "Request Entity Too Large",
	StatusRequestURITooLong:            "Request URI Too Long",
	StatusUnsupportedMediaType:         "Unsupported Media Type",
	StatusRequestedRangeNotSatisfiable: "Requested Range Not Satisfiable",
	StatusExpectationFailed:            "Expectation Failed",
	StatusTeapot:                       "I'm a teapot",
	StatusUnprocessableEntity:          "Unprocessable Entity",
	StatusLocked:                       "Locked",
	StatusFailedDependency:             "Failed Dependency",
	StatusUpgradeRequired:              "Upgrade Required",
	StatusPreconditionRequired:         "Precondition Required",
	StatusTooManyRequests:              "Too Many Requests",
	StatusRequestHeaderFieldsTooLarge:  "Request Header Fields Too Large",
	StatusUnavailableForLegalReasons:   "Unavailable For Legal Reasons",

	StatusInternalServerError:           "Internal Server Error",
	StatusNotImplemented:                "Not Implemented",
	StatusBadGateway:                    "Bad Gateway",
	StatusServiceUnavailable:            "Service Unavailable",
	StatusGatewayTimeout:                "Gateway Timeout",
	StatusHTTPVersionNotSupported:       "HTTP Version Not Supported",
	StatusVariantAlsoNegotiates:         "Variant Also Negotiates",
	StatusInsufficientStorage:           "Insufficient Storage",
	StatusLoopDetected:                  "Loop Detected",
	StatusNotExtended:                   "Not Extended",
	StatusNetworkAuthenticationRequired: "Network Authentication Required",
}

// StatusText returns a text for the HTTP status code. It returns the empty
// string if the code is unknown.
func StatusText(code int) string {
	return statusText[code]
}
<|endoftext|>


<commit_before>// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package net

import (
	"os"
	"syscall"
)

// This was copied from sockopt_linux.go

func setDefaultSockopts(s, family, sotype int, ipv6only bool) error {
	if family == syscall.AF_INET6 && sotype != syscall.SOCK_RAW {
		// Allow both IP versions even if the OS default
		// is otherwise. Note that some operating systems
		// never admit this option.
		syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, boolint(ipv6only))
	}
	// Allow broadcast.
	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1))
}

func setDefaultListenerSockopts(s int) error {
	// Allow reuse of recently-used addresses.
	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1))
}

func setDefaultMulticastSockopts(s int) error {
	// Allow multicast UDP and raw IP datagram sockets to listen
	// concurrently across multiple listeners.
	if err := syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil {
		return os.NewSyscallError("setsockopt", err)
	}
	// Allow reuse of recently-used ports.
	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEPORT, 1))
}
<commit_msg>net: drop confusing comment<commit_after>// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package net

import (
	"os"
	"syscall"
)

func setDefaultSockopts(s, family, sotype int, ipv6only bool) error {
	if family == syscall.AF_INET6 && sotype != syscall.SOCK_RAW {
		// Allow both IP versions even if the OS default
		// is otherwise. Note that some operating systems
		// never admit this option.
		syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, boolint(ipv6only))
	}
	// Allow broadcast.
	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1))
}

func setDefaultListenerSockopts(s int) error {
	// Allow reuse of recently-used addresses.
	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1))
}

func setDefaultMulticastSockopts(s int) error {
	// Allow multicast UDP and raw IP datagram sockets to listen
	// concurrently across multiple listeners.
	if err := syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil {
		return os.NewSyscallError("setsockopt", err)
	}
	// Allow reuse of recently-used ports.
	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEPORT, 1))
}
<|endoftext|>


<commit_before>package pki

import (
	"encoding/json"
	"fmt"

	"context"

	"github.com/gorilla/mux"
	"github.com/grpc-ecosystem/grpc-gateway/runtime"
	"github.com/spf13/cobra"

	abci "github.com/tendermint/tendermint/abci/types"

	"github.com/cosmos/cosmos-sdk/client"
	"github.com/cosmos/cosmos-sdk/codec"
	cdctypes "github.com/cosmos/cosmos-sdk/codec/types"
	sdk "github.com/cosmos/cosmos-sdk/types"
	"github.com/cosmos/cosmos-sdk/types/module"
	"github.com/zigbee-alliance/distributed-compliance-ledger/x/pki/client/cli"
	"github.com/zigbee-alliance/distributed-compliance-ledger/x/pki/keeper"
	"github.com/zigbee-alliance/distributed-compliance-ledger/x/pki/types"
)

var (
	_ module.AppModule      = AppModule{}
	_ module.AppModuleBasic = AppModuleBasic{}
)

// ----------------------------------------------------------------------------
// AppModuleBasic
// ----------------------------------------------------------------------------

// AppModuleBasic implements the AppModuleBasic interface for the capability module.
type AppModuleBasic struct {
	cdc codec.BinaryCodec
}

func NewAppModuleBasic(cdc codec.BinaryCodec) AppModuleBasic {
	return AppModuleBasic{cdc: cdc}
}

// Name returns the capability module's name.
func (AppModuleBasic) Name() string {
	return types.ModuleName
}

func (AppModuleBasic) RegisterCodec(cdc *codec.LegacyAmino) {
	types.RegisterCodec(cdc)
}

func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
	types.RegisterCodec(cdc)
}

// RegisterInterfaces registers the module's interface types
func (a AppModuleBasic) RegisterInterfaces(reg cdctypes.InterfaceRegistry) {
	types.RegisterInterfaces(reg)
}

// DefaultGenesis returns the capability module's default genesis state.
func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage {
	return cdc.MustMarshalJSON(types.DefaultGenesis())
}

// ValidateGenesis performs genesis state validation for the capability module.
func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error {
	var genState types.GenesisState
	if err := cdc.UnmarshalJSON(bz, &genState); err != nil {
		return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err)
	}
	return genState.Validate()
}

// RegisterRESTRoutes registers the capability module's REST service handlers.
func (AppModuleBasic) RegisterRESTRoutes(clientCtx client.Context, rtr *mux.Router) {
}

// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the module.
func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) {
	types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx))
}

// GetTxCmd returns the capability module's root tx command.
func (a AppModuleBasic) GetTxCmd() *cobra.Command {
	return cli.GetTxCmd()
}

// GetQueryCmd returns the capability module's root query command.
func (AppModuleBasic) GetQueryCmd() *cobra.Command {
	return cli.GetQueryCmd(types.StoreKey)
}

// ----------------------------------------------------------------------------
// AppModule
// ----------------------------------------------------------------------------

// AppModule implements the AppModule interface for the capability module.
type AppModule struct {
	AppModuleBasic

	keeper keeper.Keeper
}

func NewAppModule(cdc codec.Codec, keeper keeper.Keeper) AppModule {
	return AppModule{
		AppModuleBasic: NewAppModuleBasic(cdc),
		keeper:         keeper,
	}
}

// Name returns the capability module's name.
func (am AppModule) Name() string {
	return am.AppModuleBasic.Name()
}

// Route returns the capability module's message routing key.
func (am AppModule) Route() sdk.Route {
	return sdk.NewRoute(types.RouterKey, NewHandler(am.keeper))
}

// QuerierRoute returns the capability module's query routing key.
func (AppModule) QuerierRoute() string { return types.QuerierRoute }

// LegacyQuerierHandler returns the capability module's Querier.
func (am AppModule) LegacyQuerierHandler(legacyQuerierCdc *codec.LegacyAmino) sdk.Querier {
	return nil
}

// RegisterServices registers a GRPC query service to respond to the
// module-specific GRPC queries.
func (am AppModule) RegisterServices(cfg module.Configurator) {
	types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper))
	types.RegisterQueryServer(cfg.QueryServer(), am.keeper)
}

// RegisterInvariants registers the capability module's invariants.
func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {}

// InitGenesis performs the capability module's genesis initialization It returns
// no validator updates.
func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, gs json.RawMessage) []abci.ValidatorUpdate {
	var genState types.GenesisState
	// Initialize global index to index in genesis state
	cdc.MustUnmarshalJSON(gs, &genState)

	InitGenesis(ctx, am.keeper, genState)

	return []abci.ValidatorUpdate{}
}

// ExportGenesis returns the capability module's exported genesis state as raw JSON bytes.
func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage {
	genState := ExportGenesis(ctx, am.keeper)
	return cdc.MustMarshalJSON(genState)
}

// ConsensusVersion implements ConsensusVersion.
func (AppModule) ConsensusVersion() uint64 { return 2 }

// BeginBlock executes all ABCI BeginBlock logic respective to the capability module.
func (am AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {}

// EndBlock executes all ABCI EndBlock logic respective to the capability module. It
// returns no validator updates.
func (am AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate {
	return []abci.ValidatorUpdate{}
}
<commit_msg>fix generated comments (module name)<commit_after>package pki

import (
	"encoding/json"
	"fmt"

	"context"

	"github.com/gorilla/mux"
	"github.com/grpc-ecosystem/grpc-gateway/runtime"
	"github.com/spf13/cobra"

	abci "github.com/tendermint/tendermint/abci/types"

	"github.com/cosmos/cosmos-sdk/client"
	"github.com/cosmos/cosmos-sdk/codec"
	cdctypes "github.com/cosmos/cosmos-sdk/codec/types"
	sdk "github.com/cosmos/cosmos-sdk/types"
	"github.com/cosmos/cosmos-sdk/types/module"
	"github.com/zigbee-alliance/distributed-compliance-ledger/x/pki/client/cli"
	"github.com/zigbee-alliance/distributed-compliance-ledger/x/pki/keeper"
	"github.com/zigbee-alliance/distributed-compliance-ledger/x/pki/types"
)

var (
	_ module.AppModule      = AppModule{}
	_ module.AppModuleBasic = AppModuleBasic{}
)

// ----------------------------------------------------------------------------
// AppModuleBasic
// ----------------------------------------------------------------------------

// AppModuleBasic implements the AppModuleBasic interface for the pki module.
type AppModuleBasic struct {
	cdc codec.BinaryCodec
}

func NewAppModuleBasic(cdc codec.BinaryCodec) AppModuleBasic {
	return AppModuleBasic{cdc: cdc}
}

// Name returns the pki module's name.
func (AppModuleBasic) Name() string {
	return types.ModuleName
}

func (AppModuleBasic) RegisterCodec(cdc *codec.LegacyAmino) {
	types.RegisterCodec(cdc)
}

func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
	types.RegisterCodec(cdc)
}

// RegisterInterfaces registers the module's interface types
func (a AppModuleBasic) RegisterInterfaces(reg cdctypes.InterfaceRegistry) {
	types.RegisterInterfaces(reg)
}

// DefaultGenesis returns the pki module's default genesis state.
func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage {
	return cdc.MustMarshalJSON(types.DefaultGenesis())
}

// ValidateGenesis performs genesis state validation for the pki module.
func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error {
	var genState types.GenesisState
	if err := cdc.UnmarshalJSON(bz, &genState); err != nil {
		return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err)
	}
	return genState.Validate()
}

// RegisterRESTRoutes registers the pki module's REST service handlers.
func (AppModuleBasic) RegisterRESTRoutes(clientCtx client.Context, rtr *mux.Router) {
}

// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the module.
func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) {
	types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx))
}

// GetTxCmd returns the pki module's root tx command.
func (a AppModuleBasic) GetTxCmd() *cobra.Command {
	return cli.GetTxCmd()
}

// GetQueryCmd returns the pki module's root query command.
func (AppModuleBasic) GetQueryCmd() *cobra.Command {
	return cli.GetQueryCmd(types.StoreKey)
}

// ----------------------------------------------------------------------------
// AppModule
// ----------------------------------------------------------------------------

// AppModule implements the AppModule interface for the pki module.
type AppModule struct {
	AppModuleBasic

	keeper keeper.Keeper
}

func NewAppModule(cdc codec.Codec, keeper keeper.Keeper) AppModule {
	return AppModule{
		AppModuleBasic: NewAppModuleBasic(cdc),
		keeper:         keeper,
	}
}

// Name returns the pki module's name.
func (am AppModule) Name() string {
	return am.AppModuleBasic.Name()
}

// Route returns the pki module's message routing key.
func (am AppModule) Route() sdk.Route {
	return sdk.NewRoute(types.RouterKey, NewHandler(am.keeper))
}

// QuerierRoute returns the pki module's query routing key.
func (AppModule) QuerierRoute() string { return types.QuerierRoute }

// LegacyQuerierHandler returns the pki module's Querier.
func (am AppModule) LegacyQuerierHandler(legacyQuerierCdc *codec.LegacyAmino) sdk.Querier {
	return nil
}

// RegisterServices registers a GRPC query service to respond to the
// module-specific GRPC queries.
func (am AppModule) RegisterServices(cfg module.Configurator) {
	types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper))
	types.RegisterQueryServer(cfg.QueryServer(), am.keeper)
}

// RegisterInvariants registers the pki module's invariants.
func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {}

// InitGenesis performs the pki module's genesis initialization It returns
// no validator updates.
func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, gs json.RawMessage) []abci.ValidatorUpdate {
	var genState types.GenesisState
	// Initialize global index to index in genesis state
	cdc.MustUnmarshalJSON(gs, &genState)

	InitGenesis(ctx, am.keeper, genState)

	return []abci.ValidatorUpdate{}
}

// ExportGenesis returns the pki module's exported genesis state as raw JSON bytes.
func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage {
	genState := ExportGenesis(ctx, am.keeper)
	return cdc.MustMarshalJSON(genState)
}

// ConsensusVersion implements ConsensusVersion.
func (AppModule) ConsensusVersion() uint64 { return 2 }

// BeginBlock executes all ABCI BeginBlock logic respective to the pki module.
func (am AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {}

// EndBlock executes all ABCI EndBlock logic respective to the pki module. It
// returns no validator updates.
func (am AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate {
	return []abci.ValidatorUpdate{}
}
<|endoftext|>