<commit_before>// Copyright 2016 PLUMgrid
//
// 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 main

package driver

import (
	"encoding/json"
	"strings"
)

func BridgeCreate(ID string, domainid string, gatewayip string) {

	url := "/0/connectivity/domain/" + domainid + "/ne/bri" + ID
	data := []byte(`{"action": {
				"action1": {
					"action_text": "create_and_link_ifc(DYN_1)"}
				},
				"ifc": {},
				"metadata": "` + ID + `",
				"mobility": "true",
				"ne_description": "PLUMgrid Bridge",
				"ne_dname": "net-` + ID[:10] + `",
				"ne_group": "Bridge",
				"ne_type": "bridge"
	}`)

	RestCall("PUT", url, data)

	url = "/0/connectivity/domain/" + domainid + "/rule_group/cnf" + ID
	data = []byte(`{"mark_disabled": false,
			"ne_dest": "/ne/bri` + ID + `/action/action1",
			"ne_dname": "cont-` + ID[10:] + `",
			"ne_type": "cnf-vmgroup",
					"rule": {
						"rules` + ID + `": {
							"add_context": "",
							"criteria": "pgtag2",
							"match": "bri` + ID + `"
						}
					}
	}`)

	RestCall("PUT", url, data)

	url = "/0/connectivity/domain_prop/" + domainid + "/ne/brii" + ID
	data = []byte(`{"ne_metadata": "` + gatewayip + `"}`)
	RestCall("PUT", url, data)
}

func AddGatewayInfo(ID string, domainid string, gatewayip string) {

	url := "/0/connectivity/domain_prop/" + domainid + "/ne/brii" + ID
	data := []byte(`{"ne_metadata": "` + gatewayip + `"}`)
	RestCall("PUT", url, data)
}

func BridgeDelete(ID string, domainid string) {

	url := "/0/connectivity/domain_prop/" + domainid + "/ne/brii" + ID
	RestCall("DELETE", url, nil)

	url = "/0/connectivity/domain/" + domainid + "/ne/bri" + ID
	RestCall("DELETE", url, nil)

	url = "/0/connectivity/domain/" + domainid + "/rule_group/cnf" + ID
	RestCall("DELETE", url, nil)
}

func AddNetworkInfo(dNetwork string, neID string) {

	url := "/0/connectivity/domain?configonly=true&level=3"
	body, _ := RestCall("GET", url, nil)
	var domain_data map[string]interface{}
	err := json.Unmarshal([]byte(body), &domain_data)
	if err != nil {
		panic(err)
	}
	for domains, domain_val := range domain_data {
		if nes, ok := domain_val.(map[string]interface{})["ne"]; ok {
			if ne, ok := nes.(map[string]interface{})[neID]; ok {
				ne.(map[string]interface{})["metadata"] = dNetwork
				ne_data, _ := json.Marshal(ne)
				RestCall("PUT", "/0/connectivity/domain/"+domains+"/ne/"+neID, ne_data)
				break
			}
		}
	}
}

func FindDomainFromNetwork(ID string) (domainid string, netid string) {

	url := "/0/connectivity/domain?configonly=true&level=3"
	body, _ := RestCall("GET", url, nil)
	var domain_data map[string]interface{}
	err := json.Unmarshal([]byte(body), &domain_data)
	if err != nil {
		panic(err)
	}
	for domains, domain_val := range domain_data {
		if nes, ok := domain_val.(map[string]interface{})["ne"]; ok {
			for ne, data := range nes.(map[string]interface{}) {
				if data.(map[string]interface{})["metadata"] == ID {
					domainid = domains
					netid = ne
					break
				}
			}
		}
	}
	return
}

func FindNetworkGateway(domainID string, networkID string) (gatewayIP string) {

	url := "/0/connectivity/domain_prop/" + domainID + "/ne/brii" + networkID
	body, _ := RestCall("GET", url, nil)
	var domain_prop map[string]interface{}
	err := json.Unmarshal([]byte(body), &domain_prop)
	if err != nil {
		panic(err)
	}
	gatewayIP = domain_prop["ne_metadata"].(string)
	return
}

func DomainCreate(domainID string) {

	url := "/0/connectivity/domain?configonly=true"
	body, _ := RestCall("GET", url, nil)
	var domain_data map[string]interface{}
	err := json.Unmarshal([]byte(body), &domain_data)
	if err != nil {
		panic(err)
	}
	for domains := range domain_data {
		if domains == domainID {
			return
		}
	}

	url = "/0/tenant_manager/tenants" + "/" + domainID
	data := []byte(`{"containers": {
				"` + domainID + `": {
					"enable": "True",
					"context": "` + domainID + `",
					"domains": {}, "rules": {}}}}`)
	RestCall("PUT", url, data)

	url = "/0/tenant_manager/metaconfig/" + domainID
	data = []byte(`{}`)
	RestCall("PUT", url, data)

	url = "/0/tunnel_service/vnd_config/" + domainID
	data = []byte(`{"profile_name": "VXLAN",
			"add_vlan": "False"}`)
	RestCall("PUT", url, data)

	url = "/0/connectivity/domain/" + domainID
	data = []byte(`{"container_group": "` + domainID + `",
			"topology_name": "docker"}`)
	RestCall("PUT", url, data)

	url = "/0/connectivity/domain_prop/" + domainID
	data = []byte(`{}`)
	RestCall("PUT", url, data)

	url = "/0/pem_master/log_rule/" + domainID
	data = []byte(`{"rule": {
				"rule_` + domainID + `": {
					"pgtag1": "` + domainID + `",
					"log_ifc_type": "ACCESS_CONTAINER"}}}`)

	RestCall("PUT", url, data)
}

func DomainDelete(domainID string) {

	url := "/0/connectivity/domain?configonly=true"
	body, _ := RestCall("GET", url, nil)
	var domain_data map[string]interface{}
	err := json.Unmarshal([]byte(body), &domain_data)
	if err != nil {
		panic(err)
	}
	for domains, domain_val := range domain_data {
		if domains == domainID {
			res := domain_val.(map[string]interface{})["ne"]
			if len(res.(map[string]interface{})) == 0 {

				url = "/0/pem_master/log_rule/" + domainID
				RestCall("DELETE", url, nil)

				url = "/0/connectivity/domain_prop/" + domainID
				RestCall("DELETE", url, nil)

				url = "/0/connectivity/domain/" + domainID
				RestCall("DELETE", url, nil)

				url = "/0/tunnel_service/vnd_config/" + domainID
				RestCall("DELETE", url, nil)

				url = "/0/tenant_manager/metaconfig/" + domainID
				RestCall("DELETE", url, nil)

				url = "/0/tenant_manager/tenants/" + domainID
				RestCall("DELETE", url, nil)
			}
		}
	}
}

func GetNeId(NeName string, DomainID string) (NeID string) {

	url := "/0/connectivity/domain/" + DomainID + "/ne?configonly=true&level=1"
	body, _ := RestCall("GET", url, nil)
	var ne_data map[string]interface{}
	err := json.Unmarshal([]byte(body), &ne_data)
	if err != nil {
		panic(err)
	}
	for nes, ne_val := range ne_data {
		if ne_val.(map[string]interface{})["ne_dname"] == NeName {
			NeID = nes
			break
		}
	}
	return
}

func CreateNetworkLink(NeName string, DomainID string, NetworkID string, IP string, Netmask string) {

	ne_ID := GetNeId(NeName, DomainID)
	CheckNeChildList(ne_ID, DomainID, "ifc")
	CheckNeChildList(NetworkName(NetworkID), DomainID, "ifc")
	ne_ifc := NetworkID
	url := "/0/connectivity/domain/" + DomainID + "/ne/" + ne_ID + "/ifc/" + ne_ifc
	data := []byte(`{"attachable": "true",
                         "list": "true",
                         "attach_type": "static,dynamic",
                         "mobility": "true",
                         "ifc_name": "` + ne_ifc + `",
                         "ifc_type": "static",
                         "ip_address": "` + IP + `",
                         "ip_address_mask": "` + Netmask + `"}`)
	RestCall("PUT", url, data)

	net_ifc := ne_ID
	url = "/0/connectivity/domain/" + DomainID + "/ne/" + NetworkName(NetworkID) + "/ifc/" + net_ifc
	data = []byte(`{"attachable": "true",
                         "list": "true",
                         "attach_type": "static,dynamic",
                         "mobility": "true",
                         "ifc_type": "static"}`)
	RestCall("PUT", url, data)

	link_name := ne_ID + NetworkID
	url = "/0/connectivity/domain/" + DomainID + "/link/" + link_name
	data = []byte(`{"link_type": "static",
                         "link_name": "` + link_name + `",
                         "attachment1": "/ne/` + ne_ID + `/ifc/` + ne_ifc + `",
                         "attachment2": "/ne/` + NetworkName(NetworkID) + `/ifc/` + net_ifc + `"}`)
	RestCall("PUT", url, data)
}

func DeleteNetworkLinks(DomainID string, NetworkID string) {

	var ne_ID string
	var ne_ifc string
	url := "/0/connectivity/domain/" + DomainID
	body, _ := RestCall("GET", url+"?configonly=true", nil)
	var domain_data map[string]interface{}
	err := json.Unmarshal([]byte(body), &domain_data)
	if err != nil {
		panic(err)
	}
	for domains, domain_val := range domain_data {
		if domains == "link" {
			links := domain_val.(map[string]interface{})
			for att, att_info := range links {
				att_1 := att_info.(map[string]interface{})["attachment1"].(string)
				att_2 := att_info.(map[string]interface{})["attachment2"].(string)
				if strings.Split(att_1, "/")[2][3:] == NetworkID {
					ne_ID = strings.Split(att_2, "/")[2]
					ne_ifc = strings.Split(att_2, "/")[4]
					RestCall("DELETE", url+"/link/"+att, nil)
					ifc_url := url + "/ne/" + ne_ID + "/ifc/" + ne_ifc
					RestCall("DELETE", ifc_url, nil)
				} else if strings.Split(att_2, "/")[2][3:] == NetworkID {
					ne_ID = strings.Split(att_1, "/")[2]
					ne_ifc = strings.Split(att_1, "/")[4]
					RestCall("DELETE", url+"/link/"+att, nil)
					ifc_url := url + "/ne/" + ne_ID + "/ifc/" + ne_ifc
					RestCall("DELETE", ifc_url, nil)
				}
			}
		}
	}
}

func NetworkName(ID string) (name string) {
	name = "bri" + ID
	return
}

func CheckNeChildList(NeID string, DomainID string, childList string) {

	url := "/0/connectivity/domain/" + DomainID + "/ne/" + NeID + "?configonly=true"
	body, _ := RestCall("GET", url, nil)
	var ne_data map[string]interface{}
	err := json.Unmarshal([]byte(body), &ne_data)
	if err != nil {
		panic(err)
	}
	if _, ok := ne_data[childList]; ok {
		return
	} else {
		data := []byte(`{}`)
		RestCall("PUT", url+"/"+childList, data)
		return
	}
}

func AddMetaconfig(domainID string, netID string, deviceID string, endpointID string, macaddr string) {

	url := "/0/tenant_manager/metaconfig/" + domainID + "?configonly=true"
	body, _ := RestCall("GET", url, nil)
	var tm_data map[string]interface{}
	err := json.Unmarshal([]byte(body), &tm_data)
	if err != nil {
		panic(err)
	}

	for device, _ := range tm_data["workloads"].(map[string]interface{}) {
		if device == deviceID {
			url = "/0/tenant_manager/metaconfig/" + domainID + "/workloads/" + deviceID + "/prop/" + endpointID
			data := []byte(`{"phy_address": "` + macaddr + `",
					 "hint": "` + netID + `"}`)
			RestCall("PUT", url, data)
			return
		}
	}

	url = "/0/tenant_manager/metaconfig/" + domainID + "/workloads/" + deviceID
	data := []byte(`{"ne_type": "container",
			 "ne_dname": "none",
			 "prop": {
				"` + endpointID + `": {
						"phy_address": "` + macaddr + `",
						"hint": "` + netID + `"}}}`)
	RestCall("PUT", url, data)
}

func RemoveMetaconfig(domainID string, netID string, endpointID string) {

	url := "/0/tenant_manager/metaconfig/" + domainID + "?configonly=true"
	body, _ := RestCall("GET", url, nil)
	var tm_data map[string]interface{}
	err := json.Unmarshal([]byte(body), &tm_data)
	if err != nil {
		panic(err)
	}

	for device, prop := range tm_data["workloads"].(map[string]interface{}) {
		for endpoint, _ := range prop.(map[string]interface{})["prop"].(map[string]interface{}) {
			if endpoint == endpointID {
				if len(prop.(map[string]interface{})["prop"].(map[string]interface{})) < 2 {
					url = "/0/tenant_manager/metaconfig/" + domainID + "/workloads/" + device
					RestCall("DELETE", url, nil)
					return
				}
				url = "/0/tenant_manager/metaconfig/" + domainID + "/workloads/" + device + "/prop/" + endpoint
				RestCall("DELETE", url, nil)
			}
		}
	}
}
<commit_msg>minor improv<commit_after>// Copyright 2016 PLUMgrid
//
// 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 main

package driver

import (
	"encoding/json"
	"strings"
)

func BridgeCreate(ID string, domainid string, gatewayip string) {

	url := "/0/connectivity/domain/" + domainid + "/ne/bri" + ID
	data := []byte(`{"action": {
				"action1": {
					"action_text": "create_and_link_ifc(DYN_1)"}
				},
				"ifc": {},
				"metadata": "` + ID + `",
				"mobility": "true",
				"ne_description": "PLUMgrid Bridge",
				"ne_dname": "net-` + ID[:10] + `",
				"ne_group": "Bridge",
				"ne_type": "bridge"
	}`)

	RestCall("PUT", url, data)

	url = "/0/connectivity/domain/" + domainid + "/rule_group/cnf" + ID
	data = []byte(`{"mark_disabled": false,
			"ne_dest": "/ne/bri` + ID + `/action/action1",
			"ne_dname": "cont-` + ID[10:] + `",
			"ne_type": "cnf-vmgroup",
					"rule": {
						"rules` + ID + `": {
							"add_context": "",
							"criteria": "pgtag2",
							"match": "bri` + ID + `"
						}
					}
	}`)

	RestCall("PUT", url, data)

	url = "/0/connectivity/domain_prop/" + domainid + "/ne/brii" + ID
	data = []byte(`{"ne_metadata": "` + gatewayip + `"}`)
	RestCall("PUT", url, data)
}

func AddGatewayInfo(ID string, domainid string, gatewayip string) {

	url := "/0/connectivity/domain_prop/" + domainid + "/ne/brii" + ID
	data := []byte(`{"ne_metadata": "` + gatewayip + `"}`)
	RestCall("PUT", url, data)
}

func BridgeDelete(ID string, domainid string) {

	url := "/0/connectivity/domain_prop/" + domainid + "/ne/brii" + ID
	RestCall("DELETE", url, nil)

	url = "/0/connectivity/domain/" + domainid + "/ne/bri" + ID
	RestCall("DELETE", url, nil)

	url = "/0/connectivity/domain/" + domainid + "/rule_group/cnf" + ID
	RestCall("DELETE", url, nil)
}

func AddNetworkInfo(dNetwork string, neID string) {

	url := "/0/connectivity/domain?configonly=true&level=3"
	body, _ := RestCall("GET", url, nil)
	var domain_data map[string]interface{}
	err := json.Unmarshal([]byte(body), &domain_data)
	if err != nil {
		panic(err)
	}
	for domains, domain_val := range domain_data {
		if nes, ok := domain_val.(map[string]interface{})["ne"]; ok {
			if ne, ok := nes.(map[string]interface{})[neID]; ok {
				ne.(map[string]interface{})["metadata"] = dNetwork
				ne_data, _ := json.Marshal(ne)
				RestCall("PUT", "/0/connectivity/domain/"+domains+"/ne/"+neID, ne_data)
				break
			}
		}
	}
}

func FindDomainFromNetwork(ID string) (domainid string, netid string) {

	url := "/0/connectivity/domain?configonly=true&level=3"
	body, _ := RestCall("GET", url, nil)
	var domain_data map[string]interface{}
	err := json.Unmarshal([]byte(body), &domain_data)
	if err != nil {
		panic(err)
	}
	for domains, domain_val := range domain_data {
		if nes, ok := domain_val.(map[string]interface{})["ne"]; ok {
			for ne, data := range nes.(map[string]interface{}) {
				if data.(map[string]interface{})["metadata"] == ID {
					domainid = domains
					netid = ne
					break
				}
			}
		}
	}
	return
}

func FindNetworkGateway(domainID string, networkID string) (gatewayIP string) {

	url := "/0/connectivity/domain_prop/" + domainID + "/ne/brii" + networkID
	body, _ := RestCall("GET", url, nil)
	var domain_prop map[string]interface{}
	err := json.Unmarshal([]byte(body), &domain_prop)
	if err != nil {
		panic(err)
	}
	gatewayIP = domain_prop["ne_metadata"].(string)
	return
}

func DomainCreate(domainID string) {

	url := "/0/connectivity/domain?configonly=true"
	body, _ := RestCall("GET", url, nil)
	var domain_data map[string]interface{}
	err := json.Unmarshal([]byte(body), &domain_data)
	if err != nil {
		panic(err)
	}
	for domains := range domain_data {
		if domains == domainID {
			return
		}
	}

	url = "/0/tenant_manager/tenants" + "/" + domainID
	data := []byte(`{"containers": {
				"` + domainID + `": {
					"enable": "True",
					"context": "` + domainID + `",
					"domains": {}, "rules": {}}}}`)
	RestCall("PUT", url, data)

	url = "/0/tenant_manager/metaconfig/" + domainID
	data = []byte(`{}`)
	RestCall("PUT", url, data)

	url = "/0/tunnel_service/vnd_config/" + domainID
	data = []byte(`{"profile_name": "VXLAN",
			"add_vlan": "False"}`)
	RestCall("PUT", url, data)

	url = "/0/connectivity/domain/" + domainID
	data = []byte(`{"container_group": "` + domainID + `",
			"topology_name": "docker"}`)
	RestCall("PUT", url, data)

	url = "/0/connectivity/domain_prop/" + domainID
	data = []byte(`{}`)
	RestCall("PUT", url, data)

	url = "/0/pem_master/log_rule/" + domainID
	data = []byte(`{"rule": {
				"rule_` + domainID + `": {
					"pgtag1": "` + domainID + `",
					"log_ifc_type": "ACCESS_CONTAINER"}}}`)

	RestCall("PUT", url, data)
}

func DomainDelete(domainID string) {

	url := "/0/connectivity/domain?configonly=true"
	body, _ := RestCall("GET", url, nil)
	var domain_data map[string]interface{}
	err := json.Unmarshal([]byte(body), &domain_data)
	if err != nil {
		panic(err)
	}
	for domains, domain_val := range domain_data {
		if domains == domainID {
			res := domain_val.(map[string]interface{})["ne"]
			if len(res.(map[string]interface{})) == 0 {

				url = "/0/pem_master/log_rule/" + domainID
				RestCall("DELETE", url, nil)

				url = "/0/connectivity/domain_prop/" + domainID
				RestCall("DELETE", url, nil)

				url = "/0/connectivity/domain/" + domainID
				RestCall("DELETE", url, nil)

				url = "/0/tunnel_service/vnd_config/" + domainID
				RestCall("DELETE", url, nil)

				url = "/0/tenant_manager/metaconfig/" + domainID
				RestCall("DELETE", url, nil)

				url = "/0/tenant_manager/tenants/" + domainID
				RestCall("DELETE", url, nil)
			}
		}
	}
}

func GetNeId(NeName string, DomainID string) (NeID string) {

	url := "/0/connectivity/domain/" + DomainID + "/ne?configonly=true&level=1"
	body, _ := RestCall("GET", url, nil)
	var ne_data map[string]interface{}
	err := json.Unmarshal([]byte(body), &ne_data)
	if err != nil {
		panic(err)
	}
	for nes, ne_val := range ne_data {
		if ne_val.(map[string]interface{})["ne_dname"] == NeName {
			NeID = nes
			break
		}
	}
	return
}

func CreateNetworkLink(NeName string, DomainID string, NetworkID string, IP string, Netmask string) {

	ne_ID := GetNeId(NeName, DomainID)
	CheckNeChildList(ne_ID, DomainID, "ifc")
	CheckNeChildList(NetworkName(NetworkID), DomainID, "ifc")
	ne_ifc := NetworkID
	url := "/0/connectivity/domain/" + DomainID + "/ne/" + ne_ID + "/ifc/" + ne_ifc
	data := []byte(`{"attachable": "true",
                         "list": "true",
                         "attach_type": "static,dynamic",
                         "mobility": "true",
                         "ifc_name": "` + ne_ifc + `",
                         "ifc_type": "static",
                         "ip_address": "` + IP + `",
                         "ip_address_mask": "` + Netmask + `"}`)
	RestCall("PUT", url, data)

	net_ifc := ne_ID
	url = "/0/connectivity/domain/" + DomainID + "/ne/" + NetworkName(NetworkID) + "/ifc/" + net_ifc
	data = []byte(`{"attachable": "true",
                         "list": "true",
                         "attach_type": "static,dynamic",
                         "mobility": "true",
                         "ifc_type": "static"}`)
	RestCall("PUT", url, data)

	link_name := ne_ID + NetworkID
	url = "/0/connectivity/domain/" + DomainID + "/link/" + link_name
	data = []byte(`{"link_type": "static",
                         "link_name": "` + link_name + `",
                         "attachment1": "/ne/` + ne_ID + `/ifc/` + ne_ifc + `",
                         "attachment2": "/ne/` + NetworkName(NetworkID) + `/ifc/` + net_ifc + `"}`)
	RestCall("PUT", url, data)
}

func DeleteNetworkLinks(DomainID string, NetworkID string) {

	var ne_ID string
	var ne_ifc string
	url := "/0/connectivity/domain/" + DomainID
	body, _ := RestCall("GET", url+"?configonly=true", nil)
	var domain_data map[string]interface{}
	err := json.Unmarshal([]byte(body), &domain_data)
	if err != nil {
		panic(err)
	}
	for domains, domain_val := range domain_data {
		if domains == "link" {
			links := domain_val.(map[string]interface{})
			for att, att_info := range links {
				att_1 := att_info.(map[string]interface{})["attachment1"].(string)
				att_2 := att_info.(map[string]interface{})["attachment2"].(string)
				if strings.Split(att_1, "/")[2][3:] == NetworkID {
					ne_ID = strings.Split(att_2, "/")[2]
					ne_ifc = strings.Split(att_2, "/")[4]
					RestCall("DELETE", url+"/link/"+att, nil)
					ifc_url := url + "/ne/" + ne_ID + "/ifc/" + ne_ifc
					RestCall("DELETE", ifc_url, nil)
				} else if strings.Split(att_2, "/")[2][3:] == NetworkID {
					ne_ID = strings.Split(att_1, "/")[2]
					ne_ifc = strings.Split(att_1, "/")[4]
					RestCall("DELETE", url+"/link/"+att, nil)
					ifc_url := url + "/ne/" + ne_ID + "/ifc/" + ne_ifc
					RestCall("DELETE", ifc_url, nil)
				}
			}
		}
	}
}

func NetworkName(ID string) (name string) {
	name = "bri" + ID
	return
}

func CheckNeChildList(NeID string, DomainID string, childList string) {

	url := "/0/connectivity/domain/" + DomainID + "/ne/" + NeID + "?configonly=true"
	body, _ := RestCall("GET", url, nil)
	var ne_data map[string]interface{}
	err := json.Unmarshal([]byte(body), &ne_data)
	if err != nil {
		panic(err)
	}
	if _, ok := ne_data[childList]; ok {
		return
	} else {
		data := []byte(`{}`)
		RestCall("PUT", url+"/"+childList, data)
		return
	}
}

func AddMetaconfig(domainID string, netID string, deviceID string, endpointID string, macaddr string) {

	url := "/0/tenant_manager/metaconfig/" + domainID + "?configonly=true"
	body, _ := RestCall("GET", url, nil)
	var tm_data map[string]interface{}
	err := json.Unmarshal([]byte(body), &tm_data)
	if err != nil {
		panic(err)
	}

	for device, _ := range tm_data["workloads"].(map[string]interface{}) {
		if device == deviceID {
			url = "/0/tenant_manager/metaconfig/" + domainID + "/workloads/" + deviceID + "/prop/" + endpointID
			data := []byte(`{"phy_address": "` + macaddr + `",
					 "hint": "` + netID + `"}`)
			RestCall("PUT", url, data)
			return
		}
	}

	url = "/0/tenant_manager/metaconfig/" + domainID + "/workloads/" + deviceID
	data := []byte(`{"ne_type": "container",
			 "prop": {
				"` + endpointID + `": {
						"phy_address": "` + macaddr + `",
						"hint": "` + netID + `"}}}`)
	RestCall("PUT", url, data)
}

func RemoveMetaconfig(domainID string, netID string, endpointID string) {

	url := "/0/tenant_manager/metaconfig/" + domainID + "?configonly=true"
	body, _ := RestCall("GET", url, nil)
	var tm_data map[string]interface{}
	err := json.Unmarshal([]byte(body), &tm_data)
	if err != nil {
		panic(err)
	}

	for device, prop := range tm_data["workloads"].(map[string]interface{}) {
		for endpoint, _ := range prop.(map[string]interface{})["prop"].(map[string]interface{}) {
			if endpoint == endpointID {
				if len(prop.(map[string]interface{})["prop"].(map[string]interface{})) < 2 {
					url = "/0/tenant_manager/metaconfig/" + domainID + "/workloads/" + device
					RestCall("DELETE", url, nil)
					return
				}
				url = "/0/tenant_manager/metaconfig/" + domainID + "/workloads/" + device + "/prop/" + endpoint
				RestCall("DELETE", url, nil)
			}
		}
	}
}
<|endoftext|>


<commit_before>package eval

import (
	"bytes"
	"monkey/ast"
	"strings"
)

type Array struct {
	Members []Object
}

func (a *Array) Inspect() string {
	var out bytes.Buffer
	members := []string{}
	for _, m := range a.Members {
		members = append(members, m.Inspect())
	}
	out.WriteString("[")
	out.WriteString(strings.Join(members, ", "))
	out.WriteString("]")

	return out.String()
}
func (a *Array) Type() ObjectType { return ARRAY_OBJ }

func (a *Array) CallMethod(method string, args []Object) Object {
	switch method {
	case "count":
		return a.Count(args...)
	case "filter":
		return a.Filter(args...)
	case "index":
		return a.Index(args...)
	case "map":
		return a.Map(args...)
	case "push":
		return a.Push(args...)
	case "pop":
		return a.Pop(args...)
	}
	return newError(NOMETHODERROR, a.Type(), method)
}

func (a *Array) Count(args ...Object) Object {
	if len(args) < 1 || len(args) > 1 {
		return newError(ARGUMENTERROR, "1", len(args))
	}
	count := 0
	for _, v := range a.Members {
		switch c := args[0].(type) {
		case *Integer:
			if c.Value == v.(*Integer).Value {
				count++
			}
		case *String:
			if c.Value == v.(*String).Value {
				count++
			}
		default:
			if c == v {
				count++
			}
		}
	}
	return &Integer{Value: int64(count)}
}

func (a *Array) Filter(args ...Object) Object {
	if len(args) != 1 {
		return newError(ARGUMENTERROR, "1", len(args))
	}
	block, ok := args[0].(*Function)
	if !ok {
		return newError(INPUTERROR, args[0].Type(), "filter")
	}
	arr := &Array{}
	arr.Members = []Object{}
	s := NewScope(nil)
	for _, argument := range a.Members {
		s.Set(block.Literal.Parameters[0].(*ast.Identifier).Value, argument)
		r, ok := Eval(block.Literal.Body, s).(*Boolean)
		if !ok {
			return newError(RTERROR, "BOOLEAN")
		}
		if r.Value {
			arr.Members = append(arr.Members, argument)
		}
	}
	return arr
}

func (a *Array) Index(args ...Object) Object {
	if len(args) < 1 || len(args) > 1 {
		return newError(ARGUMENTERROR, "1", len(args))
	}
	for i, v := range a.Members {
		switch c := args[0].(type) {
		case *Integer:
			if c.Value == v.(*Integer).Value {
				return &Integer{Value: int64(i)}
			}
		case *String:
			if c.Value == v.(*String).Value {
				return &Integer{Value: int64(i)}
			}
		default:
			if c == v {
				return &Integer{Value: int64(i)}
			}
		}
	}
	return NULL
}
func (a *Array) Map(args ...Object) Object {
	if len(args) != 1 {
		return newError(ARGUMENTERROR, "1", len(args))
	}
	block, ok := args[0].(*Function)
	if !ok {
		return newError(INPUTERROR, args[0].Type(), "map")
	}
	arr := &Array{}
	arr.Members = []Object{}
	s := NewScope(nil)
	for _, argument := range a.Members {
		s.Set(block.Literal.Parameters[0].(*ast.Identifier).Value, argument)
		r := Eval(block.Literal.Body, s)
		if obj, ok := r.(*ReturnValue); ok {
			r = obj.Value
		}
		arr.Members = append(arr.Members, r)
	}
	return arr
}

func (a *Array) Pop(args ...Object) Object {
	last := len(a.Members) - 1
	if len(args) == 0 {
		if last < 0 {
			return newError(INDEXERROR, last)
		}
		popped := a.Members[last]
		a.Members = a.Members[:last]
		return popped
	}
	idx := args[0].(*Integer).Value
	if idx < 0 {
		idx = idx + int64(last+1)
	}
	if idx < 0 || idx > int64(last) {
		return newError(INDEXERROR, idx)
	}
	popped := a.Members[idx]
	a.Members = append(a.Members[:idx], a.Members[idx+1:]...)
	return popped
}

func (a *Array) Push(args ...Object) Object {
	l := len(args)
	if l != 1 {
		return newError(ARGUMENTERROR, "1", l)
	}
	a.Members = append(a.Members, args[0])
	return a
}
<commit_msg>added array merge<commit_after>package eval

import (
	"bytes"
	"monkey/ast"
	"strings"
)

type Array struct {
	Members []Object
}

func (a *Array) Inspect() string {
	var out bytes.Buffer
	members := []string{}
	for _, m := range a.Members {
		members = append(members, m.Inspect())
	}
	out.WriteString("[")
	out.WriteString(strings.Join(members, ", "))
	out.WriteString("]")

	return out.String()
}
func (a *Array) Type() ObjectType { return ARRAY_OBJ }

func (a *Array) CallMethod(method string, args []Object) Object {
	switch method {
	case "count":
		return a.Count(args...)
	case "filter":
		return a.Filter(args...)
	case "index":
		return a.Index(args...)
	case "map":
		return a.Map(args...)
	case "merge":
		return a.Merge(args...)
	case "push":
		return a.Push(args...)
	case "pop":
		return a.Pop(args...)
	}
	return newError(NOMETHODERROR, a.Type(), method)
}

func (a *Array) Count(args ...Object) Object {
	if len(args) < 1 || len(args) > 1 {
		return newError(ARGUMENTERROR, "1", len(args))
	}
	count := 0
	for _, v := range a.Members {
		switch c := args[0].(type) {
		case *Integer:
			if c.Value == v.(*Integer).Value {
				count++
			}
		case *String:
			if c.Value == v.(*String).Value {
				count++
			}
		default:
			if c == v {
				count++
			}
		}
	}
	return &Integer{Value: int64(count)}
}

func (a *Array) Filter(args ...Object) Object {
	if len(args) != 1 {
		return newError(ARGUMENTERROR, "1", len(args))
	}
	block, ok := args[0].(*Function)
	if !ok {
		return newError(INPUTERROR, args[0].Type(), "filter")
	}
	arr := &Array{}
	arr.Members = []Object{}
	s := NewScope(nil)
	for _, argument := range a.Members {
		s.Set(block.Literal.Parameters[0].(*ast.Identifier).Value, argument)
		r, ok := Eval(block.Literal.Body, s).(*Boolean)
		if !ok {
			return newError(RTERROR, "BOOLEAN")
		}
		if r.Value {
			arr.Members = append(arr.Members, argument)
		}
	}
	return arr
}

func (a *Array) Index(args ...Object) Object {
	if len(args) < 1 || len(args) > 1 {
		return newError(ARGUMENTERROR, "1", len(args))
	}
	for i, v := range a.Members {
		switch c := args[0].(type) {
		case *Integer:
			if c.Value == v.(*Integer).Value {
				return &Integer{Value: int64(i)}
			}
		case *String:
			if c.Value == v.(*String).Value {
				return &Integer{Value: int64(i)}
			}
		default:
			if c == v {
				return &Integer{Value: int64(i)}
			}
		}
	}
	return NULL
}
func (a *Array) Map(args ...Object) Object {
	if len(args) != 1 {
		return newError(ARGUMENTERROR, "1", len(args))
	}
	block, ok := args[0].(*Function)
	if !ok {
		return newError(INPUTERROR, args[0].Type(), "map")
	}
	arr := &Array{}
	s := NewScope(nil)
	for _, argument := range a.Members {
		s.Set(block.Literal.Parameters[0].(*ast.Identifier).Value, argument)
		r := Eval(block.Literal.Body, s)
		if obj, ok := r.(*ReturnValue); ok {
			r = obj.Value
		}
		arr.Members = append(arr.Members, r)
	}
	return arr
}

func (a *Array) Merge(args ...Object) Object {
	if len(args) != 1 {
		return newError(ARGUMENTERROR, "1", len(args))
	}
	m, ok := args[0].(*Array)
	if !ok {
		return newError(INPUTERROR, args[0].Type(), "map")
	}
	arr := &Array{}
	for _, v := range a.Members {
		arr.Members = append(arr.Members, v)
	}
	for _, v := range m.Members {
		arr.Members = append(arr.Members, v)
	}
	return arr
}

func (a *Array) Pop(args ...Object) Object {
	last := len(a.Members) - 1
	if len(args) == 0 {
		if last < 0 {
			return newError(INDEXERROR, last)
		}
		popped := a.Members[last]
		a.Members = a.Members[:last]
		return popped
	}
	idx := args[0].(*Integer).Value
	if idx < 0 {
		idx = idx + int64(last+1)
	}
	if idx < 0 || idx > int64(last) {
		return newError(INDEXERROR, idx)
	}
	popped := a.Members[idx]
	a.Members = append(a.Members[:idx], a.Members[idx+1:]...)
	return popped
}

func (a *Array) Push(args ...Object) Object {
	l := len(args)
	if l != 1 {
		return newError(ARGUMENTERROR, "1", l)
	}
	a.Members = append(a.Members, args[0])
	return a
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"math"
	"math/rand"

	"github.com/gographics/imagick/imagick"
)

var (
	output = flag.String("o", "output.gif", "output filename")
	color  = flag.String("color", "black", "background color")
)

func speedLine(mw *imagick.MagickWand, aw *imagick.MagickWand) error {
	cols, rows := mw.GetImageHeight(), mw.GetImageWidth()

	dw := imagick.NewDrawingWand()
	defer dw.Destroy()
	cw := imagick.NewPixelWand()
	cw.SetColor(*color)
	dw.SetFillColor(cw)

	center := []float64{float64(cols) / 2.0, float64(rows) / 2.0}
	const radiusCenter float64 = 0.75
	const step float64 = 0.02
	const bold float64 = 1.0
	var theeta float64

	for theeta < math.Pi*2 {
		stepNoise := rand.Float64() + 0.5
		theeta += step * stepNoise
		radiusCenterNoise := rand.Float64()*0.3 + 1.0
		boldNoise := rand.Float64() + 0.7 + 0.3

		point0 := imagick.PointInfo{
			X: math.Sin(theeta)*center[0]*radiusCenter*radiusCenterNoise + center[0],
			Y: math.Cos(theeta)*center[1]*radiusCenter*radiusCenterNoise + center[1],
		}
		point1 := imagick.PointInfo{
			X: math.Sin(theeta)*center[0]*2 + center[0],
			Y: math.Cos(theeta)*center[1]*2 + center[1],
		}
		point2 := imagick.PointInfo{
			X: math.Sin(theeta+step*bold*boldNoise)*center[0]*2 + center[0],
			Y: math.Cos(theeta+step*bold*boldNoise)*center[1]*2 + center[1],
		}

		dw.Polygon([]imagick.PointInfo{point0, point1, point2})
	}

	if err := aw.DrawImage(dw); err != nil {
		return err
	}

	return nil
}

func main() {
	flag.Parse()

	imagick.Initialize()
	defer imagick.Terminate()

	mw := imagick.NewMagickWand()
	defer mw.Destroy()
	aw := imagick.NewMagickWand()
	defer aw.Destroy()

	if err := mw.ReadImage(flag.Arg(0)); err != nil {
		panic(err)
	}

	if int(mw.GetNumberImages()) == 1 {
		mw.SetIteratorIndex(0)
		first := mw.GetImage()
		mw.ResetIterator()
		for i := 0; i < 3; i++ {
			mw.AddImage(first.Clone())
		}
	}

	for i := 0; i < int(mw.GetNumberImages()); i++ {
		mw.SetIteratorIndex(i)
		tw := mw.GetImage()
		aw.AddImage(tw)
		if err := speedLine(tw, aw); err != nil {
			fmt.Println(err)
			return
		}
		tw.Destroy()
	}
	mw.ResetIterator()

	aw.SetOption("loop", "0")
	if err := aw.WriteImages(*output, true); err != nil {
		panic(err)
	}
}
<commit_msg>Fix rows and cols<commit_after>package main

import (
	"flag"
	"fmt"
	"math"
	"math/rand"

	"github.com/gographics/imagick/imagick"
)

var (
	output = flag.String("o", "output.gif", "output filename")
	color  = flag.String("color", "black", "background color")
)

func speedLine(mw *imagick.MagickWand, aw *imagick.MagickWand) error {
	rows, cols := mw.GetImageHeight(), mw.GetImageWidth()

	dw := imagick.NewDrawingWand()
	defer dw.Destroy()
	cw := imagick.NewPixelWand()
	cw.SetColor(*color)
	dw.SetFillColor(cw)

	center := []float64{float64(cols) / 2.0, float64(rows) / 2.0}
	const radiusCenter float64 = 0.75
	const step float64 = 0.02
	const bold float64 = 1.0
	var theeta float64

	for theeta < math.Pi*2 {
		stepNoise := rand.Float64() + 0.5
		theeta += step * stepNoise
		radiusCenterNoise := rand.Float64()*0.3 + 1.0
		boldNoise := rand.Float64() + 0.7 + 0.3

		point0 := imagick.PointInfo{
			X: math.Sin(theeta)*center[0]*radiusCenter*radiusCenterNoise + center[0],
			Y: math.Cos(theeta)*center[1]*radiusCenter*radiusCenterNoise + center[1],
		}
		point1 := imagick.PointInfo{
			X: math.Sin(theeta)*center[0]*2 + center[0],
			Y: math.Cos(theeta)*center[1]*2 + center[1],
		}
		point2 := imagick.PointInfo{
			X: math.Sin(theeta+step*bold*boldNoise)*center[0]*2 + center[0],
			Y: math.Cos(theeta+step*bold*boldNoise)*center[1]*2 + center[1],
		}

		dw.Polygon([]imagick.PointInfo{point0, point1, point2})
	}

	if err := aw.DrawImage(dw); err != nil {
		return err
	}

	return nil
}

func main() {
	flag.Parse()

	imagick.Initialize()
	defer imagick.Terminate()

	mw := imagick.NewMagickWand()
	defer mw.Destroy()
	aw := imagick.NewMagickWand()
	defer aw.Destroy()

	if err := mw.ReadImage(flag.Arg(0)); err != nil {
		panic(err)
	}

	if int(mw.GetNumberImages()) == 1 {
		mw.SetIteratorIndex(0)
		first := mw.GetImage()
		mw.ResetIterator()
		for i := 0; i < 3; i++ {
			mw.AddImage(first.Clone())
		}
	}

	for i := 0; i < int(mw.GetNumberImages()); i++ {
		mw.SetIteratorIndex(i)
		tw := mw.GetImage()
		aw.AddImage(tw)
		if err := speedLine(tw, aw); err != nil {
			fmt.Println(err)
			return
		}
		tw.Destroy()
	}
	mw.ResetIterator()

	aw.SetOption("loop", "0")
	if err := aw.WriteImages(*output, true); err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>/*
 * Copyright 2014 Google Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// Package docker contains simple utilities for pulling a docker image, starting
// a container, and stoping a container. It assumes that docker is installed. If
// it is not, it will simply throw an error.
package docker

import (
	"bytes"
	"errors"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	glog "github.com/google/shipshape/third_party/go-glog"
)

const (
	shipshapeWork = "/shipshape-workspace"
	shipshapeLogs = "/shipshape-output"
)

// TODO(ciera): Consider making these all use channels.
type CommandResult struct {
	Stdout string
	Stderr string
	Err    error
}

func trimResult(stdout, stderr *bytes.Buffer, err error) CommandResult {
	return CommandResult{strings.TrimSpace(stdout.String()), strings.TrimSpace(stderr.String()), err}
}

// ContainerExists checks if a container with the given name is in the list of running, or old, containers.
// NB! This implementation assumes the last name of the 'docker ps' output will be the container name.
func ContainerExists(container string) (bool, error) {
	// Setup and run command
	stdout := bytes.NewBuffer(nil)
	cmd := exec.Command("docker", "ps", "-a")
	cmd.Stdout = stdout
	if err := cmd.Run(); err != nil {
		fmt.Printf("Problem running command, err: %v", err)
		return false, err
	}
	// Process output in search for container name match.
	// The 'docker ps' output lists the container names in the last column.
	// Prefixing the container name with a space to avoid substring matching.
	spacedName := fmt.Sprintf(" %s", container)
	for itr, line := range strings.Split(stdout.String(), "\n") {
		// Skip the title row
		if itr == 0 {
			continue
		}
		// Docker adds spaces to the end of each row
		trimmedLine := strings.Trim(line, " ")
		if strings.HasSuffix(trimmedLine, spacedName) {
			return true, nil
		}
	}
	return false, nil
}

// HasDocker determines whether docker is installed
// and included in PATH.
func HasDocker() bool {
	cmd := exec.Command("which", "docker")
	return cmd.Run() == nil
}

// FullImageName creates a full image name from a repository URI, an image name, and a tag.
func FullImageName(repo, image, tag string) string {
	fullImage := repo
	if fullImage != "" && !strings.HasSuffix(fullImage, "/") {
		fullImage += "/"
	}
	fullImage += image

	if tag != "" {
		fullImage += ":" + tag
	}
	return fullImage
}

// Pull makes a command line call to docker to pull the specified container.
// docker pull repository/name:tag.
// It returns stdout, stderr, and any errors from running.
// This is a blocking call, and should be wrapped in a go routine for asynchonous use.
func Pull(image string) CommandResult {
	cmd := exec.Command("docker", "pull", image)
	stdout := bytes.NewBuffer(nil)
	stderr := bytes.NewBuffer(nil)
	cmd.Stdout = stdout
	cmd.Stderr = stderr
	err := cmd.Run()
	return CommandResult{stdout.String(), stderr.String(), err}
}

func setupArgs(container string, portMap map[int]int, volumeMap map[string]string, linkContainers []string, environment map[string]string) []string {
	var linkArgs []string
	for _, container := range linkContainers {
		linkArgs = append(linkArgs, fmt.Sprintf("--link=%s:%s", container, container))
	}

	var environmentVars []string
	for ev, val := range environment {
		environmentVars = append(environmentVars, "-e="+strconv.Quote(ev+"="+val))
	}

	var volumeList []string
	for hostVolume, containerVolume := range volumeMap {
		volumeList = append(volumeList, fmt.Sprintf("-v=%s:%s", hostVolume, containerVolume))
	}

	var exposePorts []string
	for hostPort, containerPort := range portMap {
		exposePorts = append(exposePorts, fmt.Sprintf("-p=127.0.0.1:%d:%d", hostPort, containerPort))
	}

	args := exposePorts
	args = append(args, linkArgs...)
	args = append(args, volumeList...)
	args = append(args, environmentVars...)
	args = append(args, fmt.Sprintf("--name=%s", container))
	return args
}

// RunAnalyzer runs the analyzer image with container analyzerContainer. It runs it at port (mapped
// to internal port 10005), binds the volumes for the workspacePath and logsPath, and gives the privileged
// if dind (docker-in-docker) is true.
func RunAnalyzer(image, analyzerContainer, workspacePath, logsPath string, port int, dind bool) CommandResult {
	stdout := bytes.NewBuffer(nil)
	stderr := bytes.NewBuffer(nil)
	if len(analyzerContainer) == 0 {
		return CommandResult{"", "", errors.New("need to provide a name for the container")}
	}

	volumeMap := map[string]string{
		workspacePath: shipshapeWork,
		logsPath:      shipshapeLogs,
	}
	args := []string{"run"}
	if dind {
		args = append(args, "--privileged")
	}
	args = append(args, setupArgs(analyzerContainer, map[int]int{port: 10005}, volumeMap, nil, nil)...)
	args = append(args, "-d", image)

	glog.Infof("Running 'docker %v'\n", args)

	cmd := exec.Command("docker", args...)
	cmd.Stdout = stdout
	cmd.Stderr = stderr
	err := cmd.Run()
	return CommandResult{stdout.String(), stderr.String(), err}
}

// RunService runs the shipshape service at image, as the container named container. It binds the
// shipshape workspace and logs appropriately. It starts with the third-party analyzers already
// running at analyzerContainers. The service is started with the privileged flag if dind (docker-in-docker)
// is true.
func RunService(image, container, workspacePath, logsPath string, analyzerContainers []string, dind bool) CommandResult {
	stdout := bytes.NewBuffer(nil)
	stderr := bytes.NewBuffer(nil)
	if len(container) == 0 {
		return CommandResult{"", "", errors.New("need to provide a name for the container")}
	}

	volumeMap := map[string]string{workspacePath: shipshapeWork, logsPath: shipshapeLogs}

	var locations []string
	for _, container := range analyzerContainers {
		locations = append(locations, fmt.Sprintf(`$%s_PORT_10005_TCP_ADDR:$%s_PORT_10005_TCP_PORT`, strings.ToUpper(container), strings.ToUpper(container)))
	}
	locations = append(locations, "localhost:10005", "localhost:10006", "localhost:10008")

	args := []string{"run"}
	if dind {
		args = append(args, "--privileged")
	}
	args = append(args, setupArgs(container, map[int]int{10007: 10007}, volumeMap, analyzerContainers, map[string]string{"START_SERVICE": "true", "ANALYZERS": strings.Join(locations, ",")})...)
	args = append(args, "-d", image)

	glog.Infof("Running 'docker %v'\n", args)

	cmd := exec.Command("docker", args...)
	cmd.Stdout = stdout
	cmd.Stderr = stderr
	err := cmd.Run()
	return CommandResult{stdout.String(), stderr.String(), err}
}

// RunKythe runs the specified kythe docker image at the named container. It uses the
// source root and extractor specified, and gives the privileged flag if dind (docker-in-docker) is true.
// It returns stdout, stderr, and any errors from running.
// This is a blocking call, and should be wrapped in a go routine for asynchonous use.
func RunKythe(image, container, sourcePath, extractor string, dind bool) CommandResult {
	stdout := bytes.NewBuffer(nil)
	stderr := bytes.NewBuffer(nil)
	if len(container) == 0 {
		return CommandResult{"", "", errors.New("need to provide a name for the container")}
	}

	volumeMap := map[string]string{
		filepath.Join(sourcePath, "compilations"): "/compilations",
		sourcePath: "/repo",
	}
	home := os.Getenv("HOME")
	if len(home) > 0 {
		volumeMap[filepath.Join(home, ".m2")] = "/root/.m2"
	}

	// TODO(ciera): Can we exclude files in the .shipshape ignore path?
	// TODO(ciera/emso): Can we use the same command for blaze extraction?
	args := []string{"run"}
	if dind {
		args = append(args, "--privileged")
	}
	args = append(args, setupArgs(container, nil, volumeMap, nil, nil)...)
	args = append(args, "-i", "-a", "stdin", "-a", "stderr", "-a", "stdout", image)
	args = append(args, "--extract", extractor)

	cmd := exec.Command("docker", args...)
	cmd.Stdout = stdout
	cmd.Stderr = stderr
	err := cmd.Run()
	return CommandResult{stdout.String(), stderr.String(), err}
}

// Stop stops a running container.
// It returns stdout, stderr, and any errors from running.
// This is a blocking call, and should be wrapped in a go routine for asynchonous use.
// If requested, also remove the container.
func Stop(container string, waitTime time.Duration, remove bool) CommandResult {
	stdout := bytes.NewBuffer(nil)
	stderr := bytes.NewBuffer(nil)
	if container == "" {
		return CommandResult{"", "", errors.New("need to provide a name for the container")}
	}

	cmd := exec.Command("docker", "stop", fmt.Sprintf("-t=%d", int(waitTime.Seconds())), container)
	cmd.Stdout = stdout
	cmd.Stderr = stderr
	err := cmd.Run()

	if err == nil && remove {
		cmd := exec.Command("docker", "rm", container)
		cmd.Stdout = stdout
		cmd.Stderr = stderr
		err = cmd.Run()
	}

	return CommandResult{stdout.String(), stderr.String(), err}
}

// OutOfDate returns true if the image specified
// has not been pulled recently.
func OutOfDate(image string) bool {
	// TODO(ciera): Rather than always return true,
	// check a file that contains the last time this
	// image was updated, and only return true if it
	// is at least N days old.
	return true
}

// ImageMatches returns whether the container is running
// the current version of image.
func ImageMatches(image, container string) bool {
	imageHash, err := inspect(image, "{{.Id}}")
	if err != nil {
		return false
	}
	containerHash, err := inspect(container, "{{.Image}}")
	if err != nil {
		return false
	}
	return bytes.Equal(imageHash, containerHash)
}

// MappedVolume returns whether path is already mapped into the workspace
// of the shipshape service running at container. If it is, it returns the relative path
// of path within the mapped volume.
func MappedVolume(path, container string) (bool, string) {
	// Why this big ugly mess you ask? Because we can't use a go template to index
	// like this: .Volumes./shipshape-workspace because go templates only allow
	// alphanumeric identifiers. So instead, we do this.
	v, err := inspect(container, `{{range $k, $v := .Volumes}} {{if eq $k "/shipshape-workspace"}} {{$v}} {{end}} {{end}}`)
	if err != nil {
		return false, ""
	}
	volume := strings.TrimSpace(string(v))
	// Handle the equal case
	if path == volume {
		return true, ""
	}
	// Handle the subdirectory case by adding a trailing '/'
	// Want to rule out the case: volume='/a/b2' and path='/a/b'
	path += "/"
	return strings.HasPrefix(volume, path), strings.TrimPrefix(path, volume)
}

// ContainsLinks returns whether the given container has links to the given
// list of containers.
func ContainsLinks(container string, linkedContainers []string) bool {
	l, err := inspect(container, `{{.HostConfig.Links}}`)
	if err != nil {
		return false
	}
	links := strings.TrimSpace(string(l))
	for _, linkedContainer := range linkedContainers {
		if !strings.Contains(links, linkedContainer) {
			return false
		}
	}
	return true
}

// inspect runs docker inspect on name, which must be either an image or a container.
// If non-empty, it uses the specified format string.
// Returns the combined stdout/stderr from running docker inspect
func inspect(name, format string) ([]byte, error) {
	var formatter string
	if len(format) != 0 {
		formatter = fmt.Sprintf("--format='%s'", format)
	}
	cmd := exec.Command("docker", "inspect", formatter, name)
	return cmd.CombinedOutput()
}
<commit_msg>The docker inspect command to check if the workspace volume was the same was incorrect. This fixes to docker 1.8, which stores in Mounts<commit_after>/*
 * Copyright 2014 Google Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// Package docker contains simple utilities for pulling a docker image, starting
// a container, and stoping a container. It assumes that docker is installed. If
// it is not, it will simply throw an error.
package docker

import (
	"bytes"
	"errors"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	glog "github.com/google/shipshape/third_party/go-glog"
)

const (
	shipshapeWork = "/shipshape-workspace"
	shipshapeLogs = "/shipshape-output"
)

// TODO(ciera): Consider making these all use channels.
type CommandResult struct {
	Stdout string
	Stderr string
	Err    error
}

func trimResult(stdout, stderr *bytes.Buffer, err error) CommandResult {
	return CommandResult{strings.TrimSpace(stdout.String()), strings.TrimSpace(stderr.String()), err}
}

// ContainerExists checks if a container with the given name is in the list of running, or old, containers.
// NB! This implementation assumes the last name of the 'docker ps' output will be the container name.
func ContainerExists(container string) (bool, error) {
	// Setup and run command
	stdout := bytes.NewBuffer(nil)
	cmd := exec.Command("docker", "ps", "-a")
	cmd.Stdout = stdout
	if err := cmd.Run(); err != nil {
		fmt.Printf("Problem running command, err: %v", err)
		return false, err
	}
	// Process output in search for container name match.
	// The 'docker ps' output lists the container names in the last column.
	// Prefixing the container name with a space to avoid substring matching.
	spacedName := fmt.Sprintf(" %s", container)
	for itr, line := range strings.Split(stdout.String(), "\n") {
		// Skip the title row
		if itr == 0 {
			continue
		}
		// Docker adds spaces to the end of each row
		trimmedLine := strings.Trim(line, " ")
		if strings.HasSuffix(trimmedLine, spacedName) {
			return true, nil
		}
	}
	return false, nil
}

// HasDocker determines whether docker is installed
// and included in PATH.
func HasDocker() bool {
	cmd := exec.Command("which", "docker")
	return cmd.Run() == nil
}

// FullImageName creates a full image name from a repository URI, an image name, and a tag.
func FullImageName(repo, image, tag string) string {
	fullImage := repo
	if fullImage != "" && !strings.HasSuffix(fullImage, "/") {
		fullImage += "/"
	}
	fullImage += image

	if tag != "" {
		fullImage += ":" + tag
	}
	return fullImage
}

// Pull makes a command line call to docker to pull the specified container.
// docker pull repository/name:tag.
// It returns stdout, stderr, and any errors from running.
// This is a blocking call, and should be wrapped in a go routine for asynchonous use.
func Pull(image string) CommandResult {
	cmd := exec.Command("docker", "pull", image)
	stdout := bytes.NewBuffer(nil)
	stderr := bytes.NewBuffer(nil)
	cmd.Stdout = stdout
	cmd.Stderr = stderr
	err := cmd.Run()
	return CommandResult{stdout.String(), stderr.String(), err}
}

func setupArgs(container string, portMap map[int]int, volumeMap map[string]string, linkContainers []string, environment map[string]string) []string {
	var linkArgs []string
	for _, container := range linkContainers {
		linkArgs = append(linkArgs, fmt.Sprintf("--link=%s:%s", container, container))
	}

	var environmentVars []string
	for ev, val := range environment {
		environmentVars = append(environmentVars, "-e="+strconv.Quote(ev+"="+val))
	}

	var volumeList []string
	for hostVolume, containerVolume := range volumeMap {
		volumeList = append(volumeList, fmt.Sprintf("-v=%s:%s", hostVolume, containerVolume))
	}

	var exposePorts []string
	for hostPort, containerPort := range portMap {
		exposePorts = append(exposePorts, fmt.Sprintf("-p=127.0.0.1:%d:%d", hostPort, containerPort))
	}

	args := exposePorts
	args = append(args, linkArgs...)
	args = append(args, volumeList...)
	args = append(args, environmentVars...)
	args = append(args, fmt.Sprintf("--name=%s", container))
	return args
}

// RunAnalyzer runs the analyzer image with container analyzerContainer. It runs it at port (mapped
// to internal port 10005), binds the volumes for the workspacePath and logsPath, and gives the privileged
// if dind (docker-in-docker) is true.
func RunAnalyzer(image, analyzerContainer, workspacePath, logsPath string, port int, dind bool) CommandResult {
	stdout := bytes.NewBuffer(nil)
	stderr := bytes.NewBuffer(nil)
	if len(analyzerContainer) == 0 {
		return CommandResult{"", "", errors.New("need to provide a name for the container")}
	}

	volumeMap := map[string]string{
		workspacePath: shipshapeWork,
		logsPath:      shipshapeLogs,
	}
	args := []string{"run"}
	if dind {
		args = append(args, "--privileged")
	}
	args = append(args, setupArgs(analyzerContainer, map[int]int{port: 10005}, volumeMap, nil, nil)...)
	args = append(args, "-d", image)

	glog.Infof("Running 'docker %v'\n", args)

	cmd := exec.Command("docker", args...)
	cmd.Stdout = stdout
	cmd.Stderr = stderr
	err := cmd.Run()
	return CommandResult{stdout.String(), stderr.String(), err}
}

// RunService runs the shipshape service at image, as the container named container. It binds the
// shipshape workspace and logs appropriately. It starts with the third-party analyzers already
// running at analyzerContainers. The service is started with the privileged flag if dind (docker-in-docker)
// is true.
func RunService(image, container, workspacePath, logsPath string, analyzerContainers []string, dind bool) CommandResult {
	stdout := bytes.NewBuffer(nil)
	stderr := bytes.NewBuffer(nil)
	if len(container) == 0 {
		return CommandResult{"", "", errors.New("need to provide a name for the container")}
	}

	volumeMap := map[string]string{workspacePath: shipshapeWork, logsPath: shipshapeLogs}

	var locations []string
	for _, container := range analyzerContainers {
		locations = append(locations, fmt.Sprintf(`$%s_PORT_10005_TCP_ADDR:$%s_PORT_10005_TCP_PORT`, strings.ToUpper(container), strings.ToUpper(container)))
	}
	locations = append(locations, "localhost:10005", "localhost:10006", "localhost:10008")

	args := []string{"run"}
	if dind {
		args = append(args, "--privileged")
	}
	args = append(args, setupArgs(container, map[int]int{10007: 10007}, volumeMap, analyzerContainers, map[string]string{"START_SERVICE": "true", "ANALYZERS": strings.Join(locations, ",")})...)
	args = append(args, "-d", image)

	glog.Infof("Running 'docker %v'\n", args)

	cmd := exec.Command("docker", args...)
	cmd.Stdout = stdout
	cmd.Stderr = stderr
	err := cmd.Run()
	return CommandResult{stdout.String(), stderr.String(), err}
}

// RunKythe runs the specified kythe docker image at the named container. It uses the
// source root and extractor specified, and gives the privileged flag if dind (docker-in-docker) is true.
// It returns stdout, stderr, and any errors from running.
// This is a blocking call, and should be wrapped in a go routine for asynchonous use.
func RunKythe(image, container, sourcePath, extractor string, dind bool) CommandResult {
	stdout := bytes.NewBuffer(nil)
	stderr := bytes.NewBuffer(nil)
	if len(container) == 0 {
		return CommandResult{"", "", errors.New("need to provide a name for the container")}
	}

	volumeMap := map[string]string{
		filepath.Join(sourcePath, "compilations"): "/compilations",
		sourcePath: "/repo",
	}
	home := os.Getenv("HOME")
	if len(home) > 0 {
		volumeMap[filepath.Join(home, ".m2")] = "/root/.m2"
	}

	// TODO(ciera): Can we exclude files in the .shipshape ignore path?
	// TODO(ciera/emso): Can we use the same command for blaze extraction?
	args := []string{"run"}
	if dind {
		args = append(args, "--privileged")
	}
	args = append(args, setupArgs(container, nil, volumeMap, nil, nil)...)
	args = append(args, "-i", "-a", "stdin", "-a", "stderr", "-a", "stdout", image)
	args = append(args, "--extract", extractor)

	cmd := exec.Command("docker", args...)
	cmd.Stdout = stdout
	cmd.Stderr = stderr
	err := cmd.Run()
	return CommandResult{stdout.String(), stderr.String(), err}
}

// Stop stops a running container.
// It returns stdout, stderr, and any errors from running.
// This is a blocking call, and should be wrapped in a go routine for asynchonous use.
// If requested, also remove the container.
func Stop(container string, waitTime time.Duration, remove bool) CommandResult {
	stdout := bytes.NewBuffer(nil)
	stderr := bytes.NewBuffer(nil)
	if container == "" {
		return CommandResult{"", "", errors.New("need to provide a name for the container")}
	}

	cmd := exec.Command("docker", "stop", fmt.Sprintf("-t=%d", int(waitTime.Seconds())), container)
	cmd.Stdout = stdout
	cmd.Stderr = stderr
	err := cmd.Run()

	if err == nil && remove {
		cmd := exec.Command("docker", "rm", container)
		cmd.Stdout = stdout
		cmd.Stderr = stderr
		err = cmd.Run()
	}

	return CommandResult{stdout.String(), stderr.String(), err}
}

// OutOfDate returns true if the image specified
// has not been pulled recently.
func OutOfDate(image string) bool {
	// TODO(ciera): Rather than always return true,
	// check a file that contains the last time this
	// image was updated, and only return true if it
	// is at least N days old.
	return true
}

// ImageMatches returns whether the container is running
// the current version of image.
func ImageMatches(image, container string) bool {
	imageHash, err := inspect(image, "{{.Id}}")
	if err != nil {
		return false
	}
	containerHash, err := inspect(container, "{{.Image}}")
	if err != nil {
		return false
	}
	return bytes.Equal(imageHash, containerHash)
}

// MappedVolume returns whether path is already mapped into the workspace
// of the shipshape service running at container. If it is, it returns the relative path
// of path within the mapped volume.
func MappedVolume(path, container string) (bool, string) {
	// Why this big ugly mess you ask? Because we can't use a go template to index
	// like this: .Volumes./shipshape-workspace because go templates only allow
	// alphanumeric identifiers. So instead, we do this.
	v, err := inspect(container, `{{range $k, $v := .Mounts}} {{if eq $v.Destination "/shipshape-workspace"}} {{$v.Source}} {{end}} {{end}}`)
	if err != nil {
		return false, ""
	}
	volume := strings.TrimSpace(string(v))
	// Handle the equal case
	if path == volume {
		return true, ""
	}
	// Handle the subdirectory case by adding a trailing '/'
	// Want to rule out the case: volume='/a/b2' and path='/a/b'
	path += "/"
	return strings.HasPrefix(volume, path), strings.TrimPrefix(path, volume)
}

// ContainsLinks returns whether the given container has links to the given
// list of containers.
func ContainsLinks(container string, linkedContainers []string) bool {
	l, err := inspect(container, `{{.HostConfig.Links}}`)
	if err != nil {
		return false
	}
	links := strings.TrimSpace(string(l))
	for _, linkedContainer := range linkedContainers {
		if !strings.Contains(links, linkedContainer) {
			return false
		}
	}
	return true
}

// inspect runs docker inspect on name, which must be either an image or a container.
// If non-empty, it uses the specified format string.
// Returns the combined stdout/stderr from running docker inspect
func inspect(name, format string) ([]byte, error) {
	var formatter string
	if len(format) != 0 {
		formatter = fmt.Sprintf("--format='%s'", format)
	}
	cmd := exec.Command("docker", "inspect", formatter, name)
	return cmd.CombinedOutput()
}
<|endoftext|>


<commit_before>package clojure

import (
  azip "archive/zip"
  "errors"
  "io/ioutil"
  "os"
  "path/filepath"
  "strings"

  "github.com/apex/apex/archive"
  "github.com/apex/apex/function"
)

func init() {
  function.RegisterPlugin("clojure", &Plugin{})
}

const (
  // Runtime name used by Apex
  Runtime = "clojure"
  // RuntimeCanonical represents names used by AWS Lambda
  RuntimeCanonical = "java8"
  jarFile = "apex.jar"
)

// Plugin Does plugin things
type Plugin struct{}

// Open adds the shim and golang defaults.
func (p *Plugin) Open(fn *function.Function) error {
  if fn.Runtime != Runtime {
    return nil
  }

  if fn.Hooks.Build == "" {
    fn.Hooks.Build = "lein uberjar && mv target/*-standalone.jar target/apex.jar"
  }

  if fn.Hooks.Clean == "" {
    fn.Hooks.Clean = "rm -f target &> /dev/null"
  }

  if _, err := os.Stat(".apexignore"); err != nil {
    // Since we're deploying a fat jar, we don't need anything else.
    fn.IgnoreFile = []byte(`
*
!**/apex.jar
`)
  }

  return nil
}

// Build adds the jar contents to zipfile.
func (p *Plugin) Build(fn *function.Function, zip *archive.Zip) error {
  if fn.Runtime != Runtime {
    return nil
  }
  fn.Runtime = RuntimeCanonical

  expectedJarPath := filepath.Join(fn.Path, "target", jarFile)
  if _, err := os.Stat(expectedJarPath); err != nil {
    return errors.New("Expected jar file not found")
  }
  fn.Log.Debugf("found jar path: %s", expectedJarPath)

  fn.Log.Debug("appending compiled files")
  reader, err := azip.OpenReader(expectedJarPath)
  if err != nil {
    return err
  }
  defer reader.Close()

  for _, file := range reader.File {
    parts := strings.Split(file.Name, ".")
    extension := parts[len(parts) - 1]
    if extension == "clj" || extension == "cljx" || extension == "cljc" {
      continue
    }

    r, err := file.Open()
    if err != nil {
      return err
    }

    b, err := ioutil.ReadAll(r)
    if err != nil {
      return err
    }
    r.Close()

    zip.AddBytes(file.Name, b)
  }

  return nil
}
<commit_msg>refactor<commit_after>package clojure

import (
	azip "archive/zip"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"github.com/pkg/errors"

	"github.com/apex/apex/archive"
	"github.com/apex/apex/function"
)

func init() {
	function.RegisterPlugin("clojure", &Plugin{})
}

const (
	// Runtime name used by Apex
	Runtime = "clojure"

	// RuntimeCanonical represents names used by AWS Lambda
	RuntimeCanonical = "java8"

	jarFile = "apex.jar"
)

// Plugin Does plugin things
type Plugin struct{}

// Open adds the shim and golang defaults.
func (p *Plugin) Open(fn *function.Function) error {
	if fn.Runtime != Runtime {
		return nil
	}

	if fn.Hooks.Build == "" {
		fn.Hooks.Build = "lein uberjar && mv target/*-standalone.jar target/apex.jar"
	}

	if fn.Hooks.Clean == "" {
		fn.Hooks.Clean = "rm -f target &> /dev/null"
	}

	if _, err := os.Stat(".apexignore"); err != nil {
		// Since we're deploying a fat jar, we don't need anything else.
		fn.IgnoreFile = []byte(`
*
!**/apex.jar
`)
	}

	return nil
}

// Build adds the jar contents to zipfile.
func (p *Plugin) Build(fn *function.Function, zip *archive.Zip) error {
	if fn.Runtime != Runtime {
		return nil
	}
	fn.Runtime = RuntimeCanonical

	jar := filepath.Join(fn.Path, "target", jarFile)
	if _, err := os.Stat(jar); err != nil {
		return errors.Errorf("missing jar file %q", jar)
	}

	fn.Log.Debug("appending compiled files")
	reader, err := azip.OpenReader(jar)
	if err != nil {
		return errors.Wrap(err, "opening zip")
	}
	defer reader.Close()

	for _, file := range reader.File {
		parts := strings.Split(file.Name, ".")
		ext := parts[len(parts)-1]

		if ext == "clj" || ext == "cljx" || ext == "cljc" {
			continue
		}

		r, err := file.Open()
		if err != nil {
			return errors.Wrap(err, "opening file")
		}

		b, err := ioutil.ReadAll(r)
		if err != nil {
			return errors.Wrap(err, "reading file")
		}
		r.Close()

		zip.AddBytes(file.Name, b)
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"math/rand"
	"time"
)

// Tournament is the main container of data for this app.
type Tournament struct {
	Name        string    `json:"name"`
	ID          string    `json:"id"`
	Players     []Player  `json:"players"`
	Winners     []Player  `json:"winners"` // TODO: Refactor to pointer
	Runnerups   []*Player `json:"runnerups"`
	Judges      []Judge   `json:"judges"`
	Tryouts     []*Match  `json:"tryouts"`
	Semis       []*Match  `json:"semis"`
	Final       *Match    `json:"final"`
	Opened      time.Time `json:"opened"`
	Started     time.Time `json:"started"`
	Ended       time.Time `json:"ended"`
	playerRef   map[string]*Player
	db          *Database
	length      int
	finalLength int
}

// NewTournament returns a completely new Tournament
func NewTournament(name, id string, db *Database) (*Tournament, error) {
	t := Tournament{
		Name:   name,
		ID:     id,
		Opened: time.Now(),
		db:     db,
	}
	t.playerRef = make(map[string]*Player)
	t.Persist()
	return &t, nil
}

// LoadTournament loads a tournament from persisted JSON data
func LoadTournament(data []byte, db *Database) (t *Tournament, e error) {
	t = &Tournament{}
	err := json.Unmarshal(data, t)
	if err != nil {
		return t, err
	}

	t.db = db
	t.playerRef = make(map[string]*Player)
	return
}

// Persist tells the database to save this tournament to disk
func (t *Tournament) Persist() error {
	if t.db == nil {
		// This might happen in tests.
		return errors.New("no database instantiated")
	}
	return t.db.Persist(t)
}

// JSON returns a JSON representation of the Tournament
func (t *Tournament) JSON() (out []byte, err error) {
	out, err = json.Marshal(t)
	return
}

// AddPlayer adds a player into the tournament
//
// When adding new players, this means:
//   Generating tryouts
//   Shuffling players into positions
func (t *Tournament) AddPlayer(name string) error {
	p := Player{Name: name}
	if !t.CanJoin(name) {
		return errors.New("player already in match")
	}

	t.Players = append(t.Players, p)
	t.playerRef[name] = &p

	ts := len(t.Tryouts)
	ps := len(t.Players)
	if ts == 0 {
		// No matches yet - add four
		for i := 0; i < 4; i++ {
			match := NewMatch(t, i, "tryout")
			t.Tryouts = append(t.Tryouts, match)
		}
	} else if ts == 4 && ps == 17 {
		// More than 16 players - add four more matches
		for i := 0; i < 4; i++ {
			match := NewMatch(t, i+4, "tryout")
			t.Tryouts = append(t.Tryouts, match)
		}
	}

	// Right now there are only cases where we have two matches in the semis.
	if len(t.Semis) == 0 {
		t.Semis = []*Match{NewMatch(t, 0, "semi"), NewMatch(t, 1, "semi")}
		t.Semis[0].Prefill()
		t.Semis[1].Prefill()
	}
	if t.Final == nil {
		t.Final = NewMatch(t, 0, "final")
		t.Final.Prefill()
	}
	t.ShufflePlayers()
	t.Persist() // TODO: Error handling

	return nil
}

// ShufflePlayers will reposition players into matches
func (t *Tournament) ShufflePlayers() {
	// Reset the set matches
	for _, t := range t.Tryouts {
		t.Players = []Player{}
	}

	// Shuffle all the players
	slice := t.Players
	for i := range slice {
		j := rand.Intn(i + 1)
		slice[i], slice[j] = slice[j], slice[i]
	}

	// Loop the players and set them into the matches
	for i, p := range slice {
		m := t.Tryouts[i/4]
		m.AddPlayer(p)
	}

	for _, m := range t.Tryouts {
		m.Prefill()
	}
}

// StartTournament will generate the tournament.
//
// This includes:
//  Generating Tryout matches
//  Setting Started date
//
// It will fail if there are not between 8 and 24 players.
func (t *Tournament) StartTournament() error {
	ps := len(t.Players)
	if ps < 8 {
		return fmt.Errorf("Tournament needs at least 8 players, got %d", ps)
	}
	if ps > 24 {
		return fmt.Errorf("Tournament can only host 24 players, got %d", ps)
	}

	t.Started = time.Now()
	return nil
}

// PopulateRunnerups fills a match with the runnerups with best scores
func (t *Tournament) PopulateRunnerups(m *Match) error {
	c := 4 - m.ActualPlayers()
	r, err := t.GetRunnerups(c)
	if err != nil {
		return err
	}

	for _, p := range r {
		m.AddPlayer(p)
	}

	if m.ActualPlayers() != 4 {
		return errors.New("not enough runnerups to populate match")
	}

	return nil
}

// GetRunnerups gets the runnerups for this tournament
//
// The returned list is sorted descending by score.
func (t *Tournament) GetRunnerups(amount int) (ps []Player, err error) {
	err = t.UpdatePlayers()
	if err != nil {
		return
	}

	p := make([]Player, 0, len(t.Runnerups))
	for _, r := range t.Runnerups {
		p = append(p, *r)
	}
	bs := ByRunnerup(p)
	for i := 0; i < amount; i++ {
		// Add the runnerup to the return list
		runnerup := bs[i]
		ps = append(ps, runnerup)
	}

	if len(ps) != amount {
		return ps, errors.New("not enough players added")
	}
	return
}

// UpdatePlayers updates all the player objects with their scores from
// all the matches they have participated in.
func (t *Tournament) UpdatePlayers() error {
	var tp *Player
	var ok bool

	// Make sure all players have their score reset to nothing
	for _, p := range t.Players {
		tp = t.playerRef[p.Name]
		tp.Reset()
	}

	for _, m := range t.Tryouts {
		for _, p := range m.Players {
			if tp, ok = t.playerRef[p.Name]; ok {
				tp.Update(&p)
			}
		}
	}

	for _, m := range t.Semis {
		for _, p := range m.Players {
			if tp, ok = t.playerRef[p.Name]; ok {
				tp.Update(&p)
			}
		}
	}

	for _, p := range t.Final.Players {
		if tp, ok = t.playerRef[p.Name]; ok {
			tp.Update(&p)
		}
	}

	return nil
}

// MovePlayers moves the winner(s) of a Match into the next bracket of matches
// or into the Runnerup bracket.
func (t *Tournament) MovePlayers(m *Match) error {
	if m.Kind == "tryout" {
		ps := SortByKills(m.Players)
		for i := 0; i < len(ps); i++ {
			p := ps[i]
			// If we are in a four-match tryout, both the winner and the second-place
			// are to be sent to the semis
			if len(t.Tryouts) == 4 && i < 2 || i == 0 {
				// This spreads the winners into the semis so that the winners do not
				// face off immediately in the semis
				index := (i + m.Index) % 2
				t.Semis[index].AddPlayer(p)

				// If the player is also inside of the runnerups, move them from the
				// runnerup roster since they now have advanced to the finals. This
				// only happens for players that win the runnerup rounds.
				for j := 0; j < len(t.Runnerups); j++ {
					r := t.Runnerups[j]
					if r.Name == p.Name {
						t.Runnerups = append(t.Runnerups[:j], t.Runnerups[j+1:]...)
						break
					}
				}

			} else {
				// For everyone else, add them into the Runnerup bracket unless they are
				// already in there.
				found := false
				for j := 0; j < len(t.Runnerups); j++ {
					r := t.Runnerups[j]
					if r.Name == p.Name {
						found = true
						break
					}
				}
				if !found {
					t.Runnerups = append(t.Runnerups, &p)
				}
			}
		}
	}

	if m.Kind == "semi" {
		// For the semis, just place the winner and silver into the final
		for i, p := range SortByKills(m.Players) {
			if i < 2 {
				t.Final.AddPlayer(p)
			}
		}
	}

	return nil
}

// NextMatch returns the next match
func (t *Tournament) NextMatch() (m *Match, err error) {
	// Firstly, check the tryouts
	for x := range t.Tryouts {
		m = t.Tryouts[x]
		if !m.IsEnded() {
			return
		}
	}

	// If we don't have any tryouts, or there are no tryouts left,
	// check the semis
	for x := range t.Semis {
		m = t.Semis[x]
		if !m.IsEnded() {
			return
		}
	}

	if !t.Final.IsEnded() {
		return t.Final, nil
	}

	return m, errors.New("all matches have been played")
}

// AwardMedals places the winning players in the Winners position
func (t *Tournament) AwardMedals(m *Match) error {
	if m.Kind != "final" {
		return errors.New("awarding medals outside of the final")
	}

	ps := SortByKills(m.Players)
	t.Winners = ps[0:3]

	return nil
}

// IsOpen returns boolean true if the tournament is open for registration
func (t *Tournament) IsOpen() bool {
	return t.Started.IsZero()
}

// CanJoin checks if a player is allowed to join or is already in the tournament
func (t *Tournament) CanJoin(name string) bool {
	for _, p := range t.Players {
		if p.Name == name {
			return false
		}
	}
	return true
}
<commit_msg>Move initial match generatin to NewTournament()<commit_after>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"math/rand"
	"time"
)

// Tournament is the main container of data for this app.
type Tournament struct {
	Name        string    `json:"name"`
	ID          string    `json:"id"`
	Players     []Player  `json:"players"`
	Winners     []Player  `json:"winners"` // TODO: Refactor to pointer
	Runnerups   []*Player `json:"runnerups"`
	Judges      []Judge   `json:"judges"`
	Tryouts     []*Match  `json:"tryouts"`
	Semis       []*Match  `json:"semis"`
	Final       *Match    `json:"final"`
	Opened      time.Time `json:"opened"`
	Started     time.Time `json:"started"`
	Ended       time.Time `json:"ended"`
	playerRef   map[string]*Player
	db          *Database
	length      int
	finalLength int
}

// NewTournament returns a completely new Tournament
func NewTournament(name, id string, db *Database) (*Tournament, error) {
	t := Tournament{
		Name:   name,
		ID:     id,
		Opened: time.Now(),
		db:     db,
	}

	// No matches yet - add four
	for i := 0; i < 4; i++ {
		match := NewMatch(&t, i, "tryout")
		t.Tryouts = append(t.Tryouts, match)
	}

	t.Semis = []*Match{NewMatch(&t, 0, "semi"), NewMatch(&t, 1, "semi")}
	t.Semis[0].Prefill()
	t.Semis[1].Prefill()
	t.Final = NewMatch(&t, 0, "final")
	t.Final.Prefill()

	t.playerRef = make(map[string]*Player)
	t.Persist()
	return &t, nil
}

// LoadTournament loads a tournament from persisted JSON data
func LoadTournament(data []byte, db *Database) (t *Tournament, e error) {
	t = &Tournament{}
	err := json.Unmarshal(data, t)
	if err != nil {
		return t, err
	}

	t.db = db
	t.playerRef = make(map[string]*Player)
	return
}

// Persist tells the database to save this tournament to disk
func (t *Tournament) Persist() error {
	if t.db == nil {
		// This might happen in tests.
		return errors.New("no database instantiated")
	}
	return t.db.Persist(t)
}

// JSON returns a JSON representation of the Tournament
func (t *Tournament) JSON() (out []byte, err error) {
	out, err = json.Marshal(t)
	return
}

// AddPlayer adds a player into the tournament
//
// When adding new players, this means:
//   Generating tryouts
//   Shuffling players into positions
func (t *Tournament) AddPlayer(name string) error {
	p := Player{Name: name}
	if !t.CanJoin(name) {
		return errors.New("player already in match")
	}

	t.Players = append(t.Players, p)
	t.playerRef[name] = &p

	ts := len(t.Tryouts)
	ps := len(t.Players)
	if ts == 4 && ps == 17 {
		// More than 16 players - add four more matches
		for i := 0; i < 4; i++ {
			match := NewMatch(t, i+4, "tryout")
			t.Tryouts = append(t.Tryouts, match)
		}
	}

	t.ShufflePlayers()
	t.Persist() // TODO: Error handling

	return nil
}

// ShufflePlayers will reposition players into matches
func (t *Tournament) ShufflePlayers() {
	// Reset the set matches
	for _, t := range t.Tryouts {
		t.Players = []Player{}
	}

	// Shuffle all the players
	slice := t.Players
	for i := range slice {
		j := rand.Intn(i + 1)
		slice[i], slice[j] = slice[j], slice[i]
	}

	// Loop the players and set them into the matches
	for i, p := range slice {
		m := t.Tryouts[i/4]
		m.AddPlayer(p)
	}

	for _, m := range t.Tryouts {
		m.Prefill()
	}
}

// StartTournament will generate the tournament.
//
// This includes:
//  Generating Tryout matches
//  Setting Started date
//
// It will fail if there are not between 8 and 24 players.
func (t *Tournament) StartTournament() error {
	ps := len(t.Players)
	if ps < 8 {
		return fmt.Errorf("Tournament needs at least 8 players, got %d", ps)
	}
	if ps > 24 {
		return fmt.Errorf("Tournament can only host 24 players, got %d", ps)
	}

	t.Started = time.Now()
	return nil
}

// PopulateRunnerups fills a match with the runnerups with best scores
func (t *Tournament) PopulateRunnerups(m *Match) error {
	c := 4 - m.ActualPlayers()
	r, err := t.GetRunnerups(c)
	if err != nil {
		return err
	}

	for _, p := range r {
		m.AddPlayer(p)
	}

	if m.ActualPlayers() != 4 {
		return errors.New("not enough runnerups to populate match")
	}

	return nil
}

// GetRunnerups gets the runnerups for this tournament
//
// The returned list is sorted descending by score.
func (t *Tournament) GetRunnerups(amount int) (ps []Player, err error) {
	err = t.UpdatePlayers()
	if err != nil {
		return
	}

	p := make([]Player, 0, len(t.Runnerups))
	for _, r := range t.Runnerups {
		p = append(p, *r)
	}
	bs := ByRunnerup(p)
	for i := 0; i < amount; i++ {
		// Add the runnerup to the return list
		runnerup := bs[i]
		ps = append(ps, runnerup)
	}

	if len(ps) != amount {
		return ps, errors.New("not enough players added")
	}
	return
}

// UpdatePlayers updates all the player objects with their scores from
// all the matches they have participated in.
func (t *Tournament) UpdatePlayers() error {
	var tp *Player
	var ok bool

	// Make sure all players have their score reset to nothing
	for _, p := range t.Players {
		tp = t.playerRef[p.Name]
		tp.Reset()
	}

	for _, m := range t.Tryouts {
		for _, p := range m.Players {
			if tp, ok = t.playerRef[p.Name]; ok {
				tp.Update(&p)
			}
		}
	}

	for _, m := range t.Semis {
		for _, p := range m.Players {
			if tp, ok = t.playerRef[p.Name]; ok {
				tp.Update(&p)
			}
		}
	}

	for _, p := range t.Final.Players {
		if tp, ok = t.playerRef[p.Name]; ok {
			tp.Update(&p)
		}
	}

	return nil
}

// MovePlayers moves the winner(s) of a Match into the next bracket of matches
// or into the Runnerup bracket.
func (t *Tournament) MovePlayers(m *Match) error {
	if m.Kind == "tryout" {
		ps := SortByKills(m.Players)
		for i := 0; i < len(ps); i++ {
			p := ps[i]
			// If we are in a four-match tryout, both the winner and the second-place
			// are to be sent to the semis
			if len(t.Tryouts) == 4 && i < 2 || i == 0 {
				// This spreads the winners into the semis so that the winners do not
				// face off immediately in the semis
				index := (i + m.Index) % 2
				t.Semis[index].AddPlayer(p)

				// If the player is also inside of the runnerups, move them from the
				// runnerup roster since they now have advanced to the finals. This
				// only happens for players that win the runnerup rounds.
				for j := 0; j < len(t.Runnerups); j++ {
					r := t.Runnerups[j]
					if r.Name == p.Name {
						t.Runnerups = append(t.Runnerups[:j], t.Runnerups[j+1:]...)
						break
					}
				}

			} else {
				// For everyone else, add them into the Runnerup bracket unless they are
				// already in there.
				found := false
				for j := 0; j < len(t.Runnerups); j++ {
					r := t.Runnerups[j]
					if r.Name == p.Name {
						found = true
						break
					}
				}
				if !found {
					t.Runnerups = append(t.Runnerups, &p)
				}
			}
		}
	}

	if m.Kind == "semi" {
		// For the semis, just place the winner and silver into the final
		for i, p := range SortByKills(m.Players) {
			if i < 2 {
				t.Final.AddPlayer(p)
			}
		}
	}

	return nil
}

// NextMatch returns the next match
func (t *Tournament) NextMatch() (m *Match, err error) {
	// Firstly, check the tryouts
	for x := range t.Tryouts {
		m = t.Tryouts[x]
		if !m.IsEnded() {
			return
		}
	}

	// If we don't have any tryouts, or there are no tryouts left,
	// check the semis
	for x := range t.Semis {
		m = t.Semis[x]
		if !m.IsEnded() {
			return
		}
	}

	if !t.Final.IsEnded() {
		return t.Final, nil
	}

	return m, errors.New("all matches have been played")
}

// AwardMedals places the winning players in the Winners position
func (t *Tournament) AwardMedals(m *Match) error {
	if m.Kind != "final" {
		return errors.New("awarding medals outside of the final")
	}

	ps := SortByKills(m.Players)
	t.Winners = ps[0:3]

	return nil
}

// IsOpen returns boolean true if the tournament is open for registration
func (t *Tournament) IsOpen() bool {
	return t.Started.IsZero()
}

// CanJoin checks if a player is allowed to join or is already in the tournament
func (t *Tournament) CanJoin(name string) bool {
	for _, p := range t.Players {
		if p.Name == name {
			return false
		}
	}
	return true
}
<|endoftext|>


<commit_before>package main

import (
	"time"

	"github.com/nzlov/glog"
	"github.com/nzlov/glog/listener/console"
	"github.com/nzlov/glog/listener/file"
)

func main() {
	defer glog.Close()
	glog.SetLevel(glog.DebugLevel)
	f, err := file.New("l.log")
	if err != nil {
		panic(err)
	}
	glog.Register(f)
	glog.Register(console.New())

	a()
}
func a() {
	go func() {
		i := 1
		for {
			glog.Infoln(i)
			glog.NewFiled().
				Set("k", "v").
				Set("k1", "v1").
				Infoln(i)
			glog.NewTagFiled("tag").
				Set("k", "v").Infoln(i)
			i++
			time.Sleep(time.Second)
		}
	}()
	time.Sleep(time.Second * 2)
	go a1()
	time.Sleep(time.Second * 5)
}
func a1() {
	if 2 > 1 {
		glog.Panic("eeee", "dddddd")
		// glog.NewFiled().Set("k", "v").Set("k1", "v1").Panic("a")
		// glog.NewTagFiled("tag").Set("k", "v").Panic("a")
	}
}
<commit_msg>Test Color Console<commit_after>package main

import (
	"time"

	"github.com/nzlov/glog"
	"github.com/nzlov/glog/listener/colorconsole"
	"github.com/nzlov/glog/listener/file"
)

func main() {
	defer glog.Close()
	glog.SetLevel(glog.DebugLevel)
	f, err := file.New("l.log")
	if err != nil {
		panic(err)
	}
	glog.Register(f)
	glog.Register(colorconsole.New(colorconsole.ShowTypeDefault))

	a()
}
func a() {
	go func() {
		i := 1
		for {
			glog.Errorln(i)
			glog.Debugln(i)
			glog.NewFiled().
				Set("k", "v").
				Set("k1", "v1").
				Warnln(i)
			glog.NewTagFiled("tag").
				Set("k", "v").Infoln(i)
			i++
			time.Sleep(time.Second)
		}
	}()
	time.Sleep(time.Second * 2)
	go a1()
	time.Sleep(time.Second * 5)
}
func a1() {
	if 2 > 1 {
		glog.Panic("eeee", "dddddd")
		// glog.NewFiled().Set("k", "v").Set("k1", "v1").Panic("a")
		// glog.NewTagFiled("tag").Set("k", "v").Panic("a")
	}
}
<|endoftext|>