<commit_before>package main

import (
	"eaciit/gdrj/model"
	"eaciit/gdrj/modules"
	"os"

	"flag"
	"github.com/eaciit/dbox"
	"github.com/eaciit/orm/v1"
	"github.com/eaciit/toolkit"
	"strings"
	"sync"
	"time"
)

var conn dbox.IConnection
var count int

// var mwg sync.WaitGroup

var (
	t0                                                time.Time
	custgroup, prodgroup, plcode, ref                 string
	value, fiscalyear, iscount, gscount, scount, step int
	globalgross, globalsga                            float64
	mapsperiod                                        map[string]float64
	mapkeysvalue                                      map[string]float64
	masters                                           toolkit.M
	mwg                                               sync.WaitGroup
)

func setinitialconnection() {
	var err error
	conn, err = modules.GetDboxIConnection("db_godrej")

	if err != nil {
		toolkit.Println("Initial connection found : ", err)
		os.Exit(1)
	}

	err = gdrj.SetDb(conn)
	if err != nil {
		toolkit.Println("Initial connection found : ", err)
		os.Exit(1)
	}
}

func buildmap(holder interface{},
	fnModel func() orm.IModel,
	filter *dbox.Filter,
	fnIter func(holder interface{}, obj interface{})) interface{} {
	crx, _ := gdrj.Find(fnModel(), filter, nil)
	defer crx.Close()
	for {
		s := fnModel()
		e := crx.Fetch(s, 1, false)
		if e != nil {
			break
		}
		fnIter(holder, s)
	}
	return holder
}

func prepmaster() {
	masters = toolkit.M{}

	masters.Set("plmodel", buildmap(map[string]*gdrj.PLModel{},
		func() orm.IModel {
			return new(gdrj.PLModel)
		},
		nil,
		func(holder, obj interface{}) {
			h := holder.(map[string]*gdrj.PLModel)
			o := obj.(*gdrj.PLModel)
			h[o.ID] = o
		}).(map[string]*gdrj.PLModel))

	ccs := buildmap(map[string]*gdrj.CostCenter{},
		func() orm.IModel {
			return new(gdrj.CostCenter)
		},
		nil,
		func(holder, obj interface{}) {
			h := holder.(map[string]*gdrj.CostCenter)
			o := obj.(*gdrj.CostCenter)
			h[o.ID] = o
		}).(map[string]*gdrj.CostCenter)
	masters.Set("costcenter", ccs)
}

func main() {
	t0 = time.Now()
	mapkeysvalue = make(map[string]float64)
	mapsperiod = make(map[string]float64)
	flag.IntVar(&fiscalyear, "year", 2015, "YYYY representation of godrej fiscal year. Default is 2015")
	flag.StringVar(&ref, "ref", "", "Reference from document or other. Default is blank")
	flag.Parse()

	eperiode := time.Date(fiscalyear, 4, 1, 0, 0, 0, 0, time.UTC)
	speriode := eperiode.AddDate(-1, 0, 0)

	// if plcode == "" || value == 0 {
	// 	toolkit.Println("PLCode and Value are mandatory to fill")
	// 	os.Exit(1)
	// }

	setinitialconnection()
	defer gdrj.CloseDb()

	toolkit.Println("Get Data Master...")
	prepmaster()

	toolkit.Println("Count SGA Data Process...")
	// conn, _ = modules.GetDboxIConnection("db_godrej")
	conn, _ := modules.GetDboxIConnection("db_godrej")
	csga, _ := conn.NewQuery().Select().From("tmpsgaallocs").Where(dbox.Eq("y", fiscalyear-1)).Cursor(nil)
	defer csga.Close()
	defer conn.Close()

	i := 0
	ssga := csga.Count()
	ccs := masters.Get("costcenter").(map[string]*gdrj.CostCenter)
	for {

		i++
		tsga := toolkit.M{}
		e := csga.Fetch(&tsga, 1, false)
		if e != nil {
			break
		}

		date := time.Date(tsga.Get("y", 0).(int), time.Month(tsga.Get("p", 0).(int)), 1, 0, 0, 0, 0, time.UTC).AddDate(0, 4, 0)
		pval := toolkit.Sprintf("%d_%d", date.Year(), int(date.Month()))

		group := ""
		tcc, exist := ccs[tsga.Get("ccid", "").(string)]
		if exist {
			group = tcc.CostGroup01
		}

		if group == "" {
			group = "Other"
		}

		kval := toolkit.Sprintf("%v_%v", pval, group)
		mapkeysvalue[kval] += toolkit.ToFloat64(tsga.Get("amount", 0), 6, toolkit.RoundingAuto)
		mapsperiod[pval] += toolkit.ToFloat64(tsga.Get("amount", 0), 6, toolkit.RoundingAuto)
		globalsga += toolkit.ToFloat64(tsga.Get("amount", 0), 6, toolkit.RoundingAuto)

		if ssga%500 == 0 {
			toolkit.Printfn("Prepare sga master %d of %d in %s",
				i, ssga,
				time.Since(t0).String())
		}

	}

	// toolkit.Println(globalsga)
	// subtot := 0.0
	// for _, v := range mapkeysvalue {
	// 	// toolkit.Printfn("%v - %v", k, v)
	// 	subtot += v
	// }
	// toolkit.Printfn("subtotal 1 : %v", subtot)

	// subtot = 0.0
	// for _, v := range mapsperiod {
	// 	// toolkit.Printfn("%v - %v", k, v)
	// 	subtot += v
	// }
	// toolkit.Printfn("subtotal 2 : %v", subtot)

	toolkit.Println("Start Data Process...")
	filter := dbox.And(dbox.Gte("date.date", speriode), dbox.Lt("date.date", eperiode), dbox.Gt("skuid_vdist", ""))
	// filter = dbox.Eq("_id", "RK/IMN/15000001_1")
	c, _ := gdrj.Find(new(gdrj.SalesPL), filter, nil)
	defer c.Close()

	scount = c.Count()
	iscount = 0
	gscount = 0
	step = scount / 100
	// step = 1000

	jobs := make(chan *gdrj.SalesPL, count)
	toolkit.Println("Prepare Worker")
	for wi := 0; wi < 10; wi++ {
		mwg.Add(1)
		go worker(wi, jobs)
	}
	// ====================================
	for {
		iscount++

		spl := new(gdrj.SalesPL)
		e := c.Fetch(spl, 1, false)
		if e != nil {
			toolkit.Println("EOF")
			break
		}

		globalgross += spl.GrossAmount

		if iscount%step == 0 {
			toolkit.Printfn("Preparing %d of %d (%d) in %s", iscount, scount, iscount/step,
				time.Since(t0).String())
		}
	}

	c.ResetFetch()
	iscount = 0
	// ===========================
	for {
		iscount++

		spl := new(gdrj.SalesPL)
		e := c.Fetch(spl, 1, false)
		if e != nil {
			toolkit.Println("EOF")
			break
		}

		jobs <- spl
		if iscount%step == 0 {
			toolkit.Printfn("Processing %d of %d (%d) in %s", iscount, scount, iscount/step,
				time.Since(t0).String())
		}

	}

	close(jobs)
	mwg.Wait()

	toolkit.Printfn("Saved %d of %d (%d) in %s",
		gscount, scount, gscount/step,
		time.Since(t0).String())

	toolkit.Printfn("Processing done in %s",
		time.Since(t0).String())
}

func worker(wi int, jobs <-chan *gdrj.SalesPL) {
	workerConn, _ := modules.GetDboxIConnection("db_godrej")
	defer workerConn.Close()
	defer mwg.Done()

	var j *gdrj.SalesPL
	table := j.TableName()
	plmodels := masters.Get("plmodel").(map[string]*gdrj.PLModel)

	for j = range jobs {

		gscount++

		aplmodel := j.PLDatas
		for k, _ := range aplmodel {
			if strings.Contains(k, "PL33") || strings.Contains(k, "PL34") || strings.Contains(k, "PL35") {
				delete(aplmodel, k)
			}
		}

		j.PLDatas = aplmodel

		key := toolkit.Sprintf("%d_%d", j.Date.Year, int(j.Date.Month))

		ratio := j.GrossAmount / globalgross
		totsgaperiod, _ := mapsperiod[key]
		totsgaline := ratio * globalsga

		if totsgaperiod == 0 {
			continue
		}

		for k, v := range mapkeysvalue {
			skey := strings.Split(k, "_")
			if toolkit.ToInt(skey[0], toolkit.RoundingAuto) != j.Date.Year || toolkit.ToInt(skey[1], toolkit.RoundingAuto) != int(j.Date.Month) {
				continue
			}

			j.AddDataCC("PL33", (-totsgaline*v/totsgaperiod)*0.7, skey[2], plmodels)
			j.AddDataCC("PL34", (-totsgaline*v/totsgaperiod)*0.26, skey[2], plmodels)
			j.AddDataCC("PL35", (-totsgaline*v/totsgaperiod)*0.04, skey[2], plmodels)

		}

		j.CalcSum(masters)

		e := workerConn.NewQuery().From(table).
			Save().Exec(toolkit.M{}.Set("data", j))

		if e != nil {
			toolkit.Printfn("Unable to save %s = %s",
				j.ID, e.Error())
		}

		if gscount%step == 0 {
			toolkit.Printfn("Saved %d of %d (%d) in %s",
				gscount, scount, gscount/step,
				time.Since(t0).String())
		}
	}
}
<commit_msg>update<commit_after>package main

import (
	"eaciit/gdrj/model"
	"eaciit/gdrj/modules"
	"os"

	"flag"
	"github.com/eaciit/dbox"
	"github.com/eaciit/orm/v1"
	"github.com/eaciit/toolkit"
	"strings"
	"sync"
	"time"
)

var conn dbox.IConnection
var count int

// var mwg sync.WaitGroup

var (
	t0                                                time.Time
	custgroup, prodgroup, plcode, ref                 string
	value, fiscalyear, iscount, gscount, scount, step int
	globalgross, globalsga                            float64
	mapsperiod                                        map[string]float64
	mapkeysvalue                                      map[string]float64
	masters                                           toolkit.M
	mwg                                               sync.WaitGroup
)

func setinitialconnection() {
	var err error
	conn, err = modules.GetDboxIConnection("db_godrej")

	if err != nil {
		toolkit.Println("Initial connection found : ", err)
		os.Exit(1)
	}

	err = gdrj.SetDb(conn)
	if err != nil {
		toolkit.Println("Initial connection found : ", err)
		os.Exit(1)
	}
}

func buildmap(holder interface{},
	fnModel func() orm.IModel,
	filter *dbox.Filter,
	fnIter func(holder interface{}, obj interface{})) interface{} {
	crx, _ := gdrj.Find(fnModel(), filter, nil)
	defer crx.Close()
	for {
		s := fnModel()
		e := crx.Fetch(s, 1, false)
		if e != nil {
			break
		}
		fnIter(holder, s)
	}
	return holder
}

func prepmaster() {
	masters = toolkit.M{}

	masters.Set("plmodel", buildmap(map[string]*gdrj.PLModel{},
		func() orm.IModel {
			return new(gdrj.PLModel)
		},
		nil,
		func(holder, obj interface{}) {
			h := holder.(map[string]*gdrj.PLModel)
			o := obj.(*gdrj.PLModel)
			h[o.ID] = o
		}).(map[string]*gdrj.PLModel))

	ccs := buildmap(map[string]*gdrj.CostCenter{},
		func() orm.IModel {
			return new(gdrj.CostCenter)
		},
		nil,
		func(holder, obj interface{}) {
			h := holder.(map[string]*gdrj.CostCenter)
			o := obj.(*gdrj.CostCenter)
			h[o.ID] = o
		}).(map[string]*gdrj.CostCenter)
	masters.Set("costcenter", ccs)
}

func main() {
	t0 = time.Now()
	mapkeysvalue = make(map[string]float64)
	mapsperiod = make(map[string]float64)
	flag.IntVar(&fiscalyear, "year", 2015, "YYYY representation of godrej fiscal year. Default is 2015")
	flag.StringVar(&ref, "ref", "", "Reference from document or other. Default is blank")
	flag.Parse()

	eperiode := time.Date(fiscalyear, 4, 1, 0, 0, 0, 0, time.UTC)
	speriode := eperiode.AddDate(-1, 0, 0)

	// if plcode == "" || value == 0 {
	// 	toolkit.Println("PLCode and Value are mandatory to fill")
	// 	os.Exit(1)
	// }

	setinitialconnection()
	defer gdrj.CloseDb()

	toolkit.Println("Get Data Master...")
	prepmaster()

	toolkit.Println("Count SGA Data Process...")
	// conn, _ = modules.GetDboxIConnection("db_godrej")
	conn, _ := modules.GetDboxIConnection("db_godrej")
	csga, _ := conn.NewQuery().Select().From("tmpsgaallocs").Where(dbox.Eq("y", fiscalyear-1)).Cursor(nil)
	defer csga.Close()
	defer conn.Close()

	i := 0
	ssga := csga.Count()
	ccs := masters.Get("costcenter").(map[string]*gdrj.CostCenter)
	for {

		i++
		tsga := toolkit.M{}
		e := csga.Fetch(&tsga, 1, false)
		if e != nil {
			break
		}

		date := time.Date(tsga.Get("y", 0).(int), time.Month(tsga.Get("p", 0).(int)), 1, 0, 0, 0, 0, time.UTC).AddDate(0, 4, 0)
		pval := toolkit.Sprintf("%d_%d", date.Year(), int(date.Month()))

		group := ""
		tcc, exist := ccs[tsga.Get("ccid", "").(string)]
		if exist {
			group = tcc.CostGroup01
		}

		if group == "" {
			group = "Other"
		}

		kval := toolkit.Sprintf("%v_%v", pval, group)
		mapkeysvalue[kval] += toolkit.ToFloat64(tsga.Get("amount", 0), 6, toolkit.RoundingAuto)
		mapsperiod[pval] += toolkit.ToFloat64(tsga.Get("amount", 0), 6, toolkit.RoundingAuto)
		globalsga += toolkit.ToFloat64(tsga.Get("amount", 0), 6, toolkit.RoundingAuto)

		if ssga%500 == 0 {
			toolkit.Printfn("Prepare sga master %d of %d in %s",
				i, ssga,
				time.Since(t0).String())
		}

	}

	// toolkit.Println(globalsga)
	// subtot := 0.0
	// for _, v := range mapkeysvalue {
	// 	// toolkit.Printfn("%v - %v", k, v)
	// 	subtot += v
	// }
	// toolkit.Printfn("subtotal 1 : %v", subtot)

	subtot := 0.0
	for _, v := range mapsperiod {
		subtot += v
	}
	toolkit.Printfn("subtotal 2 : %v", subtot)

	toolkit.Println("Start Data Process...")
	filter := dbox.And(dbox.Gte("date.date", speriode), dbox.Lt("date.date", eperiode), dbox.Gt("skuid_vdist", ""))
	// filter = dbox.Eq("_id", "RK/IMN/15000001_1")
	c, _ := gdrj.Find(new(gdrj.SalesPL), filter, nil)
	defer c.Close()

	scount = c.Count()
	iscount = 0
	gscount = 0
	step = scount / 100
	// step = 1000

	jobs := make(chan *gdrj.SalesPL, count)
	toolkit.Println("Prepare Worker")
	for wi := 0; wi < 10; wi++ {
		mwg.Add(1)
		go worker(wi, jobs)
	}
	// ====================================
	for {
		iscount++

		spl := new(gdrj.SalesPL)
		e := c.Fetch(spl, 1, false)
		if e != nil {
			toolkit.Println("EOF")
			break
		}

		globalgross += spl.GrossAmount

		if iscount%step == 0 {
			toolkit.Printfn("Preparing %d of %d (%d) in %s", iscount, scount, iscount/step,
				time.Since(t0).String())
		}
	}

	c.ResetFetch()
	iscount = 0
	// ===========================
	for {
		iscount++

		spl := new(gdrj.SalesPL)
		e := c.Fetch(spl, 1, false)
		if e != nil {
			toolkit.Println("EOF")
			break
		}

		jobs <- spl
		if iscount%step == 0 {
			toolkit.Printfn("Processing %d of %d (%d) in %s", iscount, scount, iscount/step,
				time.Since(t0).String())
		}

	}

	close(jobs)
	mwg.Wait()

	toolkit.Printfn("Saved %d of %d (%d) in %s",
		gscount, scount, gscount/step,
		time.Since(t0).String())

	toolkit.Printfn("Processing done in %s",
		time.Since(t0).String())
}

func worker(wi int, jobs <-chan *gdrj.SalesPL) {
	workerConn, _ := modules.GetDboxIConnection("db_godrej")
	defer workerConn.Close()
	defer mwg.Done()

	var j *gdrj.SalesPL
	table := j.TableName()
	plmodels := masters.Get("plmodel").(map[string]*gdrj.PLModel)

	for j = range jobs {

		gscount++

		aplmodel := j.PLDatas
		for k, _ := range aplmodel {
			if strings.Contains(k, "PL33") || strings.Contains(k, "PL34") || strings.Contains(k, "PL35") {
				delete(aplmodel, k)
			}
		}

		j.PLDatas = aplmodel

		key := toolkit.Sprintf("%d_%d", j.Date.Year, int(j.Date.Month))

		ratio := j.GrossAmount / globalgross
		totsgaperiod, _ := mapsperiod[key]
		totsgaline := ratio * globalsga

		if totsgaperiod == 0 {
			continue
		}

		for k, v := range mapkeysvalue {
			skey := strings.Split(k, "_")
			if toolkit.ToInt(skey[0], toolkit.RoundingAuto) != j.Date.Year || toolkit.ToInt(skey[1], toolkit.RoundingAuto) != int(j.Date.Month) {
				continue
			}

			j.AddDataCC("PL33", (-totsgaline*v/totsgaperiod)*0.7, skey[2], plmodels)
			j.AddDataCC("PL34", (-totsgaline*v/totsgaperiod)*0.26, skey[2], plmodels)
			j.AddDataCC("PL35", (-totsgaline*v/totsgaperiod)*0.04, skey[2], plmodels)

		}

		j.CalcSum(masters)

		e := workerConn.NewQuery().From(table).
			Save().Exec(toolkit.M{}.Set("data", j))

		if e != nil {
			toolkit.Printfn("Unable to save %s = %s",
				j.ID, e.Error())
		}

		if gscount%step == 0 {
			toolkit.Printfn("Saved %d of %d (%d) in %s",
				gscount, scount, gscount/step,
				time.Since(t0).String())
		}
	}
}
<|endoftext|>


<commit_before>package commands

import (
	"fmt"
	"reflect"
	"strconv"
)

// Request represents a call to a command from a consumer
type Request struct {
	path			[]string
	options   map[string]interface{}
	arguments []string
}

func (r *Request) Path() []string {
	return r.path
}

func (r *Request) SetPath(path []string) {
	r.path = path
}

func (r *Request) Option(name string) interface{} {
	return r.options[name]
}

func (r *Request) SetOption(name string, value interface{}) {
	r.options[name] = value
}

func (r *Request) Arguments() []string {
	return r.arguments
}

type converter func(string)(interface{}, error)
var converters map[reflect.Kind]converter = map[reflect.Kind]converter{
	Bool: func(v string)(interface{}, error) {
		if v == "" {
			return true, nil
		}
		return strconv.ParseBool(v)
	},
	Int: func(v string)(interface{}, error) {
		return strconv.ParseInt(v, 0, 32)
	},
	Uint: func(v string)(interface{}, error) {
		return strconv.ParseInt(v, 0, 32)
	},
	Float: func(v string)(interface{}, error) {
		return strconv.ParseFloat(v, 64)
	},
}

func (r *Request) convertOptions(options map[string]Option) error {
	converted := make(map[string]interface{})

	for k, v := range r.options {
		opt, ok := options[k]
		if !ok {
			return fmt.Errorf("Unrecognized option: '%s'", k)
		}

		kind := reflect.TypeOf(v).Kind()
		var value interface{}

		if kind != opt.Type {
			if kind == String {
				convert := converters[opt.Type]
				val, err := convert(v.(string))
				if err != nil {
					return fmt.Errorf("Could not convert string value '%s' to type '%s'",
						v, opt.Type.String())
				}
				value = val

			} else {
				return fmt.Errorf("Option '%s' should be type '%s', but got type '%s'",
					k, opt.Type.String(), kind.String())
			}
		} else {
			value = v
		}

		for _, name := range opt.Names {
			if _, ok := r.options[name]; name != k && ok {
				return fmt.Errorf("Duplicate command options were provided ('%s' and '%s')",
					k, name)
			}

		  converted[name] = value
		}
	}

	r.options = converted
	return nil
}

func NewRequest() *Request {
	return &Request{
		make([]string, 0),
		make(map[string]interface{}),
		make([]string, 0),
	}
}
<commit_msg>commands: Allow setting Request fields in NewRequest<commit_after>package commands

import (
	"fmt"
	"reflect"
	"strconv"
)

// Request represents a call to a command from a consumer
type Request struct {
	path			[]string
	options   map[string]interface{}
	arguments []string
}

func (r *Request) Path() []string {
	return r.path
}

func (r *Request) SetPath(path []string) {
	r.path = path
}

func (r *Request) Option(name string) interface{} {
	return r.options[name]
}

func (r *Request) SetOption(name string, value interface{}) {
	r.options[name] = value
}

func (r *Request) Arguments() []string {
	return r.arguments
}

type converter func(string)(interface{}, error)
var converters map[reflect.Kind]converter = map[reflect.Kind]converter{
	Bool: func(v string)(interface{}, error) {
		if v == "" {
			return true, nil
		}
		return strconv.ParseBool(v)
	},
	Int: func(v string)(interface{}, error) {
		return strconv.ParseInt(v, 0, 32)
	},
	Uint: func(v string)(interface{}, error) {
		return strconv.ParseInt(v, 0, 32)
	},
	Float: func(v string)(interface{}, error) {
		return strconv.ParseFloat(v, 64)
	},
}

func (r *Request) convertOptions(options map[string]Option) error {
	converted := make(map[string]interface{})

	for k, v := range r.options {
		opt, ok := options[k]
		if !ok {
			return fmt.Errorf("Unrecognized option: '%s'", k)
		}

		kind := reflect.TypeOf(v).Kind()
		var value interface{}

		if kind != opt.Type {
			if kind == String {
				convert := converters[opt.Type]
				val, err := convert(v.(string))
				if err != nil {
					return fmt.Errorf("Could not convert string value '%s' to type '%s'",
						v, opt.Type.String())
				}
				value = val

			} else {
				return fmt.Errorf("Option '%s' should be type '%s', but got type '%s'",
					k, opt.Type.String(), kind.String())
			}
		} else {
			value = v
		}

		for _, name := range opt.Names {
			if _, ok := r.options[name]; name != k && ok {
				return fmt.Errorf("Duplicate command options were provided ('%s' and '%s')",
					k, name)
			}

		  converted[name] = value
		}
	}

	r.options = converted
	return nil
}

func NewRequest(path []string, opts map[string]interface{}, args []string) *Request {
	if path == nil {
		path = 	make([]string, 0)
	}
	if opts == nil {
		opts = make(map[string]interface{})
	}
	if args == nil {
		args = make([]string, 0)
	}
	return &Request{path, opts, args}
}
<|endoftext|>


<commit_before>package commands

import (
	"fmt"

	"github.com/alireza-ahmadi/hoor/version"
	"github.com/spf13/cobra"
)

// versionCmd returns the current application version.
var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Print version information of the Hoor",
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Printf("Hoor %s", version.Version)
	},
}
<commit_msg>Fix a minor bug in version command<commit_after>package commands

import (
	"github.com/alireza-ahmadi/hoor/version"
	"github.com/spf13/cobra"
	jww "github.com/spf13/jwalterweatherman"
)

// versionCmd returns the current application version.
var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Print version information of the Hoor",
	Run: func(cmd *cobra.Command, args []string) {
		jww.FEEDBACK.Println("Hoor", version.Version)
	},
}
<|endoftext|>


<commit_before>package sudoku

//GridModification is a series of CellModifications to apply to a Grid.
type GridModifcation []*CellModification

//CellModification represents a modification to be made to a given Cell in a
//grid.
type CellModification struct {
	//The cell representing the cell to modify. The cell's analog (at the same
	//row, col address) will be modified in the new grid.
	Cell Cell
	//The number to put in the cell. Negative numbers signify no changes.
	Number int
	//The excludes to proactively set. Invalid numbers will be ignored.
	//Indexes not listed will be left the same.
	ExcludesChanges map[int]bool
	//The marks to proactively set. Invalid numbers will be ignored.
	//Indexes not listed will be left the same.
	MarksChanges map[int]bool
}

//TOOD: make readOnlyCellImpl. Test if neighbors should be derived or not. Can
//burn excludes and impossibles into one array. Everything should be actual
//contiguous memory, no pointers.

//TODO: make readOnlyGridImpl. Two possible approaches: a version that is
//incredibly easy to copy and then do minor tweaks. Or a version that stores a
//dictionary of cell configs, and any time you grab a Cell we look it up in
//the dict or in the ancestors' dicts.

//newCellModification returns a CellModification for the given cell that is a
//no-op.
func newCellModification(cell Cell) *CellModification {
	return &CellModification{
		Cell:            cell,
		Number:          -1,
		ExcludesChanges: make(map[int]bool),
		MarksChanges:    make(map[int]bool),
	}
}

//equivalent returns true if the other grid modification is equivalent to this one.
func (m GridModifcation) equivalent(other GridModifcation) bool {
	if len(m) != len(other) {
		return false
	}
	for i, modification := range m {
		otherModification := other[i]
		if modification.Cell.ref().String() != otherModification.Cell.ref().String() {
			return false
		}
		if modification.Number != otherModification.Number {
			return false
		}

		if len(modification.ExcludesChanges) != len(otherModification.ExcludesChanges) {
			return false
		}

		for key, val := range modification.ExcludesChanges {
			otherVal, ok := otherModification.ExcludesChanges[key]
			if !ok {
				return false
			}
			if val != otherVal {
				return false
			}
		}

		if len(modification.MarksChanges) != len(otherModification.MarksChanges) {
			return false
		}

		for key, val := range modification.MarksChanges {
			otherVal, ok := otherModification.MarksChanges[key]
			if !ok {
				return false
			}
			if val != otherVal {
				return false
			}
		}
	}
	return true
}

func (self *gridImpl) CopyWithModifications(modifications GridModifcation) Grid {
	//TODO: when we have an honest-to-god readonly grid impl, optimize this.
	result := self.MutableCopy()

	for _, modification := range modifications {
		cell := modification.Cell.MutableInGrid(result)

		if modification.Number >= 0 && modification.Number < DIM {
			cell.SetNumber(modification.Number)
		}

		for key, val := range modification.ExcludesChanges {
			//setExcluded will skip invalid entries
			cell.SetExcluded(key, val)
		}

		for key, val := range modification.MarksChanges {
			//SetMark will skip invalid numbers
			cell.SetMark(key, val)
		}
	}

	return result
}
<commit_msg>Added a TODO<commit_after>package sudoku

//GridModification is a series of CellModifications to apply to a Grid.
type GridModifcation []*CellModification

//CellModification represents a modification to be made to a given Cell in a
//grid.
type CellModification struct {
	//The cell representing the cell to modify. The cell's analog (at the same
	//row, col address) will be modified in the new grid.
	Cell Cell
	//The number to put in the cell. Negative numbers signify no changes.
	Number int
	//The excludes to proactively set. Invalid numbers will be ignored.
	//Indexes not listed will be left the same.
	ExcludesChanges map[int]bool
	//The marks to proactively set. Invalid numbers will be ignored.
	//Indexes not listed will be left the same.
	MarksChanges map[int]bool
}

//TODO: audit all uses of step/compoundstep.Apply()

//TOOD: make readOnlyCellImpl. Test if neighbors should be derived or not. Can
//burn excludes and impossibles into one array. Everything should be actual
//contiguous memory, no pointers.

//TODO: make readOnlyGridImpl. Two possible approaches: a version that is
//incredibly easy to copy and then do minor tweaks. Or a version that stores a
//dictionary of cell configs, and any time you grab a Cell we look it up in
//the dict or in the ancestors' dicts.

//newCellModification returns a CellModification for the given cell that is a
//no-op.
func newCellModification(cell Cell) *CellModification {
	return &CellModification{
		Cell:            cell,
		Number:          -1,
		ExcludesChanges: make(map[int]bool),
		MarksChanges:    make(map[int]bool),
	}
}

//equivalent returns true if the other grid modification is equivalent to this one.
func (m GridModifcation) equivalent(other GridModifcation) bool {
	if len(m) != len(other) {
		return false
	}
	for i, modification := range m {
		otherModification := other[i]
		if modification.Cell.ref().String() != otherModification.Cell.ref().String() {
			return false
		}
		if modification.Number != otherModification.Number {
			return false
		}

		if len(modification.ExcludesChanges) != len(otherModification.ExcludesChanges) {
			return false
		}

		for key, val := range modification.ExcludesChanges {
			otherVal, ok := otherModification.ExcludesChanges[key]
			if !ok {
				return false
			}
			if val != otherVal {
				return false
			}
		}

		if len(modification.MarksChanges) != len(otherModification.MarksChanges) {
			return false
		}

		for key, val := range modification.MarksChanges {
			otherVal, ok := otherModification.MarksChanges[key]
			if !ok {
				return false
			}
			if val != otherVal {
				return false
			}
		}
	}
	return true
}

func (self *gridImpl) CopyWithModifications(modifications GridModifcation) Grid {
	//TODO: when we have an honest-to-god readonly grid impl, optimize this.
	result := self.MutableCopy()

	for _, modification := range modifications {
		cell := modification.Cell.MutableInGrid(result)

		if modification.Number >= 0 && modification.Number < DIM {
			cell.SetNumber(modification.Number)
		}

		for key, val := range modification.ExcludesChanges {
			//setExcluded will skip invalid entries
			cell.SetExcluded(key, val)
		}

		for key, val := range modification.MarksChanges {
			//SetMark will skip invalid numbers
			cell.SetMark(key, val)
		}
	}

	return result
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"math"
)

const warmer = "WARMER"
const colder = "COLDER"
const same = "SAME"
const unknown = "UNKNOWN"
const left = -1
const right = 1
const up = -1
const down = 1

func main() {
	var W, H int
	fmt.Scan(&W, &H)

	// N: maximum number of turns before game over.
	var N int
	fmt.Scan(&N)

	var X0, Y0 int
	var A, B Point
	fmt.Scan(&X0, &Y0)
	A = Point{x: X0, y: Y0}
	B = Point{x: X0, y: Y0}

	for {
		var bombDistance string
		fmt.Scan(&bombDistance)
		fmt.Fprintln(os.Stderr, bombDistance)
		if bombDistance == unknown {
			B.x, B.y = A.x, A.y
			A.x, A.y = W/2, H/2
			A.x, A.y = 1, 3
		} else if bombDistance != same {
			m, d := calcSlope(A, B), calcDistance(A, B)
			dX, dY := calcDeltas(m, d/2)
			fmt.Fprintln(os.Stderr, d)
			fmt.Fprintln(os.Stderr, m)
			fmt.Fprintln(os.Stderr, dX, dY)
			fmt.Fprintln(os.Stderr, fmt.Sprintf("%v --> %v", B, A))
		}

		fmt.Println(A.x, A.y) // Write action to stdout
	}
}

func calcDistance(a Point, b Point) float64 {
	return math.Sqrt(math.Pow(float64(a.x-b.x), 2) + math.Pow(float64(a.y-b.y), 2))
}

func calcSlope(a Point, b Point) float64 {
	return float64(a.y - b.y)/float64(a.x - b.x)
}

func calcDeltas(slope float64, distance float64) (dX float64, dY float64) {
	angle := math.Atan(slope)
	dX = math.Cos(angle) * distance
	dY = math.Sin(angle) * distance
	return dX, dY
}

type Point struct {
	x, y int
}
<commit_msg>more work on batman 2 euclidian funcs<commit_after>package main

import (
	"fmt"
	"os"
	"math"
)

const warmer = "WARMER"
const colder = "COLDER"
const same = "SAME"
const unknown = "UNKNOWN"
const left = -1
const right = 1
const up = -1
const down = 1

func main() {
	var W, H int
	fmt.Scan(&W, &H)

	// N: maximum number of turns before game over.
	var N int
	fmt.Scan(&N)

	var X0, Y0 int
	var A, B Point
	fmt.Scan(&X0, &Y0)
	A = Point{x: X0, y: Y0}
	B = Point{x: X0, y: Y0}

	for {
		var bombDistance string
		fmt.Scan(&bombDistance)
		fmt.Fprintln(os.Stderr, bombDistance)
		if bombDistance == unknown {
			B.x, B.y = A.x, A.y
			A.x, A.y = W/2, H/2
			A.x, A.y = 1, 3
		} else if bombDistance != same {
			m, perpM, d := calcSlope(A, B), calcPerpSlope(A, B), calcDistance(A, B)
			dX, dY := calcDeltas(m, d/2)
			midPoint := Point{x: A.x + int(dX), y: A.y + int(dY)}
			b := calcYOffset(midPoint, m)
			fmt.Fprintln(os.Stderr, d)
			fmt.Fprintln(os.Stderr, m, perpM, b)
			fmt.Fprintln(os.Stderr, dX, dY)
			fmt.Fprintln(os.Stderr, midPoint)
			fmt.Fprintln(os.Stderr, fmt.Sprintf("...%v --> %v", B, A))
		}

		fmt.Println(A.x, A.y) // Write action to stdout
	}
}

func calcDistance(a Point, b Point) float64 {
	return math.Sqrt(math.Pow(float64(a.x-b.x), 2) + math.Pow(float64(a.y-b.y), 2))
}

func calcSlope(a Point, b Point) float64 {
	m := float64(a.y - b.y)/float64(a.x - b.x)
	if math.IsInf(m, -1) {return 0}
	return m
}

func calcPerpSlope(a Point, b Point) float64{
	return 1 / (float64(a.y - b.y)/float64(a.x - b.x)) * -1
}

func calcYOffset(midPoint Point, slope float64) (b float64) {
	return float64(midPoint.y) - (slope * float64(midPoint.x))
}

func calcDeltas(slope float64, distance float64) (dX float64, dY float64) {
	angle := math.Atan(slope)
	dX = math.Cos(angle) * distance
	dY = math.Sin(angle) * distance
	return dX, dY
}

func Round(val float64, roundOn float64, places int ) (newVal float64) {
	var round float64
	pow := math.Pow(10, float64(places))
	digit := pow * val
	_, div := math.Modf(digit)
	_div := math.Copysign(div, val)
	_roundOn := math.Copysign(roundOn, val)
	if _div >= _roundOn {
		round = math.Ceil(digit)
	} else {
		round = math.Floor(digit)
	}
	newVal = round / pow
	return
}

type Point struct {
	x, y int
}
<|endoftext|>


<commit_before>package ungo

import (
	"fmt"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"regexp"
)

func Imagep2p(url_ string) (string, error) {
	cookie, _ := cookiejar.New(nil)

	HH.Host = "imagep2p.com"

	var cookies []*http.Cookie

	ageVerificationData := &http.Cookie{
		Name:   "AgeVerification",
		Path:   "/",
		Domain: "imagep2p.com",
		Value:  "1",
	}

	cookieURL, _ := url.Parse(url_)

	cookies = append(cookies, ageVerificationData)

	cookie.SetCookies(cookieURL, cookies)

	html := htmlDownload(url_, cookie)

	urlregex := regexp.MustCompile(`src="(images/.*?)"`)
	resutl := urlregex.FindAllStringSubmatch(html.Html, -1)[0:]

	fmt.Println(resutl)

	return "http://imagep2p.com/" + resutl[0][1], nil
}
<commit_msg>Remove fmt package!<commit_after>package ungo

import (
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"regexp"
)

func Imagep2p(url_ string) (string, error) {
	cookie, _ := cookiejar.New(nil)

	HH.Host = "imagep2p.com"

	var cookies []*http.Cookie

	ageVerificationData := &http.Cookie{
		Name:   "AgeVerification",
		Path:   "/",
		Domain: "imagep2p.com",
		Value:  "1",
	}

	cookieURL, _ := url.Parse(url_)

	cookies = append(cookies, ageVerificationData)

	cookie.SetCookies(cookieURL, cookies)

	html := htmlDownload(url_, cookie)

	urlregex := regexp.MustCompile(`src="(images/.*?)"`)
	resutl := urlregex.FindAllStringSubmatch(html.Html, -1)[0:
]
	return "http://imagep2p.com/" + resutl[0][1], nil
}
<|endoftext|>


<commit_before>package nsone

import (
	"bytes"
	"errors"
	"fmt"
	"github.com/bobtfish/go-nsone-api"
	"github.com/hashicorp/terraform/helper/hashcode"
	"github.com/hashicorp/terraform/helper/schema"
	"log"
	"regexp"
	"sort"
	"strings"
)

func recordResource() *schema.Resource {
	return &schema.Resource{
		Schema: map[string]*schema.Schema{
			"id": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
			"zone": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"domain": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"ttl": &schema.Schema{
				Type:     schema.TypeInt,
				Computed: true,
			},
			"type": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
				ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
					value := v.(string)
					if !regexp.MustCompile(`^(A|AAAA|ALIAS|AFSDB|CNAME|DNAME|HINFO|MX|NAPTR|NS|PTR|RP|SPF|SRV|TXT)$`).MatchString(value) {
						es = append(es, fmt.Errorf(
							"only A, AAAA, ALIAS, AFSDB, CNAME, DNAME, HINFO, MX, NAPTR, NS, PTR, RP, SPF, SRV, TXT allowed in %q", k))
					}
					return
				},
			},
			"meta": metaSchema(),
			"link": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
				Computed: true,
			},
			"answers": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				Computed: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"answer": &schema.Schema{
							Type:     schema.TypeString,
							Optional: true,
							Computed: true,
						},
						"region": &schema.Schema{
							Type:     schema.TypeString,
							Optional: true,
						},
						"meta": &schema.Schema{
							Type:     schema.TypeSet,
							Optional: true,
							Computed: true,
							Elem: &schema.Resource{
								Schema: map[string]*schema.Schema{
									"field": &schema.Schema{
										Type:     schema.TypeString,
										Computed: true,
										Optional: true,
									},
									"feed": &schema.Schema{
										Type:     schema.TypeString,
										Computed: true,
										Optional: true,
									},
								},
							},
							Set: metaToHash,
						},
					},
				},
				Set: answersToHash,
			},
			"regions": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				Computed: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"name": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
						"georegion": &schema.Schema{
							Type:     schema.TypeString,
							Optional: true,
							ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
								value := v.(string)
								if !regexp.MustCompile(`^(US-WEST|US-EAST|US-CENTRAL|EUROPE|AFRICA|ASIAPAC|SOUTH-AMERICA)$`).MatchString(value) {
									es = append(es, fmt.Errorf(
										"only US-WEST, US-EAST, US-CENTRAL, EUROPE, AFRICA, ASIAPAC, SOUTH-AMERICA allowed in %q", k))
								}
								return
							},
						},
					},
				},
				Set: regionsToHash,
			},
		},
		Create: RecordCreate,
		Read:   RecordRead,
		Update: RecordUpdate,
		Delete: RecordDelete,
	}
}

func regionsToHash(v interface{}) int {
	var buf bytes.Buffer
	r := v.(map[string]interface{})
	buf.WriteString(fmt.Sprintf("%s-", r["name"].(string)))
	buf.WriteString(fmt.Sprintf("%s-", r["georegion"].(string)))
	return hashcode.String(buf.String())
}

func answersToHash(v interface{}) int {
	var buf bytes.Buffer
	a := v.(map[string]interface{})
	buf.WriteString(fmt.Sprintf("%s-", a["answer"].(string)))
	buf.WriteString(fmt.Sprintf("%s-", a["region"].(string)))
	ms := a["meta"].(*schema.Set)
	metas := make([]int, ms.Len())
	for _, meta := range ms.List() {
		metas = append(metas, metaToHash(meta))
	}
	sort.Ints(metas)
	for _, metahash := range metas {
		buf.WriteString(fmt.Sprintf("%d-", metahash))
	}
	hash := hashcode.String(buf.String())
	log.Println("Generated answersToHash %d from %+v", hash, ms)
	return hash
}

func metaToHash(v interface{}) int {
	var buf bytes.Buffer
	s := v.(map[string]interface{})
	buf.WriteString(fmt.Sprintf("%s-", s["field"].(string)))
	buf.WriteString(fmt.Sprintf("%s-", s["feed"].(string)))

	hash := hashcode.String(buf.String())
	log.Println("Generated metaToHash %d from %+v", hash, s)
	return hash
}

func recordToResourceData(d *schema.ResourceData, r *nsone.Record) error {
	d.SetId(r.Id)
	d.Set("domain", r.Domain)
	d.Set("zone", r.Zone)
	d.Set("type", r.Type)
	d.Set("ttl", r.Ttl)
	if r.Link != "" {
		d.Set("link", r.Link)
	}
	if len(r.Answers) > 0 {
		answers := make([]map[string]interface{}, 0, len(r.Answers))
		for i, answer := range r.Answers {
			answers[i] = answerToMap(answer)
		}
		log.Printf("Setting answers %+v", answers)
		err := d.Set("answers", answers)
		if err != nil {
			return fmt.Errorf("[DEBUG] Error setting answers for: %s, error: %#v", r.Domain, err)
		}
	}
	if len(r.Regions) > 0 {
		regions := make([]map[string]interface{}, 0, len(r.Answers))
		for region_name, region := range r.Regions {
			var new_region map[string]interface{}
			new_region["name"] = region_name
			if len(region.Meta.GeoRegion) > 0 {
				new_region["georegion"] = region.Meta.GeoRegion[0]
			}
			regions = append(regions, new_region)
		}
		log.Printf("Setting regions %+v", regions)
		err := d.Set("regions", regions)
		if err != nil {
			return fmt.Errorf("[DEBUG] Error setting regions for: %s, error: %#v", r.Domain, err)
		}
	}
	return nil
}

func answerToMap(a nsone.Answer) map[string]interface{} {
	m := make(map[string]interface{})
	m["meta"] = make([]map[string]interface{}, 0)
	m["answer"] = strings.Join(a.Answer, " ")
	if a.Region != "" {
		m["region"] = a.Region
	}
	if a.Meta != nil {
		metas := make([]map[string]interface{}, len(a.Meta))
		for k, v := range a.Meta {
			meta := make(map[string]interface{})
			meta["field"] = k
			meta["feed"] = v.Feed
			metas = append(metas, meta)
		}
		m["meta"] = metas
	}
	return m
}

func resourceDataToRecord(r *nsone.Record, d *schema.ResourceData) error {
	r.Id = d.Id()
	if answers := d.Get("answers").(*schema.Set); answers.Len() > 0 {
		al := make([]nsone.Answer, answers.Len())
		for i, answer_raw := range answers.List() {
			answer := answer_raw.(map[string]interface{})
			a := nsone.NewAnswer()
			v := answer["answer"].(string)
			if d.Get("type") != "TXT" {
				a.Answer = strings.Split(v, " ")
			} else {
				a.Answer = []string{v}
			}
			if v, ok := d.GetOk("region"); ok {
				a.Region = v.(string)
			}
			if metas := answer["meta"].(*schema.Set); metas.Len() > 0 {
				for _, meta_raw := range metas.List() {
					meta := meta_raw.(map[string]interface{})
					key := meta["field"].(string)
					value := meta["feed"].(string)
					a.Meta[key] = nsone.NewMetaFeed(value)
				}
			}
			al[i] = a
		}
		r.Answers = al
		if _, ok := d.GetOk("link"); ok {
			return errors.New("Cannot have both link and answers in a record")
		}
	}
	if v, ok := d.GetOk("ttl"); ok {
		r.Ttl = v.(int)
	}
	if v, ok := d.GetOk("link"); ok {
		r.LinkTo(v.(string))
	}
	if regions := d.Get("regions").(*schema.Set); regions.Len() > 0 {
		rm := make(map[string]nsone.Region)
		for _, region_raw := range regions.List() {
			region := region_raw.(map[string]interface{})
			nsone_r := nsone.Region{
				Meta: nsone.RegionMeta{},
			}
			if g := region["georegion"].(string); g != "" {
				nsone_r.Meta.GeoRegion = []string{g}
			}
			rm[region["name"].(string)] = nsone_r
		}
		r.Regions = rm
	}
	return nil
}

func setToMapByKey(s *schema.Set, key string) map[string]interface{} {
	result := make(map[string]interface{})
	for _, rawData := range s.List() {
		data := rawData.(map[string]interface{})
		result[data[key].(string)] = data
	}

	return result
}

func RecordCreate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*nsone.APIClient)
	r := nsone.NewRecord(d.Get("zone").(string), d.Get("domain").(string), d.Get("type").(string))
	if err := resourceDataToRecord(r, d); err != nil {
		return err
	}
	if err := client.CreateRecord(r); err != nil {
		return err
	}
	return recordToResourceData(d, r)
}

func RecordRead(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*nsone.APIClient)
	r, err := client.GetRecord(d.Get("zone").(string), d.Get("domain").(string), d.Get("type").(string))
	if err != nil {
		return err
	}
	recordToResourceData(d, r)
	return nil
}

func RecordDelete(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*nsone.APIClient)
	err := client.DeleteRecord(d.Get("zone").(string), d.Get("domain").(string), d.Get("type").(string))
	d.SetId("")
	return err
}

func RecordUpdate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*nsone.APIClient)
	r := nsone.NewRecord(d.Get("zone").(string), d.Get("domain").(string), d.Get("type").(string))
	if err := resourceDataToRecord(r, d); err != nil {
		return err
	}
	if err := client.UpdateRecord(r); err != nil {
		return err
	}
	recordToResourceData(d, r)
	return nil
}
<commit_msg>Fix more indexing bugs<commit_after>package nsone

import (
	"bytes"
	"errors"
	"fmt"
	"github.com/bobtfish/go-nsone-api"
	"github.com/hashicorp/terraform/helper/hashcode"
	"github.com/hashicorp/terraform/helper/schema"
	"log"
	"regexp"
	"sort"
	"strings"
)

func recordResource() *schema.Resource {
	return &schema.Resource{
		Schema: map[string]*schema.Schema{
			"id": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
			"zone": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"domain": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"ttl": &schema.Schema{
				Type:     schema.TypeInt,
				Computed: true,
			},
			"type": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
				ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
					value := v.(string)
					if !regexp.MustCompile(`^(A|AAAA|ALIAS|AFSDB|CNAME|DNAME|HINFO|MX|NAPTR|NS|PTR|RP|SPF|SRV|TXT)$`).MatchString(value) {
						es = append(es, fmt.Errorf(
							"only A, AAAA, ALIAS, AFSDB, CNAME, DNAME, HINFO, MX, NAPTR, NS, PTR, RP, SPF, SRV, TXT allowed in %q", k))
					}
					return
				},
			},
			"meta": metaSchema(),
			"link": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
				Computed: true,
			},
			"answers": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				Computed: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"answer": &schema.Schema{
							Type:     schema.TypeString,
							Optional: true,
							Computed: true,
						},
						"region": &schema.Schema{
							Type:     schema.TypeString,
							Optional: true,
						},
						"meta": &schema.Schema{
							Type:     schema.TypeSet,
							Optional: true,
							Computed: true,
							Elem: &schema.Resource{
								Schema: map[string]*schema.Schema{
									"field": &schema.Schema{
										Type:     schema.TypeString,
										Computed: true,
										Optional: true,
									},
									"feed": &schema.Schema{
										Type:     schema.TypeString,
										Computed: true,
										Optional: true,
									},
								},
							},
							Set: metaToHash,
						},
					},
				},
				Set: answersToHash,
			},
			"regions": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				Computed: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"name": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
						"georegion": &schema.Schema{
							Type:     schema.TypeString,
							Optional: true,
							ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
								value := v.(string)
								if !regexp.MustCompile(`^(US-WEST|US-EAST|US-CENTRAL|EUROPE|AFRICA|ASIAPAC|SOUTH-AMERICA)$`).MatchString(value) {
									es = append(es, fmt.Errorf(
										"only US-WEST, US-EAST, US-CENTRAL, EUROPE, AFRICA, ASIAPAC, SOUTH-AMERICA allowed in %q", k))
								}
								return
							},
						},
					},
				},
				Set: regionsToHash,
			},
		},
		Create: RecordCreate,
		Read:   RecordRead,
		Update: RecordUpdate,
		Delete: RecordDelete,
	}
}

func regionsToHash(v interface{}) int {
	var buf bytes.Buffer
	r := v.(map[string]interface{})
	buf.WriteString(fmt.Sprintf("%s-", r["name"].(string)))
	buf.WriteString(fmt.Sprintf("%s-", r["georegion"].(string)))
	return hashcode.String(buf.String())
}

func answersToHash(v interface{}) int {
	var buf bytes.Buffer
	a := v.(map[string]interface{})
	buf.WriteString(fmt.Sprintf("%s-", a["answer"].(string)))
	buf.WriteString(fmt.Sprintf("%s-", a["region"].(string)))
	ms := a["meta"].(*schema.Set)
	metas := make([]int, ms.Len())
	for _, meta := range ms.List() {
		metas = append(metas, metaToHash(meta))
	}
	sort.Ints(metas)
	for _, metahash := range metas {
		buf.WriteString(fmt.Sprintf("%d-", metahash))
	}
	hash := hashcode.String(buf.String())
	log.Println("Generated answersToHash %d from %+v", hash, ms)
	return hash
}

func metaToHash(v interface{}) int {
	var buf bytes.Buffer
	s := v.(map[string]interface{})
	buf.WriteString(fmt.Sprintf("%s-", s["field"].(string)))
	buf.WriteString(fmt.Sprintf("%s-", s["feed"].(string)))

	hash := hashcode.String(buf.String())
	log.Println("Generated metaToHash %d from %+v", hash, s)
	return hash
}

func recordToResourceData(d *schema.ResourceData, r *nsone.Record) error {
	d.SetId(r.Id)
	d.Set("domain", r.Domain)
	d.Set("zone", r.Zone)
	d.Set("type", r.Type)
	d.Set("ttl", r.Ttl)
	if r.Link != "" {
		d.Set("link", r.Link)
	}
	if len(r.Answers) > 0 {
		answers := make([]map[string]interface{}, len(r.Answers))
		log.Printf("Got back from nsone answers: %+v", r.Answers)
		for i, answer := range r.Answers {
			answers[i] = answerToMap(answer)
		}
		log.Printf("Setting answers %+v", answers)
		err := d.Set("answers", answers)
		if err != nil {
			return fmt.Errorf("[DEBUG] Error setting answers for: %s, error: %#v", r.Domain, err)
		}
	}
	if len(r.Regions) > 0 {
		regions := make([]map[string]interface{}, 0, len(r.Answers))
		for region_name, region := range r.Regions {
			var new_region map[string]interface{}
			new_region["name"] = region_name
			if len(region.Meta.GeoRegion) > 0 {
				new_region["georegion"] = region.Meta.GeoRegion[0]
			}
			regions = append(regions, new_region)
		}
		log.Printf("Setting regions %+v", regions)
		err := d.Set("regions", regions)
		if err != nil {
			return fmt.Errorf("[DEBUG] Error setting regions for: %s, error: %#v", r.Domain, err)
		}
	}
	return nil
}

func answerToMap(a nsone.Answer) map[string]interface{} {
	m := make(map[string]interface{})
	m["meta"] = make([]map[string]interface{}, 0)
	m["answer"] = strings.Join(a.Answer, " ")
	if a.Region != "" {
		m["region"] = a.Region
	}
	if a.Meta != nil {
		metas := make([]map[string]interface{}, 0, len(a.Meta))
		for k, v := range a.Meta {
			meta := make(map[string]interface{})
			meta["field"] = k
			meta["feed"] = v.Feed
			metas = append(metas, meta)
		}
		m["meta"] = metas
	}
	return m
}

func resourceDataToRecord(r *nsone.Record, d *schema.ResourceData) error {
	r.Id = d.Id()
	if answers := d.Get("answers").(*schema.Set); answers.Len() > 0 {
		al := make([]nsone.Answer, answers.Len())
		for i, answer_raw := range answers.List() {
			answer := answer_raw.(map[string]interface{})
			a := nsone.NewAnswer()
			v := answer["answer"].(string)
			if d.Get("type") != "TXT" {
				a.Answer = strings.Split(v, " ")
			} else {
				a.Answer = []string{v}
			}
			if v, ok := d.GetOk("region"); ok {
				a.Region = v.(string)
			}
			if metas := answer["meta"].(*schema.Set); metas.Len() > 0 {
				for _, meta_raw := range metas.List() {
					meta := meta_raw.(map[string]interface{})
					key := meta["field"].(string)
					value := meta["feed"].(string)
					a.Meta[key] = nsone.NewMetaFeed(value)
				}
			}
			al[i] = a
		}
		r.Answers = al
		if _, ok := d.GetOk("link"); ok {
			return errors.New("Cannot have both link and answers in a record")
		}
	}
	if v, ok := d.GetOk("ttl"); ok {
		r.Ttl = v.(int)
	}
	if v, ok := d.GetOk("link"); ok {
		r.LinkTo(v.(string))
	}
	if regions := d.Get("regions").(*schema.Set); regions.Len() > 0 {
		rm := make(map[string]nsone.Region)
		for _, region_raw := range regions.List() {
			region := region_raw.(map[string]interface{})
			nsone_r := nsone.Region{
				Meta: nsone.RegionMeta{},
			}
			if g := region["georegion"].(string); g != "" {
				nsone_r.Meta.GeoRegion = []string{g}
			}
			rm[region["name"].(string)] = nsone_r
		}
		r.Regions = rm
	}
	return nil
}

func setToMapByKey(s *schema.Set, key string) map[string]interface{} {
	result := make(map[string]interface{})
	for _, rawData := range s.List() {
		data := rawData.(map[string]interface{})
		result[data[key].(string)] = data
	}

	return result
}

func RecordCreate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*nsone.APIClient)
	r := nsone.NewRecord(d.Get("zone").(string), d.Get("domain").(string), d.Get("type").(string))
	if err := resourceDataToRecord(r, d); err != nil {
		return err
	}
	if err := client.CreateRecord(r); err != nil {
		return err
	}
	return recordToResourceData(d, r)
}

func RecordRead(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*nsone.APIClient)
	r, err := client.GetRecord(d.Get("zone").(string), d.Get("domain").(string), d.Get("type").(string))
	if err != nil {
		return err
	}
	recordToResourceData(d, r)
	return nil
}

func RecordDelete(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*nsone.APIClient)
	err := client.DeleteRecord(d.Get("zone").(string), d.Get("domain").(string), d.Get("type").(string))
	d.SetId("")
	return err
}

func RecordUpdate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*nsone.APIClient)
	r := nsone.NewRecord(d.Get("zone").(string), d.Get("domain").(string), d.Get("type").(string))
	if err := resourceDataToRecord(r, d); err != nil {
		return err
	}
	if err := client.UpdateRecord(r); err != nil {
		return err
	}
	recordToResourceData(d, r)
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

package eventsink

import (
	"reflect"

	clientv1 "k8s.io/api/core/v1"
	kubev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/conversion"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/client-go/tools/record"
	fedclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_clientset"
)

// Implements k8s.io/client-go/tools/record.EventSink.
type FederatedEventSink struct {
	clientset fedclientset.Interface
}

// To check if all required functions are implemented.
var _ record.EventSink = &FederatedEventSink{}

func NewFederatedEventSink(clientset fedclientset.Interface) *FederatedEventSink {
	return &FederatedEventSink{
		clientset: clientset,
	}
}

// TODO this is uses a reflection conversion path and is very expensive.  federation should update to use client-go

var scheme = runtime.NewScheme()

func init() {
	// register client-go's and kube's Event type under two different GroupVersions
	// TODO: switch to client-go client for events
	scheme.AddKnownTypes(clientv1.SchemeGroupVersion, &clientv1.Event{})
	scheme.AddKnownTypes(schema.GroupVersion{Group: "fake-kube-" + kubev1.SchemeGroupVersion.Group, Version: kubev1.SchemeGroupVersion.Version}, &kubev1.Event{})

	if err := scheme.AddConversionFuncs(
		metav1.Convert_unversioned_Time_To_unversioned_Time,
	); err != nil {
		panic(err)
	}
	if err := scheme.AddGeneratedDeepCopyFuncs(
		conversion.GeneratedDeepCopyFunc{
			Fn:     metav1.DeepCopy_v1_Time,
			InType: reflect.TypeOf(&metav1.Time{}),
		},
	); err != nil {
		panic(err)
	}
}

func (fes *FederatedEventSink) Create(event *clientv1.Event) (*clientv1.Event, error) {
	kubeEvent := &kubev1.Event{}
	if err := scheme.Convert(event, kubeEvent, nil); err != nil {
		return nil, err
	}

	ret, err := fes.clientset.Core().Events(kubeEvent.Namespace).Create(kubeEvent)
	if err != nil {
		return nil, err
	}

	retEvent := &clientv1.Event{}
	if err := scheme.Convert(ret, retEvent, nil); err != nil {
		return nil, err
	}
	return retEvent, nil
}

func (fes *FederatedEventSink) Update(event *clientv1.Event) (*clientv1.Event, error) {
	kubeEvent := &kubev1.Event{}
	if err := scheme.Convert(event, kubeEvent, nil); err != nil {
		return nil, err
	}

	ret, err := fes.clientset.Core().Events(kubeEvent.Namespace).Update(kubeEvent)
	if err != nil {
		return nil, err
	}

	retEvent := &clientv1.Event{}
	if err := scheme.Convert(ret, retEvent, nil); err != nil {
		return nil, err
	}
	return retEvent, nil
}

func (fes *FederatedEventSink) Patch(event *clientv1.Event, data []byte) (*clientv1.Event, error) {
	kubeEvent := &kubev1.Event{}
	if err := scheme.Convert(event, kubeEvent, nil); err != nil {
		return nil, err
	}

	ret, err := fes.clientset.Core().Events(kubeEvent.Namespace).Patch(kubeEvent.Name, types.StrategicMergePatchType, data)
	if err != nil {
		return nil, err
	}

	retEvent := &clientv1.Event{}
	if err := scheme.Convert(ret, retEvent, nil); err != nil {
		return nil, err
	}
	return retEvent, nil
}
<commit_msg>deepcopy: misc fixes for static deepcopy compilation<commit_after>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

package eventsink

import (
	"reflect"

	clientv1 "k8s.io/api/core/v1"
	kubev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/conversion"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/client-go/tools/record"
	fedclientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_clientset"
)

// Implements k8s.io/client-go/tools/record.EventSink.
type FederatedEventSink struct {
	clientset fedclientset.Interface
}

// To check if all required functions are implemented.
var _ record.EventSink = &FederatedEventSink{}

func NewFederatedEventSink(clientset fedclientset.Interface) *FederatedEventSink {
	return &FederatedEventSink{
		clientset: clientset,
	}
}

// TODO this is uses a reflection conversion path and is very expensive.  federation should update to use client-go

var scheme = runtime.NewScheme()

func init() {
	// register client-go's and kube's Event type under two different GroupVersions
	// TODO: switch to client-go client for events
	scheme.AddKnownTypes(clientv1.SchemeGroupVersion, &clientv1.Event{})
	scheme.AddKnownTypes(schema.GroupVersion{Group: "fake-kube-" + kubev1.SchemeGroupVersion.Group, Version: kubev1.SchemeGroupVersion.Version}, &kubev1.Event{})

	if err := scheme.AddConversionFuncs(
		metav1.Convert_unversioned_Time_To_unversioned_Time,
	); err != nil {
		panic(err)
	}
	if err := scheme.AddGeneratedDeepCopyFuncs(
		conversion.GeneratedDeepCopyFunc{
			Fn: func(in, out interface{}, c *conversion.Cloner) error {
				in.(*metav1.Time).DeepCopyInto(out.(*metav1.Time))
				return nil
			},
			InType: reflect.TypeOf(&metav1.Time{}),
		},
	); err != nil {
		panic(err)
	}
}

func (fes *FederatedEventSink) Create(event *clientv1.Event) (*clientv1.Event, error) {
	kubeEvent := &kubev1.Event{}
	if err := scheme.Convert(event, kubeEvent, nil); err != nil {
		return nil, err
	}

	ret, err := fes.clientset.Core().Events(kubeEvent.Namespace).Create(kubeEvent)
	if err != nil {
		return nil, err
	}

	retEvent := &clientv1.Event{}
	if err := scheme.Convert(ret, retEvent, nil); err != nil {
		return nil, err
	}
	return retEvent, nil
}

func (fes *FederatedEventSink) Update(event *clientv1.Event) (*clientv1.Event, error) {
	kubeEvent := &kubev1.Event{}
	if err := scheme.Convert(event, kubeEvent, nil); err != nil {
		return nil, err
	}

	ret, err := fes.clientset.Core().Events(kubeEvent.Namespace).Update(kubeEvent)
	if err != nil {
		return nil, err
	}

	retEvent := &clientv1.Event{}
	if err := scheme.Convert(ret, retEvent, nil); err != nil {
		return nil, err
	}
	return retEvent, nil
}

func (fes *FederatedEventSink) Patch(event *clientv1.Event, data []byte) (*clientv1.Event, error) {
	kubeEvent := &kubev1.Event{}
	if err := scheme.Convert(event, kubeEvent, nil); err != nil {
		return nil, err
	}

	ret, err := fes.clientset.Core().Events(kubeEvent.Namespace).Patch(kubeEvent.Name, types.StrategicMergePatchType, data)
	if err != nil {
		return nil, err
	}

	retEvent := &clientv1.Event{}
	if err := scheme.Convert(ret, retEvent, nil); err != nil {
		return nil, err
	}
	return retEvent, nil
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Rook Authors. 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 clusterdisruption

import (
	"reflect"

	"github.com/rook/rook/pkg/operator/ceph/disruption/controllerconfig"

	"sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/controller-runtime/pkg/controller"
	"sigs.k8s.io/controller-runtime/pkg/event"
	"sigs.k8s.io/controller-runtime/pkg/handler"
	"sigs.k8s.io/controller-runtime/pkg/manager"
	"sigs.k8s.io/controller-runtime/pkg/predicate"
	"sigs.k8s.io/controller-runtime/pkg/reconcile"
	"sigs.k8s.io/controller-runtime/pkg/source"

	"github.com/pkg/errors"
	cephv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1"
	policyv1beta1 "k8s.io/api/policy/v1beta1"
	"k8s.io/apimachinery/pkg/types"
)

// Add adds a new Controller to the Manager based on clusterdisruption.ReconcileClusterDisruption and registers the relevant watches and handlers.
// Read more about how Managers, Controllers, and their Watches, Handlers, Predicates, etc work here:
// https://godoc.org/github.com/kubernetes-sigs/controller-runtime/pkg
func Add(mgr manager.Manager, context *controllerconfig.Context) error {

	// Add the cephv1 scheme to the manager scheme
	mgrScheme := mgr.GetScheme()
	if err := cephv1.AddToScheme(mgr.GetScheme()); err != nil {
		return errors.Wrap(err, "failed to add ceph scheme to manager scheme")
	}

	// this will be used to associate namespaces and cephclusters.
	sharedClusterMap := &ClusterMap{}

	reconcileClusterDisruption := &ReconcileClusterDisruption{
		client:     mgr.GetClient(),
		scheme:     mgrScheme,
		context:    context,
		clusterMap: sharedClusterMap,
	}
	reconciler := reconcile.Reconciler(reconcileClusterDisruption)
	// Create a new controller
	c, err := controller.New(controllerName, mgr, controller.Options{Reconciler: reconciler})
	if err != nil {
		return err
	}

	cephClusterPredicate := predicate.Funcs{
		CreateFunc: func(e event.CreateEvent) bool {
			logger.Info("create event from ceph cluster CR")
			return true
		},
		UpdateFunc: func(e event.UpdateEvent) bool {
			oldCluster, ok := e.ObjectOld.DeepCopyObject().(*cephv1.CephCluster)
			if !ok {
				return false
			}
			newCluster, ok := e.ObjectNew.DeepCopyObject().(*cephv1.CephCluster)
			if !ok {
				return false
			}
			return !reflect.DeepEqual(oldCluster.Spec, newCluster.Spec)
		},
	}

	// Watch for CephClusters
	err = c.Watch(&source.Kind{Type: &cephv1.CephCluster{}}, &handler.EnqueueRequestForObject{}, cephClusterPredicate)
	if err != nil {
		return err
	}

	pdbPredicate := predicate.Funcs{
		UpdateFunc: func(e event.UpdateEvent) bool {
			pdb, ok := e.ObjectNew.DeepCopyObject().(*policyv1beta1.PodDisruptionBudget)
			if !ok {
				return false
			}
			// only reconcile if allowed disruptions is 0 in the main PDB
			return pdb.Name == osdPDBAppName && pdb.Status.DisruptionsAllowed == 0
		},
	}

	// Watch for main PodDisruptionBudget and enqueue the CephCluster in the namespace
	err = c.Watch(
		&source.Kind{Type: &policyv1beta1.PodDisruptionBudget{}},
		handler.EnqueueRequestsFromMapFunc(handler.MapFunc(func(obj client.Object) []reconcile.Request {
			pdb, ok := obj.(*policyv1beta1.PodDisruptionBudget)
			if !ok {
				// not a pdb, returning empty
				logger.Errorf("PDB handler received non-PDB")
				return []reconcile.Request{}
			}
			namespace := pdb.GetNamespace()
			req := reconcile.Request{NamespacedName: types.NamespacedName{Namespace: namespace}}
			return []reconcile.Request{req}
		}),
		),
		pdbPredicate,
	)
	if err != nil {
		return err
	}

	// enqueues with an empty name that is populated by the reconciler.
	// There is a one-per-namespace limit on CephClusters
	enqueueByNamespace := handler.EnqueueRequestsFromMapFunc(handler.MapFunc(func(obj client.Object) []reconcile.Request {
		// The name will be populated in the reconcile
		namespace := obj.GetNamespace()
		if len(namespace) == 0 {
			logger.Errorf("enqueueByNamespace received an obj without a namespace. %+v", obj)
			return []reconcile.Request{}
		}
		req := reconcile.Request{NamespacedName: types.NamespacedName{Namespace: namespace}}
		return []reconcile.Request{req}
	}),
	)

	// Watch for CephBlockPools and enqueue the CephCluster in the namespace
	err = c.Watch(&source.Kind{Type: &cephv1.CephBlockPool{}}, enqueueByNamespace)
	if err != nil {
		return err
	}

	// Watch for CephFileSystems and enqueue the CephCluster in the namespace
	err = c.Watch(&source.Kind{Type: &cephv1.CephFilesystem{}}, enqueueByNamespace)
	if err != nil {
		return err
	}

	// Watch for CephObjectStores and enqueue the CephCluster in the namespace
	err = c.Watch(&source.Kind{Type: &cephv1.CephObjectStore{}}, enqueueByNamespace)
	if err != nil {
		return err
	}

	return nil
}
<commit_msg>ceph: skip pdb reconcile on create and delete events<commit_after>/*
Copyright 2019 The Rook Authors. 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 clusterdisruption

import (
	"reflect"

	"github.com/rook/rook/pkg/operator/ceph/disruption/controllerconfig"

	"sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/controller-runtime/pkg/controller"
	"sigs.k8s.io/controller-runtime/pkg/event"
	"sigs.k8s.io/controller-runtime/pkg/handler"
	"sigs.k8s.io/controller-runtime/pkg/manager"
	"sigs.k8s.io/controller-runtime/pkg/predicate"
	"sigs.k8s.io/controller-runtime/pkg/reconcile"
	"sigs.k8s.io/controller-runtime/pkg/source"

	"github.com/pkg/errors"
	cephv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1"
	policyv1beta1 "k8s.io/api/policy/v1beta1"
	"k8s.io/apimachinery/pkg/types"
)

// Add adds a new Controller to the Manager based on clusterdisruption.ReconcileClusterDisruption and registers the relevant watches and handlers.
// Read more about how Managers, Controllers, and their Watches, Handlers, Predicates, etc work here:
// https://godoc.org/github.com/kubernetes-sigs/controller-runtime/pkg
func Add(mgr manager.Manager, context *controllerconfig.Context) error {

	// Add the cephv1 scheme to the manager scheme
	mgrScheme := mgr.GetScheme()
	if err := cephv1.AddToScheme(mgr.GetScheme()); err != nil {
		return errors.Wrap(err, "failed to add ceph scheme to manager scheme")
	}

	// This will be used to associate namespaces and cephclusters.
	sharedClusterMap := &ClusterMap{}

	reconcileClusterDisruption := &ReconcileClusterDisruption{
		client:     mgr.GetClient(),
		scheme:     mgrScheme,
		context:    context,
		clusterMap: sharedClusterMap,
	}
	reconciler := reconcile.Reconciler(reconcileClusterDisruption)
	// Create a new controller
	c, err := controller.New(controllerName, mgr, controller.Options{Reconciler: reconciler})
	if err != nil {
		return err
	}

	cephClusterPredicate := predicate.Funcs{
		CreateFunc: func(e event.CreateEvent) bool {
			logger.Info("create event from ceph cluster CR")
			return true
		},
		UpdateFunc: func(e event.UpdateEvent) bool {
			oldCluster, ok := e.ObjectOld.DeepCopyObject().(*cephv1.CephCluster)
			if !ok {
				return false
			}
			newCluster, ok := e.ObjectNew.DeepCopyObject().(*cephv1.CephCluster)
			if !ok {
				return false
			}
			return !reflect.DeepEqual(oldCluster.Spec, newCluster.Spec)
		},
	}

	// Watch for CephClusters
	err = c.Watch(&source.Kind{Type: &cephv1.CephCluster{}}, &handler.EnqueueRequestForObject{}, cephClusterPredicate)
	if err != nil {
		return err
	}

	// Only reconcile for PDB update event when allowed disruptions for the main OSD PDB is 0.
	// This means that one of the OSD is down due to node drain or any other reason
	pdbPredicate := predicate.Funcs{
		CreateFunc: func(e event.CreateEvent) bool {
			// Do not reconcile when PDB is created
			return false
		},
		UpdateFunc: func(e event.UpdateEvent) bool {
			pdb, ok := e.ObjectNew.DeepCopyObject().(*policyv1beta1.PodDisruptionBudget)
			if !ok {
				return false
			}
			return pdb.Name == osdPDBAppName && pdb.Status.DisruptionsAllowed == 0
		},
		DeleteFunc: func(e event.DeleteEvent) bool {
			// Do not reconcile when PDB is deleted
			return false
		},
	}

	// Watch for main PodDisruptionBudget and enqueue the CephCluster in the namespace
	err = c.Watch(
		&source.Kind{Type: &policyv1beta1.PodDisruptionBudget{}},
		handler.EnqueueRequestsFromMapFunc(handler.MapFunc(func(obj client.Object) []reconcile.Request {
			pdb, ok := obj.(*policyv1beta1.PodDisruptionBudget)
			if !ok {
				// Not a pdb, returning empty
				logger.Errorf("PDB handler received non-PDB")
				return []reconcile.Request{}
			}
			namespace := pdb.GetNamespace()
			req := reconcile.Request{NamespacedName: types.NamespacedName{Namespace: namespace}}
			return []reconcile.Request{req}
		}),
		),
		pdbPredicate,
	)
	if err != nil {
		return err
	}

	// enqueues with an empty name that is populated by the reconciler.
	// There is a one-per-namespace limit on CephClusters
	enqueueByNamespace := handler.EnqueueRequestsFromMapFunc(handler.MapFunc(func(obj client.Object) []reconcile.Request {
		// The name will be populated in the reconcile
		namespace := obj.GetNamespace()
		if len(namespace) == 0 {
			logger.Errorf("enqueueByNamespace received an obj without a namespace. %+v", obj)
			return []reconcile.Request{}
		}
		req := reconcile.Request{NamespacedName: types.NamespacedName{Namespace: namespace}}
		return []reconcile.Request{req}
	}),
	)

	// Watch for CephBlockPools and enqueue the CephCluster in the namespace
	err = c.Watch(&source.Kind{Type: &cephv1.CephBlockPool{}}, enqueueByNamespace)
	if err != nil {
		return err
	}

	// Watch for CephFileSystems and enqueue the CephCluster in the namespace
	err = c.Watch(&source.Kind{Type: &cephv1.CephFilesystem{}}, enqueueByNamespace)
	if err != nil {
		return err
	}

	// Watch for CephObjectStores and enqueue the CephCluster in the namespace
	err = c.Watch(&source.Kind{Type: &cephv1.CephObjectStore{}}, enqueueByNamespace)
	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package backoff

import (
	"math/rand"
	"time"
)

/*
ExponentialBackOff is a backoff implementation that increases the backoff
period for each retry attempt using a randomization function that grows exponentially.

NextBackOff() is calculated using the following formula:

 randomized interval =
     RetryInterval * (random value in range [1 - RandomizationFactor, 1 + RandomizationFactor])

In other words NextBackOff() will range between the randomization factor
percentage below and above the retry interval.

For example, given the following parameters:

 RetryInterval = 2
 RandomizationFactor = 0.5
 Multiplier = 2

the actual backoff period used in the next retry attempt will range between 1 and 3 seconds,
multiplied by the exponential, that is, between 2 and 6 seconds.

Note: MaxInterval caps the RetryInterval and not the randomized interval.

If the time elapsed since an ExponentialBackOff instance is created goes past the
MaxElapsedTime, then the method NextBackOff() starts returning backoff.Stop.

The elapsed time can be reset by calling Reset().

Example: Given the following default arguments, for 10 tries the sequence will be,
and assuming we go over the MaxElapsedTime on the 10th try:

 Request #  RetryInterval (seconds)  Randomized Interval (seconds)

  1          0.5                     [0.25,   0.75]
  2          0.75                    [0.375,  1.125]
  3          1.125                   [0.562,  1.687]
  4          1.687                   [0.8435, 2.53]
  5          2.53                    [1.265,  3.795]
  6          3.795                   [1.897,  5.692]
  7          5.692                   [2.846,  8.538]
  8          8.538                   [4.269, 12.807]
  9         12.807                   [6.403, 19.210]
 10         19.210                   backoff.Stop

Note: Implementation is not thread-safe.
*/
type ExponentialBackOff struct {
	InitialInterval     time.Duration
	RandomizationFactor float64
	Multiplier          float64
	MaxInterval         time.Duration
	// After MaxElapsedTime the ExponentialBackOff stops.
	// It never stops if MaxElapsedTime == 0.
	MaxElapsedTime time.Duration
	Clock          Clock

	currentInterval time.Duration
	startTime       time.Time
}

// Clock is an interface that returns current time for BackOff.
type Clock interface {
	Now() time.Time
}

// Default values for ExponentialBackOff.
const (
	DefaultInitialInterval     = 500 * time.Millisecond
	DefaultRandomizationFactor = 0.5
	DefaultMultiplier          = 1.5
	DefaultMaxInterval         = 60 * time.Second
	DefaultMaxElapsedTime      = 15 * time.Minute
)

// withCanonicalRandomizationFactor is a utility function used by all
// NewXYZBackoff functions to clamp b.RandomizationFactor to either 0 or 1
func (b *ExponentialBackOff) withCanonicalRandomizationFactor() *ExponentialBackOff {
	if b.RandomizationFactor < 0 {
		b.RandomizationFactor = 0
	} else if b.RandomizationFactor > 1 {
		b.RandomizationFactor = 1
	}
	return b
}

// withReset is a utility function that calls 'b.Reset()' and then returns it,
// so that all NewXYZBackoff functions can reset their result and return it
// inline
func (b *ExponentialBackOff) withReset() *ExponentialBackOff {
	b.Reset()
	return b
}

// NewExponentialBackOff creates an instance of ExponentialBackOff using default values.
func NewExponentialBackOff() *ExponentialBackOff {
	b := &ExponentialBackOff{
		InitialInterval:     DefaultInitialInterval,
		RandomizationFactor: DefaultRandomizationFactor,
		Multiplier:          DefaultMultiplier,
		MaxInterval:         DefaultMaxInterval,
		MaxElapsedTime:      DefaultMaxElapsedTime,
		Clock:               SystemClock,
	}
	return b.withCanonicalRandomizationFactor().withReset()
}

// NewInfiniteBackOff creates an instance of ExponentialBackOff that never
// ends.
func NewInfiniteBackOff() *ExponentialBackOff {
	b := &ExponentialBackOff{
		InitialInterval:     DefaultInitialInterval,
		RandomizationFactor: DefaultRandomizationFactor,
		Multiplier:          DefaultMultiplier,
		MaxInterval:         15 * time.Second,
		MaxElapsedTime:      0,
		Clock:               SystemClock,
	}
	return b.withCanonicalRandomizationFactor().withReset()
}

// NewTestingBackOff returns a backoff tuned towards waiting for a Pachyderm
// state change in a test
func NewTestingBackOff() *ExponentialBackOff {
	b := &ExponentialBackOff{
		InitialInterval:     DefaultInitialInterval,
		RandomizationFactor: DefaultRandomizationFactor,
		Multiplier:          DefaultMultiplier,
		MaxInterval:         5 * time.Second,
		MaxElapsedTime:      60 * time.Second,
		Clock:               SystemClock,
	}
	return b.withCanonicalRandomizationFactor().withReset()
}

// New10sBackOff returns a backoff that's slightly more aggressive than
// NewExponentialBackOff. The Max Elapsed time for this backoff is 10s, and the
// initial backoff is 100ms (instead of 500). Therefore this will retry at most
// 10 times and then fail (depending on RPC timeout), and may be more useful
// for interactive RPCs than NewExponentialBackOff.
func New10sBackOff() *ExponentialBackOff {
	b := &ExponentialBackOff{
		InitialInterval:     100 * time.Millisecond,
		RandomizationFactor: DefaultRandomizationFactor,
		Multiplier:          DefaultMultiplier,
		MaxInterval:         2 * time.Second,
		MaxElapsedTime:      10 * time.Second,
		Clock:               SystemClock,
	}
	return b.withCanonicalRandomizationFactor().withReset()
}

// New60sBackOff returns a backoff that's slightly more aggressive than
// NewExponentialBackOff. The Max Elapsed time for this backoff is 60s, and the
// initial backoff is 100ms (instead of 500). This may be more useful for
// watcher and controllers (e.g. the PPS master or the worker) than
// NewExponentialBackOff
func New60sBackOff() *ExponentialBackOff {
	b := &ExponentialBackOff{
		InitialInterval:     100 * time.Millisecond,
		RandomizationFactor: DefaultRandomizationFactor,
		Multiplier:          DefaultMultiplier,
		MaxInterval:         2 * time.Second,
		MaxElapsedTime:      60 * time.Second,
		Clock:               SystemClock,
	}
	return b.withCanonicalRandomizationFactor().withReset()
}

type systemClock struct{}

func (t systemClock) Now() time.Time {
	return time.Now()
}

// SystemClock implements Clock interface that uses time.Now().
var SystemClock = systemClock{}

// Reset the interval back to the initial retry interval and restarts the timer.
func (b *ExponentialBackOff) Reset() {
	b.currentInterval = b.InitialInterval
	b.startTime = b.Clock.Now()
}

// NextBackOff calculates the next backoff interval using the formula:
// 	Randomized interval = RetryInterval +/- (RandomizationFactor * RetryInterval)
func (b *ExponentialBackOff) NextBackOff() time.Duration {
	// Make sure we have not gone over the maximum elapsed time.
	if b.MaxElapsedTime != 0 && b.GetElapsedTime() > b.MaxElapsedTime {
		return Stop
	}
	defer b.incrementCurrentInterval()
	return getRandomValueFromInterval(b.RandomizationFactor, rand.Float64(), b.currentInterval)
}

// GetElapsedTime returns the elapsed time since an ExponentialBackOff instance
// is created and is reset when Reset() is called.
//
// The elapsed time is computed using time.Now().UnixNano().
func (b *ExponentialBackOff) GetElapsedTime() time.Duration {
	return b.Clock.Now().Sub(b.startTime)
}

// Increments the current interval by multiplying it with the multiplier.
func (b *ExponentialBackOff) incrementCurrentInterval() {
	// Check for overflow, if overflow is detected set the current interval to the max interval.
	if float64(b.currentInterval) >= float64(b.MaxInterval)/b.Multiplier {
		b.currentInterval = b.MaxInterval
	} else {
		b.currentInterval = time.Duration(float64(b.currentInterval) * b.Multiplier)
	}
}

// Returns a random value from the following interval:
// 	[randomizationFactor * currentInterval, randomizationFactor * currentInterval].
func getRandomValueFromInterval(randomizationFactor, random float64, currentInterval time.Duration) time.Duration {
	var delta = randomizationFactor * float64(currentInterval)
	var minInterval = float64(currentInterval) - delta
	var maxInterval = float64(currentInterval) + delta

	// Get a random value from the range [minInterval, maxInterval].
	// The formula used below has a +1 because if the minInterval is 1 and the maxInterval is 3 then
	// we want a 33% chance for selecting either 1, 2 or 3.
	return time.Duration(minInterval + (random * (maxInterval - minInterval + 1)))
}
<commit_msg>backoff/exponential.go: fix comment<commit_after>package backoff

import (
	"math/rand"
	"time"
)

/*
ExponentialBackOff is a backoff implementation that increases the backoff
period for each retry attempt using a randomization function that grows exponentially.

NextBackOff() is calculated using the following formula:

 randomized interval =
     RetryInterval * (random value in range [1 - RandomizationFactor, 1 + RandomizationFactor])

In other words NextBackOff() will range between the randomization factor
percentage below and above the retry interval.

For example, given the following parameters:

 RetryInterval = 2
 RandomizationFactor = 0.5
 Multiplier = 2

the actual backoff period used in the next retry attempt will range between 1 and 3 seconds,
multiplied by the exponential, that is, between 2 and 6 seconds.

Note: MaxInterval caps the RetryInterval and not the randomized interval.

If the time elapsed since an ExponentialBackOff instance is created goes past the
MaxElapsedTime, then the method NextBackOff() starts returning backoff.Stop.

The elapsed time can be reset by calling Reset().

Example: Given the following default arguments, for 10 tries the sequence will be,
and assuming we go over the MaxElapsedTime on the 10th try:

 Request #  RetryInterval (seconds)  Randomized Interval (seconds)

  1          0.5                     [0.25,   0.75]
  2          0.75                    [0.375,  1.125]
  3          1.125                   [0.562,  1.687]
  4          1.687                   [0.8435, 2.53]
  5          2.53                    [1.265,  3.795]
  6          3.795                   [1.897,  5.692]
  7          5.692                   [2.846,  8.538]
  8          8.538                   [4.269, 12.807]
  9         12.807                   [6.403, 19.210]
 10         19.210                   backoff.Stop

Note: Implementation is not thread-safe.
*/
type ExponentialBackOff struct {
	InitialInterval     time.Duration
	RandomizationFactor float64
	Multiplier          float64
	MaxInterval         time.Duration
	// After MaxElapsedTime the ExponentialBackOff stops.
	// It never stops if MaxElapsedTime == 0.
	MaxElapsedTime time.Duration
	Clock          Clock

	currentInterval time.Duration
	startTime       time.Time
}

// Clock is an interface that returns current time for BackOff.
type Clock interface {
	Now() time.Time
}

// Default values for ExponentialBackOff.
const (
	DefaultInitialInterval     = 500 * time.Millisecond
	DefaultRandomizationFactor = 0.5
	DefaultMultiplier          = 1.5
	DefaultMaxInterval         = 60 * time.Second
	DefaultMaxElapsedTime      = 15 * time.Minute
)

// withCanonicalRandomizationFactor is a utility function used by all
// NewXYZBackoff functions to clamp b.RandomizationFactor to either 0 or 1
func (b *ExponentialBackOff) withCanonicalRandomizationFactor() *ExponentialBackOff {
	if b.RandomizationFactor < 0 {
		b.RandomizationFactor = 0
	} else if b.RandomizationFactor > 1 {
		b.RandomizationFactor = 1
	}
	return b
}

// withReset is a utility function that calls 'b.Reset()' and then returns it,
// so that all NewXYZBackoff functions can reset their result and return it
// inline
func (b *ExponentialBackOff) withReset() *ExponentialBackOff {
	b.Reset()
	return b
}

// NewExponentialBackOff creates an instance of ExponentialBackOff using default values.
func NewExponentialBackOff() *ExponentialBackOff {
	b := &ExponentialBackOff{
		InitialInterval:     DefaultInitialInterval,
		RandomizationFactor: DefaultRandomizationFactor,
		Multiplier:          DefaultMultiplier,
		MaxInterval:         DefaultMaxInterval,
		MaxElapsedTime:      DefaultMaxElapsedTime,
		Clock:               SystemClock,
	}
	return b.withCanonicalRandomizationFactor().withReset()
}

// NewInfiniteBackOff creates an instance of ExponentialBackOff that never
// ends.
func NewInfiniteBackOff() *ExponentialBackOff {
	b := &ExponentialBackOff{
		InitialInterval:     DefaultInitialInterval,
		RandomizationFactor: DefaultRandomizationFactor,
		Multiplier:          DefaultMultiplier,
		MaxInterval:         15 * time.Second,
		MaxElapsedTime:      0,
		Clock:               SystemClock,
	}
	return b.withCanonicalRandomizationFactor().withReset()
}

// NewTestingBackOff returns a backoff tuned towards waiting for a Pachyderm
// state change in a test
func NewTestingBackOff() *ExponentialBackOff {
	b := &ExponentialBackOff{
		InitialInterval:     DefaultInitialInterval,
		RandomizationFactor: DefaultRandomizationFactor,
		Multiplier:          DefaultMultiplier,
		MaxInterval:         5 * time.Second,
		MaxElapsedTime:      60 * time.Second,
		Clock:               SystemClock,
	}
	return b.withCanonicalRandomizationFactor().withReset()
}

// New10sBackOff returns a backoff that's slightly more aggressive than
// NewExponentialBackOff. The Max Elapsed time for this backoff is 10s, and the
// initial backoff is 100ms (instead of 500). Therefore this will retry at most
// 10 times and then fail (depending on RPC timeout), and may be more useful
// for interactive RPCs than NewExponentialBackOff.
func New10sBackOff() *ExponentialBackOff {
	b := &ExponentialBackOff{
		InitialInterval:     100 * time.Millisecond,
		RandomizationFactor: DefaultRandomizationFactor,
		Multiplier:          DefaultMultiplier,
		MaxInterval:         2 * time.Second,
		MaxElapsedTime:      10 * time.Second,
		Clock:               SystemClock,
	}
	return b.withCanonicalRandomizationFactor().withReset()
}

// New60sBackOff returns a backoff identical to New10sBackOff except with a
// longer MaxElapsedTime This may be more useful for watcher and controllers
// (e.g. the PPS master or the worker) than New10sBackOff, which is a length of
// time that makes more sense for the critical paths of slow RPCs (e.g. PutFile)
func New60sBackOff() *ExponentialBackOff {
	b := &ExponentialBackOff{
		InitialInterval:     100 * time.Millisecond,
		RandomizationFactor: DefaultRandomizationFactor,
		Multiplier:          DefaultMultiplier,
		MaxInterval:         2 * time.Second,
		MaxElapsedTime:      60 * time.Second,
		Clock:               SystemClock,
	}
	return b.withCanonicalRandomizationFactor().withReset()
}

type systemClock struct{}

func (t systemClock) Now() time.Time {
	return time.Now()
}

// SystemClock implements Clock interface that uses time.Now().
var SystemClock = systemClock{}

// Reset the interval back to the initial retry interval and restarts the timer.
func (b *ExponentialBackOff) Reset() {
	b.currentInterval = b.InitialInterval
	b.startTime = b.Clock.Now()
}

// NextBackOff calculates the next backoff interval using the formula:
// 	Randomized interval = RetryInterval +/- (RandomizationFactor * RetryInterval)
func (b *ExponentialBackOff) NextBackOff() time.Duration {
	// Make sure we have not gone over the maximum elapsed time.
	if b.MaxElapsedTime != 0 && b.GetElapsedTime() > b.MaxElapsedTime {
		return Stop
	}
	defer b.incrementCurrentInterval()
	return getRandomValueFromInterval(b.RandomizationFactor, rand.Float64(), b.currentInterval)
}

// GetElapsedTime returns the elapsed time since an ExponentialBackOff instance
// is created and is reset when Reset() is called.
//
// The elapsed time is computed using time.Now().UnixNano().
func (b *ExponentialBackOff) GetElapsedTime() time.Duration {
	return b.Clock.Now().Sub(b.startTime)
}

// Increments the current interval by multiplying it with the multiplier.
func (b *ExponentialBackOff) incrementCurrentInterval() {
	// Check for overflow, if overflow is detected set the current interval to the max interval.
	if float64(b.currentInterval) >= float64(b.MaxInterval)/b.Multiplier {
		b.currentInterval = b.MaxInterval
	} else {
		b.currentInterval = time.Duration(float64(b.currentInterval) * b.Multiplier)
	}
}

// Returns a random value from the following interval:
// 	[randomizationFactor * currentInterval, randomizationFactor * currentInterval].
func getRandomValueFromInterval(randomizationFactor, random float64, currentInterval time.Duration) time.Duration {
	var delta = randomizationFactor * float64(currentInterval)
	var minInterval = float64(currentInterval) - delta
	var maxInterval = float64(currentInterval) + delta

	// Get a random value from the range [minInterval, maxInterval].
	// The formula used below has a +1 because if the minInterval is 1 and the maxInterval is 3 then
	// we want a 33% chance for selecting either 1, 2 or 3.
	return time.Duration(minInterval + (random * (maxInterval - minInterval + 1)))
}
<|endoftext|>


<commit_before>package provision

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

	"github.com/docker/machine/libmachine/auth"
	"github.com/docker/machine/libmachine/log"
	"github.com/docker/machine/libmachine/mcndockerclient"
	"github.com/docker/machine/libmachine/swarm"
	"github.com/samalba/dockerclient"
)

func configureSwarm(p Provisioner, swarmOptions swarm.Options, authOptions auth.Options) error {
	if !swarmOptions.IsSwarm {
		return nil
	}

	log.Info("Configuring swarm...")

	ip, err := p.GetDriver().GetIP()
	if err != nil {
		return err
	}

	u, err := url.Parse(swarmOptions.Host)
	if err != nil {
		return err
	}

	parts := strings.Split(u.Host, ":")
	port := parts[1]

	dockerPort := "2376"
	dockerDir := p.GetDockerOptionsDir()
	dockerHost := &mcndockerclient.RemoteDocker{
		HostURL:    fmt.Sprintf("tcp://%s:%s", ip, dockerPort),
		AuthOption: &authOptions,
	}
	advertiseInfo := fmt.Sprintf("%s:%s", ip, dockerPort)

	if swarmOptions.Master {
		advertiseMasterInfo := fmt.Sprintf("%s:%s", ip, "3376")
		cmd := fmt.Sprintf("manage --tlsverify --tlscacert=%s --tlscert=%s --tlskey=%s -H %s --strategy %s --replication  --advertise %s",
			authOptions.CaCertRemotePath,
			authOptions.ServerCertRemotePath,
			authOptions.ServerKeyRemotePath,
			swarmOptions.Host,
			swarmOptions.Strategy,
			advertiseMasterInfo,
		)

		cmdMaster := strings.Fields(cmd)
		for _, option := range swarmOptions.ArbitraryFlags {
			cmdMaster = append(cmdMaster, "--"+option)
		}

		//Discovery must be at end of command
		cmdMaster = append(cmdMaster, swarmOptions.Discovery)

		hostBind := fmt.Sprintf("%s:%s", dockerDir, dockerDir)
		masterHostConfig := dockerclient.HostConfig{
			RestartPolicy: dockerclient.RestartPolicy{
				Name:              "always",
				MaximumRetryCount: 0,
			},
			Binds:        []string{hostBind},
			PortBindings: map[string][]dockerclient.PortBinding{"3376/tcp": {{"", port}}},
			NetworkMode:  "host",
		}

		swarmMasterConfig := &dockerclient.ContainerConfig{
			Image: swarmOptions.Image,
			Env:   swarmOptions.Env,
			ExposedPorts: map[string]struct{}{
				"2375/tcp": {},
				"3376/tcp": {},
			},
			Cmd:        cmdMaster,
			HostConfig: masterHostConfig,
		}

		err = mcndockerclient.CreateContainer(dockerHost, swarmMasterConfig, "swarm-agent-master")
		if err != nil {
			return err
		}
	}

	workerHostConfig := dockerclient.HostConfig{
		RestartPolicy: dockerclient.RestartPolicy{
			Name:              "always",
			MaximumRetryCount: 0,
		},
		NetworkMode: "host",
	}

	swarmWorkerConfig := &dockerclient.ContainerConfig{
		Image: swarmOptions.Image,
		Env:   swarmOptions.Env,
		Cmd: []string{
			"join",
			"--advertise",
			advertiseInfo,
			swarmOptions.Discovery,
		},
		HostConfig: workerHostConfig,
	}

	return mcndockerclient.CreateContainer(dockerHost, swarmWorkerConfig, "swarm-agent")
}
<commit_msg>Fix #2903, revert #2833 since it makes it impossible to start up a Swarm master with the token discovery method<commit_after>package provision

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

	"github.com/docker/machine/libmachine/auth"
	"github.com/docker/machine/libmachine/log"
	"github.com/docker/machine/libmachine/mcndockerclient"
	"github.com/docker/machine/libmachine/swarm"
	"github.com/samalba/dockerclient"
)

func configureSwarm(p Provisioner, swarmOptions swarm.Options, authOptions auth.Options) error {
	if !swarmOptions.IsSwarm {
		return nil
	}

	log.Info("Configuring swarm...")

	ip, err := p.GetDriver().GetIP()
	if err != nil {
		return err
	}

	u, err := url.Parse(swarmOptions.Host)
	if err != nil {
		return err
	}

	parts := strings.Split(u.Host, ":")
	port := parts[1]

	dockerPort := "2376"
	dockerDir := p.GetDockerOptionsDir()
	dockerHost := &mcndockerclient.RemoteDocker{
		HostURL:    fmt.Sprintf("tcp://%s:%s", ip, dockerPort),
		AuthOption: &authOptions,
	}
	advertiseInfo := fmt.Sprintf("%s:%s", ip, dockerPort)

	if swarmOptions.Master {
		advertiseMasterInfo := fmt.Sprintf("%s:%s", ip, "3376")
		cmd := fmt.Sprintf("manage --tlsverify --tlscacert=%s --tlscert=%s --tlskey=%s -H %s --strategy %s --advertise %s",
			authOptions.CaCertRemotePath,
			authOptions.ServerCertRemotePath,
			authOptions.ServerKeyRemotePath,
			swarmOptions.Host,
			swarmOptions.Strategy,
			advertiseMasterInfo,
		)

		cmdMaster := strings.Fields(cmd)
		for _, option := range swarmOptions.ArbitraryFlags {
			cmdMaster = append(cmdMaster, "--"+option)
		}

		//Discovery must be at end of command
		cmdMaster = append(cmdMaster, swarmOptions.Discovery)

		hostBind := fmt.Sprintf("%s:%s", dockerDir, dockerDir)
		masterHostConfig := dockerclient.HostConfig{
			RestartPolicy: dockerclient.RestartPolicy{
				Name:              "always",
				MaximumRetryCount: 0,
			},
			Binds:        []string{hostBind},
			PortBindings: map[string][]dockerclient.PortBinding{"3376/tcp": {{"", port}}},
			NetworkMode:  "host",
		}

		swarmMasterConfig := &dockerclient.ContainerConfig{
			Image: swarmOptions.Image,
			Env:   swarmOptions.Env,
			ExposedPorts: map[string]struct{}{
				"2375/tcp": {},
				"3376/tcp": {},
			},
			Cmd:        cmdMaster,
			HostConfig: masterHostConfig,
		}

		err = mcndockerclient.CreateContainer(dockerHost, swarmMasterConfig, "swarm-agent-master")
		if err != nil {
			return err
		}
	}

	workerHostConfig := dockerclient.HostConfig{
		RestartPolicy: dockerclient.RestartPolicy{
			Name:              "always",
			MaximumRetryCount: 0,
		},
		NetworkMode: "host",
	}

	swarmWorkerConfig := &dockerclient.ContainerConfig{
		Image: swarmOptions.Image,
		Env:   swarmOptions.Env,
		Cmd: []string{
			"join",
			"--advertise",
			advertiseInfo,
			swarmOptions.Discovery,
		},
		HostConfig: workerHostConfig,
	}

	return mcndockerclient.CreateContainer(dockerHost, swarmWorkerConfig, "swarm-agent")
}
<|endoftext|>