<commit_before>package provisioning

import "github.com/jiasir/playback/command"

// OpenStack interface takes methods for provision OpenStack.
type OpenStack interface {
	// Prepare OpenStack basic environment.
	PrepareBasicEnvirionment()
	// Using playback-nic to setting the network for storage network.
	ConfigureStorageNetwork()
	// Deploy HAProxy and keepalived.
	LoadBalancer()
	// LBOptimize optimizing load balancer.
	LBOptimize()
	// Deploy MariaDB cluster.
	MariadbCluster()
	// Deploy RabbitMQ cluster.
	RabbtmqCluster()
	// Deploy Keystone HA.
	Keystone()
	// Format the disk for Swift storage, only support sdb1 and sdc1 currently.
	FormatDiskForSwift()
	// Deploy Swift storage.
	SwiftStorage()
	// Deploy Swift proxy HA.
	SwiftProxy()
	// Initial Swift rings.
	InitSwiftRings()
	// Distribute Swift ring configuration files.
	DistSwiftRingConf()
	// Finalize Swift installation.
	FinalizeSwift()
	// Deploy Glance HA.
	Glance()
	// Deploy Ceph admin node.
	CephAdmin()
	// Deploy the Ceph initial monitor.
	CephInitMon()
	// Deploy the Ceph clients.
	CephClient()
	// Add Ceph initial monitor(s) and gather the keys.
	GetCephKey()
	// Add Ceph OSDs.
	AddOSD()
	// Add Ceph monitors.
	AddCephMon()
	// Copy the Ceph keys to nodes.
	SyncCephKey()
	// Create the cinder ceph user and pool name.
	CephUserPool()
	// Deploy cinder-api.
	CinderAPI()
	// Deploy cinder-volume on controller node(Ceph backend).
	CinderVolume()
	// Restart volume service dependency to take effect for ceph backend.
	RestartCephDeps()
	// Deploy Nova controller.
	NovaController()
	// Deploy Horizon.
	Dashboard()
	// Deploy Nova computes.
	NovaComputes()
	// Deploy Legacy networking nova-network(FlatDHCP Only).
	NovaNetwork()
	// Deploy Orchestration components(heat).
	Heat()
	// Enable service auto start
	AutoStart()
	// Deploy Dns as a Service
	Designate()
	// Convert kvm to Docker(OPTIONAL)
	KvmToDocker()
}

// ExtraVars takes playback command line arguments.
type ExtraVars struct {
	// Ansible Playbook *.yml
	Playbook string
	// Vars: node_name
	NodeName string
	// Vars: host
	HostIP string
	// Vars: storage_ip
	StorageIP string
	// Vars: storage_mask
	StorageMask string
	// Vars: storage_network
	StorageNetwork string
	// Vars: storage_broadcast
	StorageBroadcast string
	// Command line playback-nic
	PlaybackNic PlaybackNic
	// Vars: host
	HostName string
	// Vars: router_id
	RouterID string
	// Vars: state
	State string
	// Vars: priority
	Priority string
	// Python scripts *.py
	PythonScript string
	// Vars: my_ip
	MyIP string
	// Vars: my_storage_ip
	MyStorageIP string
	// Vars: swift_storage_storage_ip
	SwiftStorageStorageIP string
	// Vars: device_name
	DeviceName string
	// Vars: device_weight
	DeviceWeight int
	// Vars: hosts
	Hosts string
	// Vars: client
	ClientName string
	// Vars: disk
	Disk string
	// Vars: partition
	Partition string
}

// PlaybackNic using playback-nic command instaed of openstack_interface.yml
type PlaybackNic struct {
	// Args: purge
	Purge bool
	// Args: public
	Public bool
	// Args: private
	Private bool
	// Args: host
	Host string
	// Args: user
	User string
	// Args: address
	Address string
	// Args: nic
	NIC string
	// Args: netmask
	Netmask string
	// Args: gateway
	Gateway string
	// Args: dns-nameservers
	DNS string
}

// ConfigureStorageNetwork takes playback-nic to set up the storage network.
// Purge the configuration and set address to 192.169.151.19 for eth1 of host 192.169.150.19 as public interface:
//	playback-nic --purge --public --host 192.169.150.19 --user ubuntu --address 192.169.151.19 --nic eth1 --netmask 255.255.255.0 --gateway 192.169.151.1 --dns-nameservers "192.169.11.11 192.169.11.12"
//Setting address to 192.168.1.12 for eth2 of host 192.169.150.19 as private interface:
//	playback-nic --private --host 192.169.150.19 --user ubuntu --address 192.168.1.12 --nic eth2 --netmask 255.255.255.0
func (vars ExtraVars) ConfigureStorageNetwork() error {
	if vars.PlaybackNic.Purge {
		if vars.PlaybackNic.Public {
			command.ExecuteWithOutput("playback-nic", "--purge", "--public", "--host", vars.PlaybackNic.Host, "--user", vars.PlaybackNic.User, "--address", vars.PlaybackNic.Address, "--nic", vars.PlaybackNic.NIC, "--netmask", vars.PlaybackNic.Netmask, "--gateway", vars.PlaybackNic.Gateway, "--dns-nameservers", vars.PlaybackNic.DNS)
		}
	}
	if vars.PlaybackNic.Private {
		command.ExecuteWithOutput("playback-nic", "--private", "--host", vars.PlaybackNic.Host, "--user", vars.PlaybackNic.Host, "--address", vars.PlaybackNic.Address, "--nic", vars.PlaybackNic.NIC, "--netmask", vars.PlaybackNic.Netmask)
	}
	return nil
}

// LoadBalancer deploy a HAProxy and Keepalived for OpenStack HA.
// The method takes the following command:
//  playback --ansible 'openstack_haproxy.yml --extra-vars "host=lb01 router_id=lb01 state=MASTER priority=150" -vvvv'
//  playback --ansible 'openstack_haproxy.yml --extra-vars "host=lb02 router_id=lb02 state=SLAVE priority=100" -vvvv'
func (vars ExtraVars) LoadBalancer() error {
	command.ExecuteWithOutput("playback", "--ansible", "openstack_haproxy.yml", "--extra-vars", "host="+vars.HostName, "router_id="+vars.RouterID, "state="+vars.State, "priority="+vars.Priority, "-vvvv")
	return nil
}

// LBOptimize optimizing load balancer.
// the method takes the floowing command:
//  python patch-limits.py
func (vars ExtraVars) LBOptimize() error {
	command.ExecuteWithOutput("python patch-limits.py")
	return nil
}

// PrepareBasicEnvirionment prepares OpenStack basic environment.
// The method takes the following command:
//  playback --ansible 'openstack_basic_environment.yml -vvvv'
func (vars ExtraVars) PrepareBasicEnvirionment() error {
	command.ExecuteWithOutput("playback", "--ansible", "openstack_basic_environment.yml", "-vvvv")
	return nil
}

// MariadbCluster deploy MariaDB Cluster.
// The method takes the following commands:
//  playback --ansible 'openstack_mariadb.yml --extra-vars "host=controller01 my_ip=192.169.151.19" -vvvv'
//  playback --ansible 'openstack_mariadb.yml --extra-vars "host=controller02 my_ip=192.169.151.17" -vvvv'
//  python keepalived.py
func (vars ExtraVars) MariadbCluster() error {
	command.ExecuteWithOutput("playback", "--ansible", "openstack_mariadb.yml", "--extra-vars", "host="+vars.HostName, "my_ip="+vars.MyIP, "-vvvv")
	if vars.HostName == "controller02" {
		command.ExecuteWithOutput("python keepalived.py")
	}
	return nil
}

// RabbtmqCluster deploy RabbitMQ Cluster.
// The method takes the following commands:
//  playback --ansible 'openstack_rabbitmq.yml --extra-vars "host=controller01" -vvvv'
//  playback --ansible 'openstack_rabbitmq.yml --extra-vars "host=controller02" -vvvv'
func (vars ExtraVars) RabbtmqCluster() error {
	command.ExecuteWithOutput("playback", "--ansible", "openstack_rabbitmq.yml", "--extra-vars", "host="+vars.HostName, "-vvvv")
	return nil
}

// Keystone method deploy the Keystone components.
// The method takes the following commands:
//  playback --ansible 'openstack_keystone.yml --extra-vars "host=controller01" -vvvv'
//  playback --ansible 'openstack_keystone.yml --extra-vars "host=controller02" -vvvv'
func (vars ExtraVars) Keystone() error {
	command.ExecuteWithOutput("playback", "--ansible", "openstack_keystone.yml", "--extra-vars", "host="+vars.HostName, "-vvvv")
	return nil
}

// FormatDiskForSwift formats devices for Swift Storage (sdb1 and sdc1).
// Each of the swift nodes, /dev/sdb1 and /dev/sdc1, must contain a suitable partition table with one partition occupying the entire device.
// Although the Object Storage service supports any file system with extended attributes (xattr), testing and benchmarking indicate the best performance and reliability on XFS.
// The method takes the folowing commands:
//  playback --ansible 'openstack_storage_partitions.yml --extra-vars "host=compute05" -vvvv'
//  playback --ansible 'openstack_storage_partitions.yml --extra-vars "host=compute06" -vvvv'
func (vars ExtraVars) FormatDiskForSwift() error {
	command.ExecuteWithOutput("playback", "--ansible", "openstack_storage_partitions.yml", "--extra-vars", "host="+vars.HostName, "-vvvv")
	return nil
}

// SwiftStorage deploy Swift storage.
// The method takes the following commands:
//  playback --ansible 'openstack_swift_storage.yml --extra-vars "host=compute05 my_storage_ip=192.168.1.16" -vvvv'
//  playback --ansible 'openstack_swift_storage.yml --extra-vars "host=compute06 my_storage_ip=192.168.1.15" -vvvv'
func (vars ExtraVars) SwiftStorage() error {
	command.ExecuteWithOutput("playback", "--ansible", "openstack_swift_storage.yml", "--extra-vars", "host="+vars.HostName, "my_storage_ip="+vars.MyStorageIP, "-vvvv")
	return nil
}

// SwiftProxy deploy Swift proxy HA.
func (vars ExtraVars) SwiftProxy() error {
	return nil
}

// InitSwiftRings initial Swift rings.
func (vars ExtraVars) InitSwiftRings() error {
	return nil
}

// DistSwiftRingConf destribute Swift ring configuration files.
func (vars ExtraVars) DistSwiftRingConf() error {
	return nil
}

// FinalizeSwift finalize Swift installation.
func (vars ExtraVars) FinalizeSwift() error {
	return nil
}

// Glance deploy Glance HA.
func (vars ExtraVars) Glance() error {
	return nil
}

// CephAdmin deploy the Ceph admin node.
func (vars ExtraVars) CephAdmin() error {
	return nil
}

// CephInitMon deploy the Ceph initial monitor.
func (vars ExtraVars) CephInitMon() error {
	return nil
}

// CephClient deploy the Ceph client.
func (vars ExtraVars) CephClient() error {
	return nil
}

// GetCephKey add Ceph initial monitors and gather the keys.
func (vars ExtraVars) GetCephKey() error {
	return nil
}

// AddOSD add the Ceph OSDs.
func (vars ExtraVars) AddOSD() error {
	return nil
}

// AddCephMon add the Ceph monitors.
func (vars ExtraVars) AddCephMon() error {
	return nil
}

// SyncCephKey copy the Ceph keys to nodes.
func (vars ExtraVars) SyncCephKey() error {
	return nil
}

// CephUserPool creates the cinder ceph user and pool name.
func (vars ExtraVars) CephUserPool() error {
	return nil
}

// CinderAPI deploy cinder-api.
func (vars ExtraVars) CinderAPI() error {
	return nil
}

// CinderVolume deploy cinder-volume on controller node(ceph backend).
func (vars ExtraVars) CinderVolume() error {
	return nil
}

// RestartCephDeps restart volume service dependency to take effect for ceph backend.
func (vars ExtraVars) RestartCephDeps() error {
	return nil
}

// NovaController deploy Nova controller.
func (vars ExtraVars) NovaController() error {
	return nil
}

// Dashboard deploy Horizon.
func (vars ExtraVars) Dashboard() error {
	return nil
}

// NovaComputes deploy Nova computes.
func (vars ExtraVars) NovaComputes() error {
	return nil
}

// NovaNetwork deploy legacy networking nova-network(FLATdhcp Only).
func (vars ExtraVars) NovaNetwork() error {
	return nil
}

// Heat deploy orchestration components(heat).
func (vars ExtraVars) Heat() error {
	return nil
}

// AutoStart fix the service can not auto start when sys booting.
func (vars ExtraVars) AutoStart() error {
	return nil
}

// Designate deploy DNS as a Service.
func (vars ExtraVars) Designate() error {
	return nil
}

// KvmToDocker converts kvm to docker(OPTIONAL).
func (vars ExtraVars) KvmToDocker() error {
	return nil
}
<commit_msg>Add Swift proxy<commit_after>package provisioning

import "github.com/jiasir/playback/command"

// OpenStack interface takes methods for provision OpenStack.
type OpenStack interface {
	// Prepare OpenStack basic environment.
	PrepareBasicEnvirionment()
	// Using playback-nic to setting the network for storage network.
	ConfigureStorageNetwork()
	// Deploy HAProxy and keepalived.
	LoadBalancer()
	// LBOptimize optimizing load balancer.
	LBOptimize()
	// Deploy MariaDB cluster.
	MariadbCluster()
	// Deploy RabbitMQ cluster.
	RabbtmqCluster()
	// Deploy Keystone HA.
	Keystone()
	// Format the disk for Swift storage, only support sdb1 and sdc1 currently.
	FormatDiskForSwift()
	// Deploy Swift storage.
	SwiftStorage()
	// Deploy Swift proxy HA.
	SwiftProxy()
	// Initial Swift rings.
	InitSwiftRings()
	// Distribute Swift ring configuration files.
	DistSwiftRingConf()
	// Finalize Swift installation.
	FinalizeSwift()
	// Deploy Glance HA.
	Glance()
	// Deploy Ceph admin node.
	CephAdmin()
	// Deploy the Ceph initial monitor.
	CephInitMon()
	// Deploy the Ceph clients.
	CephClient()
	// Add Ceph initial monitor(s) and gather the keys.
	GetCephKey()
	// Add Ceph OSDs.
	AddOSD()
	// Add Ceph monitors.
	AddCephMon()
	// Copy the Ceph keys to nodes.
	SyncCephKey()
	// Create the cinder ceph user and pool name.
	CephUserPool()
	// Deploy cinder-api.
	CinderAPI()
	// Deploy cinder-volume on controller node(Ceph backend).
	CinderVolume()
	// Restart volume service dependency to take effect for ceph backend.
	RestartCephDeps()
	// Deploy Nova controller.
	NovaController()
	// Deploy Horizon.
	Dashboard()
	// Deploy Nova computes.
	NovaComputes()
	// Deploy Legacy networking nova-network(FlatDHCP Only).
	NovaNetwork()
	// Deploy Orchestration components(heat).
	Heat()
	// Enable service auto start
	AutoStart()
	// Deploy Dns as a Service
	Designate()
	// Convert kvm to Docker(OPTIONAL)
	KvmToDocker()
}

// ExtraVars takes playback command line arguments.
type ExtraVars struct {
	// Ansible Playbook *.yml
	Playbook string
	// Vars: node_name
	NodeName string
	// Vars: host
	HostIP string
	// Vars: storage_ip
	StorageIP string
	// Vars: storage_mask
	StorageMask string
	// Vars: storage_network
	StorageNetwork string
	// Vars: storage_broadcast
	StorageBroadcast string
	// Command line playback-nic
	PlaybackNic PlaybackNic
	// Vars: host
	HostName string
	// Vars: router_id
	RouterID string
	// Vars: state
	State string
	// Vars: priority
	Priority string
	// Python scripts *.py
	PythonScript string
	// Vars: my_ip
	MyIP string
	// Vars: my_storage_ip
	MyStorageIP string
	// Vars: swift_storage_storage_ip
	SwiftStorageStorageIP string
	// Vars: device_name
	DeviceName string
	// Vars: device_weight
	DeviceWeight int
	// Vars: hosts
	Hosts string
	// Vars: client
	ClientName string
	// Vars: disk
	Disk string
	// Vars: partition
	Partition string
}

// PlaybackNic using playback-nic command instaed of openstack_interface.yml
type PlaybackNic struct {
	// Args: purge
	Purge bool
	// Args: public
	Public bool
	// Args: private
	Private bool
	// Args: host
	Host string
	// Args: user
	User string
	// Args: address
	Address string
	// Args: nic
	NIC string
	// Args: netmask
	Netmask string
	// Args: gateway
	Gateway string
	// Args: dns-nameservers
	DNS string
}

// ConfigureStorageNetwork takes playback-nic to set up the storage network.
// Purge the configuration and set address to 192.169.151.19 for eth1 of host 192.169.150.19 as public interface:
//	playback-nic --purge --public --host 192.169.150.19 --user ubuntu --address 192.169.151.19 --nic eth1 --netmask 255.255.255.0 --gateway 192.169.151.1 --dns-nameservers "192.169.11.11 192.169.11.12"
//Setting address to 192.168.1.12 for eth2 of host 192.169.150.19 as private interface:
//	playback-nic --private --host 192.169.150.19 --user ubuntu --address 192.168.1.12 --nic eth2 --netmask 255.255.255.0
func (vars ExtraVars) ConfigureStorageNetwork() error {
	if vars.PlaybackNic.Purge {
		if vars.PlaybackNic.Public {
			command.ExecuteWithOutput("playback-nic", "--purge", "--public", "--host", vars.PlaybackNic.Host, "--user", vars.PlaybackNic.User, "--address", vars.PlaybackNic.Address, "--nic", vars.PlaybackNic.NIC, "--netmask", vars.PlaybackNic.Netmask, "--gateway", vars.PlaybackNic.Gateway, "--dns-nameservers", vars.PlaybackNic.DNS)
		}
	}
	if vars.PlaybackNic.Private {
		command.ExecuteWithOutput("playback-nic", "--private", "--host", vars.PlaybackNic.Host, "--user", vars.PlaybackNic.Host, "--address", vars.PlaybackNic.Address, "--nic", vars.PlaybackNic.NIC, "--netmask", vars.PlaybackNic.Netmask)
	}
	return nil
}

// LoadBalancer deploy a HAProxy and Keepalived for OpenStack HA.
// The method takes the following command:
//  playback --ansible 'openstack_haproxy.yml --extra-vars "host=lb01 router_id=lb01 state=MASTER priority=150" -vvvv'
//  playback --ansible 'openstack_haproxy.yml --extra-vars "host=lb02 router_id=lb02 state=SLAVE priority=100" -vvvv'
func (vars ExtraVars) LoadBalancer() error {
	command.ExecuteWithOutput("playback", "--ansible", "openstack_haproxy.yml", "--extra-vars", "host="+vars.HostName, "router_id="+vars.RouterID, "state="+vars.State, "priority="+vars.Priority, "-vvvv")
	return nil
}

// LBOptimize optimizing load balancer.
// the method takes the floowing command:
//  python patch-limits.py
func (vars ExtraVars) LBOptimize() error {
	command.ExecuteWithOutput("python patch-limits.py")
	return nil
}

// PrepareBasicEnvirionment prepares OpenStack basic environment.
// The method takes the following command:
//  playback --ansible 'openstack_basic_environment.yml -vvvv'
func (vars ExtraVars) PrepareBasicEnvirionment() error {
	command.ExecuteWithOutput("playback", "--ansible", "openstack_basic_environment.yml", "-vvvv")
	return nil
}

// MariadbCluster deploy MariaDB Cluster.
// The method takes the following commands:
//  playback --ansible 'openstack_mariadb.yml --extra-vars "host=controller01 my_ip=192.169.151.19" -vvvv'
//  playback --ansible 'openstack_mariadb.yml --extra-vars "host=controller02 my_ip=192.169.151.17" -vvvv'
//  python keepalived.py
func (vars ExtraVars) MariadbCluster() error {
	command.ExecuteWithOutput("playback", "--ansible", "openstack_mariadb.yml", "--extra-vars", "host="+vars.HostName, "my_ip="+vars.MyIP, "-vvvv")
	if vars.HostName == "controller02" {
		command.ExecuteWithOutput("python keepalived.py")
	}
	return nil
}

// RabbtmqCluster deploy RabbitMQ Cluster.
// The method takes the following commands:
//  playback --ansible 'openstack_rabbitmq.yml --extra-vars "host=controller01" -vvvv'
//  playback --ansible 'openstack_rabbitmq.yml --extra-vars "host=controller02" -vvvv'
func (vars ExtraVars) RabbtmqCluster() error {
	command.ExecuteWithOutput("playback", "--ansible", "openstack_rabbitmq.yml", "--extra-vars", "host="+vars.HostName, "-vvvv")
	return nil
}

// Keystone method deploy the Keystone components.
// The method takes the following commands:
//  playback --ansible 'openstack_keystone.yml --extra-vars "host=controller01" -vvvv'
//  playback --ansible 'openstack_keystone.yml --extra-vars "host=controller02" -vvvv'
func (vars ExtraVars) Keystone() error {
	command.ExecuteWithOutput("playback", "--ansible", "openstack_keystone.yml", "--extra-vars", "host="+vars.HostName, "-vvvv")
	return nil
}

// FormatDiskForSwift formats devices for Swift Storage (sdb1 and sdc1).
// Each of the swift nodes, /dev/sdb1 and /dev/sdc1, must contain a suitable partition table with one partition occupying the entire device.
// Although the Object Storage service supports any file system with extended attributes (xattr), testing and benchmarking indicate the best performance and reliability on XFS.
// The method takes the folowing commands:
//  playback --ansible 'openstack_storage_partitions.yml --extra-vars "host=compute05" -vvvv'
//  playback --ansible 'openstack_storage_partitions.yml --extra-vars "host=compute06" -vvvv'
func (vars ExtraVars) FormatDiskForSwift() error {
	command.ExecuteWithOutput("playback", "--ansible", "openstack_storage_partitions.yml", "--extra-vars", "host="+vars.HostName, "-vvvv")
	return nil
}

// SwiftStorage deploy Swift storage.
// The method takes the following commands:
//  playback --ansible 'openstack_swift_storage.yml --extra-vars "host=compute05 my_storage_ip=192.168.1.16" -vvvv'
//  playback --ansible 'openstack_swift_storage.yml --extra-vars "host=compute06 my_storage_ip=192.168.1.15" -vvvv'
func (vars ExtraVars) SwiftStorage() error {
	command.ExecuteWithOutput("playback", "--ansible", "openstack_swift_storage.yml", "--extra-vars", "host="+vars.HostName, "my_storage_ip="+vars.MyStorageIP, "-vvvv")
	return nil
}

// SwiftProxy deploy Swift proxy HA.
// The method takes the following commands:
//  playback --ansible 'openstack_swift_proxy.yml --extra-vars "host=controller01" -vvvv'
//  playback --ansible 'openstack_swift_proxy.yml --extra-vars "host=controller02" -vvvv'
func (vars ExtraVars) SwiftProxy() error {
	command.ExecuteWithOutput("playback", "--ansible", "openstack_swift_proxy.yml", "--extra-vars", "host="+vars.HostName, "-vvvv")
	return nil
}

// InitSwiftRings initial Swift rings.
func (vars ExtraVars) InitSwiftRings() error {
	return nil
}

// DistSwiftRingConf destribute Swift ring configuration files.
func (vars ExtraVars) DistSwiftRingConf() error {
	return nil
}

// FinalizeSwift finalize Swift installation.
func (vars ExtraVars) FinalizeSwift() error {
	return nil
}

// Glance deploy Glance HA.
func (vars ExtraVars) Glance() error {
	return nil
}

// CephAdmin deploy the Ceph admin node.
func (vars ExtraVars) CephAdmin() error {
	return nil
}

// CephInitMon deploy the Ceph initial monitor.
func (vars ExtraVars) CephInitMon() error {
	return nil
}

// CephClient deploy the Ceph client.
func (vars ExtraVars) CephClient() error {
	return nil
}

// GetCephKey add Ceph initial monitors and gather the keys.
func (vars ExtraVars) GetCephKey() error {
	return nil
}

// AddOSD add the Ceph OSDs.
func (vars ExtraVars) AddOSD() error {
	return nil
}

// AddCephMon add the Ceph monitors.
func (vars ExtraVars) AddCephMon() error {
	return nil
}

// SyncCephKey copy the Ceph keys to nodes.
func (vars ExtraVars) SyncCephKey() error {
	return nil
}

// CephUserPool creates the cinder ceph user and pool name.
func (vars ExtraVars) CephUserPool() error {
	return nil
}

// CinderAPI deploy cinder-api.
func (vars ExtraVars) CinderAPI() error {
	return nil
}

// CinderVolume deploy cinder-volume on controller node(ceph backend).
func (vars ExtraVars) CinderVolume() error {
	return nil
}

// RestartCephDeps restart volume service dependency to take effect for ceph backend.
func (vars ExtraVars) RestartCephDeps() error {
	return nil
}

// NovaController deploy Nova controller.
func (vars ExtraVars) NovaController() error {
	return nil
}

// Dashboard deploy Horizon.
func (vars ExtraVars) Dashboard() error {
	return nil
}

// NovaComputes deploy Nova computes.
func (vars ExtraVars) NovaComputes() error {
	return nil
}

// NovaNetwork deploy legacy networking nova-network(FLATdhcp Only).
func (vars ExtraVars) NovaNetwork() error {
	return nil
}

// Heat deploy orchestration components(heat).
func (vars ExtraVars) Heat() error {
	return nil
}

// AutoStart fix the service can not auto start when sys booting.
func (vars ExtraVars) AutoStart() error {
	return nil
}

// Designate deploy DNS as a Service.
func (vars ExtraVars) Designate() error {
	return nil
}

// KvmToDocker converts kvm to docker(OPTIONAL).
func (vars ExtraVars) KvmToDocker() error {
	return nil
}
<|endoftext|>


<commit_before>package proxy

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"github.com/adamdecaf/go-proxy/codec"
	"golang.org/x/net/html"
	"io"
	"log"
)

type HTMLTransformer struct {
	Transformer
}

func (t HTMLTransformer) Transform(in Response) Response {
	doc, err := html.Parse(in.Reader)
	if err != nil {
		log.Printf("error parsing html document err=%s\n", err)
	}

	var f func(*html.Node)

	f = func(n *html.Node) {
		if n.Type == html.ElementNode && n.Data == "a" {
			for i, a := range n.Attr {
				if a.Key == "href" {
					// todo: need to resolve
					// relative (/about.html)
					// and
					// protcol dependent urls (//foo.com)
					a.Val = fmt.Sprintf("/url/%s", codec.ToBase64(a.Val))
				}
				n.Attr[i] = a
			}
		}
		for c := n.FirstChild; c != nil; c = c.NextSibling {
			f(c)
		}
	}

	f(doc)

	out := new(bytes.Buffer)
	err = html.Render(out, doc)
	if err != nil {
		// log.Printf
		return in
	}

	buff := []io.Reader{out}
	combined := io.MultiReader(buff...)

	return Response{
		Reader: combined,
	}
}

// `encodeBase64` returns a UTF-8 string in it's base64 encoding
func encodeBase64(s string) string {
	bytes := []byte(s)
	return base64.StdEncoding.EncodeToString(bytes)
}

func copyNode(old *html.Node) *html.Node {
	n := new(html.Node)
	n.Type = old.Type
	n.DataAtom = old.DataAtom
	n.Data = old.Data
	n.Attr = make([]html.Attribute, len(old.Attr))
	copy(n.Attr, old.Attr)
	for c := old.FirstChild; c != nil; c = c.NextSibling {
		nc := copyNode(c)
		n.AppendChild(nc)
	}
	return n
}

func replaceNode(old, new *html.Node) *html.Node {
	parent := old.Parent

	// nil would mean the root element
	if parent != nil {
		parent.InsertBefore(copyNode(new), old)
		parent.RemoveChild(old)
	}

	return new
}

func NewHTMLTransformer() Transformer {
	return HTMLTransformer{}
}
<commit_msg>proxy: Remove old code<commit_after>package proxy

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"github.com/adamdecaf/go-proxy/codec"
	"golang.org/x/net/html"
	"io"
	"log"
)

type HTMLTransformer struct {
	Transformer
}

func (t HTMLTransformer) Transform(in Response) Response {
	doc, err := html.Parse(in.Reader)
	if err != nil {
		log.Printf("error parsing html document err=%s\n", err)
	}

	var f func(*html.Node)

	f = func(n *html.Node) {
		if n.Type == html.ElementNode && n.Data == "a" {
			for i, a := range n.Attr {
				if a.Key == "href" {
					// todo: need to resolve
					// relative (/about.html)
					// and
					// protcol dependent urls (//foo.com)
					a.Val = fmt.Sprintf("/url/%s", codec.ToBase64(a.Val))
				}
				n.Attr[i] = a
			}
		}
		for c := n.FirstChild; c != nil; c = c.NextSibling {
			f(c)
		}
	}

	f(doc)

	out := new(bytes.Buffer)
	err = html.Render(out, doc)
	if err != nil {
		// log.Printf
		return in
	}

	buff := []io.Reader{out}
	combined := io.MultiReader(buff...)

	return Response{
		Reader: combined,
	}
}

// `encodeBase64` returns a UTF-8 string in it's base64 encoding
func encodeBase64(s string) string {
	bytes := []byte(s)
	return base64.StdEncoding.EncodeToString(bytes)
}

func NewHTMLTransformer() Transformer {
	return HTMLTransformer{}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"strconv"
	"strings"
	"sync"
	"syscall"

	"github.com/gorilla/mux"
	"github.com/gorilla/websocket"
	"gopkg.in/lxc/go-lxc.v2"

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

type consoleWs struct {
	// container currently worked on
	container container

	// uid to chown pty to
	rootUid int64

	// gid to chown pty to
	rootGid int64

	// websocket connections to bridge pty fds to
	conns map[int]*websocket.Conn

	// locks needed to access the "conns" member
	connsLock sync.Mutex

	// channel to wait until all websockets are properly connected
	allConnected chan bool

	// channel to wait until the control socket is connected
	controlConnected chan bool

	// map file descriptors -> secret
	fds map[int]string

	// terminal width
	width int

	// terminal height
	height int
}

func (s *consoleWs) Metadata() interface{} {
	fds := shared.Jmap{}
	for fd, secret := range s.fds {
		if fd == -1 {
			fds["control"] = secret
		} else {
			fds[strconv.Itoa(fd)] = secret
		}
	}

	return shared.Jmap{"fds": fds}
}

func (s *consoleWs) Connect(op *operation, r *http.Request, w http.ResponseWriter) error {
	secret := r.FormValue("secret")
	if secret == "" {
		return fmt.Errorf("missing secret")
	}

	for fd, fdSecret := range s.fds {
		if secret == fdSecret {
			conn, err := shared.WebsocketUpgrader.Upgrade(w, r, nil)
			if err != nil {
				return err
			}

			s.connsLock.Lock()
			s.conns[fd] = conn
			s.connsLock.Unlock()

			if fd == -1 {
				s.controlConnected <- true
				return nil
			}

			s.connsLock.Lock()
			for i, c := range s.conns {
				if i != -1 && c == nil {
					s.connsLock.Unlock()
					return nil
				}
			}
			s.connsLock.Unlock()

			s.allConnected <- true
			return nil
		}
	}

	/* If we didn't find the right secret, the user provided a bad one,
	 * which 403, not 404, since this operation actually exists */
	return os.ErrPermission
}

func (s *consoleWs) Do(op *operation) error {
	<-s.allConnected

	var err error
	master := &os.File{}
	slave := &os.File{}
	master, slave, err = shared.OpenPty(s.rootUid, s.rootGid)
	if err != nil {
		return err
	}

	if s.width > 0 && s.height > 0 {
		shared.SetSize(int(master.Fd()), s.width, s.height)
	}

	controlExit := make(chan bool)
	var wgEOF sync.WaitGroup

	wgEOF.Add(1)
	go func() {
		select {
		case <-s.controlConnected:
			break

		case <-controlExit:
			return
		}

		for {
			s.connsLock.Lock()
			conn := s.conns[-1]
			s.connsLock.Unlock()

			mt, r, err := conn.NextReader()
			if mt == websocket.CloseMessage {
				break
			}

			if err != nil {
				logger.Debugf("Got error getting next reader %s", err)
				break
			}

			buf, err := ioutil.ReadAll(r)
			if err != nil {
				logger.Debugf("Failed to read message %s", err)
				break
			}

			command := api.ContainerConsoleControl{}

			err = json.Unmarshal(buf, &command)
			if err != nil {
				logger.Debugf("Failed to unmarshal control socket command: %s", err)
				continue
			}

			if command.Command == "window-resize" {
				winchWidth, err := strconv.Atoi(command.Args["width"])
				if err != nil {
					logger.Debugf("Unable to extract window width: %s", err)
					continue
				}

				winchHeight, err := strconv.Atoi(command.Args["height"])
				if err != nil {
					logger.Debugf("Unable to extract window height: %s", err)
					continue
				}

				err = shared.SetSize(int(master.Fd()), winchWidth, winchHeight)
				if err != nil {
					logger.Debugf("Failed to set window size to: %dx%d", winchWidth, winchHeight)
					continue
				}

				logger.Debugf("Set window size to: %dx%d", winchWidth, winchHeight)
			}
		}
	}()

	go func() {
		s.connsLock.Lock()
		conn := s.conns[0]
		s.connsLock.Unlock()

		logger.Debugf("Starting to mirror websocket")
		readDone, writeDone := shared.WebsocketConsoleMirror(conn, master, master)

		<-readDone
		<-writeDone
		logger.Debugf("Finished to mirror websocket")

		conn.Close()
		wgEOF.Done()
	}()

	finisher := func(cmdErr error) error {
		slave.Close()

		s.connsLock.Lock()
		conn := s.conns[-1]
		s.connsLock.Unlock()

		if conn == nil {
			controlExit <- true
		}

		wgEOF.Wait()

		master.Close()

		return cmdErr
	}

	err = s.container.Console(slave)
	if err != nil {
		return err
	}

	return finisher(err)
}

func containerConsolePost(d *Daemon, r *http.Request) Response {
	name := mux.Vars(r)["name"]
	c, err := containerLoadByName(d.State(), name)
	if err != nil {
		return SmartError(err)
	}

	err = fmt.Errorf("Container is not running")
	if !c.IsRunning() {
		return BadRequest(err)
	}

	err = fmt.Errorf("Container is frozen")
	if c.IsFrozen() {
		return BadRequest(err)
	}

	post := api.ContainerConsolePost{}
	buf, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return BadRequest(err)
	}

	err = json.Unmarshal(buf, &post)
	if err != nil {
		return BadRequest(err)
	}

	ws := &consoleWs{}
	ws.fds = map[int]string{}

	idmapset, err := c.IdmapSet()
	if err != nil {
		return InternalError(err)
	}

	if idmapset != nil {
		ws.rootUid, ws.rootGid = idmapset.ShiftIntoNs(0, 0)
	}

	ws.conns = map[int]*websocket.Conn{}
	ws.conns[-1] = nil
	ws.conns[0] = nil
	for i := -1; i < len(ws.conns)-1; i++ {
		ws.fds[i], err = shared.RandomCryptoString()
		if err != nil {
			return InternalError(err)
		}
	}

	ws.allConnected = make(chan bool, 1)
	ws.controlConnected = make(chan bool, 1)

	ws.container = c
	ws.width = post.Width
	ws.height = post.Height

	resources := map[string][]string{}
	resources["containers"] = []string{ws.container.Name()}

	op, err := operationCreate(operationClassWebsocket, resources,
		ws.Metadata(), ws.Do, nil, ws.Connect)
	if err != nil {
		return InternalError(err)
	}

	return OperationResponse(op)
}

func containerConsoleLogGet(d *Daemon, r *http.Request) Response {
	name := mux.Vars(r)["name"]
	c, err := containerLoadByName(d.State(), name)
	if err != nil {
		return SmartError(err)
	}

	expandedConfig := c.ExpandedConfig()
	rawLxc := expandedConfig["raw.lxc"]

	consoleLogpath := ""
	for _, line := range strings.Split(rawLxc, "\n") {
		key, val, err := lxcParseRawLXC(line)
		if err != nil {
			return SmartError(err)
		}

		if key != "lxc.console.logfile" {
			continue
		}

		consoleLogpath = val
		break
	}

	logContents := ""
	console := lxc.ConsoleLogOptions{}

	ent := fileResponseEntry{}
	if !c.IsRunning() {
		if consoleLogpath == "" {
			return SmartError(fmt.Errorf("The container does not keep a console log"))
		}

		// Hand back the contents of the on-disk logfile.
		ent.path = consoleLogpath
		ent.filename = consoleLogpath
		goto onSuccess
	}

	// Container keeps an on-disk logfile so keep sync it here.
	if consoleLogpath != "" {
		console.WriteToLogFile = true
	} else {
		console.WriteToLogFile = false
	}

	// Query the container's console ringbuffer.
	console.ClearLog = false
	console.ReadLog = true
	console.ReadMax = 0

	// Send a ringbuffer request to the container.
	logContents, err = c.ConsoleLog(console)
	if err != nil {
		errno, isErrno := shared.GetErrno(err)
		if !isErrno {
			return SmartError(err)
		}

		if errno == syscall.ENODATA {
			goto onSuccess
		}

		if errno == syscall.EFAULT && consoleLogpath != "" {
			// Hand back the contents of the on-disk logfile.
			ent.path = consoleLogpath
			ent.filename = consoleLogpath
			goto onSuccess
		}

		return SmartError(err)
	}

	ent.buffer = []byte(logContents)

onSuccess:
	return FileResponse(r, []fileResponseEntry{ent}, nil, false)
}

func containerConsoleLogDelete(d *Daemon, r *http.Request) Response {
	name := mux.Vars(r)["name"]
	c, err := containerLoadByName(d.State(), name)
	if err != nil {
		return SmartError(err)
	}

	expandedConfig := c.ExpandedConfig()
	rawLxc := expandedConfig["raw.lxc"]

	consoleLogpath := ""
	for _, line := range strings.Split(rawLxc, "\n") {
		key, val, err := lxcParseRawLXC(line)
		if err != nil {
			return SmartError(err)
		}

		if key != "lxc.console.logfile" {
			continue
		}

		consoleLogpath = val
		break
	}

	// Check that this is a regular file. We don't want to try and unlink
	// /dev/stderr or /dev/null or something.
	st, err := os.Stat(consoleLogpath)
	if err != nil {
		return SmartError(err)
	}

	if !st.Mode().IsRegular() {
		return SmartError(fmt.Errorf("The console log is not a regular file"))
	}

	if consoleLogpath == "" {
		return SmartError(fmt.Errorf("Container does not keep a console logfile"))
	}

	return SmartError(os.Truncate(consoleLogpath, 0))
}
<commit_msg>containers: implement in-memory console log DELETE<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"strconv"
	"strings"
	"sync"
	"syscall"

	"github.com/gorilla/mux"
	"github.com/gorilla/websocket"
	"gopkg.in/lxc/go-lxc.v2"

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

type consoleWs struct {
	// container currently worked on
	container container

	// uid to chown pty to
	rootUid int64

	// gid to chown pty to
	rootGid int64

	// websocket connections to bridge pty fds to
	conns map[int]*websocket.Conn

	// locks needed to access the "conns" member
	connsLock sync.Mutex

	// channel to wait until all websockets are properly connected
	allConnected chan bool

	// channel to wait until the control socket is connected
	controlConnected chan bool

	// map file descriptors -> secret
	fds map[int]string

	// terminal width
	width int

	// terminal height
	height int
}

func (s *consoleWs) Metadata() interface{} {
	fds := shared.Jmap{}
	for fd, secret := range s.fds {
		if fd == -1 {
			fds["control"] = secret
		} else {
			fds[strconv.Itoa(fd)] = secret
		}
	}

	return shared.Jmap{"fds": fds}
}

func (s *consoleWs) Connect(op *operation, r *http.Request, w http.ResponseWriter) error {
	secret := r.FormValue("secret")
	if secret == "" {
		return fmt.Errorf("missing secret")
	}

	for fd, fdSecret := range s.fds {
		if secret == fdSecret {
			conn, err := shared.WebsocketUpgrader.Upgrade(w, r, nil)
			if err != nil {
				return err
			}

			s.connsLock.Lock()
			s.conns[fd] = conn
			s.connsLock.Unlock()

			if fd == -1 {
				s.controlConnected <- true
				return nil
			}

			s.connsLock.Lock()
			for i, c := range s.conns {
				if i != -1 && c == nil {
					s.connsLock.Unlock()
					return nil
				}
			}
			s.connsLock.Unlock()

			s.allConnected <- true
			return nil
		}
	}

	/* If we didn't find the right secret, the user provided a bad one,
	 * which 403, not 404, since this operation actually exists */
	return os.ErrPermission
}

func (s *consoleWs) Do(op *operation) error {
	<-s.allConnected

	var err error
	master := &os.File{}
	slave := &os.File{}
	master, slave, err = shared.OpenPty(s.rootUid, s.rootGid)
	if err != nil {
		return err
	}

	if s.width > 0 && s.height > 0 {
		shared.SetSize(int(master.Fd()), s.width, s.height)
	}

	controlExit := make(chan bool)
	var wgEOF sync.WaitGroup

	wgEOF.Add(1)
	go func() {
		select {
		case <-s.controlConnected:
			break

		case <-controlExit:
			return
		}

		for {
			s.connsLock.Lock()
			conn := s.conns[-1]
			s.connsLock.Unlock()

			mt, r, err := conn.NextReader()
			if mt == websocket.CloseMessage {
				break
			}

			if err != nil {
				logger.Debugf("Got error getting next reader %s", err)
				break
			}

			buf, err := ioutil.ReadAll(r)
			if err != nil {
				logger.Debugf("Failed to read message %s", err)
				break
			}

			command := api.ContainerConsoleControl{}

			err = json.Unmarshal(buf, &command)
			if err != nil {
				logger.Debugf("Failed to unmarshal control socket command: %s", err)
				continue
			}

			if command.Command == "window-resize" {
				winchWidth, err := strconv.Atoi(command.Args["width"])
				if err != nil {
					logger.Debugf("Unable to extract window width: %s", err)
					continue
				}

				winchHeight, err := strconv.Atoi(command.Args["height"])
				if err != nil {
					logger.Debugf("Unable to extract window height: %s", err)
					continue
				}

				err = shared.SetSize(int(master.Fd()), winchWidth, winchHeight)
				if err != nil {
					logger.Debugf("Failed to set window size to: %dx%d", winchWidth, winchHeight)
					continue
				}

				logger.Debugf("Set window size to: %dx%d", winchWidth, winchHeight)
			}
		}
	}()

	go func() {
		s.connsLock.Lock()
		conn := s.conns[0]
		s.connsLock.Unlock()

		logger.Debugf("Starting to mirror websocket")
		readDone, writeDone := shared.WebsocketConsoleMirror(conn, master, master)

		<-readDone
		<-writeDone
		logger.Debugf("Finished to mirror websocket")

		conn.Close()
		wgEOF.Done()
	}()

	finisher := func(cmdErr error) error {
		slave.Close()

		s.connsLock.Lock()
		conn := s.conns[-1]
		s.connsLock.Unlock()

		if conn == nil {
			controlExit <- true
		}

		wgEOF.Wait()

		master.Close()

		return cmdErr
	}

	err = s.container.Console(slave)
	if err != nil {
		return err
	}

	return finisher(err)
}

func containerConsolePost(d *Daemon, r *http.Request) Response {
	name := mux.Vars(r)["name"]
	c, err := containerLoadByName(d.State(), name)
	if err != nil {
		return SmartError(err)
	}

	err = fmt.Errorf("Container is not running")
	if !c.IsRunning() {
		return BadRequest(err)
	}

	err = fmt.Errorf("Container is frozen")
	if c.IsFrozen() {
		return BadRequest(err)
	}

	post := api.ContainerConsolePost{}
	buf, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return BadRequest(err)
	}

	err = json.Unmarshal(buf, &post)
	if err != nil {
		return BadRequest(err)
	}

	ws := &consoleWs{}
	ws.fds = map[int]string{}

	idmapset, err := c.IdmapSet()
	if err != nil {
		return InternalError(err)
	}

	if idmapset != nil {
		ws.rootUid, ws.rootGid = idmapset.ShiftIntoNs(0, 0)
	}

	ws.conns = map[int]*websocket.Conn{}
	ws.conns[-1] = nil
	ws.conns[0] = nil
	for i := -1; i < len(ws.conns)-1; i++ {
		ws.fds[i], err = shared.RandomCryptoString()
		if err != nil {
			return InternalError(err)
		}
	}

	ws.allConnected = make(chan bool, 1)
	ws.controlConnected = make(chan bool, 1)

	ws.container = c
	ws.width = post.Width
	ws.height = post.Height

	resources := map[string][]string{}
	resources["containers"] = []string{ws.container.Name()}

	op, err := operationCreate(operationClassWebsocket, resources,
		ws.Metadata(), ws.Do, nil, ws.Connect)
	if err != nil {
		return InternalError(err)
	}

	return OperationResponse(op)
}

func containerConsoleLogGet(d *Daemon, r *http.Request) Response {
	name := mux.Vars(r)["name"]
	c, err := containerLoadByName(d.State(), name)
	if err != nil {
		return SmartError(err)
	}

	expandedConfig := c.ExpandedConfig()
	rawLxc := expandedConfig["raw.lxc"]

	consoleLogpath := ""
	for _, line := range strings.Split(rawLxc, "\n") {
		key, val, err := lxcParseRawLXC(line)
		if err != nil {
			return SmartError(err)
		}

		if key != "lxc.console.logfile" {
			continue
		}

		consoleLogpath = val
		break
	}

	logContents := ""
	console := lxc.ConsoleLogOptions{}

	ent := fileResponseEntry{}
	if !c.IsRunning() {
		if consoleLogpath == "" {
			return SmartError(fmt.Errorf("The container does not keep a console log"))
		}

		// Hand back the contents of the on-disk logfile.
		ent.path = consoleLogpath
		ent.filename = consoleLogpath
		goto onSuccess
	}

	// Container keeps an on-disk logfile so keep sync it here.
	if consoleLogpath != "" {
		console.WriteToLogFile = true
	} else {
		console.WriteToLogFile = false
	}

	// Query the container's console ringbuffer.
	console.ClearLog = false
	console.ReadLog = true
	console.ReadMax = 0

	// Send a ringbuffer request to the container.
	logContents, err = c.ConsoleLog(console)
	if err != nil {
		errno, isErrno := shared.GetErrno(err)
		if !isErrno {
			return SmartError(err)
		}

		if errno == syscall.ENODATA {
			goto onSuccess
		}

		if errno == syscall.EFAULT && consoleLogpath != "" {
			// Hand back the contents of the on-disk logfile.
			ent.path = consoleLogpath
			ent.filename = consoleLogpath
			goto onSuccess
		}

		return SmartError(err)
	}

	ent.buffer = []byte(logContents)

onSuccess:
	return FileResponse(r, []fileResponseEntry{ent}, nil, false)
}

func containerConsoleLogDelete(d *Daemon, r *http.Request) Response {
	name := mux.Vars(r)["name"]
	c, err := containerLoadByName(d.State(), name)
	if err != nil {
		return SmartError(err)
	}

	expandedConfig := c.ExpandedConfig()
	rawLxc := expandedConfig["raw.lxc"]

	consoleLogpath := ""
	for _, line := range strings.Split(rawLxc, "\n") {
		key, val, err := lxcParseRawLXC(line)
		if err != nil {
			return SmartError(err)
		}

		if key != "lxc.console.logfile" {
			continue
		}

		consoleLogpath = val
		break
	}

	console := lxc.ConsoleLogOptions{
		ClearLog:       true,
		ReadLog:        false,
		ReadMax:        0,
		WriteToLogFile: false,
	}

	if !c.IsRunning() {
		if consoleLogpath == "" {
			return SmartError(fmt.Errorf("The container does not keep a console log"))
		}
		goto truncateOnDiskLogFile
	}

	// Send a ringbuffer request to the container.
	_, err = c.ConsoleLog(console)
	if err != nil {
		errno, isErrno := shared.GetErrno(err)
		if !isErrno {
			return SmartError(err)
		}

		if errno == syscall.ENODATA {
			return SmartError(nil)
		}

		if errno == syscall.EFAULT {
			if consoleLogpath == "" {
				return SmartError(fmt.Errorf("The container does not keep a console log"))
			}

			goto truncateOnDiskLogFile
		}

		return SmartError(err)
	}

	return SmartError(nil)

truncateOnDiskLogFile:
	// Check that this is a regular file. We don't want to try and unlink
	// /dev/stderr or /dev/null or something.
	st, err := os.Stat(consoleLogpath)
	if err != nil {
		return SmartError(err)
	}

	if !st.Mode().IsRegular() {
		return SmartError(fmt.Errorf("The console log is not a regular file"))
	}

	if consoleLogpath == "" {
		return SmartError(fmt.Errorf("Container does not keep a console logfile"))
	}

	return SmartError(os.Truncate(consoleLogpath, 0))
}
<|endoftext|>


<commit_before>package resources

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/pkg/errors"
	"golang.org/x/sys/unix"

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

var devDiskByPath = "/dev/disk/by-path"
var devDiskByID = "/dev/disk/by-id"
var runUdevData = "/run/udev/data"
var sysClassBlock = "/sys/class/block"

func storageAddDriveInfo(devicePath string, disk *api.ResourcesStorageDisk) error {
	// Attempt to open the device path
	f, err := os.Open(devicePath)
	if err == nil {
		defer f.Close()
		fd := int(f.Fd())

		// Retrieve the block size
		res, err := unix.IoctlGetInt(fd, unix.BLKPBSZGET)
		if err != nil {
			return err
		}

		disk.BlockSize = uint64(res)
	}

	// Retrieve udev information
	udevInfo := filepath.Join(runUdevData, fmt.Sprintf("b%s", disk.Device))
	if sysfsExists(udevInfo) {
		// Get the udev information
		f, err := os.Open(udevInfo)
		if err != nil {
			return errors.Wrapf(err, "Failed to open \"%s\"", udevInfo)
		}
		defer f.Close()

		udevProperties := map[string]string{}
		udevInfo := bufio.NewScanner(f)
		for udevInfo.Scan() {
			line := strings.TrimSpace(udevInfo.Text())

			if !strings.HasPrefix(line, "E:") {
				continue
			}

			fields := strings.SplitN(line, "=", 2)
			if len(fields) != 2 {
				continue
			}

			key := strings.TrimSpace(fields[0])
			value := strings.TrimSpace(fields[1])
			udevProperties[key] = value
		}

		// Finer grained disk type
		if udevProperties["E:ID_CDROM"] == "1" {
			disk.Type = "cdrom"
		} else if udevProperties["E:ID_USB_DRIVER"] == "usb-storage" {
			disk.Type = "usb"
		} else if udevProperties["E:ID_ATA_SATA"] == "1" {
			disk.Type = "sata"
		}

		// Firmware version (if not found in sysfs)
		if udevProperties["E:ID_REVISION"] != "" && disk.FirmwareVersion == "" {
			disk.FirmwareVersion = udevProperties["E:ID_REVISION"]
		}

		// Serial number
		if udevProperties["E:ID_SERIAL_SHORT"] != "" {
			disk.Serial = udevProperties["E:ID_SERIAL_SHORT"]
		}

		// Model number (attempt to get original string from encoded value)
		if udevProperties["E:ID_MODEL_ENC"] != "" {
			model, err := udevDecode(udevProperties["E:ID_MODEL_ENC"])
			if err == nil {
				// The raw value often has padding spaces, trim them.
				disk.Model = strings.TrimSpace(model)
			} else if udevProperties["E:ID_MODEL"] != "" {
				disk.Model = udevProperties["E:ID_MODEL"]
			}
		} else if udevProperties["E:ID_MODEL"] != "" {
			disk.Model = udevProperties["E:ID_MODEL"]
		}

		// Rotation per minute
		if udevProperties["E:ID_ATA_ROTATION_RATE_RPM"] != "" && disk.RPM == 0 {
			valueUint, err := strconv.ParseUint(udevProperties["E:ID_ATA_ROTATION_RATE_RPM"], 10, 64)
			if err != nil {
				return errors.Wrap(err, "Failed to parse RPM value")
			}

			disk.RPM = valueUint
		}
	}

	return nil
}

// GetStorage returns a filled api.ResourcesStorage struct ready for use by LXD
func GetStorage() (*api.ResourcesStorage, error) {
	storage := api.ResourcesStorage{}
	storage.Disks = []api.ResourcesStorageDisk{}

	// Detect all block devices
	if sysfsExists(sysClassBlock) {
		entries, err := ioutil.ReadDir(sysClassBlock)
		if err != nil {
			return nil, errors.Wrapf(err, "Failed to list \"%s\"", sysClassBlock)
		}

		// Iterate and add to our list
		for _, entry := range entries {
			entryName := entry.Name()
			entryPath := filepath.Join(sysClassBlock, entryName)
			devicePath := filepath.Join(entryPath, "device")

			// Only keep the main entries not partitions
			if !sysfsExists(devicePath) {
				continue
			}

			// Setup the entry
			disk := api.ResourcesStorageDisk{}
			disk.ID = entryName

			// Firmware revision
			if sysfsExists(filepath.Join(devicePath, "firmware_rev")) {
				firmwareRevision, err := ioutil.ReadFile(filepath.Join(devicePath, "firmware_rev"))
				if err != nil {
					return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(devicePath, "firmware_rev"))
				}

				disk.FirmwareVersion = strings.TrimSpace(string(firmwareRevision))
			}

			// Device node
			diskDev, err := ioutil.ReadFile(filepath.Join(entryPath, "dev"))
			if err != nil {
				if os.IsNotExist(err) {
					// This happens on multipath devices, just skip as we only care about the main node.
					continue
				}

				return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(entryPath, "dev"))
			}
			disk.Device = strings.TrimSpace(string(diskDev))

			// NUMA node
			if sysfsExists(filepath.Join(devicePath, "numa_node")) {
				numaNode, err := readInt(filepath.Join(devicePath, "numa_node"))
				if err != nil {
					return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(devicePath, "numa_node"))
				}

				if numaNode > 0 {
					disk.NUMANode = uint64(numaNode)
				}
			}

			// Disk model
			if sysfsExists(filepath.Join(devicePath, "model")) {
				diskModel, err := ioutil.ReadFile(filepath.Join(devicePath, "model"))
				if err != nil {
					return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(devicePath, "model"))
				}

				disk.Model = strings.TrimSpace(string(diskModel))
			}

			// Disk type
			if sysfsExists(filepath.Join(devicePath, "subsystem")) {
				diskSubsystem, err := filepath.EvalSymlinks(filepath.Join(devicePath, "subsystem"))
				if err != nil {
					return nil, errors.Wrapf(err, "Failed to track down \"%s\"", filepath.Join(devicePath, "subsystem"))
				}

				disk.Type = filepath.Base(diskSubsystem)
			}

			// Read-only
			diskRo, err := readUint(filepath.Join(entryPath, "ro"))
			if err != nil {
				return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(entryPath, "ro"))
			}
			disk.ReadOnly = diskRo == 1

			// Size
			diskSize, err := readUint(filepath.Join(entryPath, "size"))
			if err != nil {
				return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(entryPath, "size"))
			}
			disk.Size = diskSize * 512

			// Removable
			diskRemovable, err := readUint(filepath.Join(entryPath, "removable"))
			if err != nil {
				return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(entryPath, "removable"))
			}
			disk.Removable = diskRemovable == 1

			// WWN
			if sysfsExists(filepath.Join(entryPath, "wwid")) {
				diskWWN, err := ioutil.ReadFile(filepath.Join(entryPath, "wwid"))
				if err != nil {
					return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(entryPath, "wwid"))
				}
				disk.WWN = strings.TrimSpace(string(diskWWN))
			}

			// Try to guess if dealing with CD-ROM
			if strings.HasPrefix(disk.ID, "sr") && disk.Removable {
				disk.Type = "cdrom"

				// Most cdrom drives report this as size regardless of media
				if disk.Size == 0x1fffff*512 {
					disk.Size = 0
				}
			}

			// Look for partitions
			disk.Partitions = []api.ResourcesStorageDiskPartition{}
			for _, subEntry := range entries {
				subEntryName := subEntry.Name()
				subEntryPath := filepath.Join(sysClassBlock, subEntryName)

				if !strings.HasPrefix(subEntryName, entryName) {
					continue
				}

				if !sysfsExists(filepath.Join(subEntryPath, "partition")) {
					continue
				}

				// Setup the entry
				partition := api.ResourcesStorageDiskPartition{}
				partition.ID = subEntryName

				// Parse the partition number
				partitionNumber, err := readUint(filepath.Join(subEntryPath, "partition"))
				if err != nil {
					return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(subEntryPath, "partition"))
				}
				partition.Partition = partitionNumber

				// Device node
				partitionDev, err := ioutil.ReadFile(filepath.Join(subEntryPath, "dev"))
				if err != nil {
					return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(subEntryPath, "dev"))
				}
				partition.Device = strings.TrimSpace(string(partitionDev))

				// Read-only
				partitionRo, err := readUint(filepath.Join(subEntryPath, "ro"))
				if err != nil {
					return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(subEntryPath, "ro"))
				}
				partition.ReadOnly = partitionRo == 1

				// Size
				partitionSize, err := readUint(filepath.Join(subEntryPath, "size"))
				if err != nil {
					return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(subEntryPath, "size"))
				}
				partition.Size = partitionSize * 512

				// Add to list
				disk.Partitions = append(disk.Partitions, partition)
			}

			// Try to find the udev device path
			if sysfsExists(devDiskByPath) {
				links, err := ioutil.ReadDir(devDiskByPath)
				if err != nil {
					return nil, errors.Wrapf(err, "Failed to list the links in \"%s\"", devDiskByPath)
				}

				for _, link := range links {
					linkName := link.Name()
					linkPath := filepath.Join(devDiskByPath, linkName)

					linkTarget, err := filepath.EvalSymlinks(linkPath)
					if err != nil {
						return nil, errors.Wrapf(err, "Failed to track down \"%s\"", linkPath)
					}

					if linkTarget == filepath.Join("/dev", entryName) {
						disk.DevicePath = linkName
					}
				}
			}

			// Try to find the udev device id
			if sysfsExists(devDiskByID) {
				links, err := ioutil.ReadDir(devDiskByID)
				if err != nil {
					return nil, errors.Wrapf(err, "Failed to list the links in \"%s\"", devDiskByID)
				}

				for _, link := range links {
					linkName := link.Name()
					linkPath := filepath.Join(devDiskByID, linkName)

					linkTarget, err := filepath.EvalSymlinks(linkPath)
					if err != nil {
						return nil, errors.Wrapf(err, "Failed to track down \"%s\"", linkPath)
					}

					if linkTarget == filepath.Join("/dev", entryName) {
						disk.DeviceID = linkName
					}
				}
			}

			// Pull direct disk information
			err = storageAddDriveInfo(filepath.Join("/dev", entryName), &disk)
			if err != nil {
				return nil, errors.Wrapf(err, "Failed to retrieve disk information from \"%s\"", filepath.Join("/dev", entryName))
			}

			// Add to list
			storage.Disks = append(storage.Disks, disk)
		}
	}

	storage.Total = 0
	for _, card := range storage.Disks {
		if storage.Disks != nil {
			storage.Total += uint64(len(card.Partitions))
		}

		storage.Total++
	}

	return &storage, nil
}
<commit_msg>lxd/resources: Ignore rbd devices<commit_after>package resources

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/pkg/errors"
	"golang.org/x/sys/unix"

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

var devDiskByPath = "/dev/disk/by-path"
var devDiskByID = "/dev/disk/by-id"
var runUdevData = "/run/udev/data"
var sysClassBlock = "/sys/class/block"

func storageAddDriveInfo(devicePath string, disk *api.ResourcesStorageDisk) error {
	// Attempt to open the device path
	f, err := os.Open(devicePath)
	if err == nil {
		defer f.Close()
		fd := int(f.Fd())

		// Retrieve the block size
		res, err := unix.IoctlGetInt(fd, unix.BLKPBSZGET)
		if err != nil {
			return err
		}

		disk.BlockSize = uint64(res)
	}

	// Retrieve udev information
	udevInfo := filepath.Join(runUdevData, fmt.Sprintf("b%s", disk.Device))
	if sysfsExists(udevInfo) {
		// Get the udev information
		f, err := os.Open(udevInfo)
		if err != nil {
			return errors.Wrapf(err, "Failed to open \"%s\"", udevInfo)
		}
		defer f.Close()

		udevProperties := map[string]string{}
		udevInfo := bufio.NewScanner(f)
		for udevInfo.Scan() {
			line := strings.TrimSpace(udevInfo.Text())

			if !strings.HasPrefix(line, "E:") {
				continue
			}

			fields := strings.SplitN(line, "=", 2)
			if len(fields) != 2 {
				continue
			}

			key := strings.TrimSpace(fields[0])
			value := strings.TrimSpace(fields[1])
			udevProperties[key] = value
		}

		// Finer grained disk type
		if udevProperties["E:ID_CDROM"] == "1" {
			disk.Type = "cdrom"
		} else if udevProperties["E:ID_USB_DRIVER"] == "usb-storage" {
			disk.Type = "usb"
		} else if udevProperties["E:ID_ATA_SATA"] == "1" {
			disk.Type = "sata"
		}

		// Firmware version (if not found in sysfs)
		if udevProperties["E:ID_REVISION"] != "" && disk.FirmwareVersion == "" {
			disk.FirmwareVersion = udevProperties["E:ID_REVISION"]
		}

		// Serial number
		if udevProperties["E:ID_SERIAL_SHORT"] != "" {
			disk.Serial = udevProperties["E:ID_SERIAL_SHORT"]
		}

		// Model number (attempt to get original string from encoded value)
		if udevProperties["E:ID_MODEL_ENC"] != "" {
			model, err := udevDecode(udevProperties["E:ID_MODEL_ENC"])
			if err == nil {
				// The raw value often has padding spaces, trim them.
				disk.Model = strings.TrimSpace(model)
			} else if udevProperties["E:ID_MODEL"] != "" {
				disk.Model = udevProperties["E:ID_MODEL"]
			}
		} else if udevProperties["E:ID_MODEL"] != "" {
			disk.Model = udevProperties["E:ID_MODEL"]
		}

		// Rotation per minute
		if udevProperties["E:ID_ATA_ROTATION_RATE_RPM"] != "" && disk.RPM == 0 {
			valueUint, err := strconv.ParseUint(udevProperties["E:ID_ATA_ROTATION_RATE_RPM"], 10, 64)
			if err != nil {
				return errors.Wrap(err, "Failed to parse RPM value")
			}

			disk.RPM = valueUint
		}
	}

	return nil
}

// GetStorage returns a filled api.ResourcesStorage struct ready for use by LXD
func GetStorage() (*api.ResourcesStorage, error) {
	storage := api.ResourcesStorage{}
	storage.Disks = []api.ResourcesStorageDisk{}

	// Detect all block devices
	if sysfsExists(sysClassBlock) {
		entries, err := ioutil.ReadDir(sysClassBlock)
		if err != nil {
			return nil, errors.Wrapf(err, "Failed to list \"%s\"", sysClassBlock)
		}

		// Iterate and add to our list
		for _, entry := range entries {
			entryName := entry.Name()
			entryPath := filepath.Join(sysClassBlock, entryName)
			devicePath := filepath.Join(entryPath, "device")

			// Only keep the main entries not partitions
			if !sysfsExists(devicePath) {
				continue
			}

			// Setup the entry
			disk := api.ResourcesStorageDisk{}
			disk.ID = entryName

			// Firmware revision
			if sysfsExists(filepath.Join(devicePath, "firmware_rev")) {
				firmwareRevision, err := ioutil.ReadFile(filepath.Join(devicePath, "firmware_rev"))
				if err != nil {
					return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(devicePath, "firmware_rev"))
				}

				disk.FirmwareVersion = strings.TrimSpace(string(firmwareRevision))
			}

			// Device node
			diskDev, err := ioutil.ReadFile(filepath.Join(entryPath, "dev"))
			if err != nil {
				if os.IsNotExist(err) {
					// This happens on multipath devices, just skip as we only care about the main node.
					continue
				}

				return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(entryPath, "dev"))
			}
			disk.Device = strings.TrimSpace(string(diskDev))

			// NUMA node
			if sysfsExists(filepath.Join(devicePath, "numa_node")) {
				numaNode, err := readInt(filepath.Join(devicePath, "numa_node"))
				if err != nil {
					return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(devicePath, "numa_node"))
				}

				if numaNode > 0 {
					disk.NUMANode = uint64(numaNode)
				}
			}

			// Disk model
			if sysfsExists(filepath.Join(devicePath, "model")) {
				diskModel, err := ioutil.ReadFile(filepath.Join(devicePath, "model"))
				if err != nil {
					return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(devicePath, "model"))
				}

				disk.Model = strings.TrimSpace(string(diskModel))
			}

			// Disk type
			if sysfsExists(filepath.Join(devicePath, "subsystem")) {
				diskSubsystem, err := filepath.EvalSymlinks(filepath.Join(devicePath, "subsystem"))
				if err != nil {
					return nil, errors.Wrapf(err, "Failed to track down \"%s\"", filepath.Join(devicePath, "subsystem"))
				}

				disk.Type = filepath.Base(diskSubsystem)

				if disk.Type == "rbd" {
					// Ignore rbd devices as they aren't local block devices.
					continue
				}
			}

			// Read-only
			diskRo, err := readUint(filepath.Join(entryPath, "ro"))
			if err != nil {
				return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(entryPath, "ro"))
			}
			disk.ReadOnly = diskRo == 1

			// Size
			diskSize, err := readUint(filepath.Join(entryPath, "size"))
			if err != nil {
				return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(entryPath, "size"))
			}
			disk.Size = diskSize * 512

			// Removable
			diskRemovable, err := readUint(filepath.Join(entryPath, "removable"))
			if err != nil {
				return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(entryPath, "removable"))
			}
			disk.Removable = diskRemovable == 1

			// WWN
			if sysfsExists(filepath.Join(entryPath, "wwid")) {
				diskWWN, err := ioutil.ReadFile(filepath.Join(entryPath, "wwid"))
				if err != nil {
					return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(entryPath, "wwid"))
				}
				disk.WWN = strings.TrimSpace(string(diskWWN))
			}

			// Try to guess if dealing with CD-ROM
			if strings.HasPrefix(disk.ID, "sr") && disk.Removable {
				disk.Type = "cdrom"

				// Most cdrom drives report this as size regardless of media
				if disk.Size == 0x1fffff*512 {
					disk.Size = 0
				}
			}

			// Look for partitions
			disk.Partitions = []api.ResourcesStorageDiskPartition{}
			for _, subEntry := range entries {
				subEntryName := subEntry.Name()
				subEntryPath := filepath.Join(sysClassBlock, subEntryName)

				if !strings.HasPrefix(subEntryName, entryName) {
					continue
				}

				if !sysfsExists(filepath.Join(subEntryPath, "partition")) {
					continue
				}

				// Setup the entry
				partition := api.ResourcesStorageDiskPartition{}
				partition.ID = subEntryName

				// Parse the partition number
				partitionNumber, err := readUint(filepath.Join(subEntryPath, "partition"))
				if err != nil {
					return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(subEntryPath, "partition"))
				}
				partition.Partition = partitionNumber

				// Device node
				partitionDev, err := ioutil.ReadFile(filepath.Join(subEntryPath, "dev"))
				if err != nil {
					return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(subEntryPath, "dev"))
				}
				partition.Device = strings.TrimSpace(string(partitionDev))

				// Read-only
				partitionRo, err := readUint(filepath.Join(subEntryPath, "ro"))
				if err != nil {
					return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(subEntryPath, "ro"))
				}
				partition.ReadOnly = partitionRo == 1

				// Size
				partitionSize, err := readUint(filepath.Join(subEntryPath, "size"))
				if err != nil {
					return nil, errors.Wrapf(err, "Failed to read \"%s\"", filepath.Join(subEntryPath, "size"))
				}
				partition.Size = partitionSize * 512

				// Add to list
				disk.Partitions = append(disk.Partitions, partition)
			}

			// Try to find the udev device path
			if sysfsExists(devDiskByPath) {
				links, err := ioutil.ReadDir(devDiskByPath)
				if err != nil {
					return nil, errors.Wrapf(err, "Failed to list the links in \"%s\"", devDiskByPath)
				}

				for _, link := range links {
					linkName := link.Name()
					linkPath := filepath.Join(devDiskByPath, linkName)

					linkTarget, err := filepath.EvalSymlinks(linkPath)
					if err != nil {
						return nil, errors.Wrapf(err, "Failed to track down \"%s\"", linkPath)
					}

					if linkTarget == filepath.Join("/dev", entryName) {
						disk.DevicePath = linkName
					}
				}
			}

			// Try to find the udev device id
			if sysfsExists(devDiskByID) {
				links, err := ioutil.ReadDir(devDiskByID)
				if err != nil {
					return nil, errors.Wrapf(err, "Failed to list the links in \"%s\"", devDiskByID)
				}

				for _, link := range links {
					linkName := link.Name()
					linkPath := filepath.Join(devDiskByID, linkName)

					linkTarget, err := filepath.EvalSymlinks(linkPath)
					if err != nil {
						return nil, errors.Wrapf(err, "Failed to track down \"%s\"", linkPath)
					}

					if linkTarget == filepath.Join("/dev", entryName) {
						disk.DeviceID = linkName
					}
				}
			}

			// Pull direct disk information
			err = storageAddDriveInfo(filepath.Join("/dev", entryName), &disk)
			if err != nil {
				return nil, errors.Wrapf(err, "Failed to retrieve disk information from \"%s\"", filepath.Join("/dev", entryName))
			}

			// Add to list
			storage.Disks = append(storage.Disks, disk)
		}
	}

	storage.Total = 0
	for _, card := range storage.Disks {
		if storage.Disks != nil {
			storage.Total += uint64(len(card.Partitions))
		}

		storage.Total++
	}

	return &storage, nil
}
<|endoftext|>


<commit_before>package sql

import (
	"encoding/xml"
	"fmt"
	"time"

	"github.com/Azure/azure-sdk-for-go/management"
)

// Definitions of numerous constants representing API endpoints.
const (
	azureCreateDatabaseServerURL = "services/sqlservers/servers"
	azureListDatabaseServersURL  = "/services/sqlservers/servers"
	azureDeleteDatabaseServerURL = "/services/sqlservers/servers/%s"

	azureCreateDatabaseURL = "services/sqlservers/servers/%s/databases"
	azureGetDatabaseURL    = "/services/sqlservers/servers/%s/databases/%s"
	azureListDatabasesURL  = "/services/sqlservers/servers/%s/databases?contentview=generic"
	azureUpdateDatabaseURL = "/services/sqlservers/servers/%s/databases/%s"
	azureDeleteDatabaseURL = "/services/sqlservers/servers/%s/databases/%s"

	errParamNotSpecified = "Parameter %s was not specified."

	DatabaseStateCreating = "Creating"
)

// SqlDatabaseClient defines various database CRUD operations.
// It contains a management.Client for making the actual http calls.
type SqlDatabaseClient struct {
	mgmtClient management.Client
}

// NewClient returns a new SqlDatabaseClient struct with the provided
// management.Client as the underlying client.
func NewClient(mgmtClient management.Client) SqlDatabaseClient {
	return SqlDatabaseClient{mgmtClient}
}

// CreateServer creates a new Azure SQL Database server and return its name.
//
// https://msdn.microsoft.com/en-us/library/azure/dn505699.aspx
func (c SqlDatabaseClient) CreateServer(params DatabaseServerCreateParams) (string, error) {
	req, err := xml.Marshal(params)
	if err != nil {
		return "", err
	}

	resp, err := c.mgmtClient.SendAzurePostRequestWithReturnedResponse(azureCreateDatabaseServerURL, req)
	if err != nil {
		return "", err
	}

	var name string
	err = xml.Unmarshal(resp, &name)

	return name, err
}

// ListServers retrieves the Azure SQL Database servers for this subscription.
//
// https://msdn.microsoft.com/en-us/library/azure/dn505702.aspx
func (c SqlDatabaseClient) ListServers() (ListServersResponse, error) {
	var resp ListServersResponse

	data, err := c.mgmtClient.SendAzureGetRequest(azureListDatabaseServersURL)
	if err != nil {
		return resp, err
	}

	err = xml.Unmarshal(data, &resp)
	return resp, err
}

// DeleteServer deletes an Azure SQL Database server (including all its databases).
//
// https://msdn.microsoft.com/en-us/library/azure/dn505695.aspx
func (c SqlDatabaseClient) DeleteServer(name string) error {
	if name == "" {
		return fmt.Errorf(errParamNotSpecified, "name")
	}

	url := fmt.Sprintf(azureDeleteDatabaseServerURL, name)
	_, err := c.mgmtClient.SendAzureDeleteRequest(url)
	return err
}

// CreateDatabase creates a new Microsoft Azure SQL Database on the given database server.
//
// https://msdn.microsoft.com/en-us/library/azure/dn505701.aspx
func (c SqlDatabaseClient) CreateDatabase(server string, params DatabaseCreateParams) error {
	if server == "" {
		return fmt.Errorf(errParamNotSpecified, "server")
	}

	req, err := xml.Marshal(params)
	if err != nil {
		return err
	}

	target := fmt.Sprintf(azureCreateDatabaseURL, server)
	_, err = c.mgmtClient.SendAzurePostRequest(target, req)
	return err
}

// WaitForDatabaseCreation is a helper method which waits
// for the creation of the database on the given server.
func (c SqlDatabaseClient) WaitForDatabaseCreation(
	server, database string,
	cancel chan struct{}) error {
	for {
		stat, err := c.GetDatabase(server, database)
		if err != nil {
			return err
		}
		if stat.State != DatabaseStateCreating {
			return nil
		}

		select {
		case <-time.After(management.DefaultOperationPollInterval):
		case <-cancel:
			return management.ErrOperationCancelled
		}
	}
}

// GetDatabase gets the details for an Azure SQL Database.
//
// https://msdn.microsoft.com/en-us/library/azure/dn505708.aspx
func (c SqlDatabaseClient) GetDatabase(server, database string) (ServiceResource, error) {
	var db ServiceResource

	if database == "" {
		return db, fmt.Errorf(errParamNotSpecified, "database")
	}
	if server == "" {
		return db, fmt.Errorf(errParamNotSpecified, "server")
	}

	url := fmt.Sprintf(azureGetDatabaseURL, server, database)
	resp, err := c.mgmtClient.SendAzureGetRequest(url)
	if err != nil {
		return db, err
	}

	err = xml.Unmarshal(resp, &db)
	return db, err
}

// ListDatabases returns a list of Azure SQL Databases on the given server.
//
// https://msdn.microsoft.com/en-us/library/azure/dn505711.aspx
func (c SqlDatabaseClient) ListDatabases(server string) (ListDatabasesResponse, error) {
	var databases ListDatabasesResponse
	if server == "" {
		return databases, fmt.Errorf(errParamNotSpecified, "server name")
	}

	url := fmt.Sprintf(azureListDatabasesURL, server)
	resp, err := c.mgmtClient.SendAzureGetRequest(url)
	if err != nil {
		return databases, err
	}

	err = xml.Unmarshal(resp, &databases)
	return databases, err
}

// UpdateDatabase updates the details of the given Database off the given server.
//
// https://msdn.microsoft.com/en-us/library/azure/dn505718.aspx
func (c SqlDatabaseClient) UpdateDatabase(
	server, database string,
	params ServiceResourceUpdateParams) (management.OperationID, error) {
	if database == "" {
		return "", fmt.Errorf(errParamNotSpecified, "database")
	}
	if server == "" {
		return "", fmt.Errorf(errParamNotSpecified, "server")
	}

	url := fmt.Sprintf(azureUpdateDatabaseURL, server, database)
	req, err := xml.Marshal(params)
	if err != nil {
		return "", err
	}

	return c.mgmtClient.SendAzurePutRequest(url, "text/xml", req)
}

// DeleteDatabase deletes the Azure SQL Database off the given server.
//
// https://msdn.microsoft.com/en-us/library/azure/dn505705.aspx
func (c SqlDatabaseClient) DeleteDatabase(server, database string) error {
	if database == "" {
		return fmt.Errorf(errParamNotSpecified, "database")
	}
	if server == "" {
		return fmt.Errorf(errParamNotSpecified, "server")
	}

	url := fmt.Sprintf(azureDeleteDatabaseURL, server, database)

	_, err := c.mgmtClient.SendAzureDeleteRequest(url)

	return err
}
<commit_msg>Fixed SQL Client naming scheme.<commit_after>package sql

import (
	"encoding/xml"
	"fmt"
	"time"

	"github.com/Azure/azure-sdk-for-go/management"
)

// Definitions of numerous constants representing API endpoints.
const (
	azureCreateDatabaseServerURL = "services/sqlservers/servers"
	azureListDatabaseServersURL  = "/services/sqlservers/servers"
	azureDeleteDatabaseServerURL = "/services/sqlservers/servers/%s"

	azureCreateDatabaseURL = "services/sqlservers/servers/%s/databases"
	azureGetDatabaseURL    = "/services/sqlservers/servers/%s/databases/%s"
	azureListDatabasesURL  = "/services/sqlservers/servers/%s/databases?contentview=generic"
	azureUpdateDatabaseURL = "/services/sqlservers/servers/%s/databases/%s"
	azureDeleteDatabaseURL = "/services/sqlservers/servers/%s/databases/%s"

	errParamNotSpecified = "Parameter %s was not specified."

	DatabaseStateCreating = "Creating"
)

// SQLDatabaseClient defines various database CRUD operations.
// It contains a management.Client for making the actual http calls.
type SQLDatabaseClient struct {
	mgmtClient management.Client
}

// NewClient returns a new SQLDatabaseClient struct with the provided
// management.Client as the underlying client.
func NewClient(mgmtClient management.Client) SQLDatabaseClient {
	return SQLDatabaseClient{mgmtClient}
}

// CreateServer creates a new Azure SQL Database server and return its name.
//
// https://msdn.microsoft.com/en-us/library/azure/dn505699.aspx
func (c SQLDatabaseClient) CreateServer(params DatabaseServerCreateParams) (string, error) {
	req, err := xml.Marshal(params)
	if err != nil {
		return "", err
	}

	resp, err := c.mgmtClient.SendAzurePostRequestWithReturnedResponse(azureCreateDatabaseServerURL, req)
	if err != nil {
		return "", err
	}

	var name string
	err = xml.Unmarshal(resp, &name)

	return name, err
}

// ListServers retrieves the Azure SQL Database servers for this subscription.
//
// https://msdn.microsoft.com/en-us/library/azure/dn505702.aspx
func (c SQLDatabaseClient) ListServers() (ListServersResponse, error) {
	var resp ListServersResponse

	data, err := c.mgmtClient.SendAzureGetRequest(azureListDatabaseServersURL)
	if err != nil {
		return resp, err
	}

	err = xml.Unmarshal(data, &resp)
	return resp, err
}

// DeleteServer deletes an Azure SQL Database server (including all its databases).
//
// https://msdn.microsoft.com/en-us/library/azure/dn505695.aspx
func (c SQLDatabaseClient) DeleteServer(name string) error {
	if name == "" {
		return fmt.Errorf(errParamNotSpecified, "name")
	}

	url := fmt.Sprintf(azureDeleteDatabaseServerURL, name)
	_, err := c.mgmtClient.SendAzureDeleteRequest(url)
	return err
}

// CreateDatabase creates a new Microsoft Azure SQL Database on the given database server.
//
// https://msdn.microsoft.com/en-us/library/azure/dn505701.aspx
func (c SQLDatabaseClient) CreateDatabase(server string, params DatabaseCreateParams) error {
	if server == "" {
		return fmt.Errorf(errParamNotSpecified, "server")
	}

	req, err := xml.Marshal(params)
	if err != nil {
		return err
	}

	target := fmt.Sprintf(azureCreateDatabaseURL, server)
	_, err = c.mgmtClient.SendAzurePostRequest(target, req)
	return err
}

// WaitForDatabaseCreation is a helper method which waits
// for the creation of the database on the given server.
func (c SQLDatabaseClient) WaitForDatabaseCreation(
	server, database string,
	cancel chan struct{}) error {
	for {
		stat, err := c.GetDatabase(server, database)
		if err != nil {
			return err
		}
		if stat.State != DatabaseStateCreating {
			return nil
		}

		select {
		case <-time.After(management.DefaultOperationPollInterval):
		case <-cancel:
			return management.ErrOperationCancelled
		}
	}
}

// GetDatabase gets the details for an Azure SQL Database.
//
// https://msdn.microsoft.com/en-us/library/azure/dn505708.aspx
func (c SQLDatabaseClient) GetDatabase(server, database string) (ServiceResource, error) {
	var db ServiceResource

	if database == "" {
		return db, fmt.Errorf(errParamNotSpecified, "database")
	}
	if server == "" {
		return db, fmt.Errorf(errParamNotSpecified, "server")
	}

	url := fmt.Sprintf(azureGetDatabaseURL, server, database)
	resp, err := c.mgmtClient.SendAzureGetRequest(url)
	if err != nil {
		return db, err
	}

	err = xml.Unmarshal(resp, &db)
	return db, err
}

// ListDatabases returns a list of Azure SQL Databases on the given server.
//
// https://msdn.microsoft.com/en-us/library/azure/dn505711.aspx
func (c SQLDatabaseClient) ListDatabases(server string) (ListDatabasesResponse, error) {
	var databases ListDatabasesResponse
	if server == "" {
		return databases, fmt.Errorf(errParamNotSpecified, "server name")
	}

	url := fmt.Sprintf(azureListDatabasesURL, server)
	resp, err := c.mgmtClient.SendAzureGetRequest(url)
	if err != nil {
		return databases, err
	}

	err = xml.Unmarshal(resp, &databases)
	return databases, err
}

// UpdateDatabase updates the details of the given Database off the given server.
//
// https://msdn.microsoft.com/en-us/library/azure/dn505718.aspx
func (c SQLDatabaseClient) UpdateDatabase(
	server, database string,
	params ServiceResourceUpdateParams) (management.OperationID, error) {
	if database == "" {
		return "", fmt.Errorf(errParamNotSpecified, "database")
	}
	if server == "" {
		return "", fmt.Errorf(errParamNotSpecified, "server")
	}

	url := fmt.Sprintf(azureUpdateDatabaseURL, server, database)
	req, err := xml.Marshal(params)
	if err != nil {
		return "", err
	}

	return c.mgmtClient.SendAzurePutRequest(url, "text/xml", req)
}

// DeleteDatabase deletes the Azure SQL Database off the given server.
//
// https://msdn.microsoft.com/en-us/library/azure/dn505705.aspx
func (c SQLDatabaseClient) DeleteDatabase(server, database string) error {
	if database == "" {
		return fmt.Errorf(errParamNotSpecified, "database")
	}
	if server == "" {
		return fmt.Errorf(errParamNotSpecified, "server")
	}

	url := fmt.Sprintf(azureDeleteDatabaseURL, server, database)

	_, err := c.mgmtClient.SendAzureDeleteRequest(url)

	return err
}
<|endoftext|>


<commit_before>package populartopic

import (
	"encoding/json"
	"fmt"
	"socialapi/config"
	"socialapi/models"
	"time"

	"github.com/koding/logging"
	"github.com/koding/redis"
	"github.com/koding/worker"
	"github.com/streadway/amqp"
)

var (
	PopularTopicKey = "populartopic"
)

type Action func(*PopularTopicsController, *models.ChannelMessageList) error

type PopularTopicsController struct {
	routes map[string]Action
	log    logging.Logger
	redis  *redis.RedisSession
}

func (t *PopularTopicsController) DefaultErrHandler(delivery amqp.Delivery, err error) {
	t.log.Error("an error occured putting message back to queue", err)
	// multiple false
	// reque true
	delivery.Nack(false, true)
}

func NewPopularTopicsController(log logging.Logger, redis *redis.RedisSession) *PopularTopicsController {
	ffc := &PopularTopicsController{
		log:   log,
		redis: redis,
	}

	routes := map[string]Action{
		"channel_message_list_created": (*PopularTopicsController).MessageSaved,
		"channel_message_list_deleted": (*PopularTopicsController).MessageDeleted,
	}

	ffc.routes = routes
	return ffc
}

func (f *PopularTopicsController) HandleEvent(event string, data []byte) error {
	f.log.Debug("New Event Recieved %s", event)
	handler, ok := f.routes[event]
	if !ok {
		return worker.HandlerNotFoundErr
	}

	cml, err := mapMessage(data)
	if err != nil {
		return err
	}

	if cml.ChannelId == 0 {
		f.log.Error("ChannelId is not set for Channel Message List id: %d Deleting from rabbitmq", cml.Id)
		return nil
	}

	return handler(f, cml)
}

func (f *PopularTopicsController) MessageSaved(data *models.ChannelMessageList) error {
	incrementedVal, err := f.redis.SortedSetIncrBy(GetWeeklyKey(data), 1, data.MessageId)
	if err != nil {
		return err
	}

	incrementedVal, err = f.redis.SortedSetIncrBy(GetMonthlyKey(data), 1, data.MessageId)
	if err != nil {
		return err
	}

	return nil
}

func (f *PopularTopicsController) MessageDeleted(data *models.ChannelMessageList) error {
	incrementedVal, err := f.redis.SortedSetIncrBy(GetWeeklyKey(data), -1, data.MessageId)
	if err != nil {
		return err
	}

	incrementedVal, err = f.redis.SortedSetIncrBy(GetMonthlyKey(data), -1, data.MessageId)
	if err != nil {
		return err
	}

	return nil
}

func GetRedisPrefix() string {
	return fmt.Sprintf(
		"%s:%s",
		config.Get().Environment,
		PopularTopicKey,
	)
}

func GetWeeklyKey(cml *models.ChannelMessageList) string {
	weekNumber := 0
	year := 2014

	if !cml.AddedAt.IsZero() {
		_, weekNumber = cml.AddedAt.ISOWeek()
		year, _, _ = cml.AddedAt.UTC().Date()
	} else {
		// no need to convert it to UTC
		_, weekNumber = time.Now().ISOWeek()
		year, _, _ = time.Now().UTC().Date()

	}

	dateKey := fmt.Sprintf(
		"%s:%d:%d",
		"weekly",
		year,
		weekNumber,
	)
	return dateKey
}

func GetMonthlyKey(cml *models.ChannelMessageList) string {
	var month time.Month
	year := 2014

	if !cml.AddedAt.IsZero() {
		year, month, _ = cml.AddedAt.UTC().Date()
	} else {
		year, month, _ = time.Now().UTC().Date()
	}

	dateKey := fmt.Sprintf(
		"%s:%d:%d",
		"monthly",
		year,
		int(month),
	)

	return dateKey
}

func mapMessage(data []byte) (*models.ChannelMessageList, error) {
	cm := models.NewChannelMessageList()
	if err := json.Unmarshal(data, cm); err != nil {
		return nil, err
	}

	return cm, nil
}

func (f *PopularTopicsController) isEligible(c *models.Channel) bool {
	return true
	if c.TypeConstant != models.Channel_TYPE_TOPIC {
		return false
	}

	return true
}

// todo add caching here
func fetchChannel(channelId int64) (*models.Channel, error) {
	c := models.NewChannel()
	c.Id = channelId
	if err := c.Fetch(); err != nil {
		return nil, err
	}

	return c, nil
}
<commit_msg>social: create a function for preparing redid key<commit_after>package populartopic

import (
	"encoding/json"
	"fmt"
	"socialapi/config"
	"socialapi/models"
	"time"

	"github.com/koding/logging"
	"github.com/koding/redis"
	"github.com/koding/worker"
	"github.com/streadway/amqp"
)

var (
	PopularTopicKey = "populartopic"
)

type Action func(*PopularTopicsController, *models.ChannelMessageList) error

type PopularTopicsController struct {
	routes map[string]Action
	log    logging.Logger
	redis  *redis.RedisSession
}

func (t *PopularTopicsController) DefaultErrHandler(delivery amqp.Delivery, err error) {
	t.log.Error("an error occured putting message back to queue", err)
	// multiple false
	// reque true
	delivery.Nack(false, true)
}

func NewPopularTopicsController(log logging.Logger, redis *redis.RedisSession) *PopularTopicsController {
	ffc := &PopularTopicsController{
		log:   log,
		redis: redis,
	}

	routes := map[string]Action{
		"channel_message_list_created": (*PopularTopicsController).MessageSaved,
		"channel_message_list_deleted": (*PopularTopicsController).MessageDeleted,
	}

	ffc.routes = routes
	return ffc
}

func (f *PopularTopicsController) HandleEvent(event string, data []byte) error {
	f.log.Debug("New Event Recieved %s", event)
	handler, ok := f.routes[event]
	if !ok {
		return worker.HandlerNotFoundErr
	}

	cml, err := mapMessage(data)
	if err != nil {
		return err
	}

	if cml.ChannelId == 0 {
		f.log.Error("ChannelId is not set for Channel Message List id: %d Deleting from rabbitmq", cml.Id)
		return nil
	}

	return handler(f, cml)
}

func (f *PopularTopicsController) MessageSaved(data *models.ChannelMessageList) error {
	incrementedVal, err := f.redis.SortedSetIncrBy(GetWeeklyKey(data), 1, data.MessageId)
	if err != nil {
		return err
	}

	incrementedVal, err = f.redis.SortedSetIncrBy(GetMonthlyKey(data), 1, data.MessageId)
	if err != nil {
		return err
	}

	return nil
}

func (f *PopularTopicsController) MessageDeleted(data *models.ChannelMessageList) error {
	incrementedVal, err := f.redis.SortedSetIncrBy(GetWeeklyKey(data), -1, data.MessageId)
	if err != nil {
		return err
	}

	incrementedVal, err = f.redis.SortedSetIncrBy(GetMonthlyKey(data), -1, data.MessageId)
	if err != nil {
		return err
	}

	return nil
}

func GetRedisPrefix() string {
	return config.Get().Environment
}

func prepareKey(group, statisticName string, year, dateNumber int) string {
	return fmt.Sprintf(
		"%s:%s:%d:%s:%d",
		group,
		PopularTopicKey,
		year,
		statisticName,
		dateNumber,
	)

}

func GetWeeklyKey(c *models.Channel, cml *models.ChannelMessageList) string {
	weekNumber := 0
	year := 2014

	if !cml.AddedAt.IsZero() {
		_, weekNumber = cml.AddedAt.ISOWeek()
		year, _, _ = cml.AddedAt.UTC().Date()
	} else {
		// no need to convert it to UTC
		_, weekNumber = time.Now().ISOWeek()
		year, _, _ = time.Now().UTC().Date()

	}

	dateKey := fmt.Sprintf(
		"%s:%d:%d",
		"weekly",
		year,
		weekNumber,
	)
	return dateKey
}

func GetMonthlyKey(cml *models.ChannelMessageList) string {
	var month time.Month
	year := 2014

	if !cml.AddedAt.IsZero() {
		year, month, _ = cml.AddedAt.UTC().Date()
	} else {
		year, month, _ = time.Now().UTC().Date()
	}

	dateKey := fmt.Sprintf(
		"%s:%d:%d",
		"monthly",
		year,
		int(month),
	)

	return dateKey
}

func mapMessage(data []byte) (*models.ChannelMessageList, error) {
	cm := models.NewChannelMessageList()
	if err := json.Unmarshal(data, cm); err != nil {
		return nil, err
	}

	return cm, nil
}

func (f *PopularTopicsController) isEligible(c *models.Channel) bool {
	return true
	if c.TypeConstant != models.Channel_TYPE_TOPIC {
		return false
	}

	return true
}

// todo add caching here
func fetchChannel(channelId int64) (*models.Channel, error) {
	c := models.NewChannel()
	c.Id = channelId
	if err := c.Fetch(); err != nil {
		return nil, err
	}

	return c, nil
}
<|endoftext|>


<commit_before>// Package keyring provides a cross-platform interface to keychains for
// password management
//
// Example:
// 	pw, err := keyring.Get("libFoo", "john.doe")
//
// TODO: Write SecretService Provider
//
// TODO: Write KWallet Provider?
//
// TODO: Implement encrypted local file storage Provider ?
package keyring

import "errors"

var (
	// ErrNoDefault means that no default keyring provider has been found
	ErrNoDefault    = errors.New("No default provider found")
	providers       = map[string]Provider{}
	defaultProvider Provider
)

// Provider provides a simple interface to keychain sevice
type Provider interface {
	Get(Service, Username string) (string, error)
	Set(Service, Username, Password string) error
}

// Get gets the password for a paricular Service and Username using the
// default keyring provider.
func Get(Service, Username string) (string, error) {
	if defaultProvider == nil {
		return "", ErrNoDefault
	}
	return defaultProvider.Get(Service, Username)
}

// Set sets the password for a particular Service and Username using the
// default keyring provider.
func Set(Service, Username, Password string) error {
	if defaultProvider == nil {
		return ErrNoDefault
	}
	return defaultProvider.Set(Service, Username, Password)
}

// Providers provides a map of registered Providers keyed on short names
func Providers() map[string]Provider {
	p := make(map[string]Provider)
	for k, v := range providers {
		p[k] = v
	}
	return p
}

// RegisterProvider registers a Provider with a short name (for use by Provider)
// libraries
func registerProvider(Name string, Provider Provider, makeDefault bool) {
	providers[Name] = Provider
	if makeDefault {
		defaultProvider = Provider
	}
}
<commit_msg>Update comments<commit_after>// Package keyring provides a cross-platform interface to keychains for
// password management
//
// Example:
// 	pw, err := keyring.Get("libFoo", "john.doe")
//
// TODO: Write Windows Provider
package keyring

import "errors"

var (
	// ErrNotFound means the requested password was not found
	ErrNotFound = errors.New("Password not found")
	// ErrNoDefault means that no default keyring provider has been found
	ErrNoDefault    = errors.New("No default provider found")
	providers       = map[string]Provider{}
	defaultProvider Provider
)

// Provider provides a simple interface to keychain sevice
type Provider interface {
	Get(Service, Username string) (string, error)
	Set(Service, Username, Password string) error
}

// Get gets the password for a paricular Service and Username using the
// default keyring provider.
func Get(Service, Username string) (string, error) {
	if defaultProvider == nil {
		return "", ErrNoDefault
	}
	return defaultProvider.Get(Service, Username)
}

// Set sets the password for a particular Service and Username using the
// default keyring provider.
func Set(Service, Username, Password string) error {
	if defaultProvider == nil {
		return ErrNoDefault
	}
	return defaultProvider.Set(Service, Username, Password)
}

// Providers provides a map of registered Providers keyed on short names
func Providers() map[string]Provider {
	p := make(map[string]Provider)
	for k, v := range providers {
		p[k] = v
	}
	return p
}

// RegisterProvider registers a Provider with a short name (for use by Provider)
// libraries
func registerProvider(Name string, Provider Provider, makeDefault bool) {
	providers[Name] = Provider
	if makeDefault {
		defaultProvider = Provider
	}
}
<|endoftext|>