<commit_before>package upframe

import (
	"net/http"
	"os"
	"path/filepath"

	"github.com/gorilla/sessions"
	"github.com/hacdias/upframe/pages"
	"github.com/mholt/caddy/caddyhttp/httpserver"
)

// Upframe is the startup struct
type Upframe struct {
	Next httpserver.Handler
}

func (u Upframe) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
	// Checks if a static file (not directory) exists for this path. If it doesn't, we
	// handle the request.
	if info, err := os.Stat("static" + r.URL.Path); !(os.IsNotExist(err) || info.IsDir()) {
		return u.Next.ServeHTTP(w, r)
	}

	// Gets the current session or creates a new one if there is some error
	// decrypting it or if it doesn't exist
	s, _ := store.Get(r, "upframe-auth")

	// Saves the session in the cookie and checks for errors
	err := s.Save(r, w)
	if err != nil {
		return http.StatusInternalServerError, err
	}

	// Routes the pages to the respective functions
	switch {
	case r.URL.Path == "/" && r.Method == http.MethodGet:
		return pages.IndexGET(w, r, s)
	case r.URL.Path == "/register" && r.Method == http.MethodGet:
		return pages.RegisterGET(w, r, s)
	case r.URL.Path == "/register" && r.Method == http.MethodPost:
		return pages.RegisterPOST(w, r, s)
	case r.URL.Path == "/login" && r.Method == http.MethodGet:
		return pages.LoginGET(w, r, s)
	case r.URL.Path == "/login" && r.Method == http.MethodPost:
		return pages.LoginPOST(w, r, s)
	case r.URL.Path == "/settings" && r.Method == http.MethodGet:
		return pages.SettingsGET(w, r, s)
	case r.URL.Path == "/store" && r.Method == http.MethodGet:
		return pages.StoreGET(w, r, s)
	case r.URL.Path == "/cart" && r.Method == http.MethodGet:
		return pages.CartGET(w, r, s)
	case r.URL.Path == "/checkout" && r.Method == http.MethodGet:
		return pages.CheckoutGET(w, r, s)
	case r.URL.Path == "/logout":
		return logout(w, r, s)
	}

	// If the request doesn't match any route and it isn't a GET request
	// return a Status Not Implemented
	if r.Method != http.MethodGet {
		return http.StatusNotImplemented, nil
	}

	// Checks if there is a static template for this page. If so, show it!
	if _, err := os.Stat(filepath.Clean("templates/static" + r.URL.Path + ".tmpl")); err == nil {
		return pages.RenderHTML(w, nil, r.URL.Path)
	}

	// Return 404 Not Found for the rest
	return http.StatusNotFound, nil
}

func logout(w http.ResponseWriter, r *http.Request, s *sessions.Session) (int, error) {
	s.Values = nil
	err := s.Save(r, w)
	if err != nil {
		return http.StatusInternalServerError, err
	}

	http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
	return http.StatusOK, nil
}
<commit_msg>add comment<commit_after>package upframe

import (
	"net/http"
	"os"
	"path/filepath"

	"github.com/gorilla/sessions"
	"github.com/hacdias/upframe/pages"
	"github.com/mholt/caddy/caddyhttp/httpserver"
)

// Upframe is the startup struct
type Upframe struct {
	Next httpserver.Handler
}

func (u Upframe) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
	// Checks if a static file (not directory) exists for this path. If it doesn't, we
	// handle the request.
	if info, err := os.Stat("static" + r.URL.Path); !(os.IsNotExist(err) || info.IsDir()) {
		return u.Next.ServeHTTP(w, r)
	}

	// Gets the current session or creates a new one if there is some error
	// decrypting it or if it doesn't exist
	s, _ := store.Get(r, "upframe-auth")

	// Saves the session in the cookie and checks for errors. This is useful
	// to reset the expiration time.
	err := s.Save(r, w)
	if err != nil {
		return http.StatusInternalServerError, err
	}

	// Routes the pages to the respective functions
	switch {
	case r.URL.Path == "/" && r.Method == http.MethodGet:
		return pages.IndexGET(w, r, s)
	case r.URL.Path == "/register" && r.Method == http.MethodGet:
		return pages.RegisterGET(w, r, s)
	case r.URL.Path == "/register" && r.Method == http.MethodPost:
		return pages.RegisterPOST(w, r, s)
	case r.URL.Path == "/login" && r.Method == http.MethodGet:
		return pages.LoginGET(w, r, s)
	case r.URL.Path == "/login" && r.Method == http.MethodPost:
		return pages.LoginPOST(w, r, s)
	case r.URL.Path == "/settings" && r.Method == http.MethodGet:
		return pages.SettingsGET(w, r, s)
	case r.URL.Path == "/store" && r.Method == http.MethodGet:
		return pages.StoreGET(w, r, s)
	case r.URL.Path == "/cart" && r.Method == http.MethodGet:
		return pages.CartGET(w, r, s)
	case r.URL.Path == "/checkout" && r.Method == http.MethodGet:
		return pages.CheckoutGET(w, r, s)
	case r.URL.Path == "/logout":
		return logout(w, r, s)
	}

	// If the request doesn't match any route and it isn't a GET request
	// return a Status Not Implemented
	if r.Method != http.MethodGet {
		return http.StatusNotImplemented, nil
	}

	// Checks if there is a static template for this page. If so, show it!
	if _, err := os.Stat(filepath.Clean("templates/static" + r.URL.Path + ".tmpl")); err == nil {
		return pages.RenderHTML(w, nil, r.URL.Path)
	}

	// Return 404 Not Found for the rest
	return http.StatusNotFound, nil
}

func logout(w http.ResponseWriter, r *http.Request, s *sessions.Session) (int, error) {
	s.Values = nil
	err := s.Save(r, w)
	if err != nil {
		return http.StatusInternalServerError, err
	}

	http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
	return http.StatusOK, nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2014 The btcsuite developers
// Copyright (c) 2015-2016 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package main

import (
	"os"
	"path/filepath"
)

var ticketDBName = "ticketdb.gob"
var oldTicketDBName = "ticketdb_old.gob"

// checkForAndMoveOldTicketDb checks for an old copy of the ticket database
// from before ffldb was introduced and renames it in preparation for resyncing
// the blockchain.
func checkForAndMoveOldTicketDb() error {
	ffldbPath := filepath.Join(cfg.DataDir,
		blockDbNamePrefix+"_"+defaultDbType)

	if _, err := os.Stat(ffldbPath); os.IsNotExist(err) {
		// Rename the old ticket database.
		ticketDBPath := filepath.Join(cfg.DataDir, ticketDBName)
		if _, err := os.Stat(ticketDBPath); !os.IsNotExist(err) && err != nil {
			return err
		}

		dcrdLog.Warnf("The old ticket database file has been named " +
			oldTicketDBName + ". It can be safely removed if you " +
			"no longer wish to roll back to an old version of the " +
			"software.")
		oldTicketDBPath := filepath.Join(cfg.DataDir, oldTicketDBName)
		err = os.Rename(ticketDBPath, oldTicketDBPath)
		if err != nil {
			return err
		}
	}

	return nil
}

// doUpgrades performs upgrades to dcrd as new versions require it.
func doUpgrades() error {
	return checkForAndMoveOldTicketDb()
}
<commit_msg>Don't fail if no blockchain folder exists (#326)<commit_after>// Copyright (c) 2013-2014 The btcsuite developers
// Copyright (c) 2015-2016 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package main

import (
	"os"
	"path/filepath"
)

var ticketDBName = "ticketdb.gob"
var oldTicketDBName = "ticketdb_old.gob"

// checkForAndMoveOldTicketDb checks for an old copy of the ticket database
// from before ffldb was introduced and renames it in preparation for resyncing
// the blockchain.
func checkForAndMoveOldTicketDb() error {
	ffldbPath := filepath.Join(cfg.DataDir,
		blockDbNamePrefix+"_"+defaultDbType)

	// No data path exists, break because this is a fresh start and
	// the database must be constructed.
	if _, err := os.Stat(cfg.DataDir); os.IsNotExist(err) {
		return nil
	}

	// An old version of the chain exists, update it.
	if _, err := os.Stat(ffldbPath); os.IsNotExist(err) {
		// Rename the old ticket database.
		ticketDBPath := filepath.Join(cfg.DataDir, ticketDBName)
		if _, err := os.Stat(ticketDBPath); !os.IsNotExist(err) && err != nil {
			return err
		}

		dcrdLog.Warnf("The old ticket database file has been named " +
			oldTicketDBName + ". It can be safely removed if you " +
			"no longer wish to roll back to an old version of the " +
			"software.")
		oldTicketDBPath := filepath.Join(cfg.DataDir, oldTicketDBName)
		err = os.Rename(ticketDBPath, oldTicketDBPath)
		if err != nil {
			return err
		}
	}

	return nil
}

// doUpgrades performs upgrades to dcrd as new versions require it.
func doUpgrades() error {
	return checkForAndMoveOldTicketDb()
}
<|endoftext|>


<commit_before>package patcher

import (
	"fmt"

	"github.com/itchio/wharf/pwr/bowl"
	"github.com/itchio/wharf/tlc"
	"github.com/itchio/wharf/wire"
	"github.com/itchio/wharf/wsync"
)

type Checkpoint struct {
	MessageCheckpoint *wire.MessageReaderCheckpoint

	FileIndex int64
	FileKind  FileKind

	RsyncCheckpoint  *RsyncCheckpoint
	BsdiffCheckpoint *BsdiffCheckpoint
}

type FileKind int

const (
	FileKindRsync  = 1
	FileKindBsdiff = 2
)

type RsyncCheckpoint struct {
	OutputOffset int64
}

type BsdiffCheckpoint struct {
	OutputOffset int64
	OldOffset    int64
}

type Patcher interface {
	SetSaveConsumer(sc SaveConsumer)
	Resume(checkpoint *Checkpoint, targetPool wsync.Pool, bowl bowl.Bowl) error

	GetSourceContainer() *tlc.Container
	GetTargetContainer() *tlc.Container
}

type AfterSaveAction int

const (
	AfterSaveContinue AfterSaveAction = 1
	AfterSaveStop     AfterSaveAction = 2
)

type SaveConsumer interface {
	ShouldSave() bool
	Save(c *Checkpoint) (AfterSaveAction, error)
}

var ErrStop = fmt.Errorf("patching was stopped after save!")

// nopSaveConsumer

type nopSaveConsumer struct{}

var _ SaveConsumer = (*nopSaveConsumer)(nil)

func (nsc *nopSaveConsumer) ShouldSave() bool {
	return false
}

func (nsc *nopSaveConsumer) Save(c *Checkpoint) (AfterSaveAction, error) {
	return AfterSaveContinue, nil
}
<commit_msg>use BowlCheckpoint in pwr/patcher checkpoints<commit_after>package patcher

import (
	"fmt"

	"github.com/itchio/wharf/pwr/bowl"
	"github.com/itchio/wharf/tlc"
	"github.com/itchio/wharf/wire"
	"github.com/itchio/wharf/wsync"
)

type Checkpoint struct {
	MessageCheckpoint *wire.MessageReaderCheckpoint

	FileIndex int64
	FileKind  FileKind

	RsyncCheckpoint  *RsyncCheckpoint
	BsdiffCheckpoint *BsdiffCheckpoint
}

type FileKind int

const (
	FileKindRsync  = 1
	FileKindBsdiff = 2
)

type RsyncCheckpoint struct {
	BowlCheckpoint *bowl.Checkpoint
}

type BsdiffCheckpoint struct {
	BowlCheckpoint *bowl.Checkpoint
	// instructions in bsdiff are relative seeks, so we need to keep track of
	// the offset in the (single) target file
	OldOffset int64
}

type Patcher interface {
	SetSaveConsumer(sc SaveConsumer)
	Resume(checkpoint *Checkpoint, targetPool wsync.Pool, bowl bowl.Bowl) error

	GetSourceContainer() *tlc.Container
	GetTargetContainer() *tlc.Container
}

type AfterSaveAction int

const (
	AfterSaveContinue AfterSaveAction = 1
	AfterSaveStop     AfterSaveAction = 2
)

type SaveConsumer interface {
	ShouldSave() bool
	Save(c *Checkpoint) (AfterSaveAction, error)
}

var ErrStop = fmt.Errorf("patching was stopped after save!")

// nopSaveConsumer

type nopSaveConsumer struct{}

var _ SaveConsumer = (*nopSaveConsumer)(nil)

func (nsc *nopSaveConsumer) ShouldSave() bool {
	return false
}

func (nsc *nopSaveConsumer) Save(c *Checkpoint) (AfterSaveAction, error) {
	return AfterSaveContinue, nil
}
<|endoftext|>


<commit_before>// In the name of Allah

// Copyright (c) 2015 Navid Fathollahzade
// This source code is licensed under MIT license that can be found in the LICENSE file.

// Package ptime provides functionality for implementation of Persian (Jalali) Calendar.
package pcalendar

import "errors"

// A PersianMonth specifies a month of the year in Persian calendar starting from 1.
type PersianMonth int

// A GregorianMonth specifies a month of the year in Gregorian calendar starting from 1.
type GregorianMonth int

// A PersianWeekday specifies a day of the week in Persian calendar starting from 0.
type PersianWeekday int

// A GregorianWeekday specifies a day of the week in Gregorian calendar starting from 0.
type GregorianWeekday int

// A PersianCalendar represents a day in Persian (Jalali) Calendar.
type PersianCalendar struct {
	p_year int
	p_month PersianMonth
	p_month_day int
	p_year_day int
	p_week_day PersianWeekday

	g_year int
	g_month GregorianMonth
	g_month_day int
	g_year_day int
	g_week_day GregorianWeekday
}

const (
	Farvardin PersianMonth = 1 + iota
	Ordibehesht
	Khordad
	Tir
	Mordad
	Shahrivar
	Mehr
	Aban
	Azar
	Dey
	Bahman
	Esfand
)

const (
	January GregorianMonth = 1 + iota
	February
	March
	April
	May
	June
	July
	August
	September
	October
	November
	December
)

const (
	Shanbe PersianWeekday = iota
	Yekshanbe
	Doshanbe
	Seshanbe
	Chaharshanbe
	Panjshanbe
	Jome
)

const (
	Saturday GregorianWeekday = iota
	Sunday
	Monday
	Tuesday
	Wednesday
	Thursday
	Friday
)

const (
	persian_epoch = 226899

	month_count_normal = 0
	month_count_leap = 1
	month_count_normal_before = 2
	month_count_leap_before = 3
)

var p_months = [...]string{
	"فروردین",
	"اردیبهشت",
	"خرداد",
	"تیر",
	"مرداد",
	"شهریور",
	"مهر",
	"آبان",
	"آذر",
	"دی",
	"بهمن",
	"اسفند",
}

var g_months = [...]string{
	"January",
	"February",
	"March",
	"April",
	"May",
	"June",
	"July",
	"August",
	"September",
	"October",
	"November",
	"December",
}

var p_days = [...]string{
	"شنبه",
	"یک‌شنبه",
	"دوشنبه",
	"سه‌شنبه",
	"چهارشنبه",
	"پنج‌شنبه",
	"جمعه",
}

var g_days = [...]string{
	"Saturday",
	"Sunday",
	"Monday",
	"Tuesday",
	"Wednesday",
	"Thursday",
	"Friday",
}

var p_month_count = [...][...]int {
	{31,     31,      0},       // Farvardin
	{31,     31,      31},      // Ordibehesht
	{31,     31,      62},      // Khordad
	{31,     31,      93},      // Tir
	{31,     31,      124},     // Mordad
	{31,     31,      155},     // Shahrivar
	{30,     30,      186},     // Mehr
	{30,     30,      216},     // Aban
	{30,     30,      246},     // Azar
	{30,     30,      276},     // Dey
	{30,     30,      306},     // Bahman
	{29,     30,      336},     // Esfand
}

var g_month_count = [...][...]int {
	{31,     31,      0,        0},       // Jan
	{28,     29,      31,       31},      // Feb
	{31,     31,      59,       60},      // Mar
	{30,     30,      90,       91},      // Apr
	{31,     31,      120,      121},     // May
	{30,     30,      151,      152},     // Jun
	{31,     31,      181,      182},     // Jul
	{31,     31,      212,      213},     // Aug
	{30,     30,      243,      244},     // Sep
	{31,     31,      273,      274},     // Oct
	{30,     30,      304,      305},     // Nov
	{31,     31,      334,      335},     // Dec
}

// Returns the Persian name of the month.
func (m PersianMonth) String() string {
	return p_months[m - 1]
}

// Returns the English name of the month.
func (m GregorianMonth) String() string {
	return g_months[m - 1]
}

// Returns the Persian name of the day in week.
func (d PersianWeekday) String() string {
	return p_days[d]
}

// Returns the English name of the day in week.
func (d GregorianWeekday) String() string {
	return g_days[d]
}

func NewGregorian(year int, month GregorianMonth, day int) errors {

}<commit_msg>Add methods<commit_after>// In the name of Allah

// Copyright (c) 2015 Navid Fathollahzade
// This source code is licensed under MIT license that can be found in the LICENSE file.

// Package ptime provides functionality for implementation of Persian (Jalali) Calendar.
package pcalendar

import "errors"

// A PersianMonth specifies a month of the year in Persian calendar starting from 1.
type PersianMonth int

// A GregorianMonth specifies a month of the year in Gregorian calendar starting from 1.
type GregorianMonth int

// A PersianWeekday specifies a day of the week in Persian calendar starting from 0.
type PersianWeekday int

// A GregorianWeekday specifies a day of the week in Gregorian calendar starting from 0.
type GregorianWeekday int

// A PersianCalendar represents a day in Persian (Jalali) Calendar.
type PersianCalendar struct {
	p_year int
	p_month PersianMonth
	p_month_day int
	p_year_day int
	p_week_day PersianWeekday
	g_year int
	g_month GregorianMonth
	g_month_day int
	g_year_day int
	g_week_day GregorianWeekday
}

const (
	Farvardin PersianMonth = 1 + iota
	Ordibehesht
	Khordad
	Tir
	Mordad
	Shahrivar
	Mehr
	Aban
	Azar
	Dey
	Bahman
	Esfand
)

const (
	January GregorianMonth = 1 + iota
	February
	March
	April
	May
	June
	July
	August
	September
	October
	November
	December
)

const (
	Shanbe PersianWeekday = iota
	Yekshanbe
	Doshanbe
	Seshanbe
	Chaharshanbe
	Panjshanbe
	Jome
)

const (
	Saturday GregorianWeekday = iota
	Sunday
	Monday
	Tuesday
	Wednesday
	Thursday
	Friday
)

const (
	persian_epoch = 226899

	month_count_normal = 0
	month_count_leap = 1
	month_count_normal_before = 2
	month_count_leap_before = 3
)

var p_months = [...]string{
	"فروردین",
	"اردیبهشت",
	"خرداد",
	"تیر",
	"مرداد",
	"شهریور",
	"مهر",
	"آبان",
	"آذر",
	"دی",
	"بهمن",
	"اسفند",
}

var g_months = [...]string{
	"January",
	"February",
	"March",
	"April",
	"May",
	"June",
	"July",
	"August",
	"September",
	"October",
	"November",
	"December",
}

var p_days = [...]string{
	"شنبه",
	"یک‌شنبه",
	"دوشنبه",
	"سه‌شنبه",
	"چهارشنبه",
	"پنج‌شنبه",
	"جمعه",
}

var g_days = [...]string{
	"Saturday",
	"Sunday",
	"Monday",
	"Tuesday",
	"Wednesday",
	"Thursday",
	"Friday",
}

var p_month_count = [...][...]int {
	{31,     31,      0},       // Farvardin
	{31,     31,      31},      // Ordibehesht
	{31,     31,      62},      // Khordad
	{31,     31,      93},      // Tir
	{31,     31,      124},     // Mordad
	{31,     31,      155},     // Shahrivar
	{30,     30,      186},     // Mehr
	{30,     30,      216},     // Aban
	{30,     30,      246},     // Azar
	{30,     30,      276},     // Dey
	{30,     30,      306},     // Bahman
	{29,     30,      336},     // Esfand
}

var g_month_count = [...][...]int {
	{31,     31,      0,        0},       // Jan
	{28,     29,      31,       31},      // Feb
	{31,     31,      59,       60},      // Mar
	{30,     30,      90,       91},      // Apr
	{31,     31,      120,      121},     // May
	{30,     30,      151,      152},     // Jun
	{31,     31,      181,      182},     // Jul
	{31,     31,      212,      213},     // Aug
	{30,     30,      243,      244},     // Sep
	{31,     31,      273,      274},     // Oct
	{30,     30,      304,      305},     // Nov
	{31,     31,      334,      335},     // Dec
}

// Returns the Persian name of the month.
func (m PersianMonth) String() string {
	return p_months[m - 1]
}

// Returns the English name of the month.
func (m GregorianMonth) String() string {
	return g_months[m - 1]
}

// Returns the Persian name of the day in week.
func (d PersianWeekday) String() string {
	return p_days[d]
}

// Returns the English name of the day in week.
func (d GregorianWeekday) String() string {
	return g_days[d]
}

// Returns new instance of PersianCalendar using Persian date.
func NewFromPersianDate(year int, month PersianMonth, day int) (PersianCalendar, errors) {
	err := checkPersianDate(year, month, day)
	if err != nil {
		return nil, err
	}

	gy, gm, gmd, gyd, gwd := toGregorian(year, month, day)
	pyd, pwd := calculatePersianDays(month, day)

	return PersianCalendar {
		year,   month,  day,    pyd,    pwd,
		gy,     gm,     gmd,    gyd,    gwd,
	}, nil
}

// Returns new instance of PersianCalendar using Gregorian date.
func NewFromGregorianDate(year int, month GregorianMonth, day int) (PersianCalendar, errors) {
	// TODO
	return nil, nil
}

// Changes an instance of PersianCalendar using Persian date.
func (pc PersianCalendar) SetPersianDate(year int, month PersianMonth, day int) errors {
	// TODO
	return nil
}

// Changes an instance of PersianCalendar using Gregorian date.
func (pc PersianCalendar) SetGregorianDate(year int, month GregorianMonth, day int) errors {
	// TODO
	return nil
}

// Checks Persian date inputs to be a correct day.
func checkPersianDate(year int, month PersianMonth, day int) errors {
	// TODO
	return nil
}

// Checks Gregorian date inputs to be a correct day.
func checkGregorianDate(year int, month GregorianMonth, day int) errors {
	// TODO
	return nil
}

// Converts Gregorian date to Persian date (year, month, month_day, year_day, week_day)
func toPersian(year int, month GregorianMonth, day int) (y int, m PersianMonth, md int, yd int, wd PersianWeekday) {
	// TODO
	return
}

// Converts Persian date to Gregorian date (year, month, month_day, year_day, week_day)
func toGregorian(year int, month PersianMonth, day int) (y int, m GregorianMonth, md int, yd int, wd GregorianWeekday) {
	// TODO
	return
}

// Calculates the year day and weekday of Persian date.
func calculatePersianDays(month PersianMonth, day int) (yd int, wd PersianWeekday) {
	// TODO
	return
}

// Calculates the year day and weekday of Gregorian date.
func calculateGregorianDays(month PersianMonth, day int) (yd int, wd GregorianWeekday) {
	// TODO
	return
}<|endoftext|>


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

package main

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
	"syscall"

	"v.io/x/devtools/internal/collect"
	"v.io/x/devtools/internal/tool"
	"v.io/x/devtools/internal/util"
	"v.io/x/lib/cmdline"
)

var (
	gotoolsBinPathFlag string
	commentRE          = regexp.MustCompile("^($|[:space:]*#)")
)

func init() {
	cmdApi.Flags.StringVar(&gotoolsBinPathFlag, "gotools-bin", "", "The path to the gotools binary to use. If empty, gotools will be built if necessary.")
}

// cmdApi represents the "v23 api" command.
var cmdApi = &cmdline.Command{
	Name:  "api",
	Short: "Work with Vanadium's public API",
	Long: `
Use this command to ensure that no unintended changes are made to Vanadium's
public API.
`,
	Children: []*cmdline.Command{cmdApiCheck, cmdApiUpdate},
}

// cmdApiCheck represents the "v23 api check" command.
var cmdApiCheck = &cmdline.Command{
	Run:      runApiCheck,
	Name:     "check",
	Short:    "Check to see if any changes have been made to the public API.",
	Long:     "Check to see if any changes have been made to the public API.",
	ArgsName: "<projects>",
	ArgsLong: "<projects> is a list of Vanadium projects to check. If none are specified, all projects are checked.",
}

func readApiFileContents(path string, buf *bytes.Buffer) (e error) {
	file, err := os.Open(path)
	defer collect.Error(file.Close, &e)
	if err != nil {
		return err
	}
	reader := bufio.NewReader(file)
	for {
		line, err := reader.ReadBytes('\n')
		if !commentRE.Match(line) {
			buf.Write(line)
		}
		if err == io.EOF {
			break
		} else if err != nil {
			return err
		}
	}
	return
}

type packageChange struct {
	name        string
	apiFilePath string
	newApi      string
}

// buildGotools builds the gotools binary and returns the path to the built
// binary and the function to call to clean up the built binary (always
// non-nil). If the binary could not be built, the empty string and a non-nil
// error are returned.
//
// If the gotools_bin flag is specified, that path, a no-op cleanup and a
// nil error are returned.
func buildGotools(ctx *tool.Context) (string, func() error, error) {
	if gotoolsBinPathFlag != "" {
		return gotoolsBinPathFlag, func() error { return nil }, nil
	}

	// Build the gotools binary.
	tempDir, err := ctx.Run().TempDir("", "")
	if err != nil {
		return "", func() error { return nil }, err
	}
	cleanup := func() error { return ctx.Run().RemoveAll(tempDir) }

	gotoolsBin := filepath.Join(tempDir, "gotools")
	if err := ctx.Run().Command("go", "build", "-o", gotoolsBin, "github.com/visualfc/gotools"); err != nil {
		return "", cleanup, err
	}

	return gotoolsBin, cleanup, nil
}

func getPackageChanges(ctx *tool.Context, command *cmdline.Command, args []string) (changes []packageChange, e error) {
	projects, _, err := util.ReadManifest(ctx)
	if err != nil {
		return nil, err
	}
	projectNames, err := parseArgs(args, projects)
	if err != nil {
		return nil, err
	}

	gotoolsBin, cleanup, err := buildGotools(ctx)
	if err != nil {
		return nil, err
	}
	defer collect.Error(cleanup, &e)

	for _, projectName := range projectNames {
		path := projects[projectName].Path
		branch, err := ctx.Git(tool.RootDirOpt(path)).CurrentBranchName()
		if err != nil {
			return nil, err
		}
		files, err := ctx.Git(tool.RootDirOpt(path)).ModifiedFiles("master", branch)
		if err != nil {
			return nil, err
		}
		// Extract the directories for these files.
		dirs := make(map[string]bool) // set
		for _, file := range files {
			if strings.HasSuffix(file, ".go") {
				dirs[filepath.Join(path, filepath.Dir(file))] = true
			}
		}
		if len(dirs) == 0 {
			continue
		}
		for dir := range dirs {
			// Read the existing public API file.
			apiFilePath := filepath.Join(dir, ".api")
			var apiFileContents bytes.Buffer
			err := readApiFileContents(apiFilePath, &apiFileContents)
			if err != nil {
				fmt.Fprintf(ctx.Stderr(), "WARNING: could not read public API from %s: %v\n", apiFilePath, err)
				fmt.Fprintf(ctx.Stderr(), "WARNING: skipping public API check for %s\n", dir)
				continue
			}
			var out bytes.Buffer
			opts := ctx.Run().Opts()
			opts.Stdout = &out
			if err := ctx.Run().CommandWithOpts(opts, gotoolsBin, "goapi", dir); err != nil {
				return nil, err
			}
			if out.String() != apiFileContents.String() {
				// The user has changed the public API.
				changes = append(changes, packageChange{name: dir, apiFilePath: apiFilePath, newApi: out.String()})
			}
		}
	}
	return
}

func runApiCheck(command *cmdline.Command, args []string) error {
	ctx := tool.NewContextFromCommand(command, tool.ContextOpts{
		Color:    &colorFlag,
		DryRun:   &dryRunFlag,
		Manifest: &manifestFlag,
		Verbose:  &verboseFlag})
	changes, err := getPackageChanges(ctx, command, args)
	if err != nil {
		return err
	} else if len(changes) > 0 {
		fmt.Fprintf(ctx.Stdout(), "Detected changes in the following %d package(s):\n", len(changes))
		for _, change := range changes {
			fmt.Fprintf(ctx.Stdout(), "\t%s\n", change.name)
			opts := ctx.Run().Opts()
			opts.Stdin = strings.NewReader(change.newApi)
			if err := ctx.Run().CommandWithOpts(opts, "diff", "-u", change.apiFilePath, "-"); err != nil {
				// We expect diff to return 1 if changes are
				// detected
				if exiterr, ok := err.(*exec.ExitError); ok {
					if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
						if status != 1 {
							continue
						}
					}
				}
				// If we got here, diff returned a non-nil err
				// other than an ExitError with status code=1
				fmt.Fprintf(ctx.Stderr(), "WARNING: got an error while running diff: %v", err)
			}
		}
	}
	return nil
}

// cmdApiUpdate represents the "v23 api fix" command.
var cmdApiUpdate = &cmdline.Command{
	Run:      runApiFix,
	Name:     "fix",
	Short:    "Updates the .api files to reflect your changes to the public API.",
	Long:     "Updates the .api files to reflect your changes to the public API.",
	ArgsName: "<projects>",
	ArgsLong: "<projects> is a list of Vanadium projects to update. If none are specified, all project APIs are updated.",
}

func runApiFix(command *cmdline.Command, args []string) error {
	ctx := tool.NewContextFromCommand(command, tool.ContextOpts{
		Color:    &colorFlag,
		DryRun:   &dryRunFlag,
		Manifest: &manifestFlag,
		Verbose:  &verboseFlag})
	changes, err := getPackageChanges(ctx, command, args)
	if err != nil {
		return err
	}
	for _, change := range changes {
		if err := ctx.Run().WriteFile(change.apiFilePath, []byte(change.newApi), 0644); err != nil {
			return fmt.Errorf("WriteFile(%s) failed: %v", change.apiFilePath, err)
		}
		fmt.Fprintf(ctx.Stdout(), "Updated %s.\n", change.apiFilePath)
	}
	return nil
}
<commit_msg>v23: set GOPATH when building gotools for 'api' subcommand Change-Id: Iade0726a9e4030b6d92a1368f7058b37af40093f<commit_after>// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
	"syscall"

	"v.io/x/devtools/internal/collect"
	"v.io/x/devtools/internal/tool"
	"v.io/x/devtools/internal/util"
	"v.io/x/lib/cmdline"
)

var (
	gotoolsBinPathFlag string
	commentRE          = regexp.MustCompile("^($|[:space:]*#)")
)

func init() {
	cmdApi.Flags.StringVar(&gotoolsBinPathFlag, "gotools-bin", "", "The path to the gotools binary to use. If empty, gotools will be built if necessary.")
}

// cmdApi represents the "v23 api" command.
var cmdApi = &cmdline.Command{
	Name:  "api",
	Short: "Work with Vanadium's public API",
	Long: `
Use this command to ensure that no unintended changes are made to Vanadium's
public API.
`,
	Children: []*cmdline.Command{cmdApiCheck, cmdApiUpdate},
}

// cmdApiCheck represents the "v23 api check" command.
var cmdApiCheck = &cmdline.Command{
	Run:      runApiCheck,
	Name:     "check",
	Short:    "Check to see if any changes have been made to the public API.",
	Long:     "Check to see if any changes have been made to the public API.",
	ArgsName: "<projects>",
	ArgsLong: "<projects> is a list of Vanadium projects to check. If none are specified, all projects are checked.",
}

func readApiFileContents(path string, buf *bytes.Buffer) (e error) {
	file, err := os.Open(path)
	defer collect.Error(file.Close, &e)
	if err != nil {
		return err
	}
	reader := bufio.NewReader(file)
	for {
		line, err := reader.ReadBytes('\n')
		if !commentRE.Match(line) {
			buf.Write(line)
		}
		if err == io.EOF {
			break
		} else if err != nil {
			return err
		}
	}
	return
}

type packageChange struct {
	name        string
	apiFilePath string
	newApi      string
}

// buildGotools builds the gotools binary and returns the path to the built
// binary and the function to call to clean up the built binary (always
// non-nil). If the binary could not be built, the empty string and a non-nil
// error are returned.
//
// If the gotools_bin flag is specified, that path, a no-op cleanup and a
// nil error are returned.
func buildGotools(ctx *tool.Context) (string, func() error, error) {
	nopCleanup := func() error { return nil }
	if gotoolsBinPathFlag != "" {
		return gotoolsBinPathFlag, nopCleanup, nil
	}

	// Determine the location of the gotools source.
	projects, _, err := util.ReadManifest(ctx)
	if err != nil {
		return "", nopCleanup, err
	}

	project, ok := projects["third_party"]
	if !ok {
		return "", nopCleanup, fmt.Errorf(`project "third_party" not found`)
	}
	newGoPath := filepath.Join(project.Path, "go")

	// Build the gotools binary.
	tempDir, err := ctx.Run().TempDir("", "")
	if err != nil {
		return "", nopCleanup, err
	}
	cleanup := func() error { return ctx.Run().RemoveAll(tempDir) }

	gotoolsBin := filepath.Join(tempDir, "gotools")
	opts := ctx.Run().Opts()
	opts.Env["GOPATH"] = newGoPath
	if err := ctx.Run().CommandWithOpts(opts, "go", "build", "-o", gotoolsBin, "github.com/visualfc/gotools"); err != nil {
		return "", cleanup, err
	}

	return gotoolsBin, cleanup, nil
}

func getPackageChanges(ctx *tool.Context, command *cmdline.Command, args []string) (changes []packageChange, e error) {
	projects, _, err := util.ReadManifest(ctx)
	if err != nil {
		return nil, err
	}
	projectNames, err := parseArgs(args, projects)
	if err != nil {
		return nil, err
	}

	gotoolsBin, cleanup, err := buildGotools(ctx)
	if err != nil {
		return nil, err
	}
	defer collect.Error(cleanup, &e)

	for _, projectName := range projectNames {
		path := projects[projectName].Path
		branch, err := ctx.Git(tool.RootDirOpt(path)).CurrentBranchName()
		if err != nil {
			return nil, err
		}
		files, err := ctx.Git(tool.RootDirOpt(path)).ModifiedFiles("master", branch)
		if err != nil {
			return nil, err
		}
		// Extract the directories for these files.
		dirs := make(map[string]bool) // set
		for _, file := range files {
			if strings.HasSuffix(file, ".go") {
				dirs[filepath.Join(path, filepath.Dir(file))] = true
			}
		}
		if len(dirs) == 0 {
			continue
		}
		for dir := range dirs {
			// Read the existing public API file.
			apiFilePath := filepath.Join(dir, ".api")
			var apiFileContents bytes.Buffer
			err := readApiFileContents(apiFilePath, &apiFileContents)
			if err != nil {
				fmt.Fprintf(ctx.Stderr(), "WARNING: could not read public API from %s: %v\n", apiFilePath, err)
				fmt.Fprintf(ctx.Stderr(), "WARNING: skipping public API check for %s\n", dir)
				continue
			}
			var out bytes.Buffer
			opts := ctx.Run().Opts()
			opts.Stdout = &out
			if err := ctx.Run().CommandWithOpts(opts, gotoolsBin, "goapi", dir); err != nil {
				return nil, err
			}
			if out.String() != apiFileContents.String() {
				// The user has changed the public API.
				changes = append(changes, packageChange{name: dir, apiFilePath: apiFilePath, newApi: out.String()})
			}
		}
	}
	return
}

func runApiCheck(command *cmdline.Command, args []string) error {
	ctx := tool.NewContextFromCommand(command, tool.ContextOpts{
		Color:    &colorFlag,
		DryRun:   &dryRunFlag,
		Manifest: &manifestFlag,
		Verbose:  &verboseFlag})
	changes, err := getPackageChanges(ctx, command, args)
	if err != nil {
		return err
	} else if len(changes) > 0 {
		fmt.Fprintf(ctx.Stdout(), "Detected changes in the following %d package(s):\n", len(changes))
		for _, change := range changes {
			fmt.Fprintf(ctx.Stdout(), "\t%s\n", change.name)
			opts := ctx.Run().Opts()
			opts.Stdin = strings.NewReader(change.newApi)
			if err := ctx.Run().CommandWithOpts(opts, "diff", "-u", change.apiFilePath, "-"); err != nil {
				// We expect diff to return 1 if changes are
				// detected
				if exiterr, ok := err.(*exec.ExitError); ok {
					if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
						if status != 1 {
							continue
						}
					}
				}
				// If we got here, diff returned a non-nil err
				// other than an ExitError with status code=1
				fmt.Fprintf(ctx.Stderr(), "WARNING: got an error while running diff: %v", err)
			}
		}
	}
	return nil
}

// cmdApiUpdate represents the "v23 api fix" command.
var cmdApiUpdate = &cmdline.Command{
	Run:      runApiFix,
	Name:     "fix",
	Short:    "Updates the .api files to reflect your changes to the public API.",
	Long:     "Updates the .api files to reflect your changes to the public API.",
	ArgsName: "<projects>",
	ArgsLong: "<projects> is a list of Vanadium projects to update. If none are specified, all project APIs are updated.",
}

func runApiFix(command *cmdline.Command, args []string) error {
	ctx := tool.NewContextFromCommand(command, tool.ContextOpts{
		Color:    &colorFlag,
		DryRun:   &dryRunFlag,
		Manifest: &manifestFlag,
		Verbose:  &verboseFlag})
	changes, err := getPackageChanges(ctx, command, args)
	if err != nil {
		return err
	}
	for _, change := range changes {
		if err := ctx.Run().WriteFile(change.apiFilePath, []byte(change.newApi), 0644); err != nil {
			return fmt.Errorf("WriteFile(%s) failed: %v", change.apiFilePath, err)
		}
		fmt.Fprintf(ctx.Stdout(), "Updated %s.\n", change.apiFilePath)
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/gob"
	"flag"
	"fmt"
	"github.com/4180122/distbayes/distmlMatlab"
	"github.com/arcaneiceman/GoVector/govec"
	"net"
	"os"
	"time"
)

const BUFFSIZE = 400000

//10485760

var (
	cnum      int = 0
	maxnode   int = 0
	myaddr    *net.TCPAddr
	cnumhist  map[int]int
	client    map[string]int
	claddr    map[int]*net.TCPAddr
	tempmodel map[int]aggregate
	testqueue map[int]map[int]bool
	models    map[int]distmlMatlab.MatModel
	modelR    map[int]map[int]float64
	modelC    map[int]float64
	modelD    float64
	channel   chan message
	logger    *govec.GoLog
	l         *net.TCPListener
	gmodel    distmlMatlab.MatGlobalModel
	gempty    distmlMatlab.MatGlobalModel
)

type aggregate struct {
	cnum  int
	model distmlMatlab.MatModel
	r     map[int]float64
	d     float64
	c     float64
}

type message struct {
	Id       int
	NodeIp   string
	NodeName string
	Type     string
	Model    distmlMatlab.MatModel
	GModel   distmlMatlab.MatGlobalModel
}

type response struct {
	Resp  string
	Error string
}

func main() {
	//Initialize stuff
	client = make(map[string]int)
	claddr = make(map[int]*net.TCPAddr)
	models = make(map[int]distmlMatlab.MatModel)
	modelR = make(map[int]map[int]float64)
	modelC = make(map[int]float64)
	modelD = 0.0
	gmodel = distmlMatlab.MatGlobalModel{nil}
	tempmodel = make(map[int]aggregate)
	testqueue = make(map[int]map[int]bool)
	cnumhist = make(map[int]int)
	channel = make(chan message)

	go updateGlobal(channel)

	//Parsing inputargs
	parseArgs()

	//Hacky solution to the Matlab problem (Mathworks, please fix this!)
	// see: https://www.mathworks.com/matlabcentral/answers/305877-what-is-the-primary-message-table-for-module-77
	// and  https://github.com/JuliaInterop/MATLAB.jl/issues/47
	distmlMatlab.Hack()

	//Initialize TCP Connection and listener
	l, _ = net.ListenTCP("tcp", myaddr)
	fmt.Printf("Server initialized.\n")

	for {
		conn, err := l.AcceptTCP()
		checkError(err)
		go connHandler(conn)
	}

}

func connHandler(conn *net.TCPConn) {
	var msg message
	dec := gob.NewDecoder(conn)
	enc := gob.NewEncoder(conn)
	err := dec.Decode(&msg)
	checkError(err)
	switch msg.Type {
	case "commit_request":
		//node is sending a model, must forward to others for testing
		flag := checkQueue(client[msg.NodeName])
		fmt.Printf("<-- Received commit request from %v.\n", msg.NodeName)
		if flag {
			enc.Encode(response{"OK", "Committed"})
			conn.Close()
			processTestRequest(msg)
		} else {
			//denied
			enc.Encode(response{"NO", "Pending tests are not complete."})
			fmt.Printf("--> Denied commit request from %v.\n", msg.NodeName)
			conn.Close()
		}
	case "global_request":
		//node is requesting the global model, will forward
		enc.Encode(response{"OK", ""})
		fmt.Printf("<-- Received global model request from %v.\n", msg.NodeName)
		genGlobalModel() //TODO maybe move this elsewhere
		sendGlobal(msg)
		conn.Close()
	case "test_complete":
		//node is submitting test results, will update its queue
		enc.Encode(response{"OK", ""})
		fmt.Printf("<-- Received completed test results from %v.\n", msg.NodeName)
		testqueue[client[msg.NodeName]][cnumhist[msg.Id]] = false
		conn.Close()
		//update the pending commit and merge if complete
		channel <- msg
	case "join_request":
		enc.Encode(response{"OK", "Joined"})
		processJoin(msg)
		conn.Close()
	default:
		fmt.Println("something weird happened!")
		//fmt.Println(msg.NodeIp, msg.NodeName, msg.Type)
		enc.Encode(response{"NO", "Unknown Request"})
		conn.Close()
	}

}

func updateGlobal(ch chan message) {
	// Function that aggregates the global model and commits when ready
	for {
		m := <-ch
		id := cnumhist[m.Id]
		tempAggregate := tempmodel[id]
		tempAggregate.d += m.Model.Size
		tempAggregate.r[client[m.NodeName]] = m.Model.Weight
		tempmodel[id] = tempAggregate
		if modelD < tempAggregate.d {
			modelD = tempAggregate.d
		}
		fmt.Println(modelD, m.Model.Size, m.Id, m.NodeName, tempAggregate.d)
		if float64(tempAggregate.d) > float64(modelD)*0.6 {
			models[id] = tempAggregate.model
			modelR[id] = tempAggregate.r
			modelC[id] = tempAggregate.c
			t := time.Now()
			logger.LogLocalEvent(fmt.Sprintf("%s - Committed model%v for commit number: %v", t.Format("15:04:05.0000"), id, tempAggregate.cnum))
			fmt.Printf("--- Committed model%v for commit number: %v.\n", id, tempAggregate.cnum)
		}
	}
}

func genGlobalModel() {
	modelstemp := models
	modelRtemp := modelR
	modelCtemp := modelC
	modelDtemp := modelD
	gmodel = distmlMatlab.CompactGlobal(modelstemp, modelRtemp, modelCtemp, modelDtemp)
}

//TODO this might be the problem!
func processTestRequest(m message) {
	cnum++
	tempcnum := cnum
	//initialize new aggregate
	tempweight := make(map[int]float64)
	r := m.Model.Weight
	c := m.Model.Size
	m.Model.Weight = 0.0
	m.Model.Size = 0.0
	tempweight[client[m.NodeName]] = r
	tempmodel[client[m.NodeName]] = aggregate{tempcnum, m.Model, tempweight, 0.0, c}
	cnumhist[tempcnum] = client[m.NodeName]
	for name, id := range client {
		if id != client[m.NodeName] {
			sendTestRequest(name, id, tempcnum, m.Model)
		}
	}
}

func sendTestRequest(name string, id, tcnum int, tmodel distmlMatlab.MatModel) {
	//func sendTestRequest(name string, id, tcnum int, tmodel bclass.Model) {
	//create test request
	msg := message{tcnum, myaddr.String(), "server", "test_request", tmodel, gempty}
	//increment tests in queue for that node
	if queue, ok := testqueue[id]; !ok {
		queue := make(map[int]bool)
		queue[cnumhist[tcnum]] = true
		testqueue[id] = queue
	} else {
		queue[cnumhist[tcnum]] = true
	}
	//send the request
	fmt.Printf("--> Sending test request from %v to %v.", cnumhist[tcnum], name)
	err := tcpSend(claddr[id], msg)
	if err != nil {
		fmt.Printf(" [NO!]\n*** Could not send test request to %v.\n", name)
	}
}

func sendGlobal(m message) {
	fmt.Printf("--> Sending global model to %v.", m.NodeName)
	msg := message{m.Id, myaddr.String(), "server", "global_grant", m.Model, gmodel}
	tcpSend(claddr[client[m.NodeName]], msg)
}

func tcpSend(addr *net.TCPAddr, msg message) error {
	conn, err := net.DialTCP("tcp", nil, addr)
	if err == nil {
		enc := gob.NewEncoder(conn)
		dec := gob.NewDecoder(conn)
		err := enc.Encode(msg)
		checkError(err)
		var r response
		err = dec.Decode(&r)
		checkError(err)
		if r.Resp == "OK" {
			fmt.Printf(" [OK]\n")
		} else {
			fmt.Printf(" [%s]\n<-- Request was denied by node: %v.\nEnter command: ", r.Resp, r.Error)
		}
	}
	return err
}

func checkQueue(id int) bool {
	flag := true
	for _, v := range testqueue[id] {
		if flag && v {
			flag = false
		}
	}
	return flag
}

func processJoin(m message) {
	//process depending on if it is a new node or a returning one
	if _, ok := client[m.NodeName]; !ok {
		//adding a node that has never been added before
		id := maxnode
		maxnode++
		client[m.NodeName] = id
		claddr[id], _ = net.ResolveTCPAddr("tcp", m.NodeIp)
		fmt.Printf("--- Added %v as node%v.\n", m.NodeName, id)
		t := time.Now()
		logger.LogLocalEvent(fmt.Sprintf("%s - Added %v as node %v.", t.Format("15:04:05:00"), m.NodeName, id))
		for _, v := range tempmodel {
			sendTestRequest(m.NodeName, id, v.cnum, v.model)
		}
	} else {
		//node is rejoining, update address and resend the unfinished test requests
		id := client[m.NodeName]
		claddr[id], _ = net.ResolveTCPAddr("tcp", m.NodeIp)
		fmt.Printf("--- %v at node%v is back online.\n", m.NodeName, id)
		for k, v := range testqueue[id] {
			if v {
				aggregate := tempmodel[k]
				sendTestRequest(m.NodeName, id, aggregate.cnum, aggregate.model)
			}
		}
	}
}

func parseArgs() {
	flag.Parse()
	inputargs := flag.Args()
	var err error
	if len(inputargs) < 1 {
		fmt.Printf("Not enough inputs.\n")
		return
	}
	myaddr, err = net.ResolveTCPAddr("tcp", inputargs[0])
	checkError(err)
	logger = govec.Initialize(inputargs[1], inputargs[1])
}

func checkError(err error) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
		os.Exit(1)
	}
}
<commit_msg>Signed-off-by: Alborz A. Amir-Khalili <alborza@bisicl.ad.ece.ubc.ca><commit_after>package main

import (
	"encoding/gob"
	"flag"
	"fmt"
	"github.com/4180122/distbayes/distmlMatlab"
	"github.com/arcaneiceman/GoVector/govec"
	"net"
	"os"
	"time"
)

const BUFFSIZE = 400000

//10485760

var (
	cnum      int = 0
	maxnode   int = 0
	myaddr    *net.TCPAddr
	cnumhist  map[int]int
	client    map[string]int
	claddr    map[int]*net.TCPAddr
	tempmodel map[int]aggregate
	testqueue map[int]map[int]bool
	models    map[int]distmlMatlab.MatModel
	modelR    map[int]map[int]float64
	modelC    map[int]float64
	modelD    float64
	channel   chan message
	logger    *govec.GoLog
	l         *net.TCPListener
	gmodel    distmlMatlab.MatGlobalModel
	gempty    distmlMatlab.MatGlobalModel
)

type aggregate struct {
	cnum  int
	model distmlMatlab.MatModel
	r     map[int]float64
	d     float64
	c     float64
}

type message struct {
	Id       int
	NodeIp   string
	NodeName string
	Type     string
	Model    distmlMatlab.MatModel
	GModel   distmlMatlab.MatGlobalModel
}

type response struct {
	Resp  string
	Error string
}

func main() {
	//Initialize stuff
	client = make(map[string]int)
	claddr = make(map[int]*net.TCPAddr)
	models = make(map[int]distmlMatlab.MatModel)
	modelR = make(map[int]map[int]float64)
	modelC = make(map[int]float64)
	modelD = 0.0
	gmodel = distmlMatlab.MatGlobalModel{nil}
	tempmodel = make(map[int]aggregate)
	testqueue = make(map[int]map[int]bool)
	cnumhist = make(map[int]int)
	channel = make(chan message)

	go updateGlobal(channel)

	//Parsing inputargs
	parseArgs()

	//Hacky solution to the Matlab problem (Mathworks, please fix this!)
	// see: https://www.mathworks.com/matlabcentral/answers/305877-what-is-the-primary-message-table-for-module-77
	// and  https://github.com/JuliaInterop/MATLAB.jl/issues/47
	distmlMatlab.Hack()

	//Initialize TCP Connection and listener
	l, _ = net.ListenTCP("tcp", myaddr)
	fmt.Printf("Server initialized.\n")

	for {
		conn, err := l.AcceptTCP()
		checkError(err)
		go connHandler(conn)
	}

}

func connHandler(conn *net.TCPConn) {
	var msg message
	dec := gob.NewDecoder(conn)
	enc := gob.NewEncoder(conn)
	err := dec.Decode(&msg)
	checkError(err)
	switch msg.Type {
	case "commit_request":
		//node is sending a model, must forward to others for testing
		flag := checkQueue(client[msg.NodeName])
		fmt.Printf("<-- Received commit request from %v.\n", msg.NodeName)
		if flag {
			enc.Encode(response{"OK", "Committed"})
			conn.Close()
			processTestRequest(msg)
		} else {
			//denied
			enc.Encode(response{"NO", "Pending tests are not complete."})
			fmt.Printf("--> Denied commit request from %v.\n", msg.NodeName)
			conn.Close()
		}
	case "global_request":
		//node is requesting the global model, will forward
		enc.Encode(response{"OK", ""})
		fmt.Printf("<-- Received global model request from %v.\n", msg.NodeName)
		genGlobalModel() //TODO maybe move this elsewhere
		sendGlobal(msg)
		conn.Close()
	case "test_complete":
		//node is submitting test results, will update its queue
		enc.Encode(response{"OK", ""})
		fmt.Printf("<-- Received completed test results from %v.\n", msg.NodeName)
		testqueue[client[msg.NodeName]][cnumhist[msg.Id]] = false
		conn.Close()
		//update the pending commit and merge if complete
		channel <- msg
	case "join_request":
		enc.Encode(response{"OK", "Joined"})
		processJoin(msg)
		conn.Close()
	default:
		fmt.Println("something weird happened!")
		//fmt.Println(msg.NodeIp, msg.NodeName, msg.Type)
		enc.Encode(response{"NO", "Unknown Request"})
		conn.Close()
	}

}

func updateGlobal(ch chan message) {
	// Function that aggregates the global model and commits when ready
	for {
		m := <-ch
		id := cnumhist[m.Id]
		tempAggregate := tempmodel[id]
		tempAggregate.d += m.Model.Size
		tempAggregate.r[client[m.NodeName]] = m.Model.Weight
		tempmodel[id] = tempAggregate
		if modelD < tempAggregate.d {
			modelD = tempAggregate.d
		}
		fmt.Println(modelD, m.Model.Size, m.Id, m.NodeName, tempAggregate.d)
		if float64(tempAggregate.d) > float64(modelD)*0.2 {
			models[id] = tempAggregate.model
			modelR[id] = tempAggregate.r
			modelC[id] = tempAggregate.c
			t := time.Now()
			logger.LogLocalEvent(fmt.Sprintf("%s - Committed model%v for commit number: %v", t.Format("15:04:05.0000"), id, tempAggregate.cnum))
			fmt.Printf("--- Committed model%v for commit number: %v.\n", id, tempAggregate.cnum)
		}
	}
}

func genGlobalModel() {
	modelstemp := models
	modelRtemp := modelR
	modelCtemp := modelC
	modelDtemp := modelD
	gmodel = distmlMatlab.CompactGlobal(modelstemp, modelRtemp, modelCtemp, modelDtemp)
}

//TODO this might be the problem!
func processTestRequest(m message) {
	cnum++
	tempcnum := cnum
	//initialize new aggregate
	tempweight := make(map[int]float64)
	r := m.Model.Weight
	c := m.Model.Size
	m.Model.Weight = 0.0
	m.Model.Size = 0.0
	tempweight[client[m.NodeName]] = r
	tempmodel[client[m.NodeName]] = aggregate{tempcnum, m.Model, tempweight, 0.0, c}
	cnumhist[tempcnum] = client[m.NodeName]
	for name, id := range client {
		if id != client[m.NodeName] {
			sendTestRequest(name, id, tempcnum, m.Model)
		}
	}
}

func sendTestRequest(name string, id, tcnum int, tmodel distmlMatlab.MatModel) {
	//func sendTestRequest(name string, id, tcnum int, tmodel bclass.Model) {
	//create test request
	msg := message{tcnum, myaddr.String(), "server", "test_request", tmodel, gempty}
	//increment tests in queue for that node
	if queue, ok := testqueue[id]; !ok {
		queue := make(map[int]bool)
		queue[cnumhist[tcnum]] = true
		testqueue[id] = queue
	} else {
		queue[cnumhist[tcnum]] = true
	}
	//send the request
	fmt.Printf("--> Sending test request from %v to %v.", cnumhist[tcnum], name)
	err := tcpSend(claddr[id], msg)
	if err != nil {
		fmt.Printf(" [NO!]\n*** Could not send test request to %v.\n", name)
	}
}

func sendGlobal(m message) {
	fmt.Printf("--> Sending global model to %v.", m.NodeName)
	msg := message{m.Id, myaddr.String(), "server", "global_grant", m.Model, gmodel}
	tcpSend(claddr[client[m.NodeName]], msg)
}

func tcpSend(addr *net.TCPAddr, msg message) error {
	conn, err := net.DialTCP("tcp", nil, addr)
	if err == nil {
		enc := gob.NewEncoder(conn)
		dec := gob.NewDecoder(conn)
		err := enc.Encode(msg)
		checkError(err)
		var r response
		err = dec.Decode(&r)
		checkError(err)
		if r.Resp == "OK" {
			fmt.Printf(" [OK]\n")
		} else {
			fmt.Printf(" [%s]\n<-- Request was denied by node: %v.\nEnter command: ", r.Resp, r.Error)
		}
	}
	return err
}

func checkQueue(id int) bool {
	flag := true
	for _, v := range testqueue[id] {
		if flag && v {
			flag = false
		}
	}
	return flag
}

func processJoin(m message) {
	//process depending on if it is a new node or a returning one
	if _, ok := client[m.NodeName]; !ok {
		//adding a node that has never been added before
		id := maxnode
		maxnode++
		client[m.NodeName] = id
		claddr[id], _ = net.ResolveTCPAddr("tcp", m.NodeIp)
		fmt.Printf("--- Added %v as node%v.\n", m.NodeName, id)
		t := time.Now()
		logger.LogLocalEvent(fmt.Sprintf("%s - Added %v as node %v.", t.Format("15:04:05:00"), m.NodeName, id))
		for _, v := range tempmodel {
			sendTestRequest(m.NodeName, id, v.cnum, v.model)
		}
	} else {
		//node is rejoining, update address and resend the unfinished test requests
		id := client[m.NodeName]
		claddr[id], _ = net.ResolveTCPAddr("tcp", m.NodeIp)
		fmt.Printf("--- %v at node%v is back online.\n", m.NodeName, id)
		for k, v := range testqueue[id] {
			if v {
				aggregate := tempmodel[k]
				sendTestRequest(m.NodeName, id, aggregate.cnum, aggregate.model)
			}
		}
	}
}

func parseArgs() {
	flag.Parse()
	inputargs := flag.Args()
	var err error
	if len(inputargs) < 1 {
		fmt.Printf("Not enough inputs.\n")
		return
	}
	myaddr, err = net.ResolveTCPAddr("tcp", inputargs[0])
	checkError(err)
	logger = govec.Initialize(inputargs[1], inputargs[1])
}

func checkError(err error) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package collectd

import (
	"fmt"
	"log"
	"net"
	"os"
	"sync"
	"time"

	"github.com/influxdb/influxdb/cluster"
	"github.com/influxdb/influxdb/meta"
	"github.com/influxdb/influxdb/tsdb"
	"github.com/kimor79/gollectd"
)

const leaderWaitTimeout = 30 * time.Second

// pointsWriter is an internal interface to make testing easier.
type pointsWriter interface {
	WritePoints(p *cluster.WritePointsRequest) error
}

// metaStore is an internal interface to make testing easier.
type metaStore interface {
	WaitForLeader(d time.Duration) error
	CreateDatabaseIfNotExists(name string) (*meta.DatabaseInfo, error)
}

// Service represents a UDP server which receives metrics in collectd's binary
// protocol and stores them in InfluxDB.
type Service struct {
	Config       *Config
	MetaStore    metaStore
	PointsWriter pointsWriter
	Logger       *log.Logger

	wg      sync.WaitGroup
	err     chan error
	stop    chan struct{}
	ln      *net.UDPConn
	batcher *tsdb.PointBatcher
	typesdb gollectd.Types
	addr    net.Addr
}

// NewService returns a new instance of the collectd service.
func NewService(c Config) *Service {
	s := &Service{
		Config: &c,
		Logger: log.New(os.Stderr, "[collectd] ", log.LstdFlags),
		err:    make(chan error),
	}

	return s
}

// Open starts the service.
func (s *Service) Open() error {
	if s.Config.BindAddress == "" {
		return fmt.Errorf("bind address is blank")
	} else if s.Config.Database == "" {
		return fmt.Errorf("database name is blank")
	} else if s.PointsWriter == nil {
		return fmt.Errorf("PointsWriter is nil")
	}

	if err := s.MetaStore.WaitForLeader(leaderWaitTimeout); err != nil {
		s.Logger.Printf("failed to detect a cluster leader: %s", err.Error())
		return err
	}

	if _, err := s.MetaStore.CreateDatabaseIfNotExists(s.Config.Database); err != nil {
		s.Logger.Printf("failed to ensure target database %s exists: %s", s.Config.Database, err.Error())
		return err
	}

	if s.typesdb == nil {
		// Open collectd types.
		typesdb, err := gollectd.TypesDBFile(s.Config.TypesDB)
		if err != nil {
			return fmt.Errorf("Open(): %s", err)
		}
		s.typesdb = typesdb
	}

	// Resolve our address.
	addr, err := net.ResolveUDPAddr("udp", s.Config.BindAddress)
	if err != nil {
		return fmt.Errorf("unable to resolve UDP address: %s", err)
	}
	s.addr = addr

	// Start listening
	ln, err := net.ListenUDP("udp", addr)
	if err != nil {
		return fmt.Errorf("unable to listen on UDP: %s", err)
	}
	s.ln = ln

	// Start the points batcher.
	s.batcher = tsdb.NewPointBatcher(s.Config.BatchSize, time.Duration(s.Config.BatchDuration))
	s.batcher.Start()

	// Create channel and wait group for signalling goroutines to stop.
	s.stop = make(chan struct{})
	s.wg.Add(2)

	// Start goroutines that process collectd packets.
	go s.serve()
	go s.writePoints()

	s.Logger.Println("collectd UDP started")

	return nil
}

// Close stops the service.
func (s *Service) Close() error {
	// Close the connection, and wait for the goroutine to exit.
	close(s.stop)
	s.ln.Close()
	s.batcher.Stop()
	s.wg.Wait()

	// Release all remaining resources.
	s.stop = nil
	s.ln = nil
	s.batcher = nil
	s.Logger.Println("collectd UDP closed")
	return nil
}

// SetLogger sets the internal logger to the logger passed in.
func (s *Service) SetLogger(l *log.Logger) {
	s.Logger = l
}

// SetTypes sets collectd types db.
func (s *Service) SetTypes(types string) (err error) {
	s.typesdb, err = gollectd.TypesDB([]byte(types))
	return
}

// Err returns a channel for fatal errors that occur on go routines.
func (s *Service) Err() chan error { return s.err }

// Addr returns the listener's address. Returns nil if listener is closed.
func (s *Service) Addr() net.Addr {
	return s.ln.LocalAddr()
}

func (s *Service) serve() {
	defer s.wg.Done()

	// From https://collectd.org/wiki/index.php/Binary_protocol
	//   1024 bytes (payload only, not including UDP / IP headers)
	//   In versions 4.0 through 4.7, the receive buffer has a fixed size
	//   of 1024 bytes. When longer packets are received, the trailing data
	//   is simply ignored. Since version 4.8, the buffer size can be
	//   configured. Version 5.0 will increase the default buffer size to
	//   1452 bytes (the maximum payload size when using UDP/IPv6 over
	//   Ethernet).
	buffer := make([]byte, 1452)

	for {
		select {
		case <-s.stop:
			// We closed the connection, time to go.
			return
		default:
			// Keep processing.
		}

		n, _, err := s.ln.ReadFromUDP(buffer)
		if err != nil {
			s.Logger.Printf("collectd ReadFromUDP error: %s", err)
			continue
		}
		if n > 0 {
			s.handleMessage(buffer[:n])
		}
	}
}

func (s *Service) handleMessage(buffer []byte) {
	packets, err := gollectd.Packets(buffer, s.typesdb)
	if err != nil {
		s.Logger.Printf("Collectd parse error: %s", err)
		return
	}
	for _, packet := range *packets {
		points := Unmarshal(&packet)
		for _, p := range points {
			s.batcher.In() <- p
		}
	}
}

func (s *Service) writePoints() {
	defer s.wg.Done()

	for {
		select {
		case <-s.stop:
			return
		case batch := <-s.batcher.Out():
			req := &cluster.WritePointsRequest{
				Database:         s.Config.Database,
				RetentionPolicy:  s.Config.RetentionPolicy,
				ConsistencyLevel: cluster.ConsistencyLevelAny,
				Points:           batch,
			}
			if err := s.PointsWriter.WritePoints(req); err != nil {
				s.Logger.Printf("failed to write batch: %s", err)
				continue
			}
		}
	}
}

// Unmarshal translates a collectd packet into InfluxDB data points.
func Unmarshal(packet *gollectd.Packet) []tsdb.Point {
	// Prefer high resolution timestamp.
	var timestamp time.Time
	if packet.TimeHR > 0 {
		// TimeHR is "near" nanosecond measurement, but not exactly nanasecond time
		// Since we store time in microseconds, we round here (mostly so tests will work easier)
		sec := packet.TimeHR >> 30
		// Shifting, masking, and dividing by 1 billion to get nanoseconds.
		nsec := ((packet.TimeHR & 0x3FFFFFFF) << 30) / 1000 / 1000 / 1000
		timestamp = time.Unix(int64(sec), int64(nsec)).UTC().Round(time.Microsecond)
	} else {
		// If we don't have high resolution time, fall back to basic unix time
		timestamp = time.Unix(int64(packet.Time), 0).UTC()
	}

	var points []tsdb.Point
	for i := range packet.Values {
		name := fmt.Sprintf("%s_%s", packet.Plugin, packet.Values[i].Name)
		tags := make(map[string]string)
		fields := make(map[string]interface{})

		fields["value"] = packet.Values[i].Value

		if packet.Hostname != "" {
			tags["host"] = packet.Hostname
		}
		if packet.PluginInstance != "" {
			tags["instance"] = packet.PluginInstance
		}
		if packet.Type != "" {
			tags["type"] = packet.Type
		}
		if packet.TypeInstance != "" {
			tags["type_instance"] = packet.TypeInstance
		}
		p := tsdb.NewPoint(name, tags, fields, timestamp)

		points = append(points, p)
	}
	return points
}

// assert will panic with a given formatted message if the given condition is false.
func assert(condition bool, msg string, v ...interface{}) {
	if !condition {
		panic(fmt.Sprintf("assert failed: "+msg, v...))
	}
}
<commit_msg>Fix panics when collectd fails to start<commit_after>package collectd

import (
	"fmt"
	"log"
	"net"
	"os"
	"sync"
	"time"

	"github.com/influxdb/influxdb/cluster"
	"github.com/influxdb/influxdb/meta"
	"github.com/influxdb/influxdb/tsdb"
	"github.com/kimor79/gollectd"
)

const leaderWaitTimeout = 30 * time.Second

// pointsWriter is an internal interface to make testing easier.
type pointsWriter interface {
	WritePoints(p *cluster.WritePointsRequest) error
}

// metaStore is an internal interface to make testing easier.
type metaStore interface {
	WaitForLeader(d time.Duration) error
	CreateDatabaseIfNotExists(name string) (*meta.DatabaseInfo, error)
}

// Service represents a UDP server which receives metrics in collectd's binary
// protocol and stores them in InfluxDB.
type Service struct {
	Config       *Config
	MetaStore    metaStore
	PointsWriter pointsWriter
	Logger       *log.Logger

	wg      sync.WaitGroup
	err     chan error
	stop    chan struct{}
	ln      *net.UDPConn
	batcher *tsdb.PointBatcher
	typesdb gollectd.Types
	addr    net.Addr
}

// NewService returns a new instance of the collectd service.
func NewService(c Config) *Service {
	s := &Service{
		Config: &c,
		Logger: log.New(os.Stderr, "[collectd] ", log.LstdFlags),
		err:    make(chan error),
	}

	return s
}

// Open starts the service.
func (s *Service) Open() error {
	if s.Config.BindAddress == "" {
		return fmt.Errorf("bind address is blank")
	} else if s.Config.Database == "" {
		return fmt.Errorf("database name is blank")
	} else if s.PointsWriter == nil {
		return fmt.Errorf("PointsWriter is nil")
	}

	if err := s.MetaStore.WaitForLeader(leaderWaitTimeout); err != nil {
		s.Logger.Printf("failed to detect a cluster leader: %s", err.Error())
		return err
	}

	if _, err := s.MetaStore.CreateDatabaseIfNotExists(s.Config.Database); err != nil {
		s.Logger.Printf("failed to ensure target database %s exists: %s", s.Config.Database, err.Error())
		return err
	}

	if s.typesdb == nil {
		// Open collectd types.
		typesdb, err := gollectd.TypesDBFile(s.Config.TypesDB)
		if err != nil {
			return fmt.Errorf("Open(): %s", err)
		}
		s.typesdb = typesdb
	}

	// Resolve our address.
	addr, err := net.ResolveUDPAddr("udp", s.Config.BindAddress)
	if err != nil {
		return fmt.Errorf("unable to resolve UDP address: %s", err)
	}
	s.addr = addr

	// Start listening
	ln, err := net.ListenUDP("udp", addr)
	if err != nil {
		return fmt.Errorf("unable to listen on UDP: %s", err)
	}
	s.ln = ln

	// Start the points batcher.
	s.batcher = tsdb.NewPointBatcher(s.Config.BatchSize, time.Duration(s.Config.BatchDuration))
	s.batcher.Start()

	// Create channel and wait group for signalling goroutines to stop.
	s.stop = make(chan struct{})
	s.wg.Add(2)

	// Start goroutines that process collectd packets.
	go s.serve()
	go s.writePoints()

	s.Logger.Println("collectd UDP started")

	return nil
}

// Close stops the service.
func (s *Service) Close() error {
	// Close the connection, and wait for the goroutine to exit.
	if s.stop != nil {
		close(s.stop)
	}
	if s.ln != nil {
		s.ln.Close()
	}
	if s.batcher != nil {
		s.batcher.Stop()
	}
	s.wg.Wait()

	// Release all remaining resources.
	s.stop = nil
	s.ln = nil
	s.batcher = nil
	s.Logger.Println("collectd UDP closed")
	return nil
}

// SetLogger sets the internal logger to the logger passed in.
func (s *Service) SetLogger(l *log.Logger) {
	s.Logger = l
}

// SetTypes sets collectd types db.
func (s *Service) SetTypes(types string) (err error) {
	s.typesdb, err = gollectd.TypesDB([]byte(types))
	return
}

// Err returns a channel for fatal errors that occur on go routines.
func (s *Service) Err() chan error { return s.err }

// Addr returns the listener's address. Returns nil if listener is closed.
func (s *Service) Addr() net.Addr {
	return s.ln.LocalAddr()
}

func (s *Service) serve() {
	defer s.wg.Done()

	// From https://collectd.org/wiki/index.php/Binary_protocol
	//   1024 bytes (payload only, not including UDP / IP headers)
	//   In versions 4.0 through 4.7, the receive buffer has a fixed size
	//   of 1024 bytes. When longer packets are received, the trailing data
	//   is simply ignored. Since version 4.8, the buffer size can be
	//   configured. Version 5.0 will increase the default buffer size to
	//   1452 bytes (the maximum payload size when using UDP/IPv6 over
	//   Ethernet).
	buffer := make([]byte, 1452)

	for {
		select {
		case <-s.stop:
			// We closed the connection, time to go.
			return
		default:
			// Keep processing.
		}

		n, _, err := s.ln.ReadFromUDP(buffer)
		if err != nil {
			s.Logger.Printf("collectd ReadFromUDP error: %s", err)
			continue
		}
		if n > 0 {
			s.handleMessage(buffer[:n])
		}
	}
}

func (s *Service) handleMessage(buffer []byte) {
	packets, err := gollectd.Packets(buffer, s.typesdb)
	if err != nil {
		s.Logger.Printf("Collectd parse error: %s", err)
		return
	}
	for _, packet := range *packets {
		points := Unmarshal(&packet)
		for _, p := range points {
			s.batcher.In() <- p
		}
	}
}

func (s *Service) writePoints() {
	defer s.wg.Done()

	for {
		select {
		case <-s.stop:
			return
		case batch := <-s.batcher.Out():
			req := &cluster.WritePointsRequest{
				Database:         s.Config.Database,
				RetentionPolicy:  s.Config.RetentionPolicy,
				ConsistencyLevel: cluster.ConsistencyLevelAny,
				Points:           batch,
			}
			if err := s.PointsWriter.WritePoints(req); err != nil {
				s.Logger.Printf("failed to write batch: %s", err)
				continue
			}
		}
	}
}

// Unmarshal translates a collectd packet into InfluxDB data points.
func Unmarshal(packet *gollectd.Packet) []tsdb.Point {
	// Prefer high resolution timestamp.
	var timestamp time.Time
	if packet.TimeHR > 0 {
		// TimeHR is "near" nanosecond measurement, but not exactly nanasecond time
		// Since we store time in microseconds, we round here (mostly so tests will work easier)
		sec := packet.TimeHR >> 30
		// Shifting, masking, and dividing by 1 billion to get nanoseconds.
		nsec := ((packet.TimeHR & 0x3FFFFFFF) << 30) / 1000 / 1000 / 1000
		timestamp = time.Unix(int64(sec), int64(nsec)).UTC().Round(time.Microsecond)
	} else {
		// If we don't have high resolution time, fall back to basic unix time
		timestamp = time.Unix(int64(packet.Time), 0).UTC()
	}

	var points []tsdb.Point
	for i := range packet.Values {
		name := fmt.Sprintf("%s_%s", packet.Plugin, packet.Values[i].Name)
		tags := make(map[string]string)
		fields := make(map[string]interface{})

		fields["value"] = packet.Values[i].Value

		if packet.Hostname != "" {
			tags["host"] = packet.Hostname
		}
		if packet.PluginInstance != "" {
			tags["instance"] = packet.PluginInstance
		}
		if packet.Type != "" {
			tags["type"] = packet.Type
		}
		if packet.TypeInstance != "" {
			tags["type_instance"] = packet.TypeInstance
		}
		p := tsdb.NewPoint(name, tags, fields, timestamp)

		points = append(points, p)
	}
	return points
}

// assert will panic with a given formatted message if the given condition is false.
func assert(condition bool, msg string, v ...interface{}) {
	if !condition {
		panic(fmt.Sprintf("assert failed: "+msg, v...))
	}
}
<|endoftext|>


<commit_before>package acsengine

import (
	"strconv"

	"github.com/Azure/acs-engine/pkg/api"
)

const (
	// DefaultMasterSubnet specifies the default master subnet for DCOS or Swarm
	DefaultMasterSubnet = "172.16.0.0/24"
	// DefaultFirstConsecutiveStaticIP specifies the static IP address on master 0 for DCOS or Swarm
	DefaultFirstConsecutiveStaticIP = "172.16.0.5"
	// DefaultSwarmWindowsMasterSubnet specifies the default master subnet for a Swarm Windows cluster
	DefaultSwarmWindowsMasterSubnet = "192.168.255.0/24"
	// DefaultSwarmWindowsFirstConsecutiveStaticIP specifies the static IP address on master 0 for a Swarm WIndows cluster
	DefaultSwarmWindowsFirstConsecutiveStaticIP = "192.168.255.5"
	// DefaultKubernetesMasterSubnet specifies the default subnet for masters and agents.
	DefaultKubernetesMasterSubnet = "10.240.0.0/16"
	// DefaultKubernetesClusterSubnet specifies the default subnet for pods.
	DefaultKubernetesClusterSubnet = "10.244.0.0/16"
	// DefaultDockerBridgeSubnet specifies the default subnet for the docker bridge network for masters and agents.
	DefaultDockerBridgeSubnet = "172.17.0.1/16"
	// DefaultFirstConsecutiveKubernetesStaticIP specifies the static IP address on Kubernetes master 0
	DefaultFirstConsecutiveKubernetesStaticIP = "10.240.255.5"
	// DefaultAgentSubnetTemplate specifies a default agent subnet
	DefaultAgentSubnetTemplate = "10.%d.0.0/16"
	// DefaultKubernetesSubnet specifies the default subnet used for all masters, agents and pods
	// when VNET integration is enabled.
	DefaultKubernetesSubnet = "10.240.0.0/12"
	// DefaultKubernetesFirstConsecutiveStaticIPOffset specifies the IP address offset of master 0
	// when VNET integration is enabled.
	DefaultKubernetesFirstConsecutiveStaticIPOffset = 5
	// DefaultKubernetesMaxPods is the maximum number of pods to run on a node.
	DefaultKubernetesMaxPods = 110
	// DefaultKubernetesMaxPodsVNETIntegrated is the maximum number of pods to run on a node when VNET integration is enabled.
	DefaultKubernetesMaxPodsVNETIntegrated = 30
	// DefaultKubernetesClusterDomain is the dns suffix used in the cluster (used as a SAN in the PKI generation)
	DefaultKubernetesClusterDomain = "cluster.local"
	// DefaultInternalLbStaticIPOffset specifies the offset of the internal LoadBalancer's IP
	// address relative to the first consecutive Kubernetes static IP
	DefaultInternalLbStaticIPOffset = 10
	// DefaultNetworkPolicy is disabling network policy enforcement
	DefaultNetworkPolicy = "none"
	// DefaultKubernetesNodeStatusUpdateFrequency is 10s, see --node-status-update-frequency at https://kubernetes.io/docs/admin/kubelet/
	DefaultKubernetesNodeStatusUpdateFrequency = "10s"
	// DefaultKubernetesCtrlMgrNodeMonitorGracePeriod is 40s, see --node-monitor-grace-period at https://kubernetes.io/docs/admin/kube-controller-manager/
	DefaultKubernetesCtrlMgrNodeMonitorGracePeriod = "40s"
	// DefaultKubernetesCtrlMgrPodEvictionTimeout is 5m0s, see --pod-eviction-timeout at https://kubernetes.io/docs/admin/kube-controller-manager/
	DefaultKubernetesCtrlMgrPodEvictionTimeout = "5m0s"
	// DefaultKubernetesCtrlMgrRouteReconciliationPeriod is 10s, see --route-reconciliation-period at https://kubernetes.io/docs/admin/kube-controller-manager/
	DefaultKubernetesCtrlMgrRouteReconciliationPeriod = "10s"
	// DefaultKubernetesCloudProviderBackoff is false to disable cloudprovider backoff implementation for API calls
	DefaultKubernetesCloudProviderBackoff = false
	// DefaultKubernetesCloudProviderBackoffRetries is 6, takes effect if DefaultKubernetesCloudProviderBackoff is true
	DefaultKubernetesCloudProviderBackoffRetries = 6
	// DefaultKubernetesCloudProviderBackoffJitter is 1, takes effect if DefaultKubernetesCloudProviderBackoff is true
	DefaultKubernetesCloudProviderBackoffJitter = 1.0
	// DefaultKubernetesCloudProviderBackoffDuration is 5, takes effect if DefaultKubernetesCloudProviderBackoff is true
	DefaultKubernetesCloudProviderBackoffDuration = 5
	// DefaultKubernetesCloudProviderBackoffExponent is 1.5, takes effect if DefaultKubernetesCloudProviderBackoff is true
	DefaultKubernetesCloudProviderBackoffExponent = 1.5
	// DefaultKubernetesCloudProviderRateLimit is false to disable cloudprovider rate limiting implementation for API calls
	DefaultKubernetesCloudProviderRateLimit = false
	// DefaultKubernetesCloudProviderRateLimitQPS is 3, takes effect if DefaultKubernetesCloudProviderRateLimit is true
	DefaultKubernetesCloudProviderRateLimitQPS = 3.0
	// DefaultKubernetesCloudProviderRateLimitBucket is 10, takes effect if DefaultKubernetesCloudProviderRateLimit is true
	DefaultKubernetesCloudProviderRateLimitBucket = 10
	// DefaultTillerImage defines the Helm Tiller deployment version on Kubernetes Clusters
	DefaultTillerImage = "tiller:v2.6.0"
	// DefaultKubernetesDNSServiceIP specifies the IP address that kube-dns
	// listens on by default. must by in the default Service CIDR range.
	DefaultKubernetesDNSServiceIP = "10.0.0.10"
	// DefaultKubernetesServiceCIDR specifies the IP subnet that kubernetes will
	// create Service IPs within.
	DefaultKubernetesServiceCIDR = "10.0.0.0/16"
	//DefaultKubernetesGCHighThreshold specifies the value for  for the image-gc-high-threshold kubelet flag
	DefaultKubernetesGCHighThreshold = 85
	//DefaultKubernetesGCLowThreshold specifies the value for the image-gc-low-threshold kubelet flag
	DefaultKubernetesGCLowThreshold = 80
)

const (
	// DCOSMaster represents the master node type
	DCOSMaster DCOSNodeType = "DCOSMaster"
	// DCOSPrivateAgent represents the private agent node type
	DCOSPrivateAgent DCOSNodeType = "DCOSPrivateAgent"
	// DCOSPublicAgent represents the public agent node type
	DCOSPublicAgent DCOSNodeType = "DCOSPublicAgent"
)

// KubeConfigs represents Docker images used for Kubernetes components based on Kubernetes releases (major.minor)
// For instance, Kubernetes release "1.7" would contain the version "1.7.2"
var KubeConfigs = map[string]map[string]string{
	api.KubernetesRelease1Dot8: {
		"hyperkube":       "hyperkube-amd64:v1.8.0",
		"dashboard":       "kubernetes-dashboard-amd64:v1.7.0",
		"exechealthz":     "exechealthz-amd64:1.2",
		"addonresizer":    "addon-resizer:1.7",
		"heapster":        "heapster-amd64:v1.4.2",
		"dns":             "k8s-dns-kube-dns-amd64:1.14.5",
		"addonmanager":    "kube-addon-manager-amd64:v6.4-beta.2",
		"dnsmasq":         "k8s-dns-dnsmasq-nanny-amd64:1.14.5",
		"pause":           "pause-amd64:3.0",
		"tiller":          DefaultTillerImage,
		"windowszip":      "v1.8.0-1intwinnat.zip",
		"nodestatusfreq":  DefaultKubernetesNodeStatusUpdateFrequency,
		"nodegraceperiod": DefaultKubernetesCtrlMgrNodeMonitorGracePeriod,
		"podeviction":     DefaultKubernetesCtrlMgrPodEvictionTimeout,
		"routeperiod":     DefaultKubernetesCtrlMgrRouteReconciliationPeriod,
		"backoffretries":  strconv.Itoa(DefaultKubernetesCloudProviderBackoffRetries),
		"backoffjitter":   strconv.FormatFloat(DefaultKubernetesCloudProviderBackoffJitter, 'f', -1, 64),
		"backoffduration": strconv.Itoa(DefaultKubernetesCloudProviderBackoffDuration),
		"backoffexponent": strconv.FormatFloat(DefaultKubernetesCloudProviderBackoffExponent, 'f', -1, 64),
		"ratelimitqps":    strconv.FormatFloat(DefaultKubernetesCloudProviderRateLimitQPS, 'f', -1, 64),
		"ratelimitbucket": strconv.Itoa(DefaultKubernetesCloudProviderRateLimitBucket),
		"gchighthreshold": strconv.Itoa(DefaultKubernetesGCHighThreshold),
		"gclowthreshold":  strconv.Itoa(DefaultKubernetesGCLowThreshold),
	},
	api.KubernetesRelease1Dot7: {
		"hyperkube":       "hyperkube-amd64:v1.7.7",
		"dashboard":       "kubernetes-dashboard-amd64:v1.6.3",
		"exechealthz":     "exechealthz-amd64:1.2",
		"addonresizer":    "addon-resizer:1.7",
		"heapster":        "heapster-amd64:v1.4.2",
		"dns":             "k8s-dns-kube-dns-amd64:1.14.5",
		"addonmanager":    "kube-addon-manager-amd64:v6.4-beta.2",
		"dnsmasq":         "k8s-dns-dnsmasq-nanny-amd64:1.14.5",
		"pause":           "pause-amd64:3.0",
		"tiller":          DefaultTillerImage,
		"windowszip":      "v1.7.7-1intwinnat.zip",
		"nodestatusfreq":  DefaultKubernetesNodeStatusUpdateFrequency,
		"nodegraceperiod": DefaultKubernetesCtrlMgrNodeMonitorGracePeriod,
		"podeviction":     DefaultKubernetesCtrlMgrPodEvictionTimeout,
		"routeperiod":     DefaultKubernetesCtrlMgrRouteReconciliationPeriod,
		"backoffretries":  strconv.Itoa(DefaultKubernetesCloudProviderBackoffRetries),
		"backoffjitter":   strconv.FormatFloat(DefaultKubernetesCloudProviderBackoffJitter, 'f', -1, 64),
		"backoffduration": strconv.Itoa(DefaultKubernetesCloudProviderBackoffDuration),
		"backoffexponent": strconv.FormatFloat(DefaultKubernetesCloudProviderBackoffExponent, 'f', -1, 64),
		"ratelimitqps":    strconv.FormatFloat(DefaultKubernetesCloudProviderRateLimitQPS, 'f', -1, 64),
		"ratelimitbucket": strconv.Itoa(DefaultKubernetesCloudProviderRateLimitBucket),
		"gchighthreshold": strconv.Itoa(DefaultKubernetesGCHighThreshold),
		"gclowthreshold":  strconv.Itoa(DefaultKubernetesGCLowThreshold),
	},
	api.KubernetesRelease1Dot6: {
		"hyperkube":       "hyperkube-amd64:v1.6.11",
		"dashboard":       "kubernetes-dashboard-amd64:v1.6.3",
		"exechealthz":     "exechealthz-amd64:1.2",
		"addonresizer":    "addon-resizer:1.7",
		"heapster":        "heapster-amd64:v1.3.0",
		"dns":             "k8s-dns-kube-dns-amd64:1.14.5",
		"addonmanager":    "kube-addon-manager-amd64:v6.4-beta.2",
		"dnsmasq":         "k8s-dns-dnsmasq-nanny-amd64:1.14.5",
		"pause":           "pause-amd64:3.0",
		"tiller":          DefaultTillerImage,
		"windowszip":      "v1.6.9-3intwinnat.zip",
		"nodestatusfreq":  DefaultKubernetesNodeStatusUpdateFrequency,
		"nodegraceperiod": DefaultKubernetesCtrlMgrNodeMonitorGracePeriod,
		"podeviction":     DefaultKubernetesCtrlMgrPodEvictionTimeout,
		"routeperiod":     DefaultKubernetesCtrlMgrRouteReconciliationPeriod,
		"backoffretries":  strconv.Itoa(DefaultKubernetesCloudProviderBackoffRetries),
		"backoffjitter":   strconv.FormatFloat(DefaultKubernetesCloudProviderBackoffJitter, 'f', -1, 64),
		"backoffduration": strconv.Itoa(DefaultKubernetesCloudProviderBackoffDuration),
		"backoffexponent": strconv.FormatFloat(DefaultKubernetesCloudProviderBackoffExponent, 'f', -1, 64),
		"ratelimitqps":    strconv.FormatFloat(DefaultKubernetesCloudProviderRateLimitQPS, 'f', -1, 64),
		"ratelimitbucket": strconv.Itoa(DefaultKubernetesCloudProviderRateLimitBucket),
		"gchighthreshold": strconv.Itoa(DefaultKubernetesGCHighThreshold),
		"gclowthreshold":  strconv.Itoa(DefaultKubernetesGCLowThreshold),
	},
	api.KubernetesRelease1Dot5: {
		"hyperkube":       "hyperkube-amd64:v1.5.8",
		"dashboard":       "kubernetes-dashboard-amd64:v1.5.1",
		"exechealthz":     "exechealthz-amd64:1.2",
		"addonresizer":    "addon-resizer:1.6",
		"heapster":        "heapster:v1.2.0",
		"dns":             "kubedns-amd64:1.7",
		"addonmanager":    "kube-addon-manager-amd64:v6.4-beta.2",
		"dnsmasq":         "kube-dnsmasq-amd64:1.3",
		"pause":           "pause-amd64:3.0",
		"tiller":          "tiller:v2.5.1",
		"windowszip":      "v1.5.7intwinnat.zip",
		"nodestatusfreq":  DefaultKubernetesNodeStatusUpdateFrequency,
		"nodegraceperiod": DefaultKubernetesCtrlMgrNodeMonitorGracePeriod,
		"podeviction":     DefaultKubernetesCtrlMgrPodEvictionTimeout,
		"routeperiod":     DefaultKubernetesCtrlMgrRouteReconciliationPeriod,
		"gchighthreshold": strconv.Itoa(DefaultKubernetesGCHighThreshold),
		"gclowthreshold":  strconv.Itoa(DefaultKubernetesGCLowThreshold),
	},
}

const (
	//DefaultExtensionsRootURL  Root URL for extensions
	DefaultExtensionsRootURL = "https://raw.githubusercontent.com/Azure/acs-engine/master/"
	// DefaultDockerEngineRepo for grabbing docker engine packages
	DefaultDockerEngineRepo = "https://download.docker.com/linux/ubuntu"
	// DefaultDockerComposeURL for grabbing docker images
	DefaultDockerComposeURL = "https://github.com/docker/compose/releases/download"

	//AzureEdgeDCOSBootstrapDownloadURL is the azure edge CDN download url
	AzureEdgeDCOSBootstrapDownloadURL = "https://dcosio.azureedge.net/dcos/%s/bootstrap/%s.bootstrap.tar.xz"
	//AzureChinaCloudDCOSBootstrapDownloadURL is the China specific DCOS package download url.
	AzureChinaCloudDCOSBootstrapDownloadURL = "https://acsengine.blob.core.chinacloudapi.cn/dcos/%s.bootstrap.tar.xz"
	//AzureEdgeDCOSWindowsBootstrapDownloadURL
)

const (
	//DefaultConfigurationScriptRootURL  Root URL for configuration script (used for script extension on RHEL)
	DefaultConfigurationScriptRootURL = "https://raw.githubusercontent.com/Azure/acs-engine/master/parts/"
)
<commit_msg>Update k8s windows 1.6.11 zip (#1527)<commit_after>package acsengine

import (
	"strconv"

	"github.com/Azure/acs-engine/pkg/api"
)

const (
	// DefaultMasterSubnet specifies the default master subnet for DCOS or Swarm
	DefaultMasterSubnet = "172.16.0.0/24"
	// DefaultFirstConsecutiveStaticIP specifies the static IP address on master 0 for DCOS or Swarm
	DefaultFirstConsecutiveStaticIP = "172.16.0.5"
	// DefaultSwarmWindowsMasterSubnet specifies the default master subnet for a Swarm Windows cluster
	DefaultSwarmWindowsMasterSubnet = "192.168.255.0/24"
	// DefaultSwarmWindowsFirstConsecutiveStaticIP specifies the static IP address on master 0 for a Swarm WIndows cluster
	DefaultSwarmWindowsFirstConsecutiveStaticIP = "192.168.255.5"
	// DefaultKubernetesMasterSubnet specifies the default subnet for masters and agents.
	DefaultKubernetesMasterSubnet = "10.240.0.0/16"
	// DefaultKubernetesClusterSubnet specifies the default subnet for pods.
	DefaultKubernetesClusterSubnet = "10.244.0.0/16"
	// DefaultDockerBridgeSubnet specifies the default subnet for the docker bridge network for masters and agents.
	DefaultDockerBridgeSubnet = "172.17.0.1/16"
	// DefaultFirstConsecutiveKubernetesStaticIP specifies the static IP address on Kubernetes master 0
	DefaultFirstConsecutiveKubernetesStaticIP = "10.240.255.5"
	// DefaultAgentSubnetTemplate specifies a default agent subnet
	DefaultAgentSubnetTemplate = "10.%d.0.0/16"
	// DefaultKubernetesSubnet specifies the default subnet used for all masters, agents and pods
	// when VNET integration is enabled.
	DefaultKubernetesSubnet = "10.240.0.0/12"
	// DefaultKubernetesFirstConsecutiveStaticIPOffset specifies the IP address offset of master 0
	// when VNET integration is enabled.
	DefaultKubernetesFirstConsecutiveStaticIPOffset = 5
	// DefaultKubernetesMaxPods is the maximum number of pods to run on a node.
	DefaultKubernetesMaxPods = 110
	// DefaultKubernetesMaxPodsVNETIntegrated is the maximum number of pods to run on a node when VNET integration is enabled.
	DefaultKubernetesMaxPodsVNETIntegrated = 30
	// DefaultKubernetesClusterDomain is the dns suffix used in the cluster (used as a SAN in the PKI generation)
	DefaultKubernetesClusterDomain = "cluster.local"
	// DefaultInternalLbStaticIPOffset specifies the offset of the internal LoadBalancer's IP
	// address relative to the first consecutive Kubernetes static IP
	DefaultInternalLbStaticIPOffset = 10
	// DefaultNetworkPolicy is disabling network policy enforcement
	DefaultNetworkPolicy = "none"
	// DefaultKubernetesNodeStatusUpdateFrequency is 10s, see --node-status-update-frequency at https://kubernetes.io/docs/admin/kubelet/
	DefaultKubernetesNodeStatusUpdateFrequency = "10s"
	// DefaultKubernetesCtrlMgrNodeMonitorGracePeriod is 40s, see --node-monitor-grace-period at https://kubernetes.io/docs/admin/kube-controller-manager/
	DefaultKubernetesCtrlMgrNodeMonitorGracePeriod = "40s"
	// DefaultKubernetesCtrlMgrPodEvictionTimeout is 5m0s, see --pod-eviction-timeout at https://kubernetes.io/docs/admin/kube-controller-manager/
	DefaultKubernetesCtrlMgrPodEvictionTimeout = "5m0s"
	// DefaultKubernetesCtrlMgrRouteReconciliationPeriod is 10s, see --route-reconciliation-period at https://kubernetes.io/docs/admin/kube-controller-manager/
	DefaultKubernetesCtrlMgrRouteReconciliationPeriod = "10s"
	// DefaultKubernetesCloudProviderBackoff is false to disable cloudprovider backoff implementation for API calls
	DefaultKubernetesCloudProviderBackoff = false
	// DefaultKubernetesCloudProviderBackoffRetries is 6, takes effect if DefaultKubernetesCloudProviderBackoff is true
	DefaultKubernetesCloudProviderBackoffRetries = 6
	// DefaultKubernetesCloudProviderBackoffJitter is 1, takes effect if DefaultKubernetesCloudProviderBackoff is true
	DefaultKubernetesCloudProviderBackoffJitter = 1.0
	// DefaultKubernetesCloudProviderBackoffDuration is 5, takes effect if DefaultKubernetesCloudProviderBackoff is true
	DefaultKubernetesCloudProviderBackoffDuration = 5
	// DefaultKubernetesCloudProviderBackoffExponent is 1.5, takes effect if DefaultKubernetesCloudProviderBackoff is true
	DefaultKubernetesCloudProviderBackoffExponent = 1.5
	// DefaultKubernetesCloudProviderRateLimit is false to disable cloudprovider rate limiting implementation for API calls
	DefaultKubernetesCloudProviderRateLimit = false
	// DefaultKubernetesCloudProviderRateLimitQPS is 3, takes effect if DefaultKubernetesCloudProviderRateLimit is true
	DefaultKubernetesCloudProviderRateLimitQPS = 3.0
	// DefaultKubernetesCloudProviderRateLimitBucket is 10, takes effect if DefaultKubernetesCloudProviderRateLimit is true
	DefaultKubernetesCloudProviderRateLimitBucket = 10
	// DefaultTillerImage defines the Helm Tiller deployment version on Kubernetes Clusters
	DefaultTillerImage = "tiller:v2.6.0"
	// DefaultKubernetesDNSServiceIP specifies the IP address that kube-dns
	// listens on by default. must by in the default Service CIDR range.
	DefaultKubernetesDNSServiceIP = "10.0.0.10"
	// DefaultKubernetesServiceCIDR specifies the IP subnet that kubernetes will
	// create Service IPs within.
	DefaultKubernetesServiceCIDR = "10.0.0.0/16"
	//DefaultKubernetesGCHighThreshold specifies the value for  for the image-gc-high-threshold kubelet flag
	DefaultKubernetesGCHighThreshold = 85
	//DefaultKubernetesGCLowThreshold specifies the value for the image-gc-low-threshold kubelet flag
	DefaultKubernetesGCLowThreshold = 80
)

const (
	// DCOSMaster represents the master node type
	DCOSMaster DCOSNodeType = "DCOSMaster"
	// DCOSPrivateAgent represents the private agent node type
	DCOSPrivateAgent DCOSNodeType = "DCOSPrivateAgent"
	// DCOSPublicAgent represents the public agent node type
	DCOSPublicAgent DCOSNodeType = "DCOSPublicAgent"
)

// KubeConfigs represents Docker images used for Kubernetes components based on Kubernetes releases (major.minor)
// For instance, Kubernetes release "1.7" would contain the version "1.7.2"
var KubeConfigs = map[string]map[string]string{
	api.KubernetesRelease1Dot8: {
		"hyperkube":       "hyperkube-amd64:v1.8.0",
		"dashboard":       "kubernetes-dashboard-amd64:v1.7.0",
		"exechealthz":     "exechealthz-amd64:1.2",
		"addonresizer":    "addon-resizer:1.7",
		"heapster":        "heapster-amd64:v1.4.2",
		"dns":             "k8s-dns-kube-dns-amd64:1.14.5",
		"addonmanager":    "kube-addon-manager-amd64:v6.4-beta.2",
		"dnsmasq":         "k8s-dns-dnsmasq-nanny-amd64:1.14.5",
		"pause":           "pause-amd64:3.0",
		"tiller":          DefaultTillerImage,
		"windowszip":      "v1.8.0-1intwinnat.zip",
		"nodestatusfreq":  DefaultKubernetesNodeStatusUpdateFrequency,
		"nodegraceperiod": DefaultKubernetesCtrlMgrNodeMonitorGracePeriod,
		"podeviction":     DefaultKubernetesCtrlMgrPodEvictionTimeout,
		"routeperiod":     DefaultKubernetesCtrlMgrRouteReconciliationPeriod,
		"backoffretries":  strconv.Itoa(DefaultKubernetesCloudProviderBackoffRetries),
		"backoffjitter":   strconv.FormatFloat(DefaultKubernetesCloudProviderBackoffJitter, 'f', -1, 64),
		"backoffduration": strconv.Itoa(DefaultKubernetesCloudProviderBackoffDuration),
		"backoffexponent": strconv.FormatFloat(DefaultKubernetesCloudProviderBackoffExponent, 'f', -1, 64),
		"ratelimitqps":    strconv.FormatFloat(DefaultKubernetesCloudProviderRateLimitQPS, 'f', -1, 64),
		"ratelimitbucket": strconv.Itoa(DefaultKubernetesCloudProviderRateLimitBucket),
		"gchighthreshold": strconv.Itoa(DefaultKubernetesGCHighThreshold),
		"gclowthreshold":  strconv.Itoa(DefaultKubernetesGCLowThreshold),
	},
	api.KubernetesRelease1Dot7: {
		"hyperkube":       "hyperkube-amd64:v1.7.7",
		"dashboard":       "kubernetes-dashboard-amd64:v1.6.3",
		"exechealthz":     "exechealthz-amd64:1.2",
		"addonresizer":    "addon-resizer:1.7",
		"heapster":        "heapster-amd64:v1.4.2",
		"dns":             "k8s-dns-kube-dns-amd64:1.14.5",
		"addonmanager":    "kube-addon-manager-amd64:v6.4-beta.2",
		"dnsmasq":         "k8s-dns-dnsmasq-nanny-amd64:1.14.5",
		"pause":           "pause-amd64:3.0",
		"tiller":          DefaultTillerImage,
		"windowszip":      "v1.7.7-1intwinnat.zip",
		"nodestatusfreq":  DefaultKubernetesNodeStatusUpdateFrequency,
		"nodegraceperiod": DefaultKubernetesCtrlMgrNodeMonitorGracePeriod,
		"podeviction":     DefaultKubernetesCtrlMgrPodEvictionTimeout,
		"routeperiod":     DefaultKubernetesCtrlMgrRouteReconciliationPeriod,
		"backoffretries":  strconv.Itoa(DefaultKubernetesCloudProviderBackoffRetries),
		"backoffjitter":   strconv.FormatFloat(DefaultKubernetesCloudProviderBackoffJitter, 'f', -1, 64),
		"backoffduration": strconv.Itoa(DefaultKubernetesCloudProviderBackoffDuration),
		"backoffexponent": strconv.FormatFloat(DefaultKubernetesCloudProviderBackoffExponent, 'f', -1, 64),
		"ratelimitqps":    strconv.FormatFloat(DefaultKubernetesCloudProviderRateLimitQPS, 'f', -1, 64),
		"ratelimitbucket": strconv.Itoa(DefaultKubernetesCloudProviderRateLimitBucket),
		"gchighthreshold": strconv.Itoa(DefaultKubernetesGCHighThreshold),
		"gclowthreshold":  strconv.Itoa(DefaultKubernetesGCLowThreshold),
	},
	api.KubernetesRelease1Dot6: {
		"hyperkube":       "hyperkube-amd64:v1.6.11",
		"dashboard":       "kubernetes-dashboard-amd64:v1.6.3",
		"exechealthz":     "exechealthz-amd64:1.2",
		"addonresizer":    "addon-resizer:1.7",
		"heapster":        "heapster-amd64:v1.3.0",
		"dns":             "k8s-dns-kube-dns-amd64:1.14.5",
		"addonmanager":    "kube-addon-manager-amd64:v6.4-beta.2",
		"dnsmasq":         "k8s-dns-dnsmasq-nanny-amd64:1.14.5",
		"pause":           "pause-amd64:3.0",
		"tiller":          DefaultTillerImage,
		"windowszip":      "v1.6.11-1intwinnat.zip",
		"nodestatusfreq":  DefaultKubernetesNodeStatusUpdateFrequency,
		"nodegraceperiod": DefaultKubernetesCtrlMgrNodeMonitorGracePeriod,
		"podeviction":     DefaultKubernetesCtrlMgrPodEvictionTimeout,
		"routeperiod":     DefaultKubernetesCtrlMgrRouteReconciliationPeriod,
		"backoffretries":  strconv.Itoa(DefaultKubernetesCloudProviderBackoffRetries),
		"backoffjitter":   strconv.FormatFloat(DefaultKubernetesCloudProviderBackoffJitter, 'f', -1, 64),
		"backoffduration": strconv.Itoa(DefaultKubernetesCloudProviderBackoffDuration),
		"backoffexponent": strconv.FormatFloat(DefaultKubernetesCloudProviderBackoffExponent, 'f', -1, 64),
		"ratelimitqps":    strconv.FormatFloat(DefaultKubernetesCloudProviderRateLimitQPS, 'f', -1, 64),
		"ratelimitbucket": strconv.Itoa(DefaultKubernetesCloudProviderRateLimitBucket),
		"gchighthreshold": strconv.Itoa(DefaultKubernetesGCHighThreshold),
		"gclowthreshold":  strconv.Itoa(DefaultKubernetesGCLowThreshold),
	},
	api.KubernetesRelease1Dot5: {
		"hyperkube":       "hyperkube-amd64:v1.5.8",
		"dashboard":       "kubernetes-dashboard-amd64:v1.5.1",
		"exechealthz":     "exechealthz-amd64:1.2",
		"addonresizer":    "addon-resizer:1.6",
		"heapster":        "heapster:v1.2.0",
		"dns":             "kubedns-amd64:1.7",
		"addonmanager":    "kube-addon-manager-amd64:v6.4-beta.2",
		"dnsmasq":         "kube-dnsmasq-amd64:1.3",
		"pause":           "pause-amd64:3.0",
		"tiller":          "tiller:v2.5.1",
		"windowszip":      "v1.5.7intwinnat.zip",
		"nodestatusfreq":  DefaultKubernetesNodeStatusUpdateFrequency,
		"nodegraceperiod": DefaultKubernetesCtrlMgrNodeMonitorGracePeriod,
		"podeviction":     DefaultKubernetesCtrlMgrPodEvictionTimeout,
		"routeperiod":     DefaultKubernetesCtrlMgrRouteReconciliationPeriod,
		"gchighthreshold": strconv.Itoa(DefaultKubernetesGCHighThreshold),
		"gclowthreshold":  strconv.Itoa(DefaultKubernetesGCLowThreshold),
	},
}

const (
	//DefaultExtensionsRootURL  Root URL for extensions
	DefaultExtensionsRootURL = "https://raw.githubusercontent.com/Azure/acs-engine/master/"
	// DefaultDockerEngineRepo for grabbing docker engine packages
	DefaultDockerEngineRepo = "https://download.docker.com/linux/ubuntu"
	// DefaultDockerComposeURL for grabbing docker images
	DefaultDockerComposeURL = "https://github.com/docker/compose/releases/download"

	//AzureEdgeDCOSBootstrapDownloadURL is the azure edge CDN download url
	AzureEdgeDCOSBootstrapDownloadURL = "https://dcosio.azureedge.net/dcos/%s/bootstrap/%s.bootstrap.tar.xz"
	//AzureChinaCloudDCOSBootstrapDownloadURL is the China specific DCOS package download url.
	AzureChinaCloudDCOSBootstrapDownloadURL = "https://acsengine.blob.core.chinacloudapi.cn/dcos/%s.bootstrap.tar.xz"
	//AzureEdgeDCOSWindowsBootstrapDownloadURL
)

const (
	//DefaultConfigurationScriptRootURL  Root URL for configuration script (used for script extension on RHEL)
	DefaultConfigurationScriptRootURL = "https://raw.githubusercontent.com/Azure/acs-engine/master/parts/"
)
<|endoftext|>


<commit_before>/*
Copyright 2020 Google LLC

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

    https://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 automation

import (
	"errors"
	"regexp"

	"google.golang.org/api/recommender/v1"
)

type gcloudValueMatcher = recommender.GoogleCloudRecommenderV1ValueMatcher

// Checks if the string toTest matches the member MatchesPattern of valueMatcher
// If valueMatcher is not nil. Otherwise, if value is not nil it is interpreted as string
// And equality of value.(string) and toTest is checked. If both value and valueMatcher are nil,
// then it results in an error
func test(toTest string, value interface{}, valueMatcher *gcloudValueMatcher) (bool, error) {
	if value == nil {
		if valueMatcher == nil {
			return false, errors.New("at least one of value and valueMatcher must be specified")
		}

		r, err := regexp.Compile("^" + valueMatcher.MatchesPattern + "$")
		if err != nil {
			return false, err
		}

		return r.MatchString(toTest), nil
	}

	valueString, ok := value.(string)
	if !ok {
		return false, errors.New("if value is specified it must be of type string")
	}

	return valueString == toTest, nil
}

// Checks if the machine type of the instance specified by given project, zone and instance
// matches the given value or valueMatcher
// According to Recommender API, in a test operation, either value or valueMatcher is specified.
// The value specified by the path field in the operation struct must match value or valueMatcher,
// depending on which one is defined. More can be read here:
// https://cloud.google.com/recommender/docs/reference/rest/v1/projects.locations.recommenders.recommendations#operation
func (s *googleService) TestMachineType(project string, zone string, instance string, value interface{}, valueMatcher *gcloudValueMatcher) (bool, error) {
	machineInstance, err := s.GetInstance(project, zone, instance)
	if err != nil {
		return false, err
	}

	return test(machineInstance.MachineType, value, valueMatcher)
}

// Checks if the status of the instance specified by given project, zone and instance
// matches the given value or valueMatcher
// According to Recommender API, in a test operation, either value or valueMatcher is specified.
// The value specified by the path field in the operation struct must match value or valueMatcher,
// depending on which one is defined. More can be read here:
// https://cloud.google.com/recommender/docs/reference/rest/v1/projects.locations.recommenders.recommendations#operation
func (s *googleService) TestStatus(project string, zone string, instance string, value interface{}, valueMatcher *gcloudValueMatcher) (bool, error) {
	machineInstance, err := s.GetInstance(project, zone, instance)
	if err != nil {
		return false, err
	}

	return test(machineInstance.Status, value, valueMatcher)

}
<commit_msg>Added auxiliary functions to test for matching. Changed the handling of the case, when value and valueMatcher are both nil.<commit_after>/*
Copyright 2020 Google LLC

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

    https://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 automation

import (
	"errors"
	"regexp"

	"google.golang.org/api/recommender/v1"
)

type gcloudValueMatcher = recommender.GoogleCloudRecommenderV1ValueMatcher

// Checks if the string toTest is equal to the string represented by value
// It is an error if value can't be interpreted as a string, unless
// value is nil. In that case true is returned.
func testValue(toTest string, value interface{}) (bool, error) {
	if value == nil {
		return false, nil
	}
	valueString, ok := value.(string)
	if !ok {
		return false, errors.New("if value is specified it must be of type string")
	}

	return valueString == toTest, nil
}

// Checks if the string toTest matches regex given by valueMatcher.MatchesPattern.
// If valueMatcher is nil. In that case true is returned.
func testValueMatcher(toTest string, valueMatcher *gcloudValueMatcher) (bool, error) {
	if valueMatcher == nil {
		return false, nil
	}

	r, err := regexp.Compile("^" + valueMatcher.MatchesPattern + "$")
	if err != nil {
		return false, err
	}

	return r.MatchString(toTest), nil
}

// Checks if the string toTest matches the member MatchesPattern of valueMatcher
// If valueMatcher is not nil. Otherwise, if value is not nil it is interpreted as string
// And equality of value.(string) and toTest is checked. If both value and valueMatcher are nil,
// then it results in an error
func testMatching(toTest string, value interface{}, valueMatcher *gcloudValueMatcher) (bool, error) {
	resultValue, err := testValue(toTest, value)
	if err != nil {
		return false, err
	}

	resultValueMatcher, err := testValueMatcher(toTest, valueMatcher)
	if err != nil {
		return false, err
	}

	return resultValue && resultValueMatcher, nil
}

// Checks if the machine type of the instance specified by given project, zone and instance
// matches the given value or valueMatcher
// According to Recommender API, in a test operation, either value or valueMatcher is specified.
// The value specified by the path field in the operation struct must match value or valueMatcher,
// depending on which one is defined. More can be read here:
// https://cloud.google.com/recommender/docs/reference/rest/v1/projects.locations.recommenders.recommendations#operation
func (s *googleService) TestMachineType(project string, zone string, instance string, value interface{}, valueMatcher *gcloudValueMatcher) (bool, error) {
	machineInstance, err := s.GetInstance(project, zone, instance)
	if err != nil {
		return false, err
	}

	return testMatching(machineInstance.MachineType, value, valueMatcher)
}

// Checks if the status of the instance specified by given project, zone and instance
// matches the given value or valueMatcher
// According to Recommender API, in a test operation, either value or valueMatcher is specified.
// The value specified by the path field in the operation struct must match value or valueMatcher,
// depending on which one is defined. More can be read here:
// https://cloud.google.com/recommender/docs/reference/rest/v1/projects.locations.recommenders.recommendations#operation
func (s *googleService) TestStatus(project string, zone string, instance string, value interface{}, valueMatcher *gcloudValueMatcher) (bool, error) {
	machineInstance, err := s.GetInstance(project, zone, instance)
	if err != nil {
		return false, err
	}

	return testMatching(machineInstance.Status, value, valueMatcher)

}
<|endoftext|>